public async Task AcceptToMemoryPool_WithP2WSHValidTxns_IsSuccessfullAsync() { string dataDir = GetTestDirectoryPath(this); var miner = new BitcoinSecret(new Key(), Network.RegTest); ITestChainContext context = await TestChainFactory.CreateAsync(Network.RegTest, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey, dataDir); IMempoolValidator validator = context.MempoolValidator; Assert.NotNull(validator); var bob = new BitcoinSecret(new Key(), Network.RegTest); // Fund Bob // 50 Coins come from first tx on chain - send bob 42 and change back to miner ScriptCoin witnessCoin = ScriptCoin.Create(Network.RegTest, context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey, miner.PubKey.ScriptPubKey).AssertCoherent(Network.RegTest); var txBuilder = new TransactionBuilder(Network.RegTest); Transaction p2wshTx = txBuilder .AddCoins(witnessCoin) .AddKeys(miner) .Send(bob, "42.00") .SendFees("0.001") .SetChange(miner) .BuildTransaction(true); Assert.True(txBuilder.Verify(p2wshTx)); //check fully signed var state = new MempoolValidationState(false); Assert.True(await validator.AcceptToMemoryPool(state, p2wshTx), $"Transaction: {nameof(p2wshTx)} failed mempool validation."); }
public async Task AcceptToMemoryPool_WithValidP2PKHTxn_IsSuccessfullAsync() { string dataDir = Path.Combine("TestData", nameof(MempoolValidatorTest), nameof(this.AcceptToMemoryPool_WithValidP2PKHTxn_IsSuccessfullAsync)); Directory.CreateDirectory(dataDir); BitcoinSecret minerSecret = new BitcoinSecret(new Key(), Network.RegTest); ITestChainContext context = await TestChainFactory.CreateAsync(Network.RegTest, minerSecret.PubKey.Hash.ScriptPubKey, dataDir); IMempoolValidator validator = context.MempoolValidator; Assert.NotNull(validator); BitcoinSecret destSecret = new BitcoinSecret(new Key(), Network.RegTest); Transaction tx = new Transaction(); tx.AddInput(new TxIn(new OutPoint(context.SrcTxs[0].GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(minerSecret.PubKey))); tx.AddOutput(new TxOut(new Money(Money.CENT * 11), destSecret.PubKeyHash)); tx.Sign(minerSecret, false); MempoolValidationState state = new MempoolValidationState(false); bool isSuccess = await validator.AcceptToMemoryPool(state, tx); Assert.True(isSuccess, "P2PKH tx not valid."); Directory.Delete(dataDir, true); }
public async void AcceptToMemoryPool_TxAncestorsConflictSpend_ReturnsFalseAsync() { // TODO: Execute failure cases for CheckAncestors // - conflicting spend transaction string dataDir = GetTestDirectoryPath(this); var miner = new BitcoinSecret(new Key(), Network.RegTest); ITestChainContext context = await TestChainFactory.CreateAsync(Network.RegTest, miner.PubKey.Hash.ScriptPubKey, dataDir).ConfigureAwait(false); IMempoolValidator validator = context.MempoolValidator; var bob = new BitcoinSecret(new Key(), Network.RegTest); var txBuilder = new TransactionBuilder(Network.RegTest); //Create Coin from first tx on chain var coin = new Coin(context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(miner.PubKey)); //Send 10 to Bob and return the rest as change to miner Transaction originalTx = txBuilder .AddCoins(coin) .AddKeys(miner) .Send(bob, "10.00") .SendFees("0.001") .SetChange(miner) .BuildTransaction(true); var state = new MempoolValidationState(false); //Mempool should accept it, there's nothing wrong Assert.True(await validator.AcceptToMemoryPool(state, originalTx).ConfigureAwait(false), $"Transaction: {nameof(originalTx)} failed mempool validation."); //Create second transaction spending the same coin Transaction conflictingTx = txBuilder .AddCoins(coin) .AddKeys(miner) .Send(bob, "10.00") .SendFees("0.001") .SetChange(miner) .BuildTransaction(true); //Mempool should reject the second transaction Assert.False(await validator.AcceptToMemoryPool(state, conflictingTx).ConfigureAwait(false), $"Transaction: {nameof(conflictingTx)} should have failed mempool validation."); Directory.Delete(dataDir, true); }
public async Task AcceptToMemoryPool_WithSegWitValidTxns_IsSuccessfullAsync() { string dataDir = Path.Combine("TestData", nameof(MempoolValidatorTest), nameof(this.AcceptToMemoryPool_WithSegWitValidTxns_IsSuccessfullAsync)); Directory.CreateDirectory(dataDir); BitcoinSecret miner = new BitcoinSecret(new Key(), Network.RegTest); ITestChainContext context = await TestChainFactory.CreateAsync(Network.RegTest, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey.Hash.ScriptPubKey, dataDir); IMempoolValidator validator = context.MempoolValidator; Assert.NotNull(validator); BitcoinSecret bob = new BitcoinSecret(new Key(), Network.RegTest); // Fund Bob // 50 Coins come from first tx on chain - send bob 42 and change back to miner ScriptCoin witnessCoin = new ScriptCoin(context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey.Hash.ScriptPubKey, miner.PubKey.ScriptPubKey); TransactionBuilder txBuilder = new TransactionBuilder(); Transaction p2shOverp2wpkh = txBuilder .AddCoins(witnessCoin) .AddKeys(miner) .Send(bob, "42.00") .SendFees("0.001") .SetChange(miner) .BuildTransaction(true); Assert.True(txBuilder.Verify(p2shOverp2wpkh)); //check fully signed // remove witness data from tx Transaction noWitTx = p2shOverp2wpkh.WithOptions(TransactionOptions.None); Assert.Equal(p2shOverp2wpkh.GetHash(), noWitTx.GetHash()); Assert.True(noWitTx.GetSerializedSize() < p2shOverp2wpkh.GetSerializedSize()); Assert.True(txBuilder.Verify(p2shOverp2wpkh)); //check fully signed MempoolValidationState state = new MempoolValidationState(false); Assert.True(await validator.AcceptToMemoryPool(state, p2shOverp2wpkh), $"Transaction: {nameof(p2shOverp2wpkh)} failed mempool validation."); Directory.Delete(dataDir, true); }
public async Task AcceptToMemoryPool_WithP2SHValidTxns_IsSuccessfullAsync() { string dataDir = GetTestDirectoryPath(this); var miner = new BitcoinSecret(new Key(), Network.RegTest); ITestChainContext context = await TestChainFactory.CreateAsync(Network.RegTest, miner.PubKey.Hash.ScriptPubKey, dataDir); IMempoolValidator validator = context.MempoolValidator; Assert.NotNull(validator); var alice = new BitcoinSecret(new Key(), Network.RegTest); var bob = new BitcoinSecret(new Key(), Network.RegTest); var satoshi = new BitcoinSecret(new Key(), Network.RegTest); var nico = new BitcoinSecret(new Key(), Network.RegTest); // corp needs two out of three of alice, bob, nico Script corpMultiSig = PayToMultiSigTemplate .Instance .GenerateScriptPubKey(2, new[] { alice.PubKey, bob.PubKey, nico.PubKey }); // P2SH address for corp multi-sig BitcoinScriptAddress corpRedeemAddress = corpMultiSig.GetScriptAddress(Network.RegTest); // Fund corp // 50 Coins come from first tx on chain - send corp 42 and change back to miner var coin = new Coin(context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, miner.ScriptPubKey); var txBuilder = new TransactionBuilder(Network.RegTest); Transaction fundP2shTx = txBuilder .AddCoins(new List <Coin> { coin }) .AddKeys(miner) .Send(corpRedeemAddress, "42.00") .SendFees("0.001") .SetChange(miner.GetAddress()) .BuildTransaction(true); Assert.True(txBuilder.Verify(fundP2shTx)); //check fully signed var state = new MempoolValidationState(false); Assert.True(await validator.AcceptToMemoryPool(state, fundP2shTx), $"Transaction: {nameof(fundP2shTx)} failed mempool validation."); // AliceBobNico corp. send 20 to Satoshi Coin[] corpCoins = fundP2shTx.Outputs .Where(o => o.ScriptPubKey == corpRedeemAddress.ScriptPubKey) .Select(o => ScriptCoin.Create(Network.RegTest, new OutPoint(fundP2shTx.GetHash(), fundP2shTx.Outputs.IndexOf(o)), o, corpMultiSig)) .ToArray(); txBuilder = new TransactionBuilder(Network.RegTest); Transaction p2shSpendTx = txBuilder .AddCoins(corpCoins) .AddKeys(alice, bob) .Send(satoshi.GetAddress(), "20") .SendFees("0.001") .SetChange(corpRedeemAddress) .BuildTransaction(true); Assert.True(txBuilder.Verify(p2shSpendTx)); Assert.True(await validator.AcceptToMemoryPool(state, p2shSpendTx), $"Transaction: {nameof(p2shSpendTx)} failed mempool validation."); }
public async Task AcceptToMemoryPool_WithMultiSigValidTxns_IsSuccessfullAsync() { string dataDir = GetTestDirectoryPath(this); var miner = new BitcoinSecret(new Key(), Network.RegTest); ITestChainContext context = await TestChainFactory.CreateAsync(Network.RegTest, miner.PubKey.Hash.ScriptPubKey, dataDir); IMempoolValidator validator = context.MempoolValidator; Assert.NotNull(validator); var alice = new BitcoinSecret(new Key(), Network.RegTest); var bob = new BitcoinSecret(new Key(), Network.RegTest); var satoshi = new BitcoinSecret(new Key(), Network.RegTest); var nico = new BitcoinSecret(new Key(), Network.RegTest); // corp needs two out of three of alice, bob, nico Script corpMultiSig = PayToMultiSigTemplate .Instance .GenerateScriptPubKey(2, new[] { alice.PubKey, bob.PubKey, nico.PubKey }); // Fund corp // 50 Coins come from first tx on chain - send corp 42 and change back to miner var coin = new Coin(context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, miner.ScriptPubKey); var txBuilder = new TransactionBuilder(Network.RegTest); Transaction sendToMultiSigTx = txBuilder .AddCoins(new List <Coin> { coin }) .AddKeys(miner) .Send(corpMultiSig, "42.00") .SendFees("0.001") .SetChange(miner.GetAddress()) .BuildTransaction(true); Assert.True(txBuilder.Verify(sendToMultiSigTx)); //check fully signed var state = new MempoolValidationState(false); Assert.True(await validator.AcceptToMemoryPool(state, sendToMultiSigTx), $"Transaction: {nameof(sendToMultiSigTx)} failed mempool validation."); // AliceBobNico corp. send to Satoshi Coin[] corpCoins = sendToMultiSigTx.Outputs .Where(o => o.ScriptPubKey == corpMultiSig) .Select(o => new Coin(new OutPoint(sendToMultiSigTx.GetHash(), sendToMultiSigTx.Outputs.IndexOf(o)), o)) .ToArray(); // Alice initiates the transaction txBuilder = new TransactionBuilder(Network.RegTest); Transaction multiSigTx = txBuilder .AddCoins(corpCoins) .AddKeys(alice) .Send(satoshi.GetAddress(), "4.5") .SendFees("0.001") .SetChange(corpMultiSig) .BuildTransaction(true); Assert.True(!txBuilder.Verify(multiSigTx)); //Well, only one signature on the two required... // Nico completes the transaction txBuilder = new TransactionBuilder(Network.RegTest); multiSigTx = txBuilder .AddCoins(corpCoins) .AddKeys(nico) .SignTransaction(multiSigTx); Assert.True(txBuilder.Verify(multiSigTx)); Assert.True(await validator.AcceptToMemoryPool(state, multiSigTx), $"Transaction: {nameof(multiSigTx)} failed mempool validation."); }
public async Task AcceptToMemoryPool_WithMultiInOutValidTxns_IsSuccessfullAsync() { string dataDir = GetTestDirectoryPath(this); var miner = new BitcoinSecret(new Key(), Network.RegTest); ITestChainContext context = await TestChainFactory.CreateAsync(Network.RegTest, miner.PubKey.Hash.ScriptPubKey, dataDir); IMempoolValidator validator = context.MempoolValidator; Assert.NotNull(validator); var alice = new BitcoinSecret(new Key(), Network.RegTest); var bob = new BitcoinSecret(new Key(), Network.RegTest); var satoshi = new BitcoinSecret(new Key(), Network.RegTest); // Fund Alice, Bob, Satoshi // 50 Coins come from first tx on chain - send satoshi 1, bob 2, Alice 1.5 and change back to miner var coin = new Coin(context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, miner.ScriptPubKey); var txBuilder = new TransactionBuilder(Network.RegTest); Transaction multiOutputTx = txBuilder .AddCoins(new List <Coin> { coin }) .AddKeys(miner) .Send(satoshi.GetAddress(), "1.00") .Send(bob.GetAddress(), "2.00") .Send(alice.GetAddress(), "1.50") .SendFees("0.001") .SetChange(miner.GetAddress()) .BuildTransaction(true); Assert.True(txBuilder.Verify(multiOutputTx)); //check fully signed var state = new MempoolValidationState(false); Assert.True(await validator.AcceptToMemoryPool(state, multiOutputTx), $"Transaction: {nameof(multiOutputTx)} failed mempool validation."); // Alice then Bob sends to Satoshi Coin[] aliceCoins = multiOutputTx.Outputs .Where(o => o.ScriptPubKey == alice.ScriptPubKey) .Select(o => new Coin(new OutPoint(multiOutputTx.GetHash(), multiOutputTx.Outputs.IndexOf(o)), o)) .ToArray(); Coin[] bobCoins = multiOutputTx.Outputs .Where(o => o.ScriptPubKey == bob.ScriptPubKey) .Select(o => new Coin(new OutPoint(multiOutputTx.GetHash(), multiOutputTx.Outputs.IndexOf(o)), o)) .ToArray(); txBuilder = new TransactionBuilder(Network.RegTest); Transaction multiInputTx = txBuilder .AddCoins(aliceCoins) .AddKeys(alice) .Send(satoshi.GetAddress(), "0.8") .SetChange(alice.GetAddress()) .SendFees("0.0005") .Then() .AddCoins(bobCoins) .AddKeys(bob) .Send(satoshi.GetAddress(), "0.2") .SetChange(bob.GetAddress()) .SendFees("0.0005") .BuildTransaction(true); Assert.True(txBuilder.Verify(multiInputTx)); //check fully signed Assert.True(await validator.AcceptToMemoryPool(state, multiInputTx), $"Transaction: {nameof(multiInputTx)} failed mempool validation."); }