Esempio n. 1
0
        public static bool CheckWalletBalance(CoreNode node, Money amount)
        {
            var total = node.FullNode.WalletManager().GetSpendableTransactionsInWallet(Name).Sum(s => s.Transaction.Amount);

            return(total == amount);
        }
Esempio n. 2
0
        public void TxMempoolBlockDoublespend()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode stratisNodeSync = builder.CreateStratisPowNode(this.network).WithDummyWallet().Start();

                stratisNodeSync.FullNode.NodeService <MempoolSettings>().RequireStandard = true; // make sure to test standard tx

                TestHelper.MineBlocks(stratisNodeSync, 100);                                     // coinbase maturity = 100

                // Make sure skipping validation of transctions that were
                // validated going into the memory pool does not allow
                // double-spends in blocks to pass validation when they should not.

                Script scriptPubKey = PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey);
                Block  genBlock     = stratisNodeSync.FullNode.BlockStore().GetBlockAsync(stratisNodeSync.FullNode.Chain.GetBlock(1).HashBlock).Result;

                // Create a double-spend of mature coinbase txn:
                var spends = new List <Transaction>(2);
                foreach (int index in Enumerable.Range(1, 2))
                {
                    Transaction trx = stratisNodeSync.FullNode.Network.CreateTransaction();
                    trx.AddInput(new TxIn(new OutPoint(genBlock.Transactions[0].GetHash(), 0), scriptPubKey));
                    trx.AddOutput(Money.Cents(11), new Key().PubKey.Hash);
                    // Sign:
                    trx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                    spends.Add(trx);
                }

                // Test 1: block with both of those transactions should be rejected.
                var tipBeforeBlockCreation = stratisNodeSync.FullNode.Chain.Tip;
                Assert.Throws <ConsensusException>(() => { Task.Delay(2).Wait(); Block block = TestHelper.GenerateBlockManually(stratisNodeSync, spends); });
                Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock == tipBeforeBlockCreation.HashBlock);

                // Test 2: ... and should be rejected if spend1 is in the memory pool
                tipBeforeBlockCreation = stratisNodeSync.FullNode.Chain.Tip;
                Assert.True(stratisNodeSync.AddToStratisMempool(spends[0]));
                Assert.Throws <ConsensusException>(() => { Task.Delay(2).Wait(); Block block = TestHelper.GenerateBlockManually(stratisNodeSync, spends, 100_000); });
                Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock == tipBeforeBlockCreation.HashBlock);
                stratisNodeSync.FullNode.MempoolManager().Clear().Wait();

                // Test 3: ... and should be rejected if spend2 is in the memory pool
                tipBeforeBlockCreation = stratisNodeSync.FullNode.Chain.Tip;
                Assert.True(stratisNodeSync.AddToStratisMempool(spends[1]));
                Assert.Throws <ConsensusException>(() => { Task.Delay(2).Wait(); Block block = TestHelper.GenerateBlockManually(stratisNodeSync, spends, 100_000_000); });
                Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock == tipBeforeBlockCreation.HashBlock);
                stratisNodeSync.FullNode.MempoolManager().Clear().Wait();

                // Final sanity test: first spend in mempool, second in block, that's OK:
                var oneSpend = new List <Transaction>();
                oneSpend.Add(spends[0]);
                Assert.True(stratisNodeSync.AddToStratisMempool(spends[1]));
                var validBlock = TestHelper.GenerateBlockManually(stratisNodeSync, oneSpend);
                TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusManager().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock);
                Assert.True(stratisNodeSync.FullNode.Chain.Tip.HashBlock == validBlock.GetHash());

                // spends[1] should have been removed from the mempool when the
                // block with spends[0] is accepted:
                TestHelper.WaitLoop(() => stratisNodeSync.FullNode.MempoolManager().MempoolSize().Result == 0);
            }
        }
Esempio n. 3
0
 /// <summary>
 /// Ensures a node is internally synced and at a given height.
 /// </summary>
 /// <param name="node">This node.</param>
 /// <param name="height">At which height should it be synced to.</param>
 /// <returns>Returns <c>true</c> if the node is synced at a given height.</returns>
 public static bool IsNodeSyncedAtHeight(CoreNode node, int height, int waitTimeSeconds = 60)
 {
     TestBase.WaitLoopMessage(() => { return(node.FullNode.ConsensusManager().Tip.Height == height, $"Node height: {node.FullNode.ConsensusManager().Tip.Height}; Expected height: {height}"); }, waitTimeSeconds);
     return(true);
 }
Esempio n. 4
0
 public static void EnableBlockPropagation(CoreNode from, CoreNode to)
 {
     from.FullNode.ConnectionManager.ConnectedPeers.FindByEndpoint(to.Endpoint).Behavior <BlockStoreBehavior>().CanRespondToGetDataPayload = true;
 }
Esempio n. 5
0
        public async Task RemoveTransactionsFromWalletCalledWithMoreThanOneFilter()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                // Arrange.
                CoreNode node = builder.CreateStratisPosNode(this.network).Start();

                this.AddAndLoadWalletFileToWalletFolder(node);

                // Make sure the account is used, i.e, it has transactions.
                WalletHistoryModel history = await $"http://localhost:{node.ApiPort}/api"
                                             .AppendPathSegment("wallet/history")
                                             .SetQueryParams(new { walletName = this.walletWithFundsName, accountName = "account 0" })
                                             .GetJsonAsync <WalletHistoryModel>();

                history.AccountsHistoryModel.Should().NotBeEmpty();
                history.AccountsHistoryModel.First().TransactionsHistory.Should().NotBeEmpty();

                // Act.
                Func <Task> act1 = async() => await $"http://localhost:{node.ApiPort}/api"
                                   .AppendPathSegment("wallet/remove-transactions")
                                   .SetQueryParams(new { walletName = this.walletWithFundsName, all = true, ids = new[] { "3ccdfdce538eabe4d18efd2ee8fdc2554dc95cae6ce082aa4b5c7b9074b2e0a3" } })
                                   .DeleteAsync()
                                   .ReceiveJson <HashSet <(uint256 transactionId, DateTimeOffset creationTime)> >();

                Func <Task> act2 = async() => await $"http://localhost:{node.ApiPort}/api"
                                   .AppendPathSegment("wallet/remove-transactions")
                                   .SetQueryParams(new { walletName = this.walletWithFundsName, fromDate = "06/06/2018", ids = new[] { "3ccdfdce538eabe4d18efd2ee8fdc2554dc95cae6ce082aa4b5c7b9074b2e0a3" } })
                                   .DeleteAsync()
                                   .ReceiveJson <HashSet <(uint256 transactionId, DateTimeOffset creationTime)> >();

                Func <Task> act3 = async() => await $"http://localhost:{node.ApiPort}/api"
                                   .AppendPathSegment("wallet/remove-transactions")
                                   .SetQueryParams(new { walletName = this.walletWithFundsName, fromDate = "06/06/2018", all = true })
                                   .DeleteAsync()
                                   .ReceiveJson <HashSet <(uint256 transactionId, DateTimeOffset creationTime)> >();

                Func <Task> act4 = async() => await $"http://localhost:{node.ApiPort}/api"
                                   .AppendPathSegment("wallet/remove-transactions")
                                   .SetQueryParams(new { walletName = this.walletWithFundsName, fromDate = "06/06/2018", all = true, ids = new[] { "3ccdfdce538eabe4d18efd2ee8fdc2554dc95cae6ce082aa4b5c7b9074b2e0a3" } })
                                   .DeleteAsync()
                                   .ReceiveJson <HashSet <(uint256 transactionId, DateTimeOffset creationTime)> >();

                // Assert.
                FlurlHttpException  exception1 = act1.Should().Throw <FlurlHttpException>().Which;
                HttpResponseMessage response1  = exception1.Call.Response;

                FlurlHttpException  exception2 = act2.Should().Throw <FlurlHttpException>().Which;
                HttpResponseMessage response2  = exception2.Call.Response;

                FlurlHttpException  exception3 = act3.Should().Throw <FlurlHttpException>().Which;
                HttpResponseMessage response3  = exception3.Call.Response;

                FlurlHttpException  exception4 = act4.Should().Throw <FlurlHttpException>().Which;
                HttpResponseMessage response4  = exception4.Call.Response;

                ErrorResponseLists errorResponse1 = JsonConvert.DeserializeObject <ErrorResponseLists>(await response1.Content.ReadAsStringAsync());
                ErrorResponseLists errorResponse2 = JsonConvert.DeserializeObject <ErrorResponseLists>(await response2.Content.ReadAsStringAsync());
                ErrorResponseLists errorResponse3 = JsonConvert.DeserializeObject <ErrorResponseLists>(await response3.Content.ReadAsStringAsync());
                ErrorResponseLists errorResponse4 = JsonConvert.DeserializeObject <ErrorResponseLists>(await response4.Content.ReadAsStringAsync());

                response1.StatusCode.Should().Be(HttpStatusCode.BadRequest);
                response1.StatusCode.Should().Be(response2.StatusCode);
                response2.StatusCode.Should().Be(response3.StatusCode);
                response3.StatusCode.Should().Be(response4.StatusCode);

                ErrorModel errors = errorResponse1.Errors;
                errors.DeleteAll.Should().ContainSingle();
                errors.DeleteAll.First().Should().Be($"Only one out of the query parameters '{nameof(RemoveTransactionsModel.DeleteAll)}', '{nameof(RemoveTransactionsModel.TransactionsIds)}' or '{nameof(RemoveTransactionsModel.FromDate)}' can be set.");
                errorResponse1.Should().BeEquivalentTo(errorResponse2);
                errorResponse2.Should().BeEquivalentTo(errorResponse3);
                errorResponse3.Should().BeEquivalentTo(errorResponse4);
            }
        }
Esempio n. 6
0
        public async Task SendingFromManyAddressesToOneAddress()
        {
            int sendingAccountBalanceOnStart   = 98000596;
            int receivingAccountBalanceOnStart = 0;

            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                // Arrange.
                // Create a sending and a receiving node.
                CoreNode sendingNode   = builder.CreateStratisPosNode(this.network).WithWallet().Start();
                CoreNode receivingNode = builder.CreateStratisPosNode(this.network).WithWallet().Start();

                // Mine a few blocks to fund the sending node and connect the nodes.
                IEnumerable <string> addressesToFund = await $"http://localhost:{sendingNode.ApiPort}/api"
                                                       .AppendPathSegment("wallet/unusedAddresses")
                                                       .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 150 })
                                                       .GetJsonAsync <IEnumerable <string> >();

                foreach (string address in addressesToFund)
                {
                    TestHelper.MineBlocks(sendingNode, 1, syncNode: false, miningAddress: address);
                }

                TestHelper.ConnectAndSync(sendingNode, receivingNode);

                // Check balances.
                WalletBalanceModel sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api"
                                                         .AppendPathSegment("wallet/balance")
                                                         .SetQueryParams(new { walletName = "mywallet" })
                                                         .GetJsonAsync <WalletBalanceModel>();

                AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single();
                (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC));

                WalletBalanceModel receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api"
                                                           .AppendPathSegment("wallet/balance")
                                                           .SetQueryParams(new { walletName = "mywallet" })
                                                           .GetJsonAsync <WalletBalanceModel>();

                AccountBalanceModel receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single();
                (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart));

                // Check max spendable amount.
                var maxBalanceResponse = await $"http://localhost:{sendingNode.ApiPort}/api"
                                         .AppendPathSegment("wallet/maxbalance")
                                         .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", feetype = "low", allowunconfirmed = true })
                                         .GetJsonAsync <MaxSpendableAmountModel>();

                Money totalToSpend = maxBalanceResponse.MaxSpendableAmount + maxBalanceResponse.Fee;

                // Act.
                // Get an address to send to.
                IEnumerable <string> unusedaddresses = await $"http://localhost:{receivingNode.ApiPort}/api"
                                                       .AppendPathSegment("wallet/unusedAddresses")
                                                       .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 1 })
                                                       .GetJsonAsync <IEnumerable <string> >();

                // Build and send the transaction with 50 recipients.
                WalletBuildTransactionModel buildTransactionModel = await $"http://localhost:{sendingNode.ApiPort}/api"
                                                                    .AppendPathSegment("wallet/build-transaction")
                                                                    .PostJsonAsync(new BuildTransactionRequest
                {
                    WalletName       = "mywallet",
                    AccountName      = "account 0",
                    FeeAmount        = maxBalanceResponse.Fee.ToString(),
                    Password         = "******",
                    ShuffleOutputs   = true,
                    AllowUnconfirmed = true,
                    Recipients       = unusedaddresses.Select(address => new RecipientModel
                    {
                        DestinationAddress = address,
                        Amount             = maxBalanceResponse.MaxSpendableAmount.ToString()
                    }).ToList()
                })
                                                                    .ReceiveJson <WalletBuildTransactionModel>();

                await $"http://localhost:{sendingNode.ApiPort}/api"
                .AppendPathSegment("wallet/send-transaction")
                .PostJsonAsync(new SendTransactionRequest
                {
                    Hex = buildTransactionModel.Hex
                })
                .ReceiveJson <WalletSendTransactionModel>();

                // Assert.
                // The sending node should have 50 (+ fee) fewer coins.
                sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api"
                                      .AppendPathSegment("wallet/balance")
                                      .SetQueryParams(new { walletName = "mywallet" })
                                      .GetJsonAsync <WalletBalanceModel>();

                sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single();
                (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC) - totalToSpend);

                // Mine and sync so that we make sure the receiving node is up to date.
                TestHelper.MineBlocks(sendingNode, 1);
                TestHelper.WaitForNodeToSync(sendingNode, receivingNode);

                // The receiving node should have 50 more coins.
                receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api"
                                        .AppendPathSegment("wallet/balance")
                                        .SetQueryParams(new { walletName = "mywallet" })
                                        .GetJsonAsync <WalletBalanceModel>();

                receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single();
                (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart) + maxBalanceResponse.MaxSpendableAmount);
            }
        }
 private void Mine100Coins(CoreNode node)
 {
     this.sharedSteps.MineBlocks(this.CoinBaseMaturity + 2, node, WalletAccountName, WalletName, WalletPassword);
 }
Esempio n. 8
0
        public void MustNotAnnounceABlock_WhenNotInBestChain()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode stratisNodeSync = builder.CreateStratisPowNode(this.network, "bss-2-stratisNodeSync").WithReadyBlockchainData(ReadyBlockchain.BitcoinRegTest10Miner).Start();
                CoreNode stratisNode1    = builder.CreateStratisPowNode(this.network, "bss-2-stratisNode1").WithReadyBlockchainData(ReadyBlockchain.BitcoinRegTest10Listener).Start();
                CoreNode stratisNode2    = builder.CreateStratisPowNode(this.network, "bss-2-stratisNode2").WithReadyBlockchainData(ReadyBlockchain.BitcoinRegTest10NoWallet).Start();

                // Store block 1 of chain0 for later usage
                ChainedHeader firstBlock = null;
                foreach (ChainedHeader chainedHeader in stratisNodeSync.FullNode.ChainIndexer.EnumerateToTip(this.network.GenesisHash))
                {
                    if (chainedHeader.Height == 1)
                    {
                        firstBlock = chainedHeader;
                    }
                }

                Assert.NotNull(firstBlock);

                // Mine longer chain1 using node1
                TestHelper.MineBlocks(stratisNode1, 15);

                IConnectionManager node1ConnectionManager = stratisNode1.FullNode.NodeService <IConnectionManager>();
                node1ConnectionManager.Parameters.TemplateBehaviors.Add(new TestBehavior());

                IConnectionManager node2ConnectionManager = stratisNode2.FullNode.NodeService <IConnectionManager>();
                node2ConnectionManager.Parameters.TemplateBehaviors.Add(new TestBehavior());

                // Connect node0 and node1
                TestHelper.Connect(stratisNode1, stratisNodeSync);

                INetworkPeer connectedPeer = node1ConnectionManager.ConnectedPeers.FindByEndpoint(stratisNodeSync.Endpoint);
                TestBehavior testBehavior  = connectedPeer.Behavior <TestBehavior>();

                // We expect that node0 will abandon the 10 block chain and use the 15 block chain from node1
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode1, stratisNodeSync));

                // Connect all nodes together
                TestHelper.Connect(stratisNode2, stratisNodeSync);
                TestHelper.Connect(stratisNode1, stratisNode2);

                INetworkPeer connectedPeer2 = node2ConnectionManager.ConnectedPeers.FindByEndpoint(stratisNodeSync.Endpoint);
                TestBehavior testBehavior2  = connectedPeer2.Behavior <TestBehavior>();

                // Wait for node2 to sync; it should have the 15 block chain
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode2, stratisNodeSync));

                // Insert block 1 from chain0 into node1's announce queue
                BlockStoreSignaled node1BlockStoreSignaled = stratisNode1.FullNode.NodeService <BlockStoreSignaled>();

                IAsyncQueue <ChainedHeader> node1BlocksToAnnounce = (IAsyncQueue <ChainedHeader>)node1BlockStoreSignaled.GetMemberValue("blocksToAnnounce");

                Queue <ChainedHeader> node1QueueItems = (Queue <ChainedHeader>)node1BlocksToAnnounce.GetMemberValue("items");

                TestHelper.WaitLoop(() => node1QueueItems.Count == 0);

                // Check that node2 does not have block 1 in test behaviour advertised list
                foreach (IncomingMessage message in testBehavior2.receivedMessageTracker["headers"])
                {
                    if (message.Message.Payload is HeadersPayload)
                    {
                        foreach (BlockHeader header in ((HeadersPayload)message.Message.Payload).Headers)
                        {
                            if (header.GetHash() == firstBlock.Header.GetHash())
                            {
                                throw new Exception("Should not have received payload announcing block from wrong chain");
                            }
                        }
                    }
                }
            }
        }
Esempio n. 9
0
        public async Task InitializeNoWalletAsync()
        {
            InitializationStarted = true;
            AddressManager        = null;
            var cancel = StoppingCts.Token;

            try
            {
                await SingleInstanceChecker.CheckAsync().ConfigureAwait(false);

                Cache = new MemoryCache(new MemoryCacheOptions
                {
                    SizeLimit = 1_000,
                    ExpirationScanFrequency = TimeSpan.FromSeconds(30)
                });
                var bstoreInitTask           = BitcoinStore.InitializeAsync();
                var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");

                AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
                var addrManTask = InitializeAddressManagerBehaviorAsync();

                var userAgent            = Constants.UserAgents.RandomElement();
                var connectionParameters = new NodeConnectionParameters {
                    UserAgent = userAgent
                };

                HostedServices.Register(new UpdateChecker(TimeSpan.FromMinutes(7), Synchronizer), "Software Update Checker");

                HostedServices.Register(new SystemAwakeChecker(WalletManager), "System Awake Checker");

                #region ProcessKillSubscription

                AppDomain.CurrentDomain.ProcessExit += async(s, e) => await DisposeAsync().ConfigureAwait(false);

                Console.CancelKeyPress += async(s, e) =>
                {
                    e.Cancel = true;
                    Logger.LogWarning("Process was signaled for killing.", nameof(Global));
                    await DisposeAsync().ConfigureAwait(false);
                };

                #endregion ProcessKillSubscription

                cancel.ThrowIfCancellationRequested();

                #region TorProcessInitialization

                if (Config.UseTor)
                {
                    using (BenchmarkLogger.Measure(operationName: "TorProcessManager.Start"))
                    {
                        TorManager = new TorProcessManager(TorSettings, Config.TorSocks5EndPoint);
                        await TorManager.StartAsync(ensureRunning : true).ConfigureAwait(false);
                    }

                    var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
                    TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), fallbackRequestTestUri);
                }
                else
                {
                    TorSocks5EndPoint = null;
                }

                Logger.LogInfo($"{nameof(TorProcessManager)} is initialized.");

                #endregion TorProcessInitialization

                cancel.ThrowIfCancellationRequested();

                #region BitcoinStoreInitialization

                await bstoreInitTask.ConfigureAwait(false);

                // Make sure that the height of the wallets will not be better than the current height of the filters.
                WalletManager.SetMaxBestHeight(BitcoinStore.IndexStore.SmartHeaderChain.TipHeight);

                #endregion BitcoinStoreInitialization

                cancel.ThrowIfCancellationRequested();

                #region BitcoinCoreInitialization

                try
                {
                    if (Config.StartLocalBitcoinCoreOnStartup)
                    {
                        BitcoinCoreNode = await CoreNode
                                          .CreateAsync(
                            new CoreNodeParams(
                                Network,
                                BitcoinStore.MempoolService,
                                HostedServices,
                                Config.LocalBitcoinCoreDataDir,
                                tryRestart : false,
                                tryDeleteDataDir : false,
                                EndPointStrategy.Default(Network, EndPointType.P2p),
                                EndPointStrategy.Default(Network, EndPointType.Rpc),
                                txIndex : null,
                                prune : null,
                                mempoolReplacement : "fee,optin",
                                userAgent : $"/WasabiClient:{Constants.ClientVersion}/",
                                fallbackFee : null,                                        // ToDo: Maybe we should have it, not only for tests?
                                Cache),
                            cancel)
                                          .ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                }

                await HostedServices.StartAllAsync(cancel).ConfigureAwait(false);

                var rpcFeeProvider = HostedServices.FirstOrDefault <RpcFeeProvider>();

                FeeProviders = new FeeProviders(Synchronizer, rpcFeeProvider);

                #endregion BitcoinCoreInitialization

                cancel.ThrowIfCancellationRequested();

                #region MempoolInitialization

                connectionParameters.TemplateBehaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior());

                #endregion MempoolInitialization

                cancel.ThrowIfCancellationRequested();

                #region AddressManagerInitialization

                AddressManagerBehavior addressManagerBehavior = await addrManTask.ConfigureAwait(false);

                connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

                #endregion AddressManagerInitialization

                cancel.ThrowIfCancellationRequested();

                #region P2PInitialization

                if (Network == Network.RegTest)
                {
                    Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
                    try
                    {
                        EndPoint bitcoinCoreEndpoint = Config.GetBitcoinP2pEndPoint();

                        Node node = await Node.ConnectAsync(Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        Nodes.ConnectedNodes.Add(node);

                        RegTestMempoolServingNode = await Node.ConnectAsync(Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        RegTestMempoolServingNode.Behaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior());
                    }
                    catch (SocketException ex)
                    {
                        Logger.LogError(ex);
                    }
                }
                else
                {
                    if (Config.UseTor)
                    {
                        // onlyForOnionHosts: false - Connect to clearnet IPs through Tor, too.
                        connectionParameters.TemplateBehaviors.Add(new SocksSettingsBehavior(Config.TorSocks5EndPoint, onlyForOnionHosts: false, networkCredential: null, streamIsolation: true));
                        // allowOnlyTorEndpoints: true - Connect only to onions and do not connect to clearnet IPs at all.
                        // This of course makes the first setting unnecessary, but it's better if that's around, in case someone wants to tinker here.
                        connectionParameters.EndpointConnector = new DefaultEndpointConnector(allowOnlyTorEndpoints: Network == Network.Main);

                        await AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager).ConfigureAwait(false);
                    }
                    Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);
                    Nodes.MaximumNodeConnection = 12;
                    RegTestMempoolServingNode   = null;
                }

                Nodes.Connect();
                Logger.LogInfo("Start connecting to nodes...");

                var regTestMempoolServingNode = RegTestMempoolServingNode;
                if (regTestMempoolServingNode is { })
 private HdAddress GetSecondUnusedAddressToAvoidClashWithMiningAddress(CoreNode node)
 {
     return(node.FullNode.WalletManager()
            .GetUnusedAddresses(new WalletAccountReference(WalletZero, AccountZero), 2)
            .Skip(1).First());
 }
 private void a_second_proof_of_work_node_with_api_enabled()
 {
     this.secondStratisPowApiNode          = this.powNodeBuilder.CreateStratisPowNode(this.powNetwork).WithWallet().Start();
     this.secondStratisPowApiNode.Mnemonic = this.secondStratisPowApiNode.Mnemonic;
 }
Esempio n. 12
0
        public async Task InitializeNoWalletAsync()
        {
            InitializationStarted = true;
            AddressManager        = null;
            var cancel = StoppingCts.Token;

            try
            {
                await SingleInstanceChecker.CheckAsync().ConfigureAwait(false);

                Cache = new MemoryCache(new MemoryCacheOptions
                {
                    SizeLimit = 1_000,
                    ExpirationScanFrequency = TimeSpan.FromSeconds(30)
                });
                var bstoreInitTask           = BitcoinStore.InitializeAsync();
                var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");

                AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
                var addrManTask = InitializeAddressManagerBehaviorAsync();

                var userAgent            = Constants.UserAgents.RandomElement();
                var connectionParameters = new NodeConnectionParameters {
                    UserAgent = userAgent
                };

                HostedServices.Register(new UpdateChecker(TimeSpan.FromMinutes(7), Synchronizer), "Software Update Checker");

                #region ProcessKillSubscription

                AppDomain.CurrentDomain.ProcessExit += async(s, e) => await DisposeAsync().ConfigureAwait(false);

                Console.CancelKeyPress += async(s, e) =>
                {
                    e.Cancel = true;
                    Logger.LogWarning("Process was signaled for killing.", nameof(Global));
                    await DisposeAsync().ConfigureAwait(false);
                };

                #endregion ProcessKillSubscription

                cancel.ThrowIfCancellationRequested();

                #region TorProcessInitialization

                if (Config.UseTor)
                {
                    TorManager = new TorProcessManager(TorSettings, Config.TorSocks5EndPoint);
                    TorManager.Start(ensureRunning: false);

                    var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
                    TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), fallbackRequestTestUri);
                }
                else
                {
                    TorSocks5EndPoint = null;
                }

                Logger.LogInfo($"{nameof(TorProcessManager)} is initialized.");

                #endregion TorProcessInitialization

                cancel.ThrowIfCancellationRequested();

                #region BitcoinStoreInitialization

                await bstoreInitTask.ConfigureAwait(false);

                // Make sure that the height of the wallets will not be better than the current height of the filters.
                WalletManager.SetMaxBestHeight(BitcoinStore.IndexStore.SmartHeaderChain.TipHeight);

                #endregion BitcoinStoreInitialization

                cancel.ThrowIfCancellationRequested();

                #region BitcoinCoreInitialization

                try
                {
                    if (Config.StartLocalBitcoinCoreOnStartup)
                    {
                        BitcoinCoreNode = await CoreNode
                                          .CreateAsync(
                            new CoreNodeParams(
                                Network,
                                BitcoinStore.MempoolService,
                                HostedServices,
                                Config.LocalBitcoinCoreDataDir,
                                tryRestart : false,
                                tryDeleteDataDir : false,
                                EndPointStrategy.Default(Network, EndPointType.P2p),
                                EndPointStrategy.Default(Network, EndPointType.Rpc),
                                txIndex : null,
                                prune : null,
                                mempoolReplacement : "fee,optin",
                                userAgent : $"/WasabiClient:{Constants.ClientVersion}/",
                                fallbackFee : null,                                        // ToDo: Maybe we should have it, not only for tests?
                                Cache),
                            cancel)
                                          .ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                }

                await HostedServices.StartAllAsync(cancel).ConfigureAwait(false);

                var feeProviderList = new List <IFeeProvider>
                {
                    Synchronizer
                };

                var rpcFeeProvider = HostedServices.FirstOrDefault <RpcFeeProvider>();
                if (rpcFeeProvider is { })
Esempio n. 13
0
        public void TxMempoolMapOrphans()
        {
            var rand     = new Random();
            var randByte = new byte[32];

            uint256 randHash()
            {
                rand.NextBytes(randByte);
                return(new uint256(randByte));
            }

            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode stratisNode = builder.CreateStratisPowNode(this.network).WithDummyWallet().Start();

                // 50 orphan transactions:
                for (ulong i = 0; i < 50; i++)
                {
                    Transaction tx = stratisNode.FullNode.Network.CreateTransaction();
                    tx.AddInput(new TxIn(new OutPoint(randHash(), 0), new Script(OpcodeType.OP_1)));
                    tx.AddOutput(new TxOut(new Money(1 * Money.CENT), stratisNode.MinerSecret.ScriptPubKey));

                    stratisNode.FullNode.NodeService <MempoolOrphans>().AddOrphanTx(i, tx);
                }

                Assert.Equal(50, stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count);

                // ... and 50 that depend on other orphans:
                for (ulong i = 0; i < 50; i++)
                {
                    MempoolOrphans.OrphanTx txPrev = stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().ElementAt(rand.Next(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count));

                    Transaction tx = stratisNode.FullNode.Network.CreateTransaction();
                    tx.AddInput(new TxIn(new OutPoint(txPrev.Tx.GetHash(), 0), new Script(OpcodeType.OP_1)));
                    tx.AddOutput(new TxOut(new Money((1 + i + 100) * Money.CENT), stratisNode.MinerSecret.ScriptPubKey));
                    stratisNode.FullNode.NodeService <MempoolOrphans>().AddOrphanTx(i, tx);
                }

                Assert.Equal(100, stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count);

                // This really-big orphan should be ignored:
                for (ulong i = 0; i < 10; i++)
                {
                    MempoolOrphans.OrphanTx txPrev = stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().ElementAt(rand.Next(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count));
                    Transaction             tx     = stratisNode.FullNode.Network.CreateTransaction();
                    tx.AddOutput(new TxOut(new Money(1 * Money.CENT), stratisNode.MinerSecret.ScriptPubKey));
                    foreach (int index in Enumerable.Range(0, 2777))
                    {
                        tx.AddInput(new TxIn(new OutPoint(txPrev.Tx.GetHash(), index), new Script(OpcodeType.OP_1)));
                    }

                    Assert.False(stratisNode.FullNode.NodeService <MempoolOrphans>().AddOrphanTx(i, tx));
                }

                Assert.Equal(100, stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count);

                // Test EraseOrphansFor:
                for (ulong i = 0; i < 3; i++)
                {
                    int sizeBefore = stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count;
                    stratisNode.FullNode.NodeService <MempoolOrphans>().EraseOrphansFor(i);
                    Assert.True(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count < sizeBefore);
                }

                // Test LimitOrphanTxSize() function:
                stratisNode.FullNode.NodeService <MempoolOrphans>().LimitOrphanTxSize(40);
                Assert.True(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count <= 40);
                stratisNode.FullNode.NodeService <MempoolOrphans>().LimitOrphanTxSize(10);
                Assert.True(stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Count <= 10);
                stratisNode.FullNode.NodeService <MempoolOrphans>().LimitOrphanTxSize(0);
                Assert.True(!stratisNode.FullNode.NodeService <MempoolOrphans>().OrphansList().Any());
            }
        }
Esempio n. 14
0
 private void a_pow_node_running()
 {
     this.node = this.builder.CreateStratisPowNode(this.network).NotInIBD();
     this.node.Start();
     this.node.WithWallet();
 }
        public void SBFNMinesTransaction_XSyncs()
        {
            // TODO: Currently fails due to issue #2468 (coinbase
            // reward on stratisX cannot be >4. No fees are allowed)

            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();

                // We do not want the datetime provider to be substituted,
                // so a custom builder callback has to be used.
                var callback = new Action <IFullNodeBuilder>(build => build
                                                             .UseBlockStore()
                                                             .UsePosConsensus()
                                                             .UseMempool()
                                                             .UseWallet()
                                                             .AddPowPosMining()
                                                             .AddRPC()
                                                             .UseTestChainedHeaderTree()
                                                             .MockIBD());

                CoreNode stratisNode = builder.CreateCustomNode(callback, network, protocolVersion: ProtocolVersion.ALT_PROTOCOL_VERSION).WithWallet().Start();

                RPCClient stratisXRpc    = stratisXNode.CreateRPCClient();
                RPCClient stratisNodeRpc = stratisNode.CreateRPCClient();

                stratisXRpc.AddNode(stratisNode.Endpoint, false);
                stratisNodeRpc.AddNode(stratisXNode.Endpoint, false);

                TestHelper.MineBlocks(stratisNode, 11);

                // It takes a reasonable amount of time for blocks to be generated without
                // the datetime provider substitution.
                var longCancellationToken  = new CancellationTokenSource(TimeSpan.FromMinutes(15)).Token;
                var shortCancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token;

                TestBase.WaitLoop(() => stratisNodeRpc.GetBestBlockHash() == stratisXRpc.GetBestBlockHash(), cancellationToken: longCancellationToken);

                // Send transaction to arbitrary address from SBFN side.
                var alice        = new Key().GetBitcoinSecret(network);
                var aliceAddress = alice.GetAddress();
                stratisNodeRpc.WalletPassphrase("password", 60);
                stratisNodeRpc.SendToAddress(aliceAddress, Money.Coins(1.0m));

                TestBase.WaitLoop(() => stratisNodeRpc.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken);

                // Transaction should percolate through to X's mempool.
                TestBase.WaitLoop(() => stratisXRpc.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken);

                // Now SBFN must mine the block.
                TestHelper.MineBlocks(stratisNode, 1);

                // We expect that X 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);
            }
        }
Esempio n. 16
0
        public void CheckBlocksAnnounced_AndQueueEmptiesOverTime_ForMultiplePeers_WhenOneIsDisconnected()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode stratisNodeSync = builder.CreateStratisPowNode(this.network, "bss-2-stratisNodeSync").WithReadyBlockchainData(ReadyBlockchain.BitcoinRegTest10Miner).Start();

                CoreNode stratisNode1 = builder.CreateStratisPowNode(this.network, "bss-2-stratisNode1").Start();
                CoreNode stratisNode2 = builder.CreateStratisPowNode(this.network, "bss-2-stratisNode2").Start();
                CoreNode stratisNode3 = builder.CreateStratisPowNode(this.network, "bss-2-stratisNode3").Start();

                // Change the other nodes' lists of default behaviours include the test behaviour in it.
                // We leave the other behaviors alone for this test because we want to see what messages the node gets under normal operation.
                IConnectionManager node1ConnectionManager = stratisNode1.FullNode.NodeService <IConnectionManager>();
                node1ConnectionManager.Parameters.TemplateBehaviors.Add(new TestBehavior());

                IConnectionManager node2ConnectionManager = stratisNode2.FullNode.NodeService <IConnectionManager>();
                node2ConnectionManager.Parameters.TemplateBehaviors.Add(new TestBehavior());

                // Connect other nodes to initial node.
                TestHelper.Connect(stratisNode1, stratisNodeSync);
                TestHelper.Connect(stratisNode2, stratisNodeSync);
                TestHelper.Connect(stratisNode3, stratisNodeSync);

                // Make node3 unable to respond to anything, effectively disconnecting it.
                IConnectionManager node3ConnectionManager = stratisNode3.FullNode.NodeService <IConnectionManager>();
                node3ConnectionManager.Parameters.TemplateBehaviors.Clear();
                node3ConnectionManager.Parameters.TemplateBehaviors.Add(new TestBehavior());

                INetworkPeer connectedPeer1 = node1ConnectionManager.ConnectedPeers.FindByEndpoint(stratisNodeSync.Endpoint);
                TestBehavior testBehavior1  = connectedPeer1.Behavior <TestBehavior>();

                INetworkPeer connectedPeer2 = node2ConnectionManager.ConnectedPeers.FindByEndpoint(stratisNodeSync.Endpoint);
                TestBehavior testBehavior2  = connectedPeer2.Behavior <TestBehavior>();

                INetworkPeer connectedPeer3 = node3ConnectionManager.ConnectedPeers.FindByEndpoint(stratisNodeSync.Endpoint);
                TestBehavior testBehavior3  = connectedPeer3.Behavior <TestBehavior>();

                // If the announce queue is not getting stalled, the other 2 nodes should sync properly.
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode1, stratisNodeSync));
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode2, stratisNodeSync));

                HashSet <uint256> advertised = new HashSet <uint256>();

                // Check to see that all blocks got advertised to node1 via the "headers" payload.
                foreach (IncomingMessage message in testBehavior1.receivedMessageTracker["headers"])
                {
                    if (message.Message.Payload is HeadersPayload)
                    {
                        foreach (BlockHeader header in ((HeadersPayload)message.Message.Payload).Headers)
                        {
                            advertised.Add(header.GetHash());
                        }
                    }
                }

                foreach (ChainedHeader chainedHeader in stratisNodeSync.FullNode.ChainIndexer.EnumerateToTip(this.network.GenesisHash))
                {
                    if ((!advertised.Contains(chainedHeader.HashBlock)) && (!(chainedHeader.HashBlock == this.network.GenesisHash)))
                    {
                        throw new Exception($"An expected block was not advertised to peer 1: {chainedHeader.HashBlock}");
                    }
                }

                advertised.Clear();

                // Check to see that all blocks got advertised to node1 via the "headers" payload.
                foreach (IncomingMessage message in testBehavior2.receivedMessageTracker["headers"])
                {
                    if (message.Message.Payload is HeadersPayload)
                    {
                        foreach (BlockHeader header in ((HeadersPayload)message.Message.Payload).Headers)
                        {
                            advertised.Add(header.GetHash());
                        }
                    }
                }

                foreach (ChainedHeader chainedHeader in stratisNodeSync.FullNode.ChainIndexer.EnumerateToTip(this.network.GenesisHash))
                {
                    if ((!advertised.Contains(chainedHeader.HashBlock)) && (!(chainedHeader.HashBlock == this.network.GenesisHash)))
                    {
                        throw new Exception($"An expected block was not advertised to peer 2: {chainedHeader.HashBlock}");
                    }
                }

                // Check current state of announce queue.
                BlockStoreSignaled blockStoreSignaled = stratisNodeSync.FullNode.NodeService <BlockStoreSignaled>();

                IAsyncQueue <ChainedHeader> blocksToAnnounce = (IAsyncQueue <ChainedHeader>)blockStoreSignaled.GetMemberValue("blocksToAnnounce");
                Queue <ChainedHeader>       queueItems       = (Queue <ChainedHeader>)blocksToAnnounce.GetMemberValue("items");

                // It should still eventually empty despite not being able to communicate with node3.
                TestHelper.WaitLoop(() => queueItems.Count == 0);
            }
        }
        public void SBFNCreatesOpReturnTransaction_XSyncs()
        {
            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();

                // We do not want the datetime provider to be substituted,
                // so a custom builder callback has to be used.
                var callback = new Action <IFullNodeBuilder>(build => build
                                                             .UseBlockStore()
                                                             .UsePosConsensus()
                                                             .UseMempool()
                                                             .UseWallet()
                                                             .AddPowPosMining()
                                                             .AddRPC()
                                                             .UseTestChainedHeaderTree()
                                                             .MockIBD());

                CoreNode stratisNode = builder.CreateCustomNode(callback, network, protocolVersion: ProtocolVersion.ALT_PROTOCOL_VERSION, minProtocolVersion: ProtocolVersion.ALT_PROTOCOL_VERSION).WithWallet().Start();

                RPCClient stratisXRpc    = stratisXNode.CreateRPCClient();
                RPCClient stratisNodeRpc = stratisNode.CreateRPCClient();

                stratisXRpc.AddNode(stratisNode.Endpoint, false);
                stratisNodeRpc.AddNode(stratisXNode.Endpoint, false);

                TestHelper.MineBlocks(stratisNode, 11);

                // It takes a reasonable amount of time for blocks to be generated without
                // the datetime provider substitution.
                var longCancellationToken  = new CancellationTokenSource(TimeSpan.FromMinutes(15)).Token;
                var shortCancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token;

                TestBase.WaitLoop(() => stratisNodeRpc.GetBestBlockHash() == stratisXRpc.GetBestBlockHash(), cancellationToken: longCancellationToken);

                // Send transaction to arbitrary address from SBFN side.
                var alice        = new Key().GetBitcoinSecret(network);
                var aliceAddress = alice.GetAddress();
                //stratisNodeRpc.WalletPassphrase("password", 60);

                var transactionBuildContext = new TransactionBuildContext(stratisNode.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference("mywallet", "account 0"),
                    MinConfirmations = 1,
                    OpReturnData     = "test",
                    OpReturnAmount   = Money.Coins(0.01m),
                    WalletPassword   = "******",
                    Recipients       = new List <Recipient>()
                    {
                        new Recipient()
                        {
                            Amount = Money.Coins(1), ScriptPubKey = aliceAddress.ScriptPubKey
                        }
                    }
                };

                var transaction = stratisNode.FullNode.WalletTransactionHandler().BuildTransaction(transactionBuildContext);

                stratisNode.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(transaction.ToHex()));

                TestBase.WaitLoop(() => stratisNodeRpc.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken);

                // Transaction should percolate through to X's mempool.
                TestBase.WaitLoop(() => stratisXRpc.GetRawMempool().Length == 1, cancellationToken: shortCancellationToken);
            }
        }
Esempio n. 18
0
        public void MakeNode()
        {
            using (NodeBuilder builder = NodeBuilder.Create(version: "0.15.1"))
            {
                var core3 = builder.CreateNode(true);
                var rpc3  = core3.CreateRPCClient();

                // Replicate portions of BreezeServer's Program.cs. Maybe refactor it into a class/function in future
                var serviceProvider = new ServiceCollection()
                                      .AddLogging()
                                      .AddSingleton <Breeze.BreezeServer.Services.ITumblerService, Breeze.BreezeServer.Services.TumblerService>()
                                      .BuildServiceProvider();

                serviceProvider
                .GetService <ILoggerFactory>()
                .AddConsole(LogLevel.Debug);

                // Skip the registration code - that can be tested separately

                string   configPath         = Path.Combine(core3.DataFolder, "breeze.conf");
                string[] breezeServerConfig =
                {
                    "network=regtest", // Only the network setting is currently used from this file
                    "rpc.user=dummy",
                    "rpc.password=dummy",
                    "rpc.url=http://127.0.0.1:26174/",
                    "breeze.ipv4=127.0.0.1",
                    "breeze.ipv6=2001:0db8:85a3:0000:0000:8a2e:0370:7334",
                    "breeze.onion=0123456789ABCDEF",
                    "breeze.port=37123",
                    "breeze.regtxfeevalue=10000",
                    "breeze.regtxoutputvalue=1000",
                    "tumbler.url=http://127.0.0.1:37123/api/v1/",
                    "tumbler.rsakeyfile=/Users/username/.ntumblebitserver/RegTest/Tumbler.pem",
                    "tumbler.ecdsakeyaddress=TVwRFmEKRCnQAgShf3QshBjp1Tmucm1e87"
                };
                File.WriteAllLines(configPath, breezeServerConfig);

                BreezeConfiguration config = new BreezeConfiguration(configPath);

                string   ntbServerConfigPath = Path.Combine(core3.DataFolder, "server.config");
                string[] ntbServerConfig     =
                {
                    "regtest=1",
                    "rpc.url=http://127.0.0.1:" + rpc3.Address.Port + "/",
                    "rpc.user="******"rpc.password="******"tor.enabled=true",
                    "tor.server=127.0.0.1:9051" // We assume for now that tor has been manually started
                };

                File.WriteAllLines(ntbServerConfigPath, ntbServerConfig);

                // TODO: Maybe move this to after the initial block generation so they don't have to be processed
                // TODO: Also need to see if NTB interactive console interferes with later parts of the test
                var tumbler = serviceProvider.GetService <Breeze.BreezeServer.Services.ITumblerService>();
                tumbler.StartTumbler(config, false, "server.config", Path.GetFullPath(core3.DataFolder));

                //var node1 = builder.CreateStratisPowNode();
                CoreNode node1 = builder.CreateStratisPowNode(true, fullNodeBuilder =>
                {
                    fullNodeBuilder
                    .UseConsensus()
                    .UseBlockStore()
                    .UseMempool()
                    .AddMining()
                    .UseWallet()
                    .UseApi()
                    .AddRPC();
                    //.UseTumbleBit();
                });

                node1.NotInIBD();

                // Create the source and destination wallets
                var wm1 = node1.FullNode.NodeService <IWalletManager>() as WalletManager;
                //var wm2 = node2.FullNode.NodeService<IWalletManager>() as WalletManager;
                wm1.CreateWallet("TumbleBit1", "alice");
                wm1.CreateWallet("TumbleBit1", "bob");

                // Mined coins only mature after 100 blocks on regtest
                core3.FindBlock(101);

                var rpc1 = node1.CreateRPCClient();
                //var rpc2 = node2.CreateRPCClient();

                rpc1.AddNode(core3.Endpoint, false);

                TestHelper.WaitLoop(() => rpc1.GetBestBlockHash() == rpc3.GetBestBlockHash());

                var amount      = new Money(5.0m, MoneyUnit.BTC);
                var destination = wm1.GetUnusedAddress(new WalletAccountReference("alice", "account 0"));

                rpc3.SendToAddress(BitcoinAddress.Create(destination.Address, Network.RegTest), amount);

                core3.FindBlock(1);

                var unspent = rpc1.ListUnspent();

                // TODO: Move forward specific numbers of blocks and check interim states? TB tests should already do that
                for (int i = 0; i < 100; i++)
                {
                    core3.FindBlock(1);
                    Thread.Sleep(30); // <- is TumblerService in its own thread? If not, move it into one and we wait for it
                }

                // Check destination wallet for tumbled coins

                // TODO: Need to amend TumblerService so that it can be shut down within the test

                core3.Kill(false);
                node1.Kill(false);
            }
        }
        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.ALT_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);
            }
        }
Esempio n. 20
0
        public async Task SendingFromOneAddressToFiftyAddresses()
        {
            int sendingAccountBalanceOnStart   = 98000596;
            int receivingAccountBalanceOnStart = 0;

            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                // Arrange.
                // Create a sending and a receiving node.
                CoreNode sendingNode   = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Miner).Start();
                CoreNode receivingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Listener).Start();
                TestHelper.ConnectAndSync(sendingNode, receivingNode);

                // Check balances.
                WalletBalanceModel sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api"
                                                         .AppendPathSegment("wallet/balance")
                                                         .SetQueryParams(new { walletName = "mywallet" })
                                                         .GetJsonAsync <WalletBalanceModel>();

                AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single();
                (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC));

                WalletBalanceModel receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api"
                                                           .AppendPathSegment("wallet/balance")
                                                           .SetQueryParams(new { walletName = "mywallet" })
                                                           .GetJsonAsync <WalletBalanceModel>();

                AccountBalanceModel receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single();
                (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart));

                // Act.
                // Get 50 addresses to send to.
                IEnumerable <string> unusedaddresses = await $"http://localhost:{receivingNode.ApiPort}/api"
                                                       .AppendPathSegment("wallet/unusedAddresses")
                                                       .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 50 })
                                                       .GetJsonAsync <IEnumerable <string> >();

                // Build and send the transaction with 50 recipients.
                WalletBuildTransactionModel buildTransactionModel = await $"http://localhost:{sendingNode.ApiPort}/api"
                                                                    .AppendPathSegment("wallet/build-transaction")
                                                                    .PostJsonAsync(new BuildTransactionRequest
                {
                    WalletName       = "mywallet",
                    AccountName      = "account 0",
                    FeeType          = "low",
                    Password         = "******",
                    ShuffleOutputs   = true,
                    AllowUnconfirmed = true,
                    Recipients       = unusedaddresses.Select(address => new RecipientModel
                    {
                        DestinationAddress = address,
                        Amount             = "1"
                    }).ToList()
                })
                                                                    .ReceiveJson <WalletBuildTransactionModel>();

                await $"http://localhost:{sendingNode.ApiPort}/api"
                .AppendPathSegment("wallet/send-transaction")
                .PostJsonAsync(new SendTransactionRequest
                {
                    Hex = buildTransactionModel.Hex
                })
                .ReceiveJson <WalletSendTransactionModel>();

                // Assert.
                // The sending node should have 50 (+ fee) fewer coins.
                sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api"
                                      .AppendPathSegment("wallet/balance")
                                      .SetQueryParams(new { walletName = "mywallet" })
                                      .GetJsonAsync <WalletBalanceModel>();

                sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single();
                (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart - 50 - buildTransactionModel.Fee.ToDecimal(MoneyUnit.BTC), MoneyUnit.BTC));

                // Mine and sync so that we make sure the receiving node is up to date.
                TestHelper.MineBlocks(sendingNode, 1);

                // The receiving node should have 50 more coins.
                receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api"
                                        .AppendPathSegment("wallet/balance")
                                        .SetQueryParams(new { walletName = "mywallet" })
                                        .GetJsonAsync <WalletBalanceModel>();

                receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single();
                (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart + 50, MoneyUnit.BTC));
            }
        }
        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.ALT_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);
            }
        }
Esempio n. 22
0
        public async Task SendingATransactionWithAnOpReturn()
        {
            int sendingAccountBalanceOnStart   = 98000596;
            int receivingAccountBalanceOnStart = 0;

            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                // Arrange.
                // Create a sending and a receiving node.
                CoreNode sendingNode   = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Miner).Start();
                CoreNode receivingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Listener).Start();
                TestHelper.ConnectAndSync(sendingNode, receivingNode);

                // Check balances.
                WalletBalanceModel sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api"
                                                         .AppendPathSegment("wallet/balance")
                                                         .SetQueryParams(new { walletName = "mywallet" })
                                                         .GetJsonAsync <WalletBalanceModel>();

                AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single();
                (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC));

                WalletBalanceModel receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api"
                                                           .AppendPathSegment("wallet/balance")
                                                           .SetQueryParams(new { walletName = "mywallet" })
                                                           .GetJsonAsync <WalletBalanceModel>();

                AccountBalanceModel receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single();
                (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart));

                // Act.
                // Get an address to send to.
                IEnumerable <string> unusedaddresses = await $"http://localhost:{receivingNode.ApiPort}/api"
                                                       .AppendPathSegment("wallet/unusedAddresses")
                                                       .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 1 })
                                                       .GetJsonAsync <IEnumerable <string> >();

                // Build and send the transaction with an Op_Return.
                WalletBuildTransactionModel buildTransactionModel = await $"http://localhost:{sendingNode.ApiPort}/api"
                                                                    .AppendPathSegment("wallet/build-transaction")
                                                                    .PostJsonAsync(new BuildTransactionRequest
                {
                    WalletName       = "mywallet",
                    AccountName      = "account 0",
                    FeeType          = "low",
                    Password         = "******",
                    ShuffleOutputs   = true,
                    AllowUnconfirmed = true,
                    Recipients       = unusedaddresses.Select(address => new RecipientModel
                    {
                        DestinationAddress = address,
                        Amount             = "1"
                    }).ToList(),
                    OpReturnData   = "some data to send",
                    OpReturnAmount = "1"
                })
                                                                    .ReceiveJson <WalletBuildTransactionModel>();

                await $"http://localhost:{sendingNode.ApiPort}/api"
                .AppendPathSegment("wallet/send-transaction")
                .PostJsonAsync(new SendTransactionRequest
                {
                    Hex = buildTransactionModel.Hex
                })
                .ReceiveJson <WalletSendTransactionModel>();

                // Assert.
                // Mine and sync so that we make sure the receiving node is up to date.
                TestHelper.MineBlocks(sendingNode, 1);
                TestHelper.WaitForNodeToSync(sendingNode, receivingNode);

                // The receiving node should have coins.
                receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api"
                                        .AppendPathSegment("wallet/balance")
                                        .SetQueryParams(new { walletName = "mywallet" })
                                        .GetJsonAsync <WalletBalanceModel>();

                receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single();
                (receivingAccountBalance.AmountConfirmed).Should().Be(new Money(receivingAccountBalanceOnStart + 1, MoneyUnit.BTC));

                // The sending node should have fewer coins.
                sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api"
                                      .AppendPathSegment("wallet/balance")
                                      .SetQueryParams(new { walletName = "mywallet" })
                                      .GetJsonAsync <WalletBalanceModel>();

                sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single();
                (sendingAccountBalance.AmountConfirmed).Should().Be(new Money(sendingAccountBalanceOnStart + 4 - 2, MoneyUnit.BTC));

                // Check the transaction.
                string lastBlockHash = await $"http://localhost:{receivingNode.ApiPort}/api"
                                       .AppendPathSegment("consensus/getbestblockhash")
                                       .GetJsonAsync <string>();

                BlockTransactionDetailsModel block = await $"http://localhost:{receivingNode.ApiPort}/api"
                                                     .AppendPathSegment("blockstore/block")
                                                     .SetQueryParams(new { hash = lastBlockHash, showTransactionDetails = true, outputJson = true })
                                                     .GetJsonAsync <BlockTransactionDetailsModel>();

                TransactionVerboseModel trx = block.Transactions.SingleOrDefault(t => t.TxId == buildTransactionModel.TransactionId.ToString());
                trx.Should().NotBeNull();

                Vout opReturnOutputFromBlock = trx.VOut.Single(t => t.ScriptPubKey.Type == "nulldata");
                opReturnOutputFromBlock.Value.Should().Be(1);
                var      script = opReturnOutputFromBlock.ScriptPubKey.Asm;
                string[] ops    = script.Split(" ");
                ops[0].Should().Be("OP_RETURN");
                Encoders.Hex.DecodeData(ops[1]).Should().BeEquivalentTo(System.Text.Encoding.UTF8.GetBytes("some data to send"));
            }
        }
Esempio n. 23
0
        public async Task TransactionSentFeesReceivedByMinerAsync()
        {
            TestPoANetwork network = new TestPoANetwork();

            using (PoANodeBuilder builder = PoANodeBuilder.CreatePoANodeBuilder(this))
            {
                string walletName     = "mywallet";
                string walletPassword = "******";
                string walletAccount  = "account 0";

                Money transferAmount = Money.Coins(1m);
                Money feeAmount      = Money.Coins(0.0001m);

                CoreNode nodeA = builder.CreatePoANode(network, network.FederationKey1).WithWallet(walletPassword, walletName).Start();
                CoreNode nodeB = builder.CreatePoANode(network, network.FederationKey2).WithWallet(walletPassword, walletName).Start();

                TestHelper.Connect(nodeA, nodeB);

                long toMineCount = network.Consensus.PremineHeight + network.Consensus.CoinbaseMaturity + 1 - nodeA.GetTip().Height;

                // Get coins on nodeA via the premine.
                await nodeA.MineBlocksAsync((int)toMineCount).ConfigureAwait(false);

                CoreNodePoAExtensions.WaitTillSynced(nodeA, nodeB);

                // Will send funds to one of nodeB's addresses.
                Script destination = nodeB.FullNode.WalletManager().GetUnusedAddress().ScriptPubKey;

                var context = new TransactionBuildContext(network)
                {
                    AccountReference = new WalletAccountReference(walletName, walletAccount),
                    MinConfirmations = 0,
                    FeeType          = FeeType.High,
                    WalletPassword   = walletPassword,
                    Recipients       = new[] { new Recipient {
                                                   Amount = transferAmount, ScriptPubKey = destination
                                               } }.ToList()
                };

                Transaction trx = nodeA.FullNode.WalletTransactionHandler().BuildTransaction(context);

                Assert.True(context.TransactionBuilder.Verify(trx, out _));

                await nodeA.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(trx.ToHex()));

                TestBase.WaitLoop(() => nodeA.CreateRPCClient().GetRawMempool().Length == 1 && nodeB.CreateRPCClient().GetRawMempool().Length == 1);

                await nodeB.MineBlocksAsync((int)toMineCount).ConfigureAwait(false);

                TestBase.WaitLoop(() => nodeA.CreateRPCClient().GetRawMempool().Length == 0 && nodeB.CreateRPCClient().GetRawMempool().Length == 0);

                IWalletManager walletManager = nodeB.FullNode.NodeService <IWalletManager>();

                TestBase.WaitLoop(() =>
                {
                    long balance = walletManager.GetBalances(walletName, walletAccount).Sum(x => x.AmountConfirmed);

                    return(balance == (transferAmount + feeAmount));
                });
            }
        }
Esempio n. 24
0
 /// <summary>
 /// Determines whether or not the node has any connections.
 /// </summary>
 /// <param name="node">The node to check.</param>
 /// <returns>Returns <c>true</c> if the node does not have any connected peers.</returns>
 public static bool IsNodeConnected(CoreNode node)
 {
     return(node.FullNode.ConnectionManager.ConnectedPeers.Any());
 }
Esempio n. 25
0
        public void WalletCanReorg()
        {
            // This test has 4 parts:
            // Send first transaction from one wallet to another and wait for it to be confirmed
            // Send a second transaction and wait for it to be confirmed
            // Connect to a longer chain that causes a reorg so that the second trasnaction is undone
            // Mine the second transaction back in to the main chain
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode stratisSender   = builder.CreateStratisPowNode(this.network).WithWallet().Start();
                CoreNode stratisReceiver = builder.CreateStratisPowNode(this.network).WithWallet().Start();
                CoreNode stratisReorg    = builder.CreateStratisPowNode(this.network).WithWallet().Start();

                int maturity = (int)stratisSender.FullNode.Network.Consensus.CoinbaseMaturity;
                TestHelper.MineBlocks(stratisSender, maturity + 1 + 15);

                int currentBestHeight = maturity + 1 + 15;

                // The mining should add coins to the wallet.
                long total = stratisSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * 16 * 50, total);

                // Sync all nodes.
                TestHelper.ConnectAndSync(stratisReceiver, stratisSender);
                TestHelper.ConnectAndSync(stratisReceiver, stratisReorg);
                TestHelper.ConnectAndSync(stratisSender, stratisReorg);

                // Build Transaction 1.
                // Send coins to the receiver.
                HdAddress   sendto       = stratisReceiver.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, Account));
                Transaction transaction1 = stratisSender.FullNode.WalletTransactionHandler().BuildTransaction(CreateContext(stratisSender.FullNode.Network, new WalletAccountReference(WalletName, Account), Password, sendto.ScriptPubKey, Money.COIN * 100, FeeType.Medium, 101));

                // Broadcast to the other node.
                stratisSender.FullNode.NodeController <WalletController>().SendTransactionAsync(new SendTransactionRequest(transaction1.ToHex()));

                // Wait for the transaction to arrive.
                TestBase.WaitLoop(() => stratisReceiver.CreateRPCClient().GetRawMempool().Length > 0);
                Assert.NotNull(stratisReceiver.CreateRPCClient().GetRawTransaction(transaction1.GetHash(), null, false));
                TestBase.WaitLoop(() => stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Any());

                long receivetotal = stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * 100, receivetotal);
                Assert.Null(stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).First().Transaction.BlockHeight);

                // Generate two new blocks so the transaction is confirmed.
                TestHelper.MineBlocks(stratisSender, 1);
                int transaction1MinedHeight = currentBestHeight + 1;
                TestHelper.MineBlocks(stratisSender, 1);
                currentBestHeight = currentBestHeight + 2;

                // Wait for block repo for block sync to work.
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender));
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisReorg));
                Assert.Equal(currentBestHeight, stratisReceiver.FullNode.ChainIndexer.Tip.Height);
                TestBase.WaitLoop(() => transaction1MinedHeight == stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).First().Transaction.BlockHeight);

                // Build Transaction 2.
                // Remove the reorg node.
                TestHelper.Disconnect(stratisReceiver, stratisReorg);
                TestHelper.Disconnect(stratisSender, stratisReorg);

                ChainedHeader forkblock = stratisReceiver.FullNode.ChainIndexer.Tip;

                // Send more coins to the wallet
                sendto = stratisReceiver.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, Account));
                Transaction transaction2 = stratisSender.FullNode.WalletTransactionHandler().BuildTransaction(CreateContext(stratisSender.FullNode.Network, new WalletAccountReference(WalletName, Account), Password, sendto.ScriptPubKey, Money.COIN * 10, FeeType.Medium, 101));
                stratisSender.FullNode.NodeController <WalletController>().SendTransactionAsync(new SendTransactionRequest(transaction2.ToHex()));

                // Wait for the transaction to arrive
                TestBase.WaitLoop(() => stratisReceiver.CreateRPCClient().GetRawMempool().Length > 0);
                Assert.NotNull(stratisReceiver.CreateRPCClient().GetRawTransaction(transaction2.GetHash(), null, false));
                TestBase.WaitLoop(() => stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Any());
                long newamount = stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * 110, newamount);
                Assert.Contains(stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName), b => b.Transaction.BlockHeight == null);

                // Mine more blocks so it gets included in the chain.
                TestHelper.MineBlocks(stratisSender, 1);
                int transaction2MinedHeight = currentBestHeight + 1;
                TestHelper.MineBlocks(stratisSender, 1);
                currentBestHeight = currentBestHeight + 2;
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender));
                Assert.Equal(currentBestHeight, stratisReceiver.FullNode.ChainIndexer.Tip.Height);
                TestBase.WaitLoop(() => stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Any(b => b.Transaction.BlockHeight == transaction2MinedHeight));

                // Create a reorg by mining on two different chains.
                // Advance both chains, one chain is longer.
                TestHelper.MineBlocks(stratisSender, 2);
                TestHelper.MineBlocks(stratisReorg, 10);
                currentBestHeight = forkblock.Height + 10;

                // Connect the reorg chain.
                TestHelper.Connect(stratisReceiver, stratisReorg);
                TestHelper.Connect(stratisSender, stratisReorg);

                // Wait for the chains to catch up.
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender));
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisReorg, true));
                Assert.Equal(currentBestHeight, stratisReceiver.FullNode.ChainIndexer.Tip.Height);

                // Ensure wallet reorg completes.
                TestBase.WaitLoop(() => stratisReceiver.FullNode.WalletManager().WalletTipHash == stratisReorg.CreateRPCClient().GetBestBlockHash());

                // Check the wallet amount was rolled back.
                long newtotal = stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(receivetotal, newtotal);
                TestBase.WaitLoop(() => maturity + 1 + 16 == stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).First().Transaction.BlockHeight);

                // ReBuild Transaction 2.
                // After the reorg transaction2 was returned back to mempool.
                stratisSender.FullNode.NodeController <WalletController>().SendTransactionAsync(new SendTransactionRequest(transaction2.ToHex()));
                TestBase.WaitLoop(() => stratisReceiver.CreateRPCClient().GetRawMempool().Length > 0);

                // Mine the transaction again.
                TestHelper.MineBlocks(stratisSender, 1);
                transaction2MinedHeight = currentBestHeight + 1;
                TestHelper.MineBlocks(stratisSender, 1);
                currentBestHeight = currentBestHeight + 2;

                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender));
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisReorg));

                Assert.Equal(currentBestHeight, stratisReceiver.FullNode.ChainIndexer.Tip.Height);
                long newsecondamount = stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(newamount, newsecondamount);
                TestBase.WaitLoop(() => stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Any(b => b.Transaction.BlockHeight == transaction2MinedHeight));
            }
        }
Esempio n. 26
0
 /// <summary>
 /// Connects a node to a set of other nodes and waits for all the nodes to sync.
 /// </summary>
 /// <param name="thisNode">The node the connection will be established from.</param>
 /// <param name="to">The nodes to connect to.</param>
 public static void ConnectAndSync(CoreNode thisNode, params CoreNode[] to)
 {
     ConnectAndSync(thisNode, false, to);
 }
Esempio n. 27
0
        public void WalletBalanceCorrectWhenOnlySomeUnconfirmedAreIncludedInABlock()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode stratisSender   = builder.CreateStratisPowNode(this.network).WithWallet().Start();
                CoreNode stratisReceiver = builder.CreateStratisPowNode(this.network).WithWallet().Start();

                int maturity = (int)stratisSender.FullNode.Network.Consensus.CoinbaseMaturity;
                TestHelper.MineBlocks(stratisSender, maturity + 1 + 5);

                // The mining should add coins to the wallet
                long total = stratisSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * 6 * 50, total);

                // Sync both nodes
                TestHelper.ConnectAndSync(stratisSender, stratisReceiver);

                // Send coins to the receiver
                HdAddress   sendto = stratisReceiver.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, Account));
                Transaction trx    = stratisSender.FullNode.WalletTransactionHandler().BuildTransaction(CreateContext(stratisSender.FullNode.Network,
                                                                                                                      new WalletAccountReference(WalletName, Account), Password, sendto.ScriptPubKey, Money.COIN * 100, FeeType.Medium, 101));

                // Broadcast to the other node
                stratisSender.FullNode.NodeController <WalletController>().SendTransactionAsync(new SendTransactionRequest(trx.ToHex()));

                // Wait for the transaction to arrive
                TestBase.WaitLoop(() => stratisReceiver.CreateRPCClient().GetRawMempool().Length > 0);
                TestBase.WaitLoop(() => stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Any());

                long receivetotal = stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * 100, receivetotal);

                // Generate two new blocks so the transaction is confirmed
                TestHelper.MineBlocks(stratisSender, 2);
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender));


                // Send 1 transaction from the second node and let it get to the first.
                sendto = stratisSender.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, Account));
                Transaction testTx1 = stratisReceiver.FullNode.WalletTransactionHandler().BuildTransaction(CreateContext(stratisSender.FullNode.Network,
                                                                                                                         new WalletAccountReference(WalletName, Account), Password, sendto.ScriptPubKey, Money.COIN * 10, FeeType.Medium, 0));
                stratisReceiver.FullNode.NodeController <WalletController>().SendTransactionAsync(new SendTransactionRequest(testTx1.ToHex()));
                TestBase.WaitLoop(() => stratisSender.CreateRPCClient().GetRawMempool().Length > 0);

                // Disconnect so the first node doesn't get any more transactions.
                TestHelper.Disconnect(stratisReceiver, stratisSender);

                // Send a second unconfirmed transaction on the second node which consumes the first.
                Transaction testTx2 = stratisReceiver.FullNode.WalletTransactionHandler().BuildTransaction(CreateContext(stratisSender.FullNode.Network,
                                                                                                                         new WalletAccountReference(WalletName, Account), Password, sendto.ScriptPubKey, Money.COIN * 10, FeeType.Medium, 0));
                stratisReceiver.FullNode.NodeService <IBroadcasterManager>().BroadcastTransactionAsync(testTx2);

                // Now we can mine a block on the first node with only 1 of the transactions in it.
                TestHelper.MineBlocks(stratisSender, 1);

                // Connect the nodes again.
                TestHelper.Connect(stratisSender, stratisReceiver);

                // Second node receives a block with only one transaction in it.
                TestBase.WaitLoop(() => TestHelper.AreNodesSynced(stratisReceiver, stratisSender, true));

                // Now lets see what is in the second node's wallet!
                IEnumerable <UnspentOutputReference> spendableTxs = stratisReceiver.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName);

                // There should be one spendable transaction. And it should be testTx2.
                Assert.Single(spendableTxs);
                Assert.Equal(testTx2.GetHash(), spendableTxs.First().Transaction.Id);

                // It follows that if the above assert was violated we would have conflicts when we build a transaction.
                // Specifically what we don't want is to have testTx1 in our spendable transactions, which was causing the known issue.
            }
        }
Esempio n. 28
0
        public static (bool Passed, string Message) AreNodesSyncedMessage(CoreNode node1, CoreNode node2, bool ignoreMempool = false)
        {
            if (node1.runner is BitcoinCoreRunner || node2.runner is BitcoinCoreRunner)
            {
                return(node1.CreateRPCClient().GetBestBlockHash() == node2.CreateRPCClient().GetBestBlockHash(), "[BEST_BLOCK_HASH_DOES_MATCH]");
            }

            // If the nodes are at genesis they are considered synced.
            if (node1.FullNode.ChainIndexer.Tip.Height == 0 && node2.FullNode.ChainIndexer.Tip.Height == 0)
            {
                return(true, "[TIPS_ARE_AT_GENESIS]");
            }

            if (node1.FullNode.ChainIndexer.Tip.HashBlock != node2.FullNode.ChainIndexer.Tip.HashBlock)
            {
                return(false, $"[CHAIN_TIP_HASH_DOES_NOT_MATCH_{node1.FullNode.ChainIndexer.Tip}_{node2.FullNode.ChainIndexer.Tip}]");
            }

            if (node1.FullNode.ChainBehaviorState.ConsensusTip.HashBlock != node2.FullNode.ChainBehaviorState.ConsensusTip.HashBlock)
            {
                return(false, $"[CONSENSUS_TIP_HASH_DOES_MATCH]_{node1.FullNode.ChainBehaviorState.ConsensusTip}_{node2.FullNode.ChainBehaviorState.ConsensusTip}]");
            }

            // Check that node1 tip exists in node2 store (either in disk or in the pending list)
            if (node1.FullNode.BlockStore().GetBlock(node2.FullNode.ChainBehaviorState.ConsensusTip.HashBlock) == null)
            {
                return(false, "[NODE2_TIP_NOT_IN_NODE1_STORE]");
            }

            // Check that node2 tip exists in node1 store (either in disk or in the pending list)
            if (node2.FullNode.BlockStore().GetBlock(node1.FullNode.ChainBehaviorState.ConsensusTip.HashBlock) == null)
            {
                return(false, "[NODE1_TIP_NOT_IN_NODE2_STORE]");
            }

            if (!ignoreMempool)
            {
                if (node1.FullNode.MempoolManager().InfoAll().Count != node2.FullNode.MempoolManager().InfoAll().Count)
                {
                    return(false, "[NODE1_MEMPOOL_COUNT_NOT_EQUAL_NODE2_MEMPOOL_COUNT]");
                }
            }

            if ((node1.FullNode.WalletManager().ContainsWallets) && (node2.FullNode.WalletManager().ContainsWallets))
            {
                if (node1.FullNode.WalletManager().WalletTipHash != node2.FullNode.WalletManager().WalletTipHash)
                {
                    return(false, "[WALLET_TIP_HASH_DOESNOT_MATCH]");
                }
            }

            if (node1.CreateRPCClient().GetBestBlockHash() != node2.CreateRPCClient().GetBestBlockHash())
            {
                return(false, "[RPC_CLIENT_BEST_BLOCK_HASH_DOES_NOT_MATCH]");
            }

            return(true, string.Empty);
        }
        public void MempoolSyncTransactions()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode stratisNodeSync = builder.CreateStratisPowNode();
                CoreNode stratisNode1    = builder.CreateStratisPowNode();
                CoreNode stratisNode2    = builder.CreateStratisPowNode();
                builder.StartAll();

                stratisNodeSync.NotInIBD();
                stratisNode1.NotInIBD();
                stratisNode2.NotInIBD();

                // generate blocks and wait for the downloader to pickup
                stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network));
                stratisNodeSync.GenerateStratisWithMiner(105); // coinbase maturity = 100
                // wait for block repo for block sync to work
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(stratisNodeSync));

                // sync both nodes
                stratisNode1.CreateRPCClient().AddNode(stratisNodeSync.Endpoint, true);
                stratisNode2.CreateRPCClient().AddNode(stratisNodeSync.Endpoint, true);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode1, stratisNodeSync));
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(stratisNode2, stratisNodeSync));

                // create some transactions and push them to the pool
                var trxs = new List <Transaction>();
                foreach (int index in Enumerable.Range(1, 5))
                {
                    Block       block   = stratisNodeSync.FullNode.BlockStoreManager().BlockRepository.GetAsync(stratisNodeSync.FullNode.Chain.GetBlock(index).HashBlock).Result;
                    Transaction prevTrx = block.Transactions.First();
                    var         dest    = new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network);

                    Transaction tx = stratisNodeSync.FullNode.Network.CreateTransaction();
                    tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                    tx.AddOutput(new TxOut("25", dest.PubKey.Hash));
                    tx.AddOutput(new TxOut("24", new Key().PubKey.Hash)); // 1 btc fee
                    tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                    trxs.Add(tx);
                }
                var options = new ParallelOptions {
                    MaxDegreeOfParallelism = 5
                };
                Parallel.ForEach(trxs, options, transaction =>
                {
                    stratisNodeSync.Broadcast(transaction);
                });

                // wait for all nodes to have all trx
                TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 5);

                // the full node should be connected to both nodes
                Assert.True(stratisNodeSync.FullNode.ConnectionManager.ConnectedPeers.Count() >= 2);

                TestHelper.WaitLoop(() => stratisNode1.CreateRPCClient().GetRawMempool().Length == 5);
                TestHelper.WaitLoop(() => stratisNode2.CreateRPCClient().GetRawMempool().Length == 5);

                // mine the transactions in the mempool
                stratisNodeSync.GenerateStratisWithMiner(1);
                TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 0);

                // wait for block and mempool to change
                TestHelper.WaitLoop(() => stratisNode1.CreateRPCClient().GetBestBlockHash() == stratisNodeSync.CreateRPCClient().GetBestBlockHash());
                TestHelper.WaitLoop(() => stratisNode2.CreateRPCClient().GetBestBlockHash() == stratisNodeSync.CreateRPCClient().GetBestBlockHash());
                TestHelper.WaitLoop(() => stratisNode1.CreateRPCClient().GetRawMempool().Length == 0);
                TestHelper.WaitLoop(() => stratisNode2.CreateRPCClient().GetRawMempool().Length == 0);
            }
        }