1

I am writing tests for an app I built that uses NBitcoin to send bitcoin and make bitcoin transactions.

I have the following code to create fake bitcoins for an integration test:

private ICoin[] CreateFakeCoins(TxInList inputs, Script scriptPubKey)
{
    var coins = inputs.Select(i => new Coin(i.PrevOut, inputs.Transaction.Outputs.CreateNewTxOut(Money.Coins(0.1m), scriptPubKey.WitHash.ScriptPubKey))).ToArray();
    for (int i = 0; i < coins.Length; i++)
    {
        coins[i] = coins[i].ToScriptCoin(scriptPubKey);
    }
    return coins;
}

My integration test has this piece of code that's supposed to send the fake bitcoins to another wallet.

var k = new BitcoinSecret(new Key(), Network.TestNet);
var moneyInWallet1 = BitcoinHelper.GetBitcoinAddress(walletTestNet?.Address, Network.TestNet);

Transaction tx = Network.TestNet.CreateTransaction();
var privkey = new BitcoinSecret(walletTestNet?.Address, Network.TestNet);
var scriptPubKey = PayToWitScriptHashTemplate.Instance.GenerateScriptPubKey(k.PubKey.ScriptPubKey.WitHash);
var scriptPubKeyRec = PayToWitScriptHashTemplate.Instance.GenerateScriptPubKey(privkey.PubKey.ScriptPubKey.WitHash);

tx.Inputs.Add(new OutPoint(tx.GetHash(), 0), scriptPubKey.ToWitScript());
tx.Inputs.Add(new OutPoint(tx.GetHash(), 1), scriptPubKey.ToWitScript());
tx.Outputs.Add("21", k.PubKey.WitHash);
tx.Sign(new[] { k }, CreateFakeCoins(tx.Inputs, scriptPubKey));

Assert.Equal(k.GetAddress(ScriptPubKeyType.Segwit).ToString().Substring(0, 3), "tb1");
Assert.Equal(tx.Outputs[0].Value.Satoshi / 100000000, 21);
Assert.Equal(moneyInWallet1.Address.ToString().Substring(0, 3), "tb1");

var builder = Network.TestNet.CreateTransactionBuilder();
var (receiveAddress, receiveBtcSecret) = BitcoinHelper.GetBitcoinAddress(privKeyCurrent, Network.TestNet);
var (fromAddressProcessed, fromBtcSecret) = BitcoinHelper.GetBitcoinAddress(walletTestNet?.Address, Network.TestNet);
            
var amountSatoshiMult = Math.Ceiling(0.0006*100000000.00);
Money amountConvertedtoMoney = new Money((long)amountSatoshiMult);

var testibleOutputs = tx.Outputs.AsCoins().Cast<ICoin>().ToArray();
var txBuild = builder
    .AddCoins(testibleOutputs)
    .AddKeys(fromBtcSecret)
    .Send(receiveAddress, amountConvertedtoMoney)
    .SetChange(fromAddressProcessed, ChangeType.All)
    .SendFees(Money.Coins(new decimal(0.0001)));

NBitcoin.Policy.TransactionPolicyError[] errors = null;
Transaction nextTx = txBuild.BuildTransaction(true);
var testerForBuilder = builder.Verify(nextTx, out errors);
Console.WriteLine(errors);
Console.WriteLine(testerForBuilder);
Assert.Equal(true, testerForBuilder);

In this code, the BitcoinHelper.GetBitcoinAddress function simply receives an address string and returns a proper NBitcoin BitcoinAddress object.

This is a picture of the error I get:
enter image description here

Notice the WitnessProgramMissmatch error.

What is the problem? Is CreateFakeCoins not correctly creating fake coins for testing? How can I make this work?

1

1 Answer 1

0

The fix was simple. I changed:

tx.Outputs.Add("21", k.PubKey.WitHash);
tx.Sign(new[] { k }, CreateFakeCoins(tx.Inputs, scriptPubKey));

To

tx.Outputs.Add("21", privkey.PubKey.WitHash);
tx.Sign(new[] { k }, CreateFakeCoins(tx.Inputs, scriptPubKey.ToWitScript()));

After this it worked. I was adding the 21 coins to the receiving private key, not the sending private key. Also I had to convert scriptPubKey which was a Script to a WitScript.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.