示例#1
0
        public void CheckSegwitP2PSerialisationForWitnessNode()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node     = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).Start();
                CoreNode listener = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).Start();

                IConnectionManager listenerConnMan = listener.FullNode.NodeService <IConnectionManager>();
                listenerConnMan.Parameters.TemplateBehaviors.Add(new TestBehavior());

                // The listener node will have default settings, i.e. it should ask for witness data in P2P messages.
                Assert.True(listenerConnMan.Parameters.Services.HasFlag(NetworkPeerServices.NODE_WITNESS));

                TestHelper.Connect(listener, node);

                // Mine a Segwit block on the first node.
                var            script     = new Key().PubKey.WitHash.ScriptPubKey;
                var            miner      = node.FullNode.NodeService <IPowMining>() as PowMining;
                List <uint256> res        = miner.GenerateBlocks(new ReserveScript(script), 1, int.MaxValue);
                Block          block      = node.FullNode.ChainIndexer.GetHeader(res.First()).Block;
                Script         commitment = WitnessCommitmentsRule.GetWitnessCommitment(node.FullNode.Network, block);
                Assert.NotNull(commitment);

                var cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token;
                TestBase.WaitLoop(() => listener.CreateRPCClient().GetBlockCount() >= 1, cancellationToken: cancellationToken);

                // We need to capture a message on the witness-enabled destination node and see that it contains a block serialised with witness data.
                INetworkPeer connectedPeer = listenerConnMan.ConnectedPeers.FindByEndpoint(node.Endpoint);
                TestBehavior testBehavior  = connectedPeer.Behavior <TestBehavior>();

                var blockMessages = testBehavior.receivedMessageTracker["block"];
                var blockReceived = blockMessages.First();

                var receivedBlock   = blockReceived.Message.Payload as BlockPayload;
                var parsedBlock     = receivedBlock.Obj;
                var nonWitnessBlock = parsedBlock.WithOptions(listener.FullNode.Network.Consensus.ConsensusFactory, TransactionOptions.None);

                Assert.True(parsedBlock.GetSerializedSize() > nonWitnessBlock.GetSerializedSize());
            }
        }
示例#2
0
        public override object Clone()
        {
            var res = new TestBehavior();

            return(res);
        }
示例#3
0
        public void CheckSegwitP2PSerialisationForNonWitnessNode()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                // We have to name the networks differently because the NBitcoin network registration won't allow two identical networks to coexist otherwise.
                var network = new StraxRegTest();
                network.SetPrivatePropertyValue("Name", "StraxRegTestWithDeployments");
                Assert.NotNull(network.Consensus.BIP9Deployments[2]);

                var networkNoBIP9 = new StraxRegTest();
                networkNoBIP9.SetPrivatePropertyValue("Name", "StraxRegTestWithoutDeployments");
                Assert.NotNull(networkNoBIP9.Consensus.BIP9Deployments[2]);

                // Remove BIP9 deployments (i.e. segwit).
                for (int i = 0; i < networkNoBIP9.Consensus.BIP9Deployments.Length; i++)
                {
                    networkNoBIP9.Consensus.BIP9Deployments[i] = null;
                }

                // Ensure the workaround had the desired effect.
                Assert.Null(networkNoBIP9.Consensus.BIP9Deployments[2]);
                Assert.NotNull(network.Consensus.BIP9Deployments[2]);

                // Explicitly use new & separate instances of StratisRegTest because we modified the BIP9 deployments on one instance.
                CoreNode node     = builder.CreateStratisPosNode(network).Start();
                CoreNode listener = builder.CreateStratisPosNode(networkNoBIP9).Start();

                // Sanity check.
                Assert.Null(listener.FullNode.Network.Consensus.BIP9Deployments[2]);
                Assert.NotNull(node.FullNode.Network.Consensus.BIP9Deployments[2]);

                // By disabling Segwit on the listener node we also prevent the WitnessCommitments rule from rejecting the mining node's blocks once we modify the listener's peer services.

                IConnectionManager listenerConnMan = listener.FullNode.NodeService <IConnectionManager>();
                listenerConnMan.Parameters.TemplateBehaviors.Add(new TestBehavior());

                // Override the listener node's default settings, so that it will not ask for witness data in P2P messages.
                listenerConnMan.Parameters.Services &= ~NetworkPeerServices.NODE_WITNESS;

                TestHelper.Connect(listener, node);

                // Mine a Segwit block on the first node. It should have commitment data as its settings have not been modified.
                var            script     = new Key().PubKey.WitHash.ScriptPubKey;
                var            miner      = node.FullNode.NodeService <IPowMining>() as PowMining;
                List <uint256> res        = miner.GenerateBlocks(new ReserveScript(script), 1, int.MaxValue);
                Block          block      = node.FullNode.ChainIndexer.GetHeader(res.First()).Block;
                Script         commitment = WitnessCommitmentsRule.GetWitnessCommitment(node.FullNode.Network, block);
                Assert.NotNull(commitment);

                // The listener should sync the mined block without validation failures.
                var cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token;
                TestBase.WaitLoop(() => listener.CreateRPCClient().GetBlockCount() >= 1, cancellationToken: cancellationToken);

                // We need to capture a message on the non-witness-enabled destination node and see that it contains a block serialised without witness data.
                INetworkPeer connectedPeer = listenerConnMan.ConnectedPeers.FindByEndpoint(node.Endpoint);
                TestBehavior testBehavior  = connectedPeer.Behavior <TestBehavior>();

                var blockMessages = testBehavior.receivedMessageTracker["block"];
                var blockReceived = blockMessages.First();

                var receivedBlock = blockReceived.Message.Payload as BlockPayload;
                var parsedBlock   = receivedBlock.Obj;

                // The block mined on the mining node (witness) should be bigger than the one received by the listener (no witness).
                Assert.True(block.GetSerializedSize() > parsedBlock.GetSerializedSize());

                // Reserialise the received block without witness data (this should have no effect on its size).
                var nonWitnessBlock = parsedBlock.WithOptions(listener.FullNode.Network.Consensus.ConsensusFactory, TransactionOptions.None);

                // We received a block without witness data in the first place.
                Assert.True(parsedBlock.GetSerializedSize() == nonWitnessBlock.GetSerializedSize());
            }
        }
示例#4
0
        public void SegwitWalletTransactionBuildingAndPropagationTest()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node     = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).WithWallet().Start();
                CoreNode listener = builder.CreateStratisPosNode(KnownNetworks.StraxRegTest).WithWallet().Start();

                IConnectionManager listenerConnMan = listener.FullNode.NodeService <IConnectionManager>();
                listenerConnMan.Parameters.TemplateBehaviors.Add(new TestBehavior());

                // The listener node will have default settings, i.e. it should ask for witness data in P2P messages.
                Assert.True(listenerConnMan.Parameters.Services.HasFlag(NetworkPeerServices.NODE_WITNESS));

                TestHelper.Connect(listener, node);

                var mineAddress = node.FullNode.WalletManager().GetUnusedAddress();

                var miner = node.FullNode.NodeService <IPowMining>() as PowMining;
                miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), (ulong)(node.FullNode.Network.Consensus.CoinbaseMaturity + 1), int.MaxValue);

                // Wait for listener to sync to the same block height so that it won't reject the coinbase spend as being premature.
                TestHelper.WaitForNodeToSync(node, listener);

                // Send a transaction from first node to itself so that it has a proper segwit input to spend.
                var destinationAddress = node.FullNode.WalletManager().GetUnusedAddress();
                var witAddress         = destinationAddress.Bech32Address;

                IActionResult transactionResult = node.FullNode.NodeController <WalletController>()
                                                  .BuildTransaction(new BuildTransactionRequest
                {
                    AccountName      = "account 0",
                    AllowUnconfirmed = true,
                    Recipients       = new List <RecipientModel> {
                        new RecipientModel {
                            DestinationAddress = witAddress, Amount = Money.Coins(1).ToString()
                        }
                    },
                    Password   = node.WalletPassword,
                    WalletName = node.WalletName,
                    FeeAmount  = Money.Coins(0.001m).ToString()
                }).GetAwaiter().GetResult();

                var walletBuildTransactionModel = (WalletBuildTransactionModel)(transactionResult as JsonResult)?.Value;

                node.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(walletBuildTransactionModel.Hex));

                Transaction witFunds = node.FullNode.Network.CreateTransaction(walletBuildTransactionModel.Hex);
                uint        witIndex = witFunds.Outputs.AsIndexedOutputs().First(o => o.TxOut.ScriptPubKey.IsScriptType(ScriptType.P2WPKH)).N;

                TestBase.WaitLoop(() => listener.CreateRPCClient().GetBlockCount() >= 1, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);
                TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);
                TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);

                INetworkPeer connectedPeer = listenerConnMan.ConnectedPeers.FindByEndpoint(node.Endpoint);
                TestBehavior testBehavior  = connectedPeer.Behavior <TestBehavior>();

                miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), 1, int.MaxValue);

                TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);
                TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);

                // Make sure wallet is synced.
                TestBase.WaitLoop(() => node.CreateRPCClient().GetBlockCount() == node.FullNode.WalletManager().LastBlockHeight(), cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);

                // We need to capture a message on the witness-enabled destination node and see that it contains a transaction serialised with witness data.
                // However, the first transaction has no witness data since it was only being sent to a segwit scriptPubKey (i.e. no witness input data).
                // So clear all messages for now.
                testBehavior.receivedMessageTracker.Clear();

                // Send a transaction that has a segwit input, to a segwit address.
                transactionResult = node.FullNode.NodeController <WalletController>()
                                    .BuildTransaction(new BuildTransactionRequest
                {
                    AccountName      = "account 0",
                    AllowUnconfirmed = true,
                    Outpoints        = new List <OutpointRequest>()
                    {
                        new OutpointRequest()
                        {
                            Index = (int)witIndex, TransactionId = witFunds.GetHash().ToString()
                        }
                    },
                    Recipients = new List <RecipientModel> {
                        new RecipientModel {
                            DestinationAddress = witAddress, Amount = Money.Coins(0.5m).ToString()
                        }
                    },
                    Password   = node.WalletPassword,
                    WalletName = node.WalletName,
                    FeeAmount  = Money.Coins(0.001m).ToString()
                }).GetAwaiter().GetResult();

                walletBuildTransactionModel = (WalletBuildTransactionModel)(transactionResult as JsonResult)?.Value;

                node.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(walletBuildTransactionModel.Hex));

                TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);
                TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length > 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);

                var txMessages = testBehavior.receivedMessageTracker["tx"];
                var txMessage  = txMessages.First();

                var receivedTransaction   = txMessage.Message.Payload as TxPayload;
                var parsedTransaction     = receivedTransaction.Obj;
                var nonWitnessTransaction = parsedTransaction.WithOptions(TransactionOptions.None, listener.FullNode.Network.Consensus.ConsensusFactory);

                Assert.True(parsedTransaction.GetSerializedSize() > nonWitnessTransaction.GetSerializedSize());

                miner.GenerateBlocks(new ReserveScript(mineAddress.ScriptPubKey), 1, int.MaxValue);

                TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);
                TestBase.WaitLoop(() => listener.CreateRPCClient().GetRawMempool().Length == 0, cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token);
            }
        }