MetacoSA / QBitNinja

An Open Source and powerful blockchain API
MIT License
69 stars 42 forks source link

Please help me to overcome broadcast transaction. #35

Closed cryptodeveloperin closed 6 years ago

cryptodeveloperin commented 6 years ago

I have automate btc sending from c# webapplication using following code. This following code works sometime but sometime not works. If i use the transaction.tohex() and paste to https://testnet.smartbit.com.au/txs then it will transfer the btc. Please let me know what is wrong? I am using nbitcoin version 39. i want permanent solution. please help me. Because i want to make my code live tomorrow.

transaction.Inputs.Add(new TxIn(coin.Outpoint, masterKey.ExtKey.Derive((uint)txBalance.UserAutoId).ScriptPubKey));

        // calculate what amount of bitcoin needed to be send
        Money currrentBalance = new Money(currentBalanceDecimal, MoneyUnit.BTC);
        Money minerFee = new Money(fee, MoneyUnit.BTC);
        Money receiverAmount = new Money(amount, MoneyUnit.BTC);
        Money changeBackAmount = currrentBalance - receiverAmount - minerFee;

        Script receiverScriptPubKey = new BitcoinPubKeyAddress(receiverAdress).ScriptPubKey;

        transaction.Outputs.Add(new TxOut
        {
            Value = receiverAmount,
            ScriptPubKey = receiverScriptPubKey
        });
        if (changeBackAmount > 0)
        {
            transaction.Outputs.Add(new TxOut
            {
                Value = changeBackAmount,
                ScriptPubKey = masterPubKey.Derive((uint)lastUserAutoIdTransactionChange).ScriptPubKey
            });
        }

        // sign transaction
        var keys = new List<ExtKey>();
        foreach (var userAutoId in txBalanceListToUse.Select(x => x.UserAutoId).Distinct())
            keys.Add(masterKey.ExtKey.Derive((uint)userAutoId));

        transaction.Sign(keys.ToArray(), coinList.ToArray());

        var builder = new TransactionBuilder();
        NBitcoin.Policy.TransactionPolicyError[] error = null;
        builder.AddCoins(coinList.ToArray());
        bool verifyTransactionHash = builder.Verify(transaction, out error);

        if (verifyTransactionHash == true && error.Length == 0)
        {
            // Broadcast your transaction to all miners
            BroadcastResponse broadcastResponse = client.Broadcast(transaction).Result;
            if (!broadcastResponse.Success)
                throw new Exception(broadcastResponse.Error.Reason);

}

NicolasDorier commented 6 years ago

The likely reason it does not work is because of race conditions.

Imagine both Alice and Bob ask to send to Satoshi at same time.

Alice:

Now because Alice and Bob are both using the same UTXO 1, one of those transaction will fail.

You should keep track locally of the UTXO you used so that you can filter them out before feeding the transaction builder with the coins.