예제 #1
0
        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);
            }
        }
예제 #2
0
        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));
            }
        }
예제 #3
0
        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));
            }
        }
예제 #4
0
        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);
            }
        }
예제 #5
0
        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);
            }
        }