MetacoSA / NBitcoin

Comprehensive Bitcoin library for the .NET framework.
MIT License
1.87k stars 846 forks source link

Trouble submitting a transaction - "Missing inputs" #520

Open replaysMike opened 6 years ago

replaysMike commented 6 years ago

I've been working through how to get a transaction submitted successfully for a couple days now and I think I'm stuck.

Here I'm generating the transaction:

var recoveredMasterKey = ExtKey.Parse("privatekeyaddress", _targetNetwork);
var privateKey = recoveredMasterKey.PrivateKey;
var client = GetNBXplorerClient();
var walletPubKey = new BitcoinExtPubKey(PublicKeyAddress);
var userDerivationScheme = client.Network.DerivationStrategyFactory
    .CreateDirectDerivationStrategy(walletPubKey.ExtPubKey,
        new DerivationStrategyOptions() {
            // Use segwit
            Legacy = true
        });
Transaction tx = Transaction.Create(_targetNetwork);
var pubKeyAddress = BitcoinAddress.Create("2N3dbULVtQ8iUVpVLLywmdmw3DyNh9WFKB9", _targetNetwork);
var utxos = client.GetUTXOs(userDerivationScheme, null, false);
var coins = utxos.GetUnspentCoins();
var keys = utxos.GetKeys(recoveredMasterKey);
var changeAddress = await client.GetUnusedAsync(userDerivationScheme, DerivationFeature.Change);

var amountToSend = new Money(5, MoneyUnit.Satoshi); //how much to send
var builder = new TransactionBuilder();
tx = builder
    .AddCoins(coins)
    .AddKeys(keys)
    .Send(pubKeyAddress, amountToSend)
    //.SubtractFees()
    .SetChange(changeAddress.ScriptPubKey)
    .SendEstimatedFees(new FeeRate(new Money(0.03743594M, MoneyUnit.BTC), 1000)) // using estimatesmartfees(1)
    .BuildTransaction(true);
var isVerified = builder.Verify(tx, out errors); // returns true
var broadcastResponse = await client.BroadcastAsync(tx); // use NBXplorer
var isSuccess = broadcastResponse.Success; // returns false

The broadcastResponse returns: RPC_TRANSACTION_ERROR Missing Inputs

and the transaction hex:

01000000013547e0bdc00e93e1eb2ad848ffe04aea15734e135bc9d92c94c274d2ed0979a8000000006a4730440220769753315850c057d14f4ef5b9a1996d5d73806cb915cb1e7ece89d98401f8de0220177a72a385c565ec8ca4e0b3f461be308d548aa155ff81267e1baf7d9852cb2f012102aff6782447c68d888440a4799339e0a6c48e48550b562dc436528844e4e58c9effffffff0176296b02000000001976a914938ccc194943b3c62fb13079f5a7a46c54e930d888ac00000000

and decoded transaction:

{
    "addresses": [
        "mrpVyS5XskJ36fnvLAQm9Q9h176yW5jiFV", 
        "mty8J21k7wBmduyzx1Mdks92mrDjM7DQxR"
    ], 
    "block_height": -1, 
    "block_index": -1, 
    "confirmations": 0, 
    "double_spend": false, 
    "fees": 465, 
    "hash": "8792c55d3d62b5c75bee8fe4952e153ff0bd6c808d6c11e16acc6ba41dd4a95f", 
    "inputs": [
        {
            "addresses": [
                "mrpVyS5XskJ36fnvLAQm9Q9h176yW5jiFV"
            ], 
            "age": 0, 
            "output_index": 0, 
            "output_value": 40577863, 
            "prev_hash": "a87909edd274c2942cd9c95b134e7315ea4ae0ff48d82aebe1930ec0bde04735", 
            "script": "4730440220769753315850c057d14f4ef5b9a1996d5d73806cb915cb1e7ece89d98401f8de0220177a72a385c565ec8ca4e0b3f461be308d548aa155ff81267e1baf7d9852cb2f012102aff6782447c68d888440a4799339e0a6c48e48550b562dc436528844e4e58c9e", 
            "script_type": "pay-to-pubkey-hash", 
            "sequence": 4294967295
        }
    ], 
    "outputs": [
        {
            "addresses": [
                "mty8J21k7wBmduyzx1Mdks92mrDjM7DQxR"
            ], 
            "script": "76a914938ccc194943b3c62fb13079f5a7a46c54e930d888ac", 
            "script_type": "pay-to-pubkey-hash", 
            "value": 40577398
        }
    ], 
    "preference": "low", 
    "received": "2018-09-03T20:50:35.318423832Z", 
    "relayed_by": "54.158.249.225", 
    "size": 191, 
    "total": 40577398, 
    "ver": 1, 
    "vin_sz": 1, 
    "vout_sz": 1
}

I'm a little stuck here.

NicolasDorier commented 6 years ago

Your code seems good.

I think your problem is that NBXplorer may have indexed the unspent coins long time ago. Then you restarted bitcoind (or restarted it from scratch?) before mining the transaction. So bitcoind is unable to find your unspent coin.

Here is a full example working

[Fact]
public void CanSendFromNBXPlorer()
{
    var provider = new NBXplorerNetworkProvider(NetworkType.Regtest);
    var nbxplorer = new ExplorerClient(provider.GetBTC());
    var rpc = new RPCClient(Network.RegTest);
    rpc.Generate(1);
    var status = nbxplorer.GetStatus();
    Assert.True(status.IsFullySynched);

    // Comment if you mined already 101 blocks
    //rpc.Generate(network.Consensus.CoinbaseMaturity + 1);

    var rootKey = new ExtKey();
    var accountKey = rootKey.Derive(new KeyPath("49'/1'/0'"));

    var expectedScriptPukey =
        accountKey.Derive(new KeyPath("0/0"))
          .PrivateKey
          .PubKey
          .WitHash.ScriptPubKey // P2WPKH
          .Hash.ScriptPubKey; // P2SH

    var factory = new DerivationStrategyFactory(Network.RegTest);
    var derivationScheme = factory.Parse($"{accountKey.Neuter().ToString(Network.RegTest)}-[p2sh]");
    nbxplorer.Track(derivationScheme);

    KeyPathInformation unused = nbxplorer.GetUnused(derivationScheme, DerivationFeature.Deposit);

    Assert.Equal(expectedScriptPukey, unused.ScriptPubKey);

    var listening = nbxplorer.CreateNotificationSession();
    listening.ListenAllDerivationSchemes();
    listening.ListenNewBlock();

    rpc.SendToAddress(unused.ScriptPubKey.GetDestinationAddress(Network.RegTest), Money.Coins(1.0m));

    // NBXplorer.Models.NewBlockEvent
    // NBXplorer.Models.NewTransactionEvent
    listening.NextEvent();

    var utxos = nbxplorer.GetUTXOs(derivationScheme, null);
    Assert.Single(utxos.Unconfirmed.UTXOs);

    var minerAddress = rpc.GetNewAddress();

    Key[] keys = utxos.GetKeys(accountKey);
    Coin[] coins = utxos.GetUnspentCoins();
    var feeRate = rpc.TryEstimateSmartFee(1)?.FeeRate ?? new FeeRate(Money.Satoshis(100), 1);

    var tx = new TransactionBuilder()
        .SetConsensusFactory(network)
        .AddCoins(coins)
        .AddKeys(keys)
        .Send(minerAddress, Money.Coins(0.1m))
        .SetChange(nbxplorer.GetUnused(derivationScheme, DerivationFeature.Change).ScriptPubKey)
        .SendEstimatedFees(feeRate)
        .BuildTransaction(true);
    Assert.True(new TransactionBuilder().SetConsensusFactory(network).AddCoins(coins).Verify(tx));
    var result = nbxplorer.Broadcast(tx);
    Assert.True(result.Success);
}
replaysMike commented 6 years ago

Hi Nicolas thanks for the response. I'm not quite sure I fully understand what you're saying, but the coins deposited into the source account were a few weeks old at most. So yes, definitely there would have been multiple restarts of NBXplorer and Bitcoin core. I noticed that when using NBXplorer I at least get an error, but with the Node client it silently passed on the transaction.

I'll see if I can get my hands on more Testnet coins as I'm now out of them, it's been difficult to find new ones with all of the faucets down.

NicolasDorier commented 6 years ago

Ah you are testing on testnet that's why.

Have you checked that the coin you are trying to spend have been confirmed?

replaysMike commented 6 years ago

Indeed I have, 88+ confirmations on the coin.

replaysMike commented 6 years ago

but I think I'm going to dump my test wallet and try again when I can find a working faucet or something. It's not entirely unlikely that I screwed something up.

NicolasDorier commented 6 years ago

Can you try again your code? Because when you posted the issue, the coin did not had confirmation.

replaysMike commented 6 years ago

hmm interesting, I'll try again

NicolasDorier commented 6 years ago

any news?

witterlee commented 5 years ago

same problem: I try use same inputs , outpus to create tx, but nbitcoin's signedtx retrun miss inputs;

here is the signed raw tx

testnet : use nbitcoin sign tx 0100000001a7c8aabeca0bef825e5d1177f4d60b7f071f2e0da97cf9012715c956d778815a020000006a47304402206dd14f6615cb4e0dc922e1b75b5968f15fdca73aebaed8af8369f72c8e69adee02204dce92ca07d440626f8e42694702a40d008622125d9c8e4adbc49752443fc4e80121026fe485b5ff7420da0be833560c1d179b02e8f9ea50b1b7d347004b9b50f097dfffffffff02c8f681020000000017a9142166c2c5d2a11ae6f1e6707195f57948973b726287f07e0e000000000017a9149a9f750a49dc4a553904b3c1a19318d74fabc1b88700000000

use bitcoin 0.17 sign tx 02000000000101a7c8aabeca0bef825e5d1177f4d60b7f071f2e0da97cf9012715c956d778815a02000000171600147bb4327ddea9180e90b1b788984326f03a6f5816ffffffff02f07e0e000000000017a9149a9f750a49dc4a553904b3c1a19318d74fabc1b887c8f681020000000017a9142166c2c5d2a11ae6f1e6707195f57948973b726287024730440220426b774bed54cfa4ff1f16c1ac41aa420264159d0fdb4b9fb56a91d9c6707197022060f6261629fcb7c529084b84e7f76e2602c6a791913f90b058c8326d30a189040121026fe485b5ff7420da0be833560c1d179b02e8f9ea50b1b7d347004b9b50f097df00000000

lontivero commented 5 years ago

The coin is already spent https://testnet.smartbit.com.au/tx/a87909edd274c2942cd9c95b134e7315ea4ae0ff48d82aebe1930ec0bde04735

witterlee commented 5 years ago

@lontivero yes,I have use the bitcoin 0.17 send it out. It is not spent when I test it.

bitcoinbrisbane commented 4 years ago

Ive got the same issue. Was working great, then our node went down.