public void ConsensusManager_Connect_New_Block_Failed()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                var syncerNetwork = new StratisOverrideRegTest();

                var minerA = builder.CreateStratisPosNode(this.posNetwork);
                var syncer = builder.CreateStratisPosNode(syncerNetwork);

                builder.StartAll();

                minerA.NotInIBD().WithWallet();
                syncer.NotInIBD();

                // Miner A mines to height 11.
                TestHelper.MineBlocks(minerA, 11);

                // Inject a rule that will fail at block 11 of the new chain
                ConsensusRuleEngine engine = syncer.FullNode.NodeService <IConsensusRuleEngine>() as ConsensusRuleEngine;
                syncerNetwork.Consensus.FullValidationRules.Insert(1, new FailValidation(11));
                engine.Register();

                // Connect syncer to Miner A, reorg should fail.
                TestHelper.Connect(syncer, minerA);

                // Syncer should disconnect from miner A after the failed block.
                TestHelper.WaitLoop(() => !TestHelper.IsNodeConnectedTo(syncer, minerA));

                // Make sure syncer rolled back
                Assert.True(syncer.FullNode.ConsensusManager().Tip.Height == 10);
            }
        }
        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.
                network.Consensus.BIP9Deployments[StratisBIP9Deployments.ColdStaking] = new BIP9DeploymentsParameters(1, 0, DateTime.Now.AddDays(50).ToUnixTimestamp());

                // Set a small confirmation window to reduce time taken by this test.
                network.Consensus.MinerConfirmationWindow = 10;

                // Minimum number of 'votes' required within the conformation window to reach 'LockedIn' state.
                network.Consensus.RuleChangeActivationThreshold = 8;

                CoreNode stratisNode = builder.CreateStratisPosNode(network).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.Chain.GetBlock(startedHeight - 1), StratisBIP9Deployments.ColdStaking));
                Assert.Equal(ThresholdState.Started, cache.GetState(stratisNode.FullNode.Chain.GetBlock(startedHeight), StratisBIP9Deployments.ColdStaking));
                Assert.Equal(ThresholdState.LockedIn, cache.GetState(stratisNode.FullNode.Chain.GetBlock(lockedInHeight), StratisBIP9Deployments.ColdStaking));
                Assert.Equal(ThresholdState.Active, cache.GetState(stratisNode.FullNode.Chain.GetBlock(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.Chain.GetBlock(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.Chain.Tip);
                Assert.NotEqual(0, (int)(flags2.ScriptFlags & ScriptVerify.CheckColdStakeVerify));
            }
        }
        public void ConsensusManager_Reorgs_Then_Try_To_Connect_Longer_Chain__With_Connected_Blocks_And_Fail_Then_Revert_Back()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                var syncerNetwork = new StratisOverrideRegTest();

                var minerA = builder.CreateStratisPosNode(this.posNetwork);
                var minerB = builder.CreateStratisPosNode(this.posNetwork);
                var syncer = builder.CreateStratisPosNode(syncerNetwork);

                builder.StartAll();

                minerA.NotInIBD().WithWallet();
                minerB.NotInIBD().WithWallet();
                syncer.NotInIBD();

                // MinerA mines to height 10.
                TestHelper.MineBlocks(minerA, 10);

                // Sync the network to height 10.
                TestHelper.ConnectAndSync(syncer, minerA, minerB);

                // Disable syncer from sending blocks to miner B
                TestHelper.DisableBlockPropagation(syncer, minerB);

                // Miner A and syncer continues to mine to height 20.
                TestHelper.MineBlocks(minerA, 10);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(syncer, minerA));

                // Inject a rule that will fail at block 15 of the new chain.
                ConsensusRuleEngine engine = syncer.FullNode.NodeService <IConsensusRuleEngine>() as ConsensusRuleEngine;
                syncerNetwork.Consensus.FullValidationRules.Insert(1, new FailValidation(15));
                engine.Register();

                // Miner B continues to mine to height 30 on a new and longer chain.
                TestHelper.MineBlocks(minerB, 20);

                // check miner B at height 30.
                Assert.True(minerB.FullNode.ConsensusManager().Tip.Height == 30);

                // Miner B should become disconnected.
                TestHelper.WaitLoop(() => !TestHelper.IsNodeConnectedTo(syncer, minerB));

                // Make sure syncer rolled back.
                Assert.True(syncer.FullNode.ConsensusManager().Tip.Height == 20);

                // Check syncer is still synced with Miner A.
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(syncer, minerA));
            }
        }