/// <inheritdoc /> protected override void InitializeFixture() { // TODO: Make a ReadyBlockChainData for these tests this.Builder = NodeBuilder.Create(this); this.Node = this.Builder.CreateStratisXNode().Start(); // Add a peer node and connect the nodes together var config = new NodeConfigParameters() { { "addnode", this.Node.Endpoint.ToString() } }; this.Builder.CreateStratisXNode(configParameters: config).Start(); this.RpcClient = this.Node.CreateRPCClient(); // Generate 11 blocks this.RpcClient.SendCommand(RPCOperations.generate, 11); var cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token; TestBase.WaitLoop(() => this.RpcClient.GetBlockCount() >= 11, cancellationToken: cancellationToken); //TestBase.WaitLoop(() => this.RpcClient.GetPeersInfo().Length > 0, cancellationToken: cancellationToken); // TODO: Disable staking }
public async Task GetRawTransactionWithTransactionAndBlockHashInBlockchainAndNotIndexedAsync() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var configParameters = new NodeConfigParameters { { "txindex", "0" } }; CoreNode node = builder.CreateStratisCustomPowNode(new BitcoinRegTest(), configParameters).WithWallet().Start(); TestHelper.MineBlocks(node, 5); // Get the last block we have. string lastBlockHash = await $"http://localhost:{node.ApiPort}/api" .AppendPathSegment("consensus/getbestblockhash") .GetJsonAsync <string>(); BlockTransactionDetailsModel tip = await $"http://localhost:{node.ApiPort}/api" .AppendPathSegment("blockstore/block") .SetQueryParams(new { hash = lastBlockHash, outputJson = true, showtransactiondetails = true }) .GetJsonAsync <BlockTransactionDetailsModel>(); string txId = tip.Transactions.First().TxId; RPCClient rpc = node.CreateRPCClient(); Func <Task> getTransaction = async() => { await rpc.SendCommandAsync(RPCOperations.getrawtransaction, txId); }; RPCException exception = getTransaction.Should().Throw <RPCException>().Which; exception.RPCCode.Should().Be(RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY); exception.Message.Should().Be("No such mempool transaction. Use -txindex to enable blockchain transaction queries."); } }
public void GatewayNodeCanSyncFirst15KBlocks() { Network network = new StratisMain10KCheckpoint(); if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // TODO: Add the necessary executables for Linux & OSX return; } using (NodeBuilder builder = NodeBuilder.Create(this).WithLogsEnabled()) { CoreNode stratisXNode = builder.CreateMainnetStratisXNode() .WithReadyBlockchainData(ReadyBlockchain.StratisXMainnet15K); var gatewayParameters = new NodeConfigParameters(); gatewayParameters.Add("regtest", "0"); gatewayParameters.Add("gateway", "1"); gatewayParameters.Add("whitelist", stratisXNode.Endpoint.ToString()); CoreNode gatewayNode = builder.CreateStratisPosNode(network, configParameters: gatewayParameters, isGateway: true); gatewayNode.Start(); stratisXNode.Start(); RPCClient stratisXRpc = stratisXNode.CreateRPCClient(); RPCClient gatewayNodeRpc = gatewayNode.CreateRPCClient(); gatewayNodeRpc.AddNode(stratisXNode.Endpoint); TestBase.WaitLoop(() => gatewayNode.FullNode.ChainIndexer.Height >= 15_000, waitTimeSeconds: 600); } }
public void Transaction_CreatedByXNode_TraversesSBFN_ReachesSecondXNode() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // TODO: Add the necessary executables for Linux & OSX return; } using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisRegTest(); CoreNode xNode1 = builder.CreateStratisXNode(version: "2.0.0.5").Start(); var callback = new Action <IFullNodeBuilder>(build => build .UseBlockStore() .UsePosConsensus() .UseMempool() .UseWallet() .AddPowPosMining() .AddRPC()); var config = new NodeConfigParameters(); config.Add("whitelist", xNode1.Endpoint.ToString()); config.Add("gateway", "1"); CoreNode sbfnNode2 = builder .CreateCustomNode(callback, network, protocolVersion: ProtocolVersion.PROVEN_HEADER_VERSION, minProtocolVersion: ProtocolVersion.POS_PROTOCOL_VERSION, configParameters: config) .WithWallet().Start(); CoreNode xNode3 = builder.CreateStratisXNode(version: "2.0.0.5").Start(); RPCClient xRpc1 = xNode1.CreateRPCClient(); RPCClient sbfnRpc2 = sbfnNode2.CreateRPCClient(); RPCClient xRpc3 = xNode3.CreateRPCClient(); // Connect the nodes linearly. X does not appear to respond properly to the addnode RPC so SBFN needs to initiate. sbfnRpc2.AddNode(xNode1.Endpoint, false); sbfnRpc2.AddNode(xNode3.Endpoint, false); xRpc1.SendCommand(RPCOperations.generate, 11); var shortCancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token; TestBase.WaitLoop(() => xRpc1.GetBlockCount() >= 11, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc1.GetBestBlockHash() == sbfnRpc2.GetBestBlockHash(), cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc1.GetBestBlockHash() == xRpc3.GetBestBlockHash(), cancellationToken: shortCancellationToken); // Send transaction to arbitrary address. var alice = new Key().GetBitcoinSecret(network); var aliceAddress = alice.GetAddress(); xRpc1.SendCommand(RPCOperations.sendtoaddress, aliceAddress.ToString(), 1); TestBase.WaitLoop(() => xRpc1.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => sbfnRpc2.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc3.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); } }
public CustomNodeRunner(string dataDir, Action <IFullNodeBuilder> callback, Network network, ProtocolVersion protocolVersion = ProtocolVersion.PROTOCOL_VERSION, NodeConfigParameters configParameters = null, string agent = "Custom") : base(dataDir) { this.callback = callback; this.Network = network; this.protocolVersion = protocolVersion; this.agent = agent; this.configParameters = configParameters ?? new NodeConfigParameters(); }
public CustomNodeRunner(string dataDir, Action <IFullNodeBuilder> callback, Network network, uint protocolVersion, NodeConfigParameters configParameters = null, string agent = "Custom", uint minProtocolVersion = ProtocolVersion.SENDHEADERS_VERSION) : base(dataDir, agent) { this.callback = callback; this.Network = network; this.protocolVersion = protocolVersion; this.configParameters = configParameters ?? new NodeConfigParameters(); this.minProtocolVersion = minProtocolVersion; }
private void a_gap_limit_of_21() { int customUnusedAddressBuffer = 21; var configParameters = new NodeConfigParameters { { "walletaddressbuffer", customUnusedAddressBuffer.ToString() } }; this.sendingStratisBitcoinNode = this.nodeBuilder.CreateStratisPowNode(this.network).WithWallet().Start(); this.receivingStratisBitcoinNode = this.nodeBuilder.CreateStratisCustomPowNode(this.network, configParameters).WithWallet().Start(); TestHelper.ConnectAndSync(this.sendingStratisBitcoinNode, this.receivingStratisBitcoinNode); this.MineSpendableCoins(); }
public void When_Connecting_WithConnectOnly_Connect_ToTheRequestedPeer() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode node1 = builder.CreateStratisPosNode(this.posNetwork, "conn-4-node1").Start(); var nodeConfig = new NodeConfigParameters { { "-connect", node1.Endpoint.ToString() } }; CoreNode node2 = builder.CreateStratisPosNode(this.posNetwork, "conn-4-node2", configParameters: nodeConfig).Start(); TestBase.WaitLoop(() => TestHelper.IsNodeConnectedTo(node1, node2)); } }
public async Task Can_BanAndDisconnect_Peer_From_ApiAsync() { using (var builder = NodeBuilder.Create(this)) { var network = new StratisRegTest(); var nodeA = builder.CreateStratisPosNode(network, "nc-1-nodeA").Start(); var nodeBIp = "127.0.0.2"; var nodeBIpAddress = IPAddress.Parse(nodeBIp); var nodeBConfig = new NodeConfigParameters { { "-externalip", nodeBIp } }; var nodeB = builder.CreateStratisPosNode(network, agent: "nc-1-nodeB", configParameters: nodeBConfig).Start(); var nodeAaddressManager = nodeA.FullNode.NodeService <IPeerAddressManager>(); nodeAaddressManager.AddPeer(new IPEndPoint(nodeBIpAddress, nodeB.Endpoint.Port), IPAddress.Loopback); TestHelper.Connect(nodeA, nodeB); var banPeerModel = new SetBanPeerViewModel() { BanDurationSeconds = 100, BanCommand = "add", PeerAddress = nodeBIp }; await $"http://localhost:{nodeA.ApiPort}/api".AppendPathSegment("network/setban").PostJsonAsync(banPeerModel); TestBase.WaitLoop(() => !TestHelper.IsNodeConnectedTo(nodeA, nodeB)); var nodeBEndPoint = new IPEndPoint(nodeBIpAddress, nodeB.Endpoint.Port); var addressManager = nodeA.FullNode.NodeService <IPeerAddressManager>(); var peer = nodeAaddressManager.FindPeer(nodeBEndPoint); var peerBanning = nodeA.FullNode.NodeService <IPeerBanning>(); Assert.True(peerBanning.IsBanned(nodeBEndPoint)); } }
public void XMinesBlocks_SBFNSyncs() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // TODO: Add the necessary executables for Linux & OSX return; } using (NodeBuilder builder = NodeBuilder.Create(this).WithLogsEnabled()) { var network = new StratisRegTest(); CoreNode stratisXNode = builder.CreateStratisXNode(version: "2.0.0.5").Start(); var callback = new Action <IFullNodeBuilder>(build => build .UseBlockStore() .UsePosConsensus() .UseMempool() .UseWallet() .AddPowPosMining() .AddRPC()); var config = new NodeConfigParameters(); config.Add("whitelist", stratisXNode.Endpoint.ToString()); config.Add("gateway", "1"); CoreNode stratisNode = builder .CreateCustomNode(callback, network, protocolVersion: ProtocolVersion.PROVEN_HEADER_VERSION, minProtocolVersion: ProtocolVersion.POS_PROTOCOL_VERSION, configParameters: config) .WithWallet().Start(); RPCClient stratisXRpc = stratisXNode.CreateRPCClient(); RPCClient stratisNodeRpc = stratisNode.CreateRPCClient(); stratisNodeRpc.AddNode(stratisXNode.Endpoint, false); stratisXRpc.SendCommand(RPCOperations.generate, 10); var cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token; TestBase.WaitLoop(() => stratisXRpc.GetBlockCount() >= 10, cancellationToken: cancellationToken); TestBase.WaitLoop(() => stratisXRpc.GetBestBlockHash() == stratisNodeRpc.GetBestBlockHash(), cancellationToken: cancellationToken); } }
public void PremineNodeWithWalletWithOverrides() { var configParameters = new NodeConfigParameters { { "savetrxhex", "true" } }; var callback = new Action <IFullNodeBuilder>(builder => builder .UseBlockStore() .UsePosConsensus() .UseMempool() .UseWallet() .AddPowPosMining() .AddRPC() .MockIBD() .UseTestChainedHeaderTree() .OverrideDateTimeProviderFor <MiningFeature>()); this.PremineNodeWithCoins = this.nodeBuilder.CreateCustomNode(callback, new StratisRegTest(), ProtocolVersion.PROTOCOL_VERSION, agent: "mint-pmnode", configParameters: configParameters); this.PremineNodeWithCoins.WithWallet().Start(); }
private void a_gap_limit_of_21() { int customUnusedAddressBuffer = 21; var configParameters = new NodeConfigParameters { { "walletaddressbuffer", customUnusedAddressBuffer.ToString() } }; this.nodeGroup = this.nodeGroupBuilder .StratisPowNode(SendingNodeName).Start().NotInIBD() .WithWallet(SendingWalletName, WalletPassword) .StratisCustomPowNode(ReceivingNodeName, configParameters).Start() .WithWallet(ReceivingWalletName, WalletPassword) .WithConnections() .Connect(SendingNodeName, ReceivingNodeName) .AndNoMoreConnections() .Build(); MineSpendableCoins(); }
public void Ensure_Node_DoesNot_ReconnectTo_SameNode() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var nodeConfig = new NodeConfigParameters { { "-debug", "1" } }; CoreNode nodeA = builder.CreateStratisPowNode(this.powNetwork, "conn-1-nodeA", configParameters: nodeConfig).Start(); CoreNode nodeB = builder.CreateStratisPowNode(this.powNetwork, "conn-1-nodeB", configParameters: nodeConfig).Start(); TestHelper.Connect(nodeA, nodeB); TestHelper.ConnectNoCheck(nodeA, nodeB); TestBase.WaitLoop(() => nodeA.FullNode.ConnectionManager.ConnectedPeers.Count() == 1); TestBase.WaitLoop(() => nodeB.FullNode.ConnectionManager.ConnectedPeers.Count() == 1); Assert.False(nodeA.FullNode.ConnectionManager.ConnectedPeers.First().Inbound); Assert.True(nodeB.FullNode.ConnectionManager.ConnectedPeers.First().Inbound); } }
public void NodeServer_Enabled_When_ConnectNode_Args_Specified_And_Listen_Specified() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var nodeConfig = new NodeConfigParameters { { "-connect", "0" }, { "-listen", "1" } }; CoreNode node1 = builder.CreateStratisPowNode(this.powNetwork, "conn-9-node1", configParameters: nodeConfig).Start(); CoreNode node2 = builder.CreateStratisPowNode(this.powNetwork, "conn-9-node2").Start(); Assert.True(node1.FullNode.ConnectionManager.Servers.Any()); TestHelper.Connect(node1, node2); Assert.True(TestHelper.IsNodeConnectedTo(node2, node1)); TestHelper.DisconnectAll(node1, node2); } }
private void a_gap_limit_of_21() { int customUnusedAddressBuffer = 21; var configParameters = new NodeConfigParameters { { "walletaddressbuffer", customUnusedAddressBuffer.ToString() } }; this.sendingStratisBitcoinNode = this.nodeBuilder.CreateStratisPowNode(this.network); this.sendingStratisBitcoinNode.Start(); this.sendingStratisBitcoinNode.NotInIBD(); Mnemonic sendingMnemonic = this.sendingStratisBitcoinNode.FullNode.WalletManager().CreateWallet(WalletPassword, SendingWalletName, WalletPassphrase); this.sendingStratisBitcoinNode.Mnemonic = sendingMnemonic; this.receivingStratisBitcoinNode = this.nodeBuilder.CreateStratisCustomPowNode(this.network, configParameters); this.receivingStratisBitcoinNode.Start(); this.receivingStratisBitcoinNode.NotInIBD(); Mnemonic receivingMnemonic = this.receivingStratisBitcoinNode.FullNode.WalletManager().CreateWallet(WalletPassword, ReceivingWalletName, WalletPassphrase); this.receivingStratisBitcoinNode.Mnemonic = receivingMnemonic; TestHelper.ConnectAndSync(this.sendingStratisBitcoinNode, this.receivingStratisBitcoinNode); this.MineSpendableCoins(); }
public NodeGroupBuilder StratisCustomPowNode(string nodeName, NodeConfigParameters configParameters) { this.nodes.Add(nodeName, this.nodeBuilder.CreateStratisCustomPowNode(configParameters)); return(this); }
public void Transaction_TraversesNodes_AndIsMined_AndNodesSync() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // TODO: Add the necessary executables for Linux & OSX return; } using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisRegTest(); CoreNode xNode1 = builder.CreateStratisXNode(version: "2.0.0.5").Start(); var callback = new Action <IFullNodeBuilder>(build => build .UseBlockStore() .UsePosConsensus() .UseMempool() .UseWallet() .AddPowPosMining() .AddRPC()); var config = new NodeConfigParameters(); config.Add("whitelist", xNode1.Endpoint.ToString()); config.Add("gateway", "1"); CoreNode sbfnNode2 = builder .CreateCustomNode(callback, network, protocolVersion: ProtocolVersion.PROVEN_HEADER_VERSION, minProtocolVersion: ProtocolVersion.POS_PROTOCOL_VERSION, configParameters: config) .WithWallet().Start(); CoreNode xNode3 = builder.CreateStratisXNode(version: "2.0.0.5").Start(); RPCClient xRpc1 = xNode1.CreateRPCClient(); RPCClient sbfnRpc2 = sbfnNode2.CreateRPCClient(); RPCClient xRpc3 = xNode3.CreateRPCClient(); sbfnRpc2.AddNode(xNode1.Endpoint, false); sbfnRpc2.AddNode(xNode3.Endpoint, false); xRpc1.SendCommand(RPCOperations.generate, 11); var shortCancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token; TestBase.WaitLoop(() => xRpc1.GetBlockCount() >= 11, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc1.GetBestBlockHash() == sbfnRpc2.GetBestBlockHash(), cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc1.GetBestBlockHash() == xRpc3.GetBestBlockHash(), cancellationToken: shortCancellationToken); // Send transaction to arbitrary address. var alice = new Key().GetBitcoinSecret(network); var aliceAddress = alice.GetAddress(); xRpc1.SendCommand(RPCOperations.sendtoaddress, aliceAddress.ToString(), 1); TestBase.WaitLoop(() => xRpc1.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => sbfnRpc2.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc3.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); // TODO: Until #2468 is fixed we need an X node to mine the block so it doesn't get rejected. xRpc1.SendCommand(RPCOperations.generate, 1); TestBase.WaitLoop(() => xRpc1.GetBlockCount() >= 12, cancellationToken: shortCancellationToken); // We expect that SBFN and the other X node will sync correctly. TestBase.WaitLoop(() => sbfnRpc2.GetBestBlockHash() == xRpc1.GetBestBlockHash(), cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc3.GetBestBlockHash() == xRpc1.GetBestBlockHash(), cancellationToken: shortCancellationToken); // Sanity check - mempools should all become empty. TestBase.WaitLoop(() => xRpc1.GetRawMempool().Length == 0, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => sbfnRpc2.GetRawMempool().Length == 0, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => xRpc3.GetRawMempool().Length == 0, cancellationToken: shortCancellationToken); } }
public void XMinesTransaction_SBFNSyncs() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // TODO: Add the necessary executables for Linux & OSX return; } using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisRegTest(); CoreNode stratisXNode = builder.CreateStratisXNode(version: "2.0.0.5").Start(); var callback = new Action <IFullNodeBuilder>(build => build .UseBlockStore() .UsePosConsensus() .UseMempool() .UseWallet() .AddPowPosMining() .AddRPC()); var config = new NodeConfigParameters(); config.Add("whitelist", stratisXNode.Endpoint.ToString()); config.Add("gateway", "1"); CoreNode stratisNode = builder .CreateCustomNode(callback, network, protocolVersion: ProtocolVersion.PROVEN_HEADER_VERSION, minProtocolVersion: ProtocolVersion.POS_PROTOCOL_VERSION, configParameters: config) .WithWallet().Start(); RPCClient stratisXRpc = stratisXNode.CreateRPCClient(); RPCClient stratisNodeRpc = stratisNode.CreateRPCClient(); stratisXRpc.AddNode(stratisNode.Endpoint, false); stratisNodeRpc.AddNode(stratisXNode.Endpoint, false); stratisXRpc.SendCommand(RPCOperations.generate, 11); var shortCancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(2)).Token; // Without this there seems to be a race condition between the blocks all getting generated and SBFN syncing high enough to fall through the getbestblockhash check. TestBase.WaitLoop(() => stratisXRpc.GetBlockCount() >= 11, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => stratisNodeRpc.GetBestBlockHash() == stratisXRpc.GetBestBlockHash(), cancellationToken: shortCancellationToken); // Send transaction to arbitrary address from X side. var alice = new Key().GetBitcoinSecret(network); var aliceAddress = alice.GetAddress(); stratisXRpc.SendCommand(RPCOperations.sendtoaddress, aliceAddress.ToString(), 1); TestBase.WaitLoop(() => stratisXRpc.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); // Transaction should percolate through to SBFN's mempool. TestBase.WaitLoop(() => stratisNodeRpc.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken); // Now X must mine the block. stratisXRpc.SendCommand(RPCOperations.generate, 1); TestBase.WaitLoop(() => stratisXRpc.GetBlockCount() >= 12, cancellationToken: shortCancellationToken); // We expect that SBFN will sync correctly. TestBase.WaitLoop(() => stratisNodeRpc.GetBestBlockHash() == stratisXRpc.GetBestBlockHash(), cancellationToken: shortCancellationToken); // Sanity check - mempools should both become empty. TestBase.WaitLoop(() => stratisNodeRpc.GetRawMempool().Length == 0, cancellationToken: shortCancellationToken); TestBase.WaitLoop(() => stratisXRpc.GetRawMempool().Length == 0, cancellationToken: shortCancellationToken); } }
public CoreNode CreateNode(NodeBuilder nodeBuilder, string agent, ProtocolVersion version = ProtocolVersion.ALT_PROTOCOL_VERSION, NodeConfigParameters configParameters = null) { var callback = new Action <IFullNodeBuilder>(builder => builder .UseBlockStore() .UsePosConsensus() .UseMempool() .AddRPC() .UseNodeHost() .UseTestChainedHeaderTree() .MockIBD() ); return(nodeBuilder.CreateCustomNode(callback, new StratisOverrideRegTest(), ProtocolVersion.PROVEN_HEADER_VERSION, agent: agent, configParameters: configParameters)); }
public async Task ListAddressGroupingsAsync() { using (var builder = NodeBuilder.Create(this)) { var network = new BitcoinRegTest(); var nodeConfig = new NodeConfigParameters { { "-txIndex", "1" } }; this.miner = builder.CreateStratisPowNode(network, agent: "la-1-miner", configParameters: nodeConfig).WithWallet().Start(); this.receiver = builder.CreateStratisPowNode(network, agent: "la-1-receiver", configParameters: nodeConfig).WithWallet().Start(); // Mine blocks to get coins. TestHelper.MineBlocks(this.miner, 101); // Sync miner with receiver. TestHelper.ConnectAndSync(this.miner, this.receiver); // Send 10 coins from miner to receiver. SendCoins(this.miner, this.receiver, Money.Coins(10)); // Receiver's listaddressgroupings response contains 1 array with 1 item. var result = await CallListAddressGroupingsAsync(); result.Count().Should().Be(1); result[0].AddressGroups.First().Amount.Should().Be(Money.Coins(10)); // Send 5 coins to miner from receiver; this will return 5 coins back to a change address on receiver. SendCoins(this.receiver, this.miner, Money.Coins(5)); // Get the change address. var receiver_Wallet = this.receiver.FullNode.WalletManager().GetWallet(walletName); var firstChangeAddress = receiver_Wallet.GetAllAddresses().First(a => a.IsChangeAddress() && a.Transactions.Any()); //--------------------------------------------------- // Receiver's listaddressgroupings response contains 1 array with 2 items: // - The initial receive address // - The change address address //--------------------------------------------------- result = await CallListAddressGroupingsAsync(); result.Count().Should().Be(1); result[0].AddressGroups.Count().Should().Be(2); result[0].AddressGroups.First().Amount.Should().Be(Money.Coins(0)); // Initial receive address balance should be 0. result[0].AddressGroups.First(a => a.Address == firstChangeAddress.Address).Amount.Should().Be(Money.Coins((decimal)4.9999548)); // Change address balance after sending 5 coins. //--------------------------------------------------- // Send 5 coins from miner to receiver's change address SendCoins(this.miner, this.receiver, Money.Coins(5), firstChangeAddress); //--------------------------------------------------- // Receiver's listaddressgroupings response contains 1 array with 2 items: // - The initial receive address // - The change address address //--------------------------------------------------- result = await CallListAddressGroupingsAsync(); result.Count().Should().Be(1); result[0].AddressGroups.Count().Should().Be(2); result[0].AddressGroups.First().Amount.Should().Be(Money.Coins(0)); // Initial receive address balance should be 0. result[0].AddressGroups.First(a => a.Address == firstChangeAddress.Address).Amount.Should().Be(Money.Coins((decimal)4.9999548 + 5)); // Change address balance + 5 coins. //--------------------------------------------------- // Send the (full balance - 1) from receiver to miner. var balance = this.receiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(walletName).Sum(t => t.Transaction.Amount) - Money.Coins(1); SendCoins(this.receiver, this.miner, balance); // Get the change address. receiver_Wallet = this.receiver.FullNode.WalletManager().GetWallet(walletName); var changeAddresses = receiver_Wallet.GetAllAddresses().Where(a => a.IsChangeAddress() && a.Transactions.Any()); var secondChangeAddress = receiver_Wallet.GetAllAddresses().First(a => a.IsChangeAddress() && a.Transactions.Any() && a.Address != firstChangeAddress.Address); //--------------------------------------------------- // Receiver's listaddressgroupings response contains 1 array with 3 items: // - The initial receive address // - The change address address // - The change address of sending the full balance - 1 //--------------------------------------------------- result = await CallListAddressGroupingsAsync(); result.Count().Should().Be(1); result[0].AddressGroups.Count().Should().Be(3); result[0].AddressGroups.Count(a => a.Address == firstChangeAddress.Address).Should().Be(1); result[0].AddressGroups.Count(a => a.Address == secondChangeAddress.Address).Should().Be(1); result[0].AddressGroups.First(a => a.Address == secondChangeAddress.Address).Amount.Should().Be(Money.Coins((decimal)0.99992520)); //--------------------------------------------------- // Send 5 coins to a new unused address on the receiver's wallet. SendCoins(this.miner, this.receiver, Money.Coins(5)); // Receiver's listaddressgroupings response contains 2 arrays: // - Array 1 > The initial receive address // - Array 1 > The change address address // - Array 1 > The change address of sending the full balance - 1 // - Array 2 > The receive address of the new transaction result = await CallListAddressGroupingsAsync(); result.Count().Should().Be(2); result[1].AddressGroups[0].Amount.Should().Be(Money.Coins(5)); } }
public void IndexAddresses_All_Nodes_Synced_Reorg() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new BitcoinRegTest(); var nodeConfig = new NodeConfigParameters { { "-addressindex", "1" } }; var minerA = builder.CreateStratisPowNode(network, "ai-2-minerA", configParameters: nodeConfig).WithReadyBlockchainData(ReadyBlockchain.BitcoinRegTest10Miner).Start(); var minerB = builder.CreateStratisPowNode(network, "ai-2-minerB", configParameters: nodeConfig).WithDummyWallet().Start(); var syncer = builder.CreateStratisPowNode(network, "ai-2-syncer", configParameters: nodeConfig).Start(); // Sync the network to height 10. TestHelper.ConnectAndSync(syncer, minerA, minerB); // Disconnect syncer from miner B TestHelper.Disconnect(syncer, minerB); // MinerA = 15 // MinerB = 10 // Syncer = 15 TestHelper.MineBlocks(minerA, 5); TestBase.WaitLoop(() => TestHelper.AreNodesSynced(syncer, minerA)); // MinerA = 15 // MinerB = 15 // Syncer = 15 TestHelper.Connect(syncer, minerB); // Disconnect syncer from miner A TestHelper.Disconnect(syncer, minerA); // MinerA = 15 // MinerB = 25 // Syncer = 25 TestHelper.MineBlocks(minerB, 10); TestBase.WaitLoop(() => TestHelper.AreNodesSynced(syncer, minerB)); // Connect syncer to miner A //TestHelper.Connect(syncer, minerA); // MinerA = 35 // MinerB = 25 // Syncer = 25 TestHelper.MineBlocks(minerA, 20); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerA, 35)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerB, 25)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(syncer, 25)); TestHelper.Connect(syncer, minerA); Assert.True(TestHelper.IsNodeSyncedAtHeight(syncer, 35)); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerA, 35)); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerB, 35)); TestBase.WaitLoop(() => minerA.FullNode.NodeService <IAddressIndexer>().IndexerTip.Height == 35); TestBase.WaitLoop(() => minerB.FullNode.NodeService <IAddressIndexer>().IndexerTip.Height == 35); TestBase.WaitLoop(() => syncer.FullNode.NodeService <IAddressIndexer>().IndexerTip.Height == 35); } }
public void IndexAddresses_All_Nodes_Synced_Reorg_With_UTXOs() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new BitcoinRegTestOverrideCoinbaseMaturity(5); var nodeConfig = new NodeConfigParameters { { "-addressindex", "1" } }; var minerA = builder.CreateStratisPowNode(network, "ai-3-minerA", configParameters: nodeConfig).WithWallet().Start(); var minerB = builder.CreateStratisPowNode(network, "ai-3-minerB", configParameters: nodeConfig).WithWallet().Start(); var syncer = builder.CreateStratisPowNode(network, "ai-3-syncer", configParameters: nodeConfig).WithWallet().Start(); // minerA mines to height 10 // MinerA = 10 // MinerB = 10 // Syncer = 10 TestHelper.MineBlocks(minerA, 10); // Sync the network to height 10. TestHelper.ConnectAndSync(syncer, minerA); TestHelper.ConnectAndSync(syncer, minerB); // Disconnect syncer from miner A TestHelper.Disconnect(syncer, minerA); TestHelper.Disconnect(syncer, minerB); // minerB mines to height 10 // MinerA = 10 // MinerB = 20 // Syncer = 10 TestHelper.MineBlocks(minerB, 10); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerA, 10)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerB, 20)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(syncer, 10)); // Miner A mines on its own chain. // MinerA = 25 // MinerB = 20 // Syncer = 10 TestHelper.MineBlocks(minerA, 15); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerA, 25)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerB, 20)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(syncer, 10)); // Reconnect syncer to minerA. TestHelper.Connect(syncer, minerA); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerA, 25)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerB, 20)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(syncer, 25)); // Spend some coins on minerA by sending 10 STRAT to syncer. TestHelper.SendCoins(minerA, syncer, Money.Coins(10)); // Miner A mines the transaction and advances onto 35. // MinerA = 40 // MinerB = 20 // Syncer = 20 TestHelper.MineBlocks(minerA, 15); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerA, 40)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(minerB, 20)); TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(syncer, 40)); // minerB mines to height 50 // MinerA = 40 // MinerB = 50 // Syncer = 40 TestHelper.MineBlocks(minerB, 40); // Reconnect minerB (the longer chain), this will trigger the reorg. TestHelper.Connect(syncer, minerB); Assert.True(TestHelper.IsNodeSyncedAtHeight(syncer, 60)); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerA, 60)); Assert.True(TestHelper.IsNodeSyncedAtHeight(minerB, 60)); TestBase.WaitLoop(() => minerA.FullNode.NodeService <IAddressIndexer>().IndexerTip.Height == 60); TestBase.WaitLoop(() => minerB.FullNode.NodeService <IAddressIndexer>().IndexerTip.Height == 60); TestBase.WaitLoop(() => syncer.FullNode.NodeService <IAddressIndexer>().IndexerTip.Height == 60); // The transaction got reverted. TestHelper.CheckWalletBalance(syncer, 0); } }
public void Staking_Wallet_Can_Mint_New_Coins() { using (var builder = NodeBuilder.Create(this)) { var configParameters = new NodeConfigParameters { { "txindex", "1" } }; var network = new StraxRegTest(); var minerA = builder.CreateStratisPosNode(network, "stake-1-minerA", configParameters: configParameters).OverrideDateTimeProvider().WithWallet().Start(); var addressUsed = TestHelper.MineBlocks(minerA, (int)network.Consensus.PremineHeight).AddressUsed; //Since the pre - mine will not be immediately spendable, the transactions have to be counted directly from the address. addressUsed.Transactions.Count().Should().Be((int)network.Consensus.PremineHeight); addressUsed.Transactions.Sum(s => s.Amount).Should().Be(network.Consensus.PremineReward + network.Consensus.ProofOfWorkReward); // Mine blocks to maturity TestHelper.MineBlocks(minerA, (int)network.Consensus.CoinbaseMaturity + 10); // Get set of transaction IDs present in wallet before staking is started. this.transactionsBeforeStaking.Clear(); foreach (TransactionData transactionData in this.GetTransactionsSnapshot(minerA)) { this.transactionsBeforeStaking.Add(transactionData.Id); } // Start staking on the node. var minter = minerA.FullNode.NodeService <IPosMinting>(); minter.Stake(new WalletSecret() { WalletName = "mywallet", WalletPassword = "******" }); // If new transactions are appearing in the wallet, staking has been successful. Due to coin maturity settings the // spendable balance of the wallet actually drops after staking, so the wallet balance should not be used to // determine whether staking occurred. TestBase.WaitLoop(() => { List <TransactionData> transactions = this.GetTransactionsSnapshot(minerA); foreach (TransactionData transactionData in transactions) { if (!this.transactionsBeforeStaking.Contains(transactionData.Id) && (transactionData.IsCoinStake ?? false)) { return(true); } } return(false); }); // build a dictionary of coinstake tx's indexed by tx id. foreach (var tx in this.GetTransactionsSnapshot(minerA)) { this.transactionLookup[tx.Id] = tx; } TestBase.WaitLoop(() => { List <TransactionData> transactions = this.GetTransactionsSnapshot(minerA); foreach (TransactionData transactionData in transactions) { if (!this.transactionsBeforeStaking.Contains(transactionData.Id) && (transactionData.IsCoinStake ?? false)) { Transaction coinstakeTransaction = minerA.FullNode.BlockStore().GetTransactionById(transactionData.Id); var balance = new Money(0); // Add coinstake outputs to balance. foreach (TxOut output in coinstakeTransaction.Outputs) { balance += output.Value; } //Subtract coinstake inputs from balance. foreach (TxIn input in coinstakeTransaction.Inputs) { this.transactionLookup.TryGetValue(input.PrevOut.Hash, out TransactionData prevTransactionData); if (prevTransactionData == null) { continue; } Transaction prevTransaction = minerA.FullNode.BlockStore().GetTransactionById(prevTransactionData.Id); balance -= prevTransaction.Outputs[input.PrevOut.N].Value; } Assert.Equal(minerA.FullNode.Network.Consensus.ProofOfStakeReward, balance); return(true); } } return(false); }); } }
public async Task WalletCanReturnStakingHistoryCorrectlyAsync() { using var builder = NodeBuilder.Create(this); var configParameters = new NodeConfigParameters { { "txindex", "1" } }; var network = new StraxRegTestAdjusedCoinbaseMaturity(); // Start 2 nodes CoreNode miner = builder.CreateStratisPosNode(network, "history-1-nodeA", configParameters: configParameters).OverrideDateTimeProvider().WithWallet().Start(); CoreNode syncer = builder.CreateStratisPosNode(network, "history-1-nodeB", configParameters: configParameters).OverrideDateTimeProvider().WithWallet().Start(); TestHelper.ConnectAndSync(miner, syncer); // Get mining address IEnumerable <string> miningAddresses = await $"http://localhost:{miner.ApiPort}/api" .AppendPathSegment("wallet/unusedAddresses") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 1 }) .GetJsonAsync <IEnumerable <string> >(); // Assert empty history call result. var noHistoryCall = $"http://localhost:{miner.ApiPort}/api" .AppendPathSegment("wallet/history") .SetQueryParams(new WalletHistoryRequest { WalletName = "mywallet", AccountName = "account 0" }) .GetAsync() .ReceiveJson <WalletHistoryModel>().GetAwaiter().GetResult(); Assert.Empty(noHistoryCall.AccountsHistoryModel.First().TransactionsHistory); // Mine some blocks to receive the premine and mature the chain. TestHelper.MineBlocks(miner, 20, miningAddress: miningAddresses.First()); // Start staking on the node. IPosMinting minter = miner.FullNode.NodeService <IPosMinting>(); minter.Stake(new List <WalletSecret>() { new WalletSecret() { WalletName = "mywallet", WalletPassword = "******" } }); // Stake to block height 30 TestBase.WaitLoop(() => TestHelper.IsNodeSyncedAtHeight(miner, 30, 120), waitTimeSeconds: 120); // Stop staking. minter.StopStake(); // Ensure nodes are synced. TestBase.WaitLoop(() => TestHelper.AreNodesSynced(miner, syncer)); // Assert ordering var history = await CallHistoryAsync(miner); // Staking items should appear first in the result. var stakingTxs = history.Where(t => t.Type == TransactionItemType.Staked); Assert.NotEmpty(stakingTxs); var index = 0; do { var item = history[index]; if (item.Type == TransactionItemType.Mined) { break; } Assert.Equal(Money.Coins(9), item.Amount); Assert.Equal(TransactionItemType.Staked, item.Type); index += 1; } while (true); // Then the rest are mining txs for (int mIndex = index; mIndex < index + 20; mIndex++) { var item = history[mIndex]; if ((miner.FullNode.ChainIndexer.Tip.Height - 2) == mIndex) { Assert.Equal(Money.Coins(130_000_000), item.Amount); //premine } else { Assert.Equal(Money.Coins(18), item.Amount); } Assert.Equal(miningAddresses.First(), item.ToAddress); Assert.Equal(TransactionItemType.Mined, item.Type); } // Assert Pagination and ordering var paging = $"http://localhost:{miner.ApiPort}/api" .AppendPathSegment("wallet/history") .SetQueryParams(new WalletHistoryRequest { WalletName = "mywallet", AccountName = "account 0", Skip = 0, Take = 10 }) .GetAsync() .ReceiveJson <WalletHistoryModel>().GetAwaiter().GetResult(); Assert.Equal(10, paging.AccountsHistoryModel.First().TransactionsHistory.Count()); }
public void Staking_Wont_Include_Time_Ahead_Of_Coinstake_Timestamp() { using (var builder = NodeBuilder.Create(this)) { var configParameters = new NodeConfigParameters { { "savetrxhex", "true" } }; var network = new StratisRegTest(); var minerA = builder.CreateStratisPosNode(network, "stake-1-minerA", configParameters: configParameters).OverrideDateTimeProvider().WithWallet().Start(); var addressUsed = TestHelper.MineBlocks(minerA, (int)network.Consensus.PremineHeight).AddressUsed; var wallet = minerA.FullNode.WalletManager().Wallets.Single(w => w.Name == "mywallet"); var allTrx = wallet.walletStore.GetForAddress(addressUsed.Address); // Since the pre-mine will not be immediately spendable, the transactions have to be counted directly from the address. allTrx.Count().Should().Be((int)network.Consensus.PremineHeight); allTrx.Sum(s => s.Amount).Should().Be(network.Consensus.PremineReward + network.Consensus.ProofOfWorkReward); var balance = minerA.FullNode.WalletManager().GetAddressBalance(addressUsed.Address); balance.AmountConfirmed.Should().Be(network.Consensus.PremineReward + network.Consensus.ProofOfWorkReward); // Mine blocks to maturity. TestHelper.MineBlocks(minerA, (int)network.Consensus.CoinbaseMaturity + 1); // Create a transaction and set its timestamp to one that will be rejected from the block. Transaction tx = minerA.FullNode.WalletTransactionHandler().BuildTransaction(new TransactionBuildContext(network) { Recipients = new List <Recipient>() { new Recipient { ScriptPubKey = addressUsed.ScriptPubKey, Amount = Money.Coins(1m) } }, AccountReference = new WalletAccountReference(minerA.WalletName, "account 0"), WalletPassword = minerA.WalletPassword, Time = (uint)minerA.FullNode.DateTimeProvider.GetAdjustedTimeAsUnixTimestamp() }); minerA.AddToStratisMempool(tx); TestBase.WaitLoop(() => minerA.FullNode.MempoolManager().InfoAll().Count == 1); // Get our height right now. int currentHeight = minerA.FullNode.ChainIndexer.Height; // Start staking on the node. var minter = minerA.FullNode.NodeService <IPosMinting>(); minter.Stake(new WalletSecret() { WalletName = minerA.WalletName, WalletPassword = minerA.WalletPassword }); // Ensure we've staked a block. TestBase.WaitLoop(() => minerA.FullNode.ChainIndexer.Height > currentHeight); // Get the staked block. ChainedHeader header = minerA.FullNode.ChainIndexer.GetHeader(currentHeight + 1); Block block = minerA.FullNode.BlockStore().GetBlock(header.HashBlock); // The transaction should not be in it. Assert.DoesNotContain(block.Transactions, x => x.GetHash() == tx.GetHash()); } }