public void MineBlocks(int blockCount, CoreNode node, string accountName, string toWalletName, string withPassword, long expectedFees = 0) { this.WaitForBlockStoreToSync(node); var address = node.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(toWalletName, accountName)); var balanceBeforeMining = node.FullNode.WalletManager() .GetSpendableTransactionsInWallet(toWalletName) .Where(x => x.Address == address) .Sum(s => s.Transaction.Amount); var wallet = node.FullNode.WalletManager().GetWalletByName(toWalletName); var extendedPrivateKey = wallet.GetExtendedPrivateKeyForAddress(withPassword, address).PrivateKey; node.SetDummyMinerSecret(new BitcoinSecret(extendedPrivateKey, node.FullNode.Network)); node.GenerateStratisWithMiner(blockCount); var balanceAfterMining = node.FullNode.WalletManager() .GetSpendableTransactionsInWallet(toWalletName) .Where(x => x.Address == address) .Sum(s => s.Transaction.Amount); var balanceIncrease = balanceAfterMining - balanceBeforeMining; this.WaitForBlockStoreToSync(node); var rewardCoinCount = blockCount * Money.COIN * 50; balanceIncrease.Should().Be(rewardCoinCount + expectedFees); }
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 AddToMempool() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNodeSync = builder.CreateStratisPowNode(); builder.StartAll(); stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network)); stratisNodeSync.GenerateStratisWithMiner(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 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); stratisNodeSync.Broadcast(tx); TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 1); } }
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 Miner_Create_Block_Whilst_Disconnected_Syncs() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode miner = builder.CreateStratisPowNode(KnownNetworks.RegTest).NotInIBD(); CoreNode syncer = builder.CreateStratisPowNode(KnownNetworks.RegTest).NotInIBD(); builder.StartAll(); miner.SetDummyMinerSecret(new BitcoinSecret(new Key(), miner.FullNode.Network)); TestHelper.MineBlocks(miner, 1); miner.CreateRPCClient().AddNode(syncer.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(miner, syncer)); } }
public void MinePremineBlocks(CoreNode node, string walletName, string walletAccount, string walletPassword) { this.WaitForNodeToSync(node); var unusedAddress = node.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(walletName, walletAccount)); var wallet = node.FullNode.WalletManager().GetWalletByName(walletName); var extendedPrivateKey = wallet.GetExtendedPrivateKeyForAddress(walletPassword, unusedAddress).PrivateKey; node.SetDummyMinerSecret(new BitcoinSecret(extendedPrivateKey, node.FullNode.Network)); node.GenerateStratisWithMiner(2); this.WaitForNodeToSync(node); var spendable = node.FullNode.WalletManager().GetSpendableTransactionsInWallet(walletName); var amountShouldBe = node.FullNode.Network.Consensus.Option <PosConsensusOptions>().PremineReward + node.FullNode.Network.Consensus.Option <PosConsensusOptions>().ProofOfWorkReward; spendable.Sum(s => s.Transaction.Amount).Should().Be(amountShouldBe); }
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 GetProofOfWorkRewardForMinedBlocksTest() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode node = builder.CreateStratisPowNode(KnownNetworks.RegTest).NotInIBD(); builder.StartAll(); node.SetDummyMinerSecret(new BitcoinSecret(new Key(), node.FullNode.Network)); TestHelper.MineBlocks(node, 10); node.GetProofOfWorkRewardForMinedBlocks(10).Should().Be(Money.Coins(500)); TestHelper.MineBlocks(node, 90); node.GetProofOfWorkRewardForMinedBlocks(100).Should().Be(Money.Coins(5000)); TestHelper.MineBlocks(node, 100); node.GetProofOfWorkRewardForMinedBlocks(200).Should().Be(Money.Coins(8725)); TestHelper.MineBlocks(node, 200); node.GetProofOfWorkRewardForMinedBlocks(400).Should().Be(Money.Coins((decimal)12462.50)); } }
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 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 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); } }
public void TxMempoolMapOrphans() { var rand = new Random(); var randByte = new byte[32]; Func <uint256> randHash = () => { rand.NextBytes(randByte); return(new uint256(randByte)); }; using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode stratisNode = builder.CreateStratisPowNode(); builder.StartAll(); stratisNode.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNode.FullNode.Network)); // 50 orphan transactions: for (ulong i = 0; i < 50; i++) { Transaction tx = stratisNode.FullNode.Network.Consensus.ConsensusFactory.CreateTransaction(); tx.AddInput(new TxIn(new OutPoint(randHash(), 0), new Script(OpcodeType.OP_1))); tx.AddOutput(new TxOut(new Money(1 * Money.CENT), stratisNode.MinerSecret.ScriptPubKey)); stratisNode.FullNode.NodeService <MempoolOrphans>().AddOrphanTx(i, tx); } Assert.Equal(50, stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count); // ... and 50 that depend on other orphans: for (ulong i = 0; i < 50; i++) { MempoolOrphans.OrphanTx txPrev = stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().ElementAt(rand.Next(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count)); Transaction tx = stratisNode.FullNode.Network.Consensus.ConsensusFactory.CreateTransaction(); tx.AddInput(new TxIn(new OutPoint(txPrev.Tx.GetHash(), 0), new Script(OpcodeType.OP_1))); tx.AddOutput(new TxOut(new Money((1 + i + 100) * Money.CENT), stratisNode.MinerSecret.ScriptPubKey)); stratisNode.FullNode.NodeService <MempoolOrphans>().AddOrphanTx(i, tx); } Assert.Equal(100, stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count); // This really-big orphan should be ignored: for (ulong i = 0; i < 10; i++) { MempoolOrphans.OrphanTx txPrev = stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().ElementAt(rand.Next(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count)); Transaction tx = stratisNode.FullNode.Network.Consensus.ConsensusFactory.CreateTransaction(); tx.AddOutput(new TxOut(new Money(1 * Money.CENT), stratisNode.MinerSecret.ScriptPubKey)); foreach (int index in Enumerable.Range(0, 2777)) { tx.AddInput(new TxIn(new OutPoint(txPrev.Tx.GetHash(), index), new Script(OpcodeType.OP_1))); } Assert.False(stratisNode.FullNode.NodeService <MempoolOrphans>().AddOrphanTx(i, tx)); } Assert.Equal(100, stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count); // Test EraseOrphansFor: for (ulong i = 0; i < 3; i++) { int sizeBefore = stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count; stratisNode.FullNode.NodeService <MempoolOrphans>().EraseOrphansFor(i); Assert.True(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count < sizeBefore); } // Test LimitOrphanTxSize() function: stratisNode.FullNode.NodeService <MempoolOrphans>().LimitOrphanTxSize(40); Assert.True(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count <= 40); stratisNode.FullNode.NodeService <MempoolOrphans>().LimitOrphanTxSize(10); Assert.True(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count <= 10); stratisNode.FullNode.NodeService <MempoolOrphans>().LimitOrphanTxSize(0); Assert.True(!stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Any()); } }
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); } }