public void Given_NodesAreSynced_When_ABigReorgHappens_Then_TheReorgIsIgnored() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisMiner = builder.CreateStratisPosNode(this.posNetwork); CoreNode stratisSyncer = builder.CreateStratisPosNode(this.posNetwork); CoreNode stratisReorg = builder.CreateStratisPosNode(this.posNetwork); builder.StartAll(); stratisMiner.NotInIBD().WithWallet(); stratisSyncer.NotInIBD(); stratisReorg.NotInIBD().WithWallet(); TestHelper.MineBlocks(stratisMiner, 1); // wait for block repo for block sync to work stratisMiner.CreateRPCClient().AddNode(stratisReorg.Endpoint, true); stratisMiner.CreateRPCClient().AddNode(stratisSyncer.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisSyncer)); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisReorg)); // create a reorg by mining on two different chains // ================================================ stratisMiner.CreateRPCClient().RemoveNode(stratisReorg.Endpoint); stratisSyncer.CreateRPCClient().RemoveNode(stratisReorg.Endpoint); TestHelper.WaitLoop(() => !TestHelper.IsNodeConnected(stratisReorg)); TestHelper.MineBlocks(stratisMiner, 11); TestHelper.MineBlocks(stratisReorg, 12); // make sure the nodes are actually on different chains. Assert.NotEqual(stratisMiner.FullNode.Chain.GetBlock(2).HashBlock, stratisReorg.FullNode.Chain.GetBlock(2).HashBlock); TestHelper.TriggerSync(stratisSyncer); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisSyncer)); // The hash before the reorg node is connected. uint256 hashBeforeReorg = stratisMiner.FullNode.Chain.Tip.HashBlock; // connect the reorg chain stratisMiner.CreateRPCClient().AddNode(stratisReorg.Endpoint, true); stratisSyncer.CreateRPCClient().AddNode(stratisReorg.Endpoint, true); // trigger nodes to sync TestHelper.TriggerSync(stratisMiner); TestHelper.TriggerSync(stratisReorg); TestHelper.TriggerSync(stratisSyncer); // wait for the synced chain to get headers updated. TestHelper.WaitLoop(() => !stratisReorg.FullNode.ConnectionManager.ConnectedPeers.Any()); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisSyncer)); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisReorg, stratisMiner) == false); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisReorg, stratisSyncer) == false); // check that a reorg did not happen. Assert.Equal(hashBeforeReorg, stratisSyncer.FullNode.Chain.Tip.HashBlock); } }
public void SegwitWalletTransactionBuildingTest_SendToBech32AndNormalDestination() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode node = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).WithWallet().Start(); CoreNode listener = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).WithWallet().Start(); TestHelper.Connect(listener, node); var mineAddress = node.FullNode.WalletManager().GetUnusedAddress(); int maturity = (int)node.FullNode.Network.Consensus.CoinbaseMaturity; var miner = node.FullNode.NodeService <IPowMining>() as PowMining; miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), (ulong)(maturity + 1), int.MaxValue); TestHelper.WaitForNodeToSync(node, listener); var destinationAddress = node.FullNode.WalletManager().GetUnusedAddress(); var witAddress = destinationAddress.Bech32Address; var nonWitAddress = destinationAddress.Address; IActionResult transactionResult = node.FullNode.NodeController <WalletController>() .BuildTransaction(new BuildTransactionRequest { AccountName = "account 0", AllowUnconfirmed = true, Recipients = new List <RecipientModel> { new RecipientModel { DestinationAddress = witAddress, Amount = Money.Coins(1).ToString() } }, Password = node.WalletPassword, WalletName = node.WalletName, FeeAmount = Money.Coins(0.001m).ToString() }).GetAwaiter().GetResult(); var walletBuildTransactionModel = (WalletBuildTransactionModel)(transactionResult as JsonResult)?.Value; node.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(walletBuildTransactionModel.Hex)); Transaction witFunds = node.FullNode.Network.CreateTransaction(walletBuildTransactionModel.Hex); uint witIndex = witFunds.Outputs.AsIndexedOutputs().First(o => o.TxOut.ScriptPubKey.IsScriptType(ScriptType.P2WPKH)).N; TestBase.WaitLoop(() => listener.CreateRPCClient().GetBlockCount() >= (maturity + 1), cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), 1, int.MaxValue); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); // Make sure wallet is synced. TestBase.WaitLoop(() => node.CreateRPCClient().GetBlockCount() == node.FullNode.WalletManager().LastBlockHeight(), cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); // By sending more than the size of the P2WPKH UTXO, we guarantee that at least one non-P2WPKH UTXO gets included transactionResult = node.FullNode.NodeController <WalletController>() .BuildTransaction(new BuildTransactionRequest { AccountName = "account 0", AllowUnconfirmed = true, Outpoints = new List <OutpointRequest>() { new OutpointRequest() { Index = (int)witIndex, TransactionId = witFunds.GetHash().ToString() } }, Recipients = new List <RecipientModel> { new RecipientModel { DestinationAddress = witAddress, Amount = Money.Coins(0.4m).ToString() }, new RecipientModel { DestinationAddress = nonWitAddress, Amount = Money.Coins(0.4m).ToString() } }, Password = node.WalletPassword, WalletName = node.WalletName, FeeAmount = Money.Coins(0.001m).ToString() }).GetAwaiter().GetResult(); walletBuildTransactionModel = (WalletBuildTransactionModel)(transactionResult as JsonResult)?.Value; node.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(walletBuildTransactionModel.Hex)); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), 1, int.MaxValue); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); } }
public void CanCoreSyncFromStratis() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNode = builder.CreateStratisPowNode(this.powNetwork); CoreNode coreNodeSync = builder.CreateBitcoinCoreNode(); CoreNode coreCreateNode = builder.CreateBitcoinCoreNode(); builder.StartAll(); stratisNode.NotInIBD(); // first seed a core node with blocks and sync them to a stratis node // and wait till the stratis node is fully synced Block tip = coreCreateNode.FindBlock(5).Last(); stratisNode.CreateRPCClient().AddNode(coreCreateNode.Endpoint, true); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreCreateNode.CreateRPCClient().GetBestBlockHash()); TestHelper.WaitLoop(() => stratisNode.FullNode.GetBlockStoreTip().HashBlock == stratisNode.FullNode.Chain.Tip.HashBlock); uint256 bestBlockHash = stratisNode.CreateRPCClient().GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); // add a new stratis node which will download // the blocks using the GetData payload coreNodeSync.CreateRPCClient().AddNode(stratisNode.Endpoint, true); // wait for download and assert TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNodeSync.CreateRPCClient().GetBestBlockHash()); bestBlockHash = coreNodeSync.CreateRPCClient().GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); } }
public void Given_NodesAreSynced_When_ABigReorgHappens_Then_TheReorgIsIgnored() { // Temporary fix so the Network static initialize will not break. Network m = Network.Main; using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisMiner = builder.CreateStratisPosNode(); CoreNode stratisSyncer = builder.CreateStratisPosNode(); CoreNode stratisReorg = builder.CreateStratisPosNode(); builder.StartAll(); stratisMiner.NotInIBD(); stratisSyncer.NotInIBD(); stratisReorg.NotInIBD(); // TODO: set the max allowed reorg threshold here // assume a reorg of 10 blocks is not allowed. stratisMiner.FullNode.ChainBehaviorState.MaxReorgLength = 10; stratisSyncer.FullNode.ChainBehaviorState.MaxReorgLength = 10; stratisReorg.FullNode.ChainBehaviorState.MaxReorgLength = 10; stratisMiner.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisMiner.FullNode.Network)); stratisReorg.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisReorg.FullNode.Network)); stratisMiner.GenerateStratisWithMiner(1); // wait for block repo for block sync to work TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisMiner)); stratisMiner.CreateRPCClient().AddNode(stratisReorg.Endpoint, true); stratisMiner.CreateRPCClient().AddNode(stratisSyncer.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisSyncer)); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisReorg)); // create a reorg by mining on two different chains // ================================================ stratisMiner.CreateRPCClient().RemoveNode(stratisReorg.Endpoint); stratisSyncer.CreateRPCClient().RemoveNode(stratisReorg.Endpoint); TestHelper.WaitLoop(() => !TestHelper.IsNodeConnected(stratisReorg)); Task <List <uint256> > t1 = Task.Run(() => stratisMiner.GenerateStratisWithMiner(11)); Task <List <uint256> > t2 = Task.Delay(1000).ContinueWith(t => stratisReorg.GenerateStratisWithMiner(12)); Task.WaitAll(t1, t2); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisMiner)); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisReorg)); // make sure the nodes are actually on different chains. Assert.NotEqual(stratisMiner.FullNode.Chain.GetBlock(2).HashBlock, stratisReorg.FullNode.Chain.GetBlock(2).HashBlock); TestHelper.TriggerSync(stratisSyncer); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisSyncer)); // The hash before the reorg node is connected. uint256 hashBeforeReorg = stratisMiner.FullNode.Chain.Tip.HashBlock; // connect the reorg chain stratisMiner.CreateRPCClient().AddNode(stratisReorg.Endpoint, true); stratisSyncer.CreateRPCClient().AddNode(stratisReorg.Endpoint, true); // trigger nodes to sync TestHelper.TriggerSync(stratisMiner); TestHelper.TriggerSync(stratisReorg); TestHelper.TriggerSync(stratisSyncer); // wait for the synced chain to get headers updated. TestHelper.WaitLoop(() => !stratisReorg.FullNode.ConnectionManager.ConnectedPeers.Any()); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMiner, stratisSyncer)); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisReorg, stratisMiner) == false); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisReorg, stratisSyncer) == false); // check that a reorg did not happen. Assert.Equal(hashBeforeReorg, stratisSyncer.FullNode.Chain.Tip.HashBlock); } }
public void CheckSegwitP2PSerialisationForNonWitnessNode() { using (NodeBuilder builder = NodeBuilder.Create(this)) { // We have to name the networks differently because the NBitcoin network registration won't allow two identical networks to coexist otherwise. var network = new StraxRegTest(); network.SetPrivatePropertyValue("Name", "StraxRegTestWithDeployments"); Assert.NotNull(network.Consensus.BIP9Deployments[2]); var networkNoBIP9 = new StraxRegTest(); networkNoBIP9.SetPrivatePropertyValue("Name", "StraxRegTestWithoutDeployments"); Assert.NotNull(networkNoBIP9.Consensus.BIP9Deployments[2]); // Remove BIP9 deployments (i.e. segwit). for (int i = 0; i < networkNoBIP9.Consensus.BIP9Deployments.Length; i++) { networkNoBIP9.Consensus.BIP9Deployments[i] = null; } // Ensure the workaround had the desired effect. Assert.Null(networkNoBIP9.Consensus.BIP9Deployments[2]); Assert.NotNull(network.Consensus.BIP9Deployments[2]); // Explicitly use new & separate instances of StratisRegTest because we modified the BIP9 deployments on one instance. CoreNode node = builder.CreateStratisPosNode(network).Start(); CoreNode listener = builder.CreateStratisPosNode(networkNoBIP9).Start(); // Sanity check. Assert.Null(listener.FullNode.Network.Consensus.BIP9Deployments[2]); Assert.NotNull(node.FullNode.Network.Consensus.BIP9Deployments[2]); // By disabling Segwit on the listener node we also prevent the WitnessCommitments rule from rejecting the mining node's blocks once we modify the listener's peer services. IConnectionManager listenerConnMan = listener.FullNode.NodeService <IConnectionManager>(); listenerConnMan.Parameters.TemplateBehaviors.Add(new TestBehavior()); // Override the listener node's default settings, so that it will not ask for witness data in P2P messages. listenerConnMan.Parameters.Services &= ~NetworkPeerServices.NODE_WITNESS; TestHelper.Connect(listener, node); // Mine a Segwit block on the first node. It should have commitment data as its settings have not been modified. var script = new Key().PubKey.WitHash.ScriptPubKey; var miner = node.FullNode.NodeService <IPowMining>() as PowMining; List <uint256> res = miner.GenerateBlocks(new ReserveScript(script), 1, int.MaxValue); Block block = node.FullNode.ChainIndexer.GetHeader(res.First()).Block; Script commitment = WitnessCommitmentsRule.GetWitnessCommitment(node.FullNode.Network, block); Assert.NotNull(commitment); // The listener should sync the mined block without validation failures. var cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token; TestBase.WaitLoop(() => listener.CreateRPCClient().GetBlockCount() >= 1, cancellationToken: cancellationToken); // We need to capture a message on the non-witness-enabled destination node and see that it contains a block serialised without witness data. INetworkPeer connectedPeer = listenerConnMan.ConnectedPeers.FindByEndpoint(node.Endpoint); TestBehavior testBehavior = connectedPeer.Behavior <TestBehavior>(); var blockMessages = testBehavior.receivedMessageTracker["block"]; var blockReceived = blockMessages.First(); var receivedBlock = blockReceived.Message.Payload as BlockPayload; var parsedBlock = receivedBlock.Obj; // The block mined on the mining node (witness) should be bigger than the one received by the listener (no witness). Assert.True(block.GetSerializedSize() > parsedBlock.GetSerializedSize()); // Reserialise the received block without witness data (this should have no effect on its size). var nonWitnessBlock = parsedBlock.WithOptions(listener.FullNode.Network.Consensus.ConsensusFactory, TransactionOptions.None); // We received a block without witness data in the first place. Assert.True(parsedBlock.GetSerializedSize() == nonWitnessBlock.GetSerializedSize()); } }
public void WalletCanSendOneTransactionWithManyOutputs() { using (NodeBuilder builder = NodeBuilder.Create()) { CoreNode stratisSender = builder.CreateStratisPowNode(); CoreNode stratisReceiver = builder.CreateStratisPowNode(); builder.StartAll(); stratisSender.NotInIBD(); stratisReceiver.NotInIBD(); stratisSender.FullNode.WalletManager().CreateWallet("123456", "mywallet"); stratisReceiver.FullNode.WalletManager().CreateWallet("123456", "mywallet"); HdAddress addr = stratisSender.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference("mywallet", "account 0")); Wallet wallet = stratisSender.FullNode.WalletManager().GetWalletByName("mywallet"); Key key = wallet.GetExtendedPrivateKeyForAddress("123456", addr).PrivateKey; stratisSender.SetDummyMinerSecret(new BitcoinSecret(key, stratisSender.FullNode.Network)); int maturity = (int)stratisSender.FullNode.Network.Consensus.Option <PowConsensusOptions>().CoinbaseMaturity; stratisSender.GenerateStratisWithMiner(maturity + 51); // Wait for block repo for block sync to work. TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisSender)); Assert.Equal(Money.COIN * 150 * 50, stratisSender.FullNode.WalletManager().GetSpendableTransactionsInWallet("mywallet").Sum(s => s.Transaction.Amount)); // Sync both nodes. stratisSender.CreateRPCClient().AddNode(stratisReceiver.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender)); // Get 50 unused addresses from the receiver. IEnumerable <HdAddress> recevierAddresses = stratisReceiver.FullNode.WalletManager() .GetUnusedAddresses(new WalletAccountReference("mywallet", "account 0"), 50); List <Recipient> recipients = recevierAddresses.Select(address => new Recipient { ScriptPubKey = address.ScriptPubKey, Amount = Money.COIN }) .ToList(); var transactionBuildContext = new TransactionBuildContext( new WalletAccountReference("mywallet", "account 0"), recipients, "123456") { FeeType = FeeType.Medium, MinConfirmations = 101 }; Transaction transaction = stratisSender.FullNode.WalletTransactionHandler().BuildTransaction(transactionBuildContext); Assert.Equal(51, transaction.Outputs.Count); // Broadcast to the other node. stratisSender.FullNode.NodeService <WalletController>().SendTransaction(new SendTransactionRequest(transaction.ToHex())); // Wait for the trx's to arrive. TestHelper.WaitLoop(() => stratisReceiver.CreateRPCClient().GetRawMempool().Length > 0); TestHelper.WaitLoop(() => stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet("mywallet").Any()); Assert.Equal(Money.COIN * 50, stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet("mywallet").Sum(s => s.Transaction.Amount)); Assert.Null(stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet("mywallet").First().Transaction.BlockHeight); // Generate new blocks so the trx is confirmed. stratisSender.GenerateStratisWithMiner(1); // Wait for block repo for block sync to work. TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisSender)); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender)); // Confirm trx's have been committed to the block. Assert.Equal(maturity + 52, stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet("mywallet").First().Transaction.BlockHeight); } }
public void MiningNodeWithOneConnectionAlwaysSynced() { var simulator = new NetworkSimulator(this); simulator.Initialize(4); CoreNode miner = simulator.Nodes[0]; CoreNode connector = simulator.Nodes[1]; CoreNode networkNode1 = simulator.Nodes[2]; CoreNode networkNode2 = simulator.Nodes[3]; // Connect nodes with each other. Miner is connected to connector and connector, node1, node2 are connected with each other. miner.CreateRPCClient().AddNode(connector.Endpoint, true); connector.CreateRPCClient().AddNode(networkNode1.Endpoint, true); connector.CreateRPCClient().AddNode(networkNode2.Endpoint, true); networkNode1.CreateRPCClient().AddNode(networkNode2.Endpoint, true); simulator.MakeSureEachNodeCanMineAndSync(); int networkHeight = miner.FullNode.Chain.Height; Assert.Equal(networkHeight, simulator.Nodes.Count); // Random node on network generates a block. networkNode1.GenerateStratis(1); // Wait until connector get the hash of network's block. while ((connector.FullNode.ChainBehaviorState.ConsensusTip.HashBlock != networkNode1.FullNode.ChainBehaviorState.ConsensusTip.HashBlock) || (networkNode1.FullNode.ChainBehaviorState.ConsensusTip.Height == networkHeight)) { Thread.Sleep(1); } // Make sure that miner did not advance yet but connector did. Assert.NotEqual(miner.FullNode.Chain.Tip.HashBlock, networkNode1.FullNode.Chain.Tip.HashBlock); Assert.Equal(connector.FullNode.Chain.Tip.HashBlock, networkNode1.FullNode.Chain.Tip.HashBlock); Assert.Equal(miner.FullNode.Chain.Tip.Height, networkHeight); Assert.Equal(connector.FullNode.Chain.Tip.Height, networkHeight + 1); // Miner mines the block. miner.GenerateStratis(1); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(miner)); networkHeight++; // Make sure that at this moment miner's tip != network's and connector's tip. Assert.NotEqual(miner.FullNode.Chain.Tip.HashBlock, networkNode1.FullNode.Chain.Tip.HashBlock); Assert.Equal(connector.FullNode.Chain.Tip.HashBlock, networkNode1.FullNode.Chain.Tip.HashBlock); Assert.Equal(miner.FullNode.Chain.Tip.Height, networkHeight); Assert.Equal(connector.FullNode.Chain.Tip.Height, networkHeight); connector.GenerateStratis(1); networkHeight++; int delay = 0; while (true) { Thread.Sleep(50); if (simulator.DidAllNodesReachHeight(networkHeight)) { break; } delay += 50; Assert.True(delay < 10 * 1000, "Miner node was not able to advance!"); } Assert.Equal(networkNode1.FullNode.Chain.Tip.HashBlock, miner.FullNode.Chain.Tip.HashBlock); }
public void CanHandleReorgs() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNode = builder.CreateStratisPowNode(); CoreNode coreNode1 = builder.CreateBitcoinCoreNode(); CoreNode coreNode2 = builder.CreateBitcoinCoreNode(); builder.StartAll(); //Core1 discovers 10 blocks, sends to stratis Block tip = coreNode1.FindBlock(10).Last(); stratisNode.CreateRPCClient().AddNode(coreNode1.Endpoint, true); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNode1.CreateRPCClient().GetBestBlockHash()); stratisNode.CreateRPCClient().RemoveNode(coreNode1.Endpoint); //Core2 discovers 20 blocks, sends to stratis tip = coreNode2.FindBlock(20).Last(); stratisNode.CreateRPCClient().AddNode(coreNode2.Endpoint, true); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNode2.CreateRPCClient().GetBestBlockHash()); stratisNode.CreateRPCClient().RemoveNode(coreNode2.Endpoint); ((CachedCoinView)stratisNode.FullNode.CoinView()).FlushAsync().Wait(); //Core1 discovers 30 blocks, sends to stratis tip = coreNode1.FindBlock(30).Last(); stratisNode.CreateRPCClient().AddNode(coreNode1.Endpoint, true); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNode1.CreateRPCClient().GetBestBlockHash()); stratisNode.CreateRPCClient().RemoveNode(coreNode1.Endpoint); //Core2 discovers 50 blocks, sends to stratis tip = coreNode2.FindBlock(50).Last(); stratisNode.CreateRPCClient().AddNode(coreNode2.Endpoint, true); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNode2.CreateRPCClient().GetBestBlockHash()); stratisNode.CreateRPCClient().RemoveNode(coreNode2.Endpoint); ((CachedCoinView)stratisNode.FullNode.CoinView()).FlushAsync().Wait(); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNode2.CreateRPCClient().GetBestBlockHash()); } }
public void SegwitWalletTransactionBuildingAndPropagationTest() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode node = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).WithWallet().Start(); CoreNode listener = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).WithWallet().Start(); IConnectionManager listenerConnMan = listener.FullNode.NodeService <IConnectionManager>(); listenerConnMan.Parameters.TemplateBehaviors.Add(new TestBehavior()); // The listener node will have default settings, i.e. it should ask for witness data in P2P messages. Assert.True(listenerConnMan.Parameters.Services.HasFlag(NetworkPeerServices.NODE_WITNESS)); TestHelper.Connect(listener, node); var mineAddress = node.FullNode.WalletManager().GetUnusedAddress(); var miner = node.FullNode.NodeService <IPowMining>() as PowMining; miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), (ulong)(node.FullNode.Network.Consensus.CoinbaseMaturity + 1), int.MaxValue); // Wait for listener to sync to the same block height so that it won't reject the coinbase spend as being premature. TestHelper.WaitForNodeToSync(node, listener); // Send a transaction from first node to itself so that it has a proper segwit input to spend. var destinationAddress = node.FullNode.WalletManager().GetUnusedAddress(); var witAddress = destinationAddress.Bech32Address; IActionResult transactionResult = node.FullNode.NodeController <WalletController>() .BuildTransaction(new BuildTransactionRequest { AccountName = "account 0", AllowUnconfirmed = true, Recipients = new List <RecipientModel> { new RecipientModel { DestinationAddress = witAddress, Amount = Money.Coins(1).ToString() } }, Password = node.WalletPassword, WalletName = node.WalletName, FeeAmount = Money.Coins(0.001m).ToString() }).GetAwaiter().GetResult(); var walletBuildTransactionModel = (WalletBuildTransactionModel)(transactionResult as JsonResult)?.Value; node.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(walletBuildTransactionModel.Hex)); Transaction witFunds = node.FullNode.Network.CreateTransaction(walletBuildTransactionModel.Hex); uint witIndex = witFunds.Outputs.AsIndexedOutputs().First(o => o.TxOut.ScriptPubKey.IsScriptType(ScriptType.P2WPKH)).N; TestBase.WaitLoop(() => listener.CreateRPCClient().GetBlockCount() >= 1, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); INetworkPeer connectedPeer = listenerConnMan.ConnectedPeers.FindByEndpoint(node.Endpoint); TestBehavior testBehavior = connectedPeer.Behavior <TestBehavior>(); miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), 1, int.MaxValue); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); // Make sure wallet is synced. TestBase.WaitLoop(() => node.CreateRPCClient().GetBlockCount() == node.FullNode.WalletManager().LastBlockHeight(), cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); // We need to capture a message on the witness-enabled destination node and see that it contains a transaction serialised with witness data. // However, the first transaction has no witness data since it was only being sent to a segwit scriptPubKey (i.e. no witness input data). // So clear all messages for now. testBehavior.receivedMessageTracker.Clear(); // Send a transaction that has a segwit input, to a segwit address. transactionResult = node.FullNode.NodeController <WalletController>() .BuildTransaction(new BuildTransactionRequest { AccountName = "account 0", AllowUnconfirmed = true, Outpoints = new List <OutpointRequest>() { new OutpointRequest() { Index = (int)witIndex, TransactionId = witFunds.GetHash().ToString() } }, Recipients = new List <RecipientModel> { new RecipientModel { DestinationAddress = witAddress, Amount = Money.Coins(0.5m).ToString() } }, Password = node.WalletPassword, WalletName = node.WalletName, FeeAmount = Money.Coins(0.001m).ToString() }).GetAwaiter().GetResult(); walletBuildTransactionModel = (WalletBuildTransactionModel)(transactionResult as JsonResult)?.Value; node.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(walletBuildTransactionModel.Hex)); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); var txMessages = testBehavior.receivedMessageTracker["tx"]; var txMessage = txMessages.First(); var receivedTransaction = txMessage.Message.Payload as TxPayload; var parsedTransaction = receivedTransaction.Obj; var nonWitnessTransaction = parsedTransaction.WithOptions(TransactionOptions.None, listener.FullNode.Network.Consensus.ConsensusFactory); Assert.True(parsedTransaction.GetSerializedSize() > nonWitnessTransaction.GetSerializedSize()); miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), 1, int.MaxValue); TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token); } }
public void MempoolSyncTransactions() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNodeSync = builder.CreateStratisPowNode(); CoreNode stratisNode1 = builder.CreateStratisPowNode(); CoreNode stratisNode2 = builder.CreateStratisPowNode(); builder.StartAll(); stratisNodeSync.NotInIBD(); stratisNode1.NotInIBD(); stratisNode2.NotInIBD(); // generate blocks and wait for the downloader to pickup stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network)); stratisNodeSync.GenerateStratisWithMiner(105); // coinbase maturity = 100 // wait for block repo for block sync to work TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisNodeSync)); // sync both nodes stratisNode1.CreateRPCClient().AddNode(stratisNodeSync.Endpoint, true); stratisNode2.CreateRPCClient().AddNode(stratisNodeSync.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode1, stratisNodeSync)); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode2, stratisNodeSync)); // create some transactions and push them to the pool var trxs = new List <Transaction>(); foreach (int index in Enumerable.Range(1, 5)) { Block block = stratisNodeSync.FullNode.BlockStoreManager().BlockRepository.GetAsync(stratisNodeSync.FullNode.Chain.GetBlock(index).HashBlock).Result; Transaction prevTrx = block.Transactions.First(); var dest = new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network); Transaction tx = stratisNodeSync.FullNode.Network.CreateTransaction(); tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey))); tx.AddOutput(new TxOut("25", dest.PubKey.Hash)); tx.AddOutput(new TxOut("24", new Key().PubKey.Hash)); // 1 btc fee tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false); trxs.Add(tx); } var options = new ParallelOptions { MaxDegreeOfParallelism = 5 }; Parallel.ForEach(trxs, options, transaction => { stratisNodeSync.Broadcast(transaction); }); // wait for all nodes to have all trx TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 5); // the full node should be connected to both nodes Assert.True(stratisNodeSync.FullNode.ConnectionManager.ConnectedPeers.Count() >= 2); TestHelper.WaitLoop(() => stratisNode1.CreateRPCClient().GetRawMempool().Length == 5); TestHelper.WaitLoop(() => stratisNode2.CreateRPCClient().GetRawMempool().Length == 5); // mine the transactions in the mempool stratisNodeSync.GenerateStratisWithMiner(1); TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 0); // wait for block and mempool to change TestHelper.WaitLoop(() => stratisNode1.CreateRPCClient().GetBestBlockHash() == stratisNodeSync.CreateRPCClient().GetBestBlockHash()); TestHelper.WaitLoop(() => stratisNode2.CreateRPCClient().GetBestBlockHash() == stratisNodeSync.CreateRPCClient().GetBestBlockHash()); TestHelper.WaitLoop(() => stratisNode1.CreateRPCClient().GetRawMempool().Length == 0); TestHelper.WaitLoop(() => stratisNode2.CreateRPCClient().GetRawMempool().Length == 0); } }