public void ConsensusManager_Fork_Occurs_When_Same_Coins_Are_Staked_On_Different_Chains() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisOverrideRegTest(); var minerA = builder.CreateStratisPosNode(network, "cm-11-minerA").OverrideDateTimeProvider().WithWallet().Start(); var minerB = builder.CreateStratisPosNode(network, "cm-11-minerB").OverrideDateTimeProvider().Start(); minerB.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase, minerA.Mnemonic); var coinbaseMaturity = (int)network.Consensus.CoinbaseMaturity; // MinerA mines maturity +2 blocks to get the big premine coin and make it stakable. TestHelper.MineBlocks(minerA, coinbaseMaturity + 2); // Sync the peers A and B (height 12) TestHelper.ConnectAndSync(minerA, minerB); // Disconnect Miner A and B. TestHelper.DisconnectAll(minerA, minerB); // Miner A stakes one coin. (height 13) var minterA = minerA.FullNode.NodeService <IPosMinting>(); var minterAHeigh = minerA.FullNode.ConsensusManager().Tip.Height; minterA.Stake(new WalletSecret() { WalletName = WalletName, WalletPassword = Password }); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerA, minterAHeigh + 1)); minterA.StopStake(); var minterB = minerB.FullNode.NodeService <IPosMinting>(); var minterBHeigh = minerB.FullNode.ConsensusManager().Tip.Height; minterB.Stake(new WalletSecret() { WalletName = WalletName, WalletPassword = Password }); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerB, minterBHeigh + 1)); minterB.StopStake(); // MinerB mines 1 block on its own fork. (heightB 13) TestHelper.MineBlocks(minerA, 2); TestHelper.MineBlocks(minerB, 3); TestHelper.ConnectAndSync(minerA, minerB); TestBase.WaitLoop(() => minerA.FullNode.ConsensusManager().Tip.HashBlock == minerB.FullNode.ConsensusManager().Tip.HashBlock); Assert.True(minerA.FullNode.ConsensusManager().Tip.HashBlock == minerB.FullNode.ConsensusManager().Tip.HashBlock); } }
public void ColdStakingActivatedOnStratisNode() { using (NodeBuilder builder = NodeBuilder.Create(this)) { // Create separate network parameters for this test. var network = new StratisOverrideRegTest(); // Set the date ranges such that ColdStaking will 'Start' immediately after the initial confirmation window. // Also reduce the minimum number of 'votes' required within the confirmation window to reach 'LockedIn' state. network.Consensus.BIP9Deployments[StratisBIP9Deployments.ColdStaking] = new BIP9DeploymentsParameters("Test", 1, 0, DateTime.Now.AddDays(50).ToUnixTimestamp(), 8); // Set a small confirmation window to reduce time taken by this test. network.Consensus.MinerConfirmationWindow = 10; CoreNode stratisNode = builder.CreateStratisPosNode(network, "cs-1-stratisNode").WithWallet(); stratisNode.Start(); // ColdStaking activation: // - Deployment state changes every 'MinerConfirmationWindow' blocks. // - Remains in 'Defined' state until 'startedHeight'. // - Changes to 'Started' state at 'startedHeight'. // - Changes to 'LockedIn' state at 'lockedInHeight' (as coldstaking should already be signaled in blocks). // - Changes to 'Active' state at 'activeHeight'. int startedHeight = network.Consensus.MinerConfirmationWindow - 1; int lockedInHeight = startedHeight + network.Consensus.MinerConfirmationWindow; int activeHeight = lockedInHeight + network.Consensus.MinerConfirmationWindow; // Generate enough blocks to cover all state changes. TestHelper.MineBlocks(stratisNode, activeHeight + 1); // Check that coldstaking states got updated as expected. ThresholdConditionCache cache = (stratisNode.FullNode.NodeService <IConsensusRuleEngine>() as ConsensusRuleEngine).NodeDeployments.BIP9; Assert.Equal(ThresholdState.Defined, cache.GetState(stratisNode.FullNode.ChainIndexer.GetHeader(startedHeight - 1), StratisBIP9Deployments.ColdStaking)); Assert.Equal(ThresholdState.Started, cache.GetState(stratisNode.FullNode.ChainIndexer.GetHeader(startedHeight), StratisBIP9Deployments.ColdStaking)); Assert.Equal(ThresholdState.LockedIn, cache.GetState(stratisNode.FullNode.ChainIndexer.GetHeader(lockedInHeight), StratisBIP9Deployments.ColdStaking)); Assert.Equal(ThresholdState.Active, cache.GetState(stratisNode.FullNode.ChainIndexer.GetHeader(activeHeight), StratisBIP9Deployments.ColdStaking)); // Verify that the block created before activation does not have the 'CheckColdStakeVerify' flag set. var rulesEngine = stratisNode.FullNode.NodeService <IConsensusRuleEngine>(); ChainedHeader prevHeader = stratisNode.FullNode.ChainIndexer.GetHeader(activeHeight - 1); DeploymentFlags flags1 = (rulesEngine as ConsensusRuleEngine).NodeDeployments.GetFlags(prevHeader); Assert.Equal(0, (int)(flags1.ScriptFlags & ScriptVerify.CheckColdStakeVerify)); // Verify that the block created after activation has the 'CheckColdStakeVerify' flag set. DeploymentFlags flags2 = (rulesEngine as ConsensusRuleEngine).NodeDeployments.GetFlags(stratisNode.FullNode.ChainIndexer.Tip); Assert.NotEqual(0, (int)(flags2.ScriptFlags & ScriptVerify.CheckColdStakeVerify)); } }
public void ConsensusManager_Fork_Occurs_When_Stake_Coins_Are_Mined_And_Found_In_Rewind_Data() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisOverrideRegTest("mined_coins"); var sharedMnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve).ToString(); // MinerA requires an physical wallet to stake with. var minerA = builder.CreateStratisPosNode(network, "cm-10-minerA").OverrideDateTimeProvider().WithWallet(walletMnemonic: sharedMnemonic).Start(); var minerB = builder.CreateStratisPosNode(network, "cm-10-minerB").OverrideDateTimeProvider().WithWallet(walletMnemonic: sharedMnemonic).Start(); // MinerA mines 2 blocks to get the big premine coin and mature them (regtest maturity is 10). TestHelper.MineBlocks(minerA, 12); // Sync the peers A and B (height 12) TestHelper.ConnectAndSync(minerA, minerB); // Disconnect Miner A and B. TestHelper.DisconnectAll(minerA, minerB); // Miner A stakes one coin. (height 13) var minterA = minerA.FullNode.NodeService <IPosMinting>(); minterA.Stake(new WalletSecret() { WalletName = "mywallet", WalletPassword = "******" }); TestBase.WaitLoop(() => minerA.FullNode.ConsensusManager().Tip.Height == 13); minterA.StopStake(); TestHelper.MineBlocks(minerB, 2); // this will push minerB total work to be highest var minterB = minerB.FullNode.NodeService <IPosMinting>(); minterB.Stake(new WalletSecret() { WalletName = WalletName, WalletPassword = Password }); TestBase.WaitLoop(() => minerB.FullNode.ConsensusManager().Tip.Height == 15); minterB.StopStake(); var expectedValidChainHeight = minerB.FullNode.ConsensusManager().Tip.Height; // Sync the network, minerA should switch to minerB. TestHelper.ConnectAndSync(minerA, minerB); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerA, expectedValidChainHeight)); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerB, expectedValidChainHeight)); } }
public void ConsensusManager_Block_That_Failed_Partial_Validation_Is_Rejected() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisOverrideRegTest(); // MinerA requires a physical wallet to stake with. var minerA = builder.CreateStratisPosNode(network, "minerA").WithWallet().Start(); var minerB = builder.CreateStratisPosNode(network, "minerB").Start(); var minerC = builder.CreateStratisPosNode(network, "minerC").Start(); // MinerA mines to height 5. TestHelper.MineBlocks(minerA, 5); // Connect and sync minerA and minerB. TestHelper.ConnectAndSync(minerA, minerB); TestHelper.Disconnect(minerA, minerB); // Mark block 5 as invalid by changing the signature of the block in memory. (minerB.FullNode.ChainIndexer.GetHeader(5).Block as PosBlock).BlockSignature.Signature = new byte[] { 0 }; // Connect and sync minerB and minerC. TestHelper.ConnectNoCheck(minerB, minerC); // TODO: when signaling failed blocks is enabled we should check this here. // Wait for the nodes to disconnect due to invalid block. TestBase.WaitLoop(() => !TestHelper.IsNodeConnectedTo(minerB, minerC)); Assert.True(minerC.FullNode.NodeService <IPeerBanning>().IsBanned(minerB.Endpoint)); minerC.FullNode.NodeService <IPeerBanning>().UnBanPeer(minerA.Endpoint); TestHelper.ConnectAndSync(minerC, minerA); TestBase.WaitLoop(() => TestHelper.AreNodesSyncedMessage(minerA, minerC).Passed); } }
public void ConsensusManager_Fork_Occurs_When_Stake_Coins_Are_Spent_And_Found_In_Rewind_Data() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisOverrideRegTest("stake_coins"); var sharedMnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve).ToString(); // MinerA requires an physical wallet to stake with. var minerA = builder.CreateStratisPosNode(network, "cm-10-minerA").OverrideDateTimeProvider().WithWallet(walletMnemonic: sharedMnemonic).Start(); var minerB = builder.CreateStratisPosNode(network, "cm-10-minerB").OverrideDateTimeProvider().WithWallet(walletMnemonic: sharedMnemonic).Start(); // MinerA mines 2 blocks to get the big premine coin and mature them (regtest maturity is 10). TestHelper.MineBlocks(minerA, 12); // Sync the peers A and B (height 3) TestHelper.ConnectAndSync(minerA, minerB); // Miner A will spend the coins WalletSendTransactionModel walletSendTransactionModel = $"http://localhost:{minerA.ApiPort}/api" .AppendPathSegment("wallet/splitcoins") .PostJsonAsync(new SplitCoinsRequest { WalletName = minerA.WalletName, AccountName = "account 0", WalletPassword = minerA.WalletPassword, TotalAmountToSplit = network.Consensus.PremineReward.ToString(), UtxosCount = 2 }) .ReceiveJson <WalletSendTransactionModel>().Result; TestBase.WaitLoop(() => minerA.FullNode.MempoolManager().InfoAll().Count > 0); TestHelper.MineBlocks(minerA, 12); TestBase.WaitLoop(() => minerA.FullNode.ConsensusManager().Tip.Height == 24); Assert.Empty(minerA.FullNode.MempoolManager().InfoAll()); TestBase.WaitLoop(() => TestHelper.AreNodesSynced(minerA, minerB)); // Disconnect Miner A and B. TestHelper.Disconnect(minerA, minerB); // Miner A stakes one coin. (height 13) var minterA = minerA.FullNode.NodeService <IPosMinting>(); minterA.Stake(new WalletSecret() { WalletName = "mywallet", WalletPassword = "******" }); TestBase.WaitLoop(() => minerA.FullNode.ConsensusManager().Tip.Height == 25); minterA.StopStake(); TestHelper.MineBlocks(minerB, 2); // this will push minerB total work to be highest var minterB = minerB.FullNode.NodeService <IPosMinting>(); minterB.Stake(new WalletSecret() { WalletName = WalletName, WalletPassword = Password }); TestBase.WaitLoop(() => minerB.FullNode.ConsensusManager().Tip.Height == 27); minterB.StopStake(); var expectedValidChainHeight = minerB.FullNode.ConsensusManager().Tip.Height; // Sync the network, minerA should switch to minerB. TestHelper.Connect(minerA, minerB); TestHelper.IsNodeSyncedAtHeight(minerA, expectedValidChainHeight); TestHelper.IsNodeSyncedAtHeight(minerB, expectedValidChainHeight); } }