public void MinerCreateBlockCoinbaseMempoolTemplateCreationFails() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode miner = builder.CreateStratisPowNode(this.network); builder.StartAll(); miner.NotInIBD(); miner.SetDummyMinerSecret(new BitcoinSecret(new Key(), miner.FullNode.Network)); miner.GenerateStratisWithMiner(1); // Create an invalid coinbase transaction to be added to the mempool. var duplicateCoinbase = this.network.CreateTransaction(); duplicateCoinbase.AddInput(new TxIn()); duplicateCoinbase.AddOutput(new TxOut()); duplicateCoinbase.Inputs[0].PrevOut = new OutPoint(); duplicateCoinbase.Inputs[0].ScriptSig = new Script(OpcodeType.OP_0, OpcodeType.OP_1); duplicateCoinbase.Outputs[0].Value = 0; var txMempoolHelper = new TestMemPoolEntryHelper(); var txMempoolEntry = txMempoolHelper.Fee(Money.CENT).Time(DateTimeProvider.Default.GetTime()).SpendsCoinbase(false).FromTx(duplicateCoinbase); miner.FullNode.NodeService <ITxMempool>().AddUnchecked(duplicateCoinbase.GetHash(), txMempoolEntry); var error = Assert.Throws <ConsensusException>(() => miner.GenerateStratisWithMiner(1)); Assert.True(error.Message == ConsensusErrors.BadMultipleCoinbase.Message); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(miner)); Assert.True(miner.FullNode.ConsensusManager().Tip.Height == 1); } }
public void CanStratisSyncFromCore() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNode = builder.CreateStratisPowNode(); CoreNode coreNode = builder.CreateBitcoinCoreNode(); builder.StartAll(); stratisNode.NotInIBD(); Block tip = coreNode.FindBlock(10).Last(); RPCClient stratisNodeRpcClient = stratisNode.CreateRPCClient(); stratisNodeRpcClient.AddNode(coreNode.Endpoint, true); RPCClient coreNodeRpcClient = coreNode.CreateRPCClient(); TestHelper.WaitLoop(() => stratisNodeRpcClient.GetBestBlockHash() == coreNodeRpcClient.GetBestBlockHash()); uint256 bestBlockHash = stratisNodeRpcClient.GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); stratisNodeRpcClient.RemoveNode(coreNode.Endpoint); TestHelper.WaitLoop(() => coreNodeRpcClient.GetPeersInfo() .All(pi => pi.Address.MapToIpv6().ToString() != coreNode.Endpoint.MapToIpv6().ToString())); tip = coreNode.FindBlock(10).Last(); coreNodeRpcClient.AddNode(stratisNode.Endpoint, true); TestHelper.WaitLoop(() => stratisNodeRpcClient.GetBestBlockHash() == coreNodeRpcClient.GetBestBlockHash()); bestBlockHash = stratisNodeRpcClient.GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); } }
public void CanStratisSyncFromStratis() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNode = builder.CreateStratisPowNode(); CoreNode stratisNodeSync = builder.CreateStratisPowNode(); CoreNode coreCreateNode = builder.CreateBitcoinCoreNode(); builder.StartAll(); stratisNode.NotInIBD(); stratisNodeSync.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()); uint256 bestBlockHash = stratisNode.CreateRPCClient().GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); // add a new stratis node which will download // the blocks using the GetData payload stratisNodeSync.CreateRPCClient().AddNode(stratisNode.Endpoint, true); // wait for download and assert TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == stratisNodeSync.CreateRPCClient().GetBestBlockHash()); bestBlockHash = stratisNodeSync.CreateRPCClient().GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); } }
public void CanStratisSyncFromCore() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNode = builder.CreateStratisPowNode(); CoreNode coreNode = builder.CreateBitcoinCoreNode(); builder.StartAll(); stratisNode.NotInIBD(); Block tip = coreNode.FindBlock(10).Last(); stratisNode.CreateRPCClient().AddNode(coreNode.Endpoint, true); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNode.CreateRPCClient().GetBestBlockHash()); uint256 bestBlockHash = stratisNode.CreateRPCClient().GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); //Now check if Core connect to stratis stratisNode.CreateRPCClient().RemoveNode(coreNode.Endpoint); TestHelper.WaitLoop(() => coreNode.CreateRPCClient().GetPeersInfo().Length == 0); tip = coreNode.FindBlock(10).Last(); coreNode.CreateRPCClient().AddNode(stratisNode.Endpoint, true); TestHelper.WaitLoop(() => stratisNode.CreateRPCClient().GetBestBlockHash() == coreNode.CreateRPCClient().GetBestBlockHash()); bestBlockHash = stratisNode.CreateRPCClient().GetBestBlockHash(); Assert.Equal(tip.GetHash(), bestBlockHash); } }
public void PullerVsMinerRaceCondition() { // Temporary fix so the Network static initialize will not break. Network m = Network.Main; using (NodeBuilder builder = NodeBuilder.Create(this)) { // This represents local node. CoreNode stratisMinerLocal = builder.CreateStratisPosNode(); // This represents remote, which blocks are received by local node using its puller. CoreNode stratisMinerRemote = builder.CreateStratisPosNode(); builder.StartAll(); stratisMinerLocal.NotInIBD(); stratisMinerRemote.NotInIBD(); stratisMinerLocal.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisMinerLocal.FullNode.Network)); stratisMinerRemote.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisMinerRemote.FullNode.Network)); // Let's mine block Ap and Bp. stratisMinerRemote.GenerateStratisWithMiner(2); // Wait for block repository for block sync to work. TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisMinerRemote)); stratisMinerLocal.CreateRPCClient().AddNode(stratisMinerRemote.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMinerLocal, stratisMinerRemote)); // Now disconnect the peers and mine block C2p on remote. stratisMinerLocal.CreateRPCClient().RemoveNode(stratisMinerRemote.Endpoint); TestHelper.WaitLoop(() => !TestHelper.IsNodeConnected(stratisMinerRemote)); // Mine block C2p. stratisMinerRemote.GenerateStratisWithMiner(1); Thread.Sleep(2000); // Now reconnect nodes and mine block C1s before C2p arrives. stratisMinerLocal.CreateRPCClient().AddNode(stratisMinerRemote.Endpoint, true); stratisMinerLocal.GenerateStratisWithMiner(1); // Mine block Dp. uint256 dpHash = stratisMinerRemote.GenerateStratisWithMiner(1)[0]; // Now we wait until the local node's chain tip has correct hash of Dp. TestHelper.WaitLoop(() => stratisMinerLocal.FullNode.Chain.Tip.HashBlock.Equals(dpHash)); // Then give it time to receive the block from the puller. Thread.Sleep(2500); // Check that local node accepted the Dp as consensus tip. Assert.Equal(stratisMinerLocal.FullNode.ChainBehaviorState.ConsensusTip.HashBlock, dpHash); } }
public void PullerVsMinerRaceCondition() { using (NodeBuilder builder = NodeBuilder.Create(this)) { // This represents local node. CoreNode stratisMinerLocal = builder.CreateStratisPosNode(this.posNetwork); // This represents remote, which blocks are received by local node using its puller. CoreNode stratisMinerRemote = builder.CreateStratisPosNode(this.posNetwork); builder.StartAll(); stratisMinerLocal.NotInIBD().WithWallet(walletPassword, walletName, walletPassphrase); stratisMinerRemote.NotInIBD().WithWallet(walletPassword, walletName, walletPassphrase); // Let's mine block Ap and Bp. TestHelper.MineBlocks(stratisMinerRemote, walletName, walletPassword, walletAccount, 2); // Wait for block repository for block sync to work. TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisMinerRemote)); stratisMinerLocal.CreateRPCClient().AddNode(stratisMinerRemote.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisMinerLocal, stratisMinerRemote)); // Now disconnect the peers and mine block C2p on remote. stratisMinerLocal.CreateRPCClient().RemoveNode(stratisMinerRemote.Endpoint); TestHelper.WaitLoop(() => !TestHelper.IsNodeConnected(stratisMinerRemote)); // Mine block C2p. stratisMinerRemote.GenerateStratisWithMiner(1); Thread.Sleep(2000); // Now reconnect nodes and mine block C1s before C2p arrives. stratisMinerLocal.CreateRPCClient().AddNode(stratisMinerRemote.Endpoint, true); TestHelper.MineBlocks(stratisMinerLocal, walletName, walletPassword, walletAccount, 1); // Mine block Dp. uint256 dpHash = TestHelper.MineBlocks(stratisMinerRemote, walletName, walletPassword, walletAccount, 1).BlockHashes[0]; // Now we wait until the local node's chain tip has correct hash of Dp. TestHelper.WaitLoop(() => stratisMinerLocal.FullNode.Chain.Tip.HashBlock.Equals(dpHash)); // Then give it time to receive the block from the puller. Thread.Sleep(2500); // Check that local node accepted the Dp as consensus tip. Assert.Equal(stratisMinerLocal.FullNode.ChainBehaviorState.ConsensusTip.HashBlock, dpHash); } }
public void Miner_Create_Block_Whilst_Disconnected_Syncs() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode miner = builder.CreateStratisPowNode(KnownNetworks.RegTest); CoreNode syncer = builder.CreateStratisPowNode(KnownNetworks.RegTest); builder.StartAll(); miner.NotInIBD(); syncer.NotInIBD(); miner.SetDummyMinerSecret(new BitcoinSecret(new Key(), miner.FullNode.Network)); miner.GenerateStratisWithMiner(1); miner.CreateRPCClient().AddNode(syncer.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(miner, syncer)); } }
public void MinerCreateBlockSigopsLimit1000() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode miner = builder.CreateStratisPowNode(this.network); builder.StartAll(); miner.NotInIBD(); miner.SetDummyMinerSecret(new BitcoinSecret(new Key(), miner.FullNode.Network)); miner.GenerateStratisWithMiner(1); var txMempoolHelper = new TestMemPoolEntryHelper(); // Block sigops > limit: 1000 CHECKMULTISIG + 1 var genesis = this.network.GetGenesis(); var genesisCoinbase = genesis.Transactions[0]; var tx = this.network.CreateTransaction(); tx.AddInput(new TxIn(new OutPoint(genesisCoinbase.GetHash(), 0), new Script(new byte[] { (byte)OpcodeType.OP_0, (byte)OpcodeType.OP_0, (byte)OpcodeType.OP_0, (byte)OpcodeType.OP_NOP, (byte)OpcodeType.OP_CHECKMULTISIG, (byte)OpcodeType.OP_1 }))); // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG tx.AddOutput(Money.Coins(50), new Script()); for (int i = 0; i < 1001; ++i) { tx.Outputs[0].Value -= Money.CENT; bool spendsCoinbase = (i == 0); // only first tx spends coinbase // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails var txMempoolEntry = txMempoolHelper.Fee(Money.CENT).Time(DateTimeProvider.Default.GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx); miner.FullNode.NodeService <ITxMempool>().AddUnchecked(tx.GetHash(), txMempoolEntry); tx = this.network.CreateTransaction(tx.ToBytes()); tx.Inputs[0].PrevOut.Hash = tx.GetHash(); } var error = Assert.Throws <ConsensusException>(() => miner.GenerateStratisWithMiner(1)); Assert.True(error.Message == ConsensusErrors.BadBlockSigOps.Message); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(miner)); Assert.True(miner.FullNode.ConsensusManager().Tip.Height == 1); } }
public void AddToMempoolTrxSpendingTwoOutputFromSameTrx() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNodeSync = builder.CreateStratisPowNode(); builder.StartAll(); stratisNodeSync.NotInIBD(); stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network)); stratisNodeSync.GenerateStratis(105); // coinbase maturity = 100 TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.GetBlockStoreTip().HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); Block block = stratisNodeSync.FullNode.BlockStoreManager().BlockRepository.GetAsync(stratisNodeSync.FullNode.Chain.GetBlock(4).HashBlock).Result; Transaction prevTrx = block.Transactions.First(); var dest1 = new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network); var dest2 = new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network); Transaction parentTx = stratisNodeSync.FullNode.Network.Consensus.ConsensusFactory.CreateTransaction(); parentTx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey))); parentTx.AddOutput(new TxOut("25", dest1.PubKey.Hash)); parentTx.AddOutput(new TxOut("24", dest2.PubKey.Hash)); // 1 btc fee parentTx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false); stratisNodeSync.Broadcast(parentTx); // wiat for the trx to enter the pool TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 1); // mine the transactions in the mempool stratisNodeSync.GenerateStratis(1, stratisNodeSync.FullNode.MempoolManager().InfoAllAsync().Result.Select(s => s.Trx).ToList()); TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 0); //create a new trx spending both outputs Transaction tx = stratisNodeSync.FullNode.Network.Consensus.ConsensusFactory.CreateTransaction(); tx.AddInput(new TxIn(new OutPoint(parentTx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(dest1.PubKey))); tx.AddInput(new TxIn(new OutPoint(parentTx.GetHash(), 1), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(dest2.PubKey))); tx.AddOutput(new TxOut("48", new Key().PubKey.Hash)); // 1 btc fee Transaction signed = new TransactionBuilder(stratisNodeSync.FullNode.Network).AddKeys(dest1, dest2).AddCoins(parentTx.Outputs.AsCoins()).SignTransaction(tx); stratisNodeSync.Broadcast(signed); TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 1); } }
public void MempoolAddNodeWithOrphans() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNodeSync = builder.CreateStratisPowNode(); builder.StartAll(); stratisNodeSync.NotInIBD(); stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network)); stratisNodeSync.GenerateStratis(101); // coinbase maturity = 100 TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ChainBehaviorState.ConsensusTip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.GetBlockStoreTip().HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); Block block = stratisNodeSync.FullNode.BlockStoreManager().BlockRepository.GetAsync(stratisNodeSync.FullNode.Chain.GetBlock(1).HashBlock).Result; Transaction prevTrx = block.Transactions.First(); var dest = new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network); var key = new Key(); Transaction tx = stratisNodeSync.FullNode.Network.Consensus.ConsensusFactory.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", key.PubKey.Hash)); // 1 btc fee tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false); Transaction txOrphan = stratisNodeSync.FullNode.Network.Consensus.ConsensusFactory.CreateTransaction(); txOrphan.AddInput(new TxIn(new OutPoint(tx.GetHash(), 1), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(key.PubKey))); txOrphan.AddOutput(new TxOut("10", new Key().PubKey.Hash)); txOrphan.Sign(stratisNodeSync.FullNode.Network, key.GetBitcoinSecret(stratisNodeSync.FullNode.Network), false); // broadcast the orphan stratisNodeSync.Broadcast(txOrphan); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.NodeService <MempoolOrphans>().OrphansList().Count == 1); // broadcast the parent stratisNodeSync.Broadcast(tx); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.NodeService <MempoolOrphans>().OrphansList().Count == 0); // wait for orphan to get in the pool TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 2); } }
public void MempoolReceiveFromManyNodes() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNodeSync = builder.CreateStratisPowNode(); builder.StartAll(); stratisNodeSync.NotInIBD(); stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network)); stratisNodeSync.GenerateStratisWithMiner(201); // coinbase maturity = 100 TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.GetBlockStoreTip().HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); var trxs = new List <Transaction>(); foreach (int index in Enumerable.Range(1, 100)) { 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.Consensus.ConsensusFactory.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 = 10 }; Parallel.ForEach(trxs, options, transaction => { stratisNodeSync.Broadcast(transaction); }); TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 100); } }
public void GetProofOfWorkRewardForMinedBlocksTest() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode node = builder.CreateStratisPowNode(); builder.StartAll(); node.NotInIBD(); node.SetDummyMinerSecret(new BitcoinSecret(new Key(), node.FullNode.Network)); node.GenerateStratisWithMiner(10); node.GetProofOfWorkRewardForMinedBlocks(10).Should().Be(Money.Coins(500)); node.GenerateStratisWithMiner(90); node.GetProofOfWorkRewardForMinedBlocks(100).Should().Be(Money.Coins(5000)); node.GenerateStratisWithMiner(100); node.GetProofOfWorkRewardForMinedBlocks(200).Should().Be(Money.Coins(8725)); node.GenerateStratisWithMiner(200); node.GetProofOfWorkRewardForMinedBlocks(400).Should().Be(Money.Coins((decimal)12462.50)); } }
public void NodesCanConnectToEachOthers() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode node1 = builder.CreateStratisPowNode(this.powNetwork); CoreNode node2 = builder.CreateStratisPowNode(this.powNetwork); builder.StartAll(); node1.NotInIBD(); node2.NotInIBD(); Assert.Empty(node1.FullNode.ConnectionManager.ConnectedPeers); Assert.Empty(node2.FullNode.ConnectionManager.ConnectedPeers); RPCClient rpc1 = node1.CreateRPCClient(); rpc1.AddNode(node2.Endpoint, true); Assert.Single(node1.FullNode.ConnectionManager.ConnectedPeers); Assert.Single(node2.FullNode.ConnectionManager.ConnectedPeers); var behavior = node1.FullNode.ConnectionManager.ConnectedPeers.First().Behaviors.Find <IConnectionManagerBehavior>(); Assert.False(behavior.Inbound); Assert.True(behavior.OneTry); behavior = node2.FullNode.ConnectionManager.ConnectedPeers.First().Behaviors.Find <IConnectionManagerBehavior>(); Assert.True(behavior.Inbound); Assert.False(behavior.OneTry); } }
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 MiningNodeWithOneConnectionAlwaysSynced() { string testFolderPath = Path.Combine(this.GetType().Name, nameof(MiningNodeWithOneConnectionAlwaysSynced)); using (NodeBuilder nodeBuilder = NodeBuilder.Create(testFolderPath)) { CoreNode minerNode = nodeBuilder.CreateStratisPowNode(this.powNetwork); minerNode.Start(); minerNode.NotInIBD().WithWallet(); CoreNode connectorNode = nodeBuilder.CreateStratisPowNode(this.powNetwork); connectorNode.Start(); connectorNode.NotInIBD().WithWallet(); CoreNode firstNode = nodeBuilder.CreateStratisPowNode(this.powNetwork); firstNode.Start(); firstNode.NotInIBD().WithWallet(); CoreNode secondNode = nodeBuilder.CreateStratisPowNode(this.powNetwork); secondNode.Start(); secondNode.NotInIBD().WithWallet(); TestHelper.Connect(minerNode, connectorNode); TestHelper.Connect(connectorNode, firstNode); TestHelper.Connect(connectorNode, secondNode); TestHelper.Connect(firstNode, secondNode); List <CoreNode> nodes = new List <CoreNode> { minerNode, connectorNode, firstNode, secondNode }; nodes.ForEach(n => { TestHelper.MineBlocks(n, 1); TestHelper.WaitForNodeToSync(nodes.ToArray()); }); int networkHeight = minerNode.FullNode.Chain.Height; Assert.Equal(networkHeight, nodes.Count); // Random node on network generates a block. TestHelper.MineBlocks(firstNode, 1); // Wait until connector get the hash of network's block. while ((connectorNode.FullNode.ChainBehaviorState.ConsensusTip.HashBlock != firstNode.FullNode.ChainBehaviorState.ConsensusTip.HashBlock) || (firstNode.FullNode.ChainBehaviorState.ConsensusTip.Height == networkHeight)) { Thread.Sleep(1); } Assert.Equal(connectorNode.FullNode.Chain.Tip.HashBlock, firstNode.FullNode.Chain.Tip.HashBlock); Assert.Equal(minerNode.FullNode.Chain.Tip.Height, networkHeight); Assert.Equal(connectorNode.FullNode.Chain.Tip.Height, networkHeight + 1); // Miner mines the block. TestHelper.MineBlocks(minerNode, 1); networkHeight++; Assert.Equal(connectorNode.FullNode.Chain.Tip.HashBlock, firstNode.FullNode.Chain.Tip.HashBlock); Assert.Equal(minerNode.FullNode.Chain.Tip.Height, networkHeight); Assert.Equal(connectorNode.FullNode.Chain.Tip.Height, networkHeight); TestHelper.MineBlocks(connectorNode, 1); networkHeight++; TestHelper.WaitForNodeToSync(nodes.ToArray()); nodes.All(n => n.FullNode.Chain.Height == networkHeight).Should() .BeTrue(because: "all nodes have synced to chain height"); Assert.Equal(firstNode.FullNode.Chain.Tip.HashBlock, minerNode.FullNode.Chain.Tip.HashBlock); } }
public void Given_NodesAreSynced_When_ABigReorgHappens_Then_TheReorgIsIgnored() { 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 TxMempoolBlockDoublespend() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNodeSync = builder.CreateStratisPowNode(); builder.StartAll(); stratisNodeSync.NotInIBD(); stratisNodeSync.FullNode.NodeService <MempoolSettings>().RequireStandard = true; // make sure to test standard tx stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network)); stratisNodeSync.GenerateStratisWithMiner(100); // coinbase maturity = 100 TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.GetBlockStoreTip().HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); // Make sure skipping validation of transctions that were // validated going into the memory pool does not allow // double-spends in blocks to pass validation when they should not. Script scriptPubKey = PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey); Block genBlock = stratisNodeSync.FullNode.BlockStoreManager().BlockRepository.GetAsync(stratisNodeSync.FullNode.Chain.GetBlock(1).HashBlock).Result; // Create a double-spend of mature coinbase txn: var spends = new List <Transaction>(2); foreach (int index in Enumerable.Range(1, 2)) { Transaction trx = stratisNodeSync.FullNode.Network.Consensus.ConsensusFactory.CreateTransaction(); trx.AddInput(new TxIn(new OutPoint(genBlock.Transactions[0].GetHash(), 0), scriptPubKey)); trx.AddOutput(Money.Cents(11), new Key().PubKey.Hash); // Sign: trx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false); spends.Add(trx); } // Test 1: block with both of those transactions should be rejected. Block block = stratisNodeSync.GenerateStratis(1, spends).Single(); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock != block.GetHash()); // Test 2: ... and should be rejected if spend1 is in the memory pool Assert.True(stratisNodeSync.AddToStratisMempool(spends[0])); block = stratisNodeSync.GenerateStratis(1, spends).Single(); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock != block.GetHash()); stratisNodeSync.FullNode.MempoolManager().Clear().Wait(); // Test 3: ... and should be rejected if spend2 is in the memory pool Assert.True(stratisNodeSync.AddToStratisMempool(spends[1])); block = stratisNodeSync.GenerateStratis(1, spends).Single(); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock != block.GetHash()); stratisNodeSync.FullNode.MempoolManager().Clear().Wait(); // Final sanity test: first spend in mempool, second in block, that's OK: var oneSpend = new List <Transaction>(); oneSpend.Add(spends[0]); Assert.True(stratisNodeSync.AddToStratisMempool(spends[1])); block = stratisNodeSync.GenerateStratis(1, oneSpend).Single(); TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock); Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock == block.GetHash()); // spends[1] should have been removed from the mempool when the // block with spends[0] is accepted: TestHelper.WaitLoop(() => stratisNodeSync.FullNode.MempoolManager().MempoolSize().Result == 0); } }
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 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.Consensus.ConsensusFactory.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); } }