public async Task TestServicesAsync(string networkString) { await RuntimeParams.LoadAsync(); var network = Network.GetNetwork(networkString); var blocksToDownload = new List <uint256>(); if (network == Network.Main) { blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0")); blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9")); blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629")); } else if (network == Network.TestNet) { blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524")); blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc")); blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66")); } else { throw new NotSupportedNetworkException(network); } BitcoinStore bitcoinStore = new BitcoinStore(); await bitcoinStore.InitializeAsync(Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName()), network); var addressManagerFolderPath = Path.Combine(Global.Instance.DataDir, "AddressManager"); var addressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat"); var blocksFolderPath = Path.Combine(Global.Instance.DataDir, "Blocks", network.ToString()); var connectionParameters = new NodeConnectionParameters(); AddressManager addressManager = null; try { addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath); Logger.LogInfo($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`."); } catch (DirectoryNotFoundException) { addressManager = new AddressManager(); } catch (FileNotFoundException) { addressManager = new AddressManager(); } catch (OverflowException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } catch (FormatException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager)); connectionParameters.TemplateBehaviors.Add(bitcoinStore.CreateMempoolBehavior()); using var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements); KeyManager keyManager = KeyManager.CreateNew(out _, "password"); WasabiSynchronizer syncer = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint); WalletService walletService = new WalletService( bitcoinStore, keyManager, syncer, new CoinJoinClient(syncer, network, keyManager, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint), nodes, Global.Instance.DataDir, new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold))); Assert.True(Directory.Exists(blocksFolderPath)); try { var mempoolTransactionAwaiter = new EventsAwaiter <SmartTransaction>( h => bitcoinStore.MempoolService.TransactionReceived += h, h => bitcoinStore.MempoolService.TransactionReceived -= h, 3); var nodeConnectionAwaiter = new EventsAwaiter <NodeEventArgs>( h => nodes.ConnectedNodes.Added += h, h => nodes.ConnectedNodes.Added -= h, 3); nodes.Connect(); var downloadTasks = new List <Task <Block> >(); using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(4)); foreach (var hash in blocksToDownload) { downloadTasks.Add(walletService.FetchBlockAsync(hash, cts.Token)); } await nodeConnectionAwaiter.WaitAsync(TimeSpan.FromMinutes(3)); var i = 0; var hashArray = blocksToDownload.ToArray(); foreach (var block in await Task.WhenAll(downloadTasks)) { Assert.True(File.Exists(Path.Combine(blocksFolderPath, hashArray[i].ToString()))); i++; } await mempoolTransactionAwaiter.WaitAsync(TimeSpan.FromMinutes(1)); } finally { // So next test will download the block. foreach (var hash in blocksToDownload) { await walletService?.DeleteBlockAsync(hash); } if (walletService != null) { await walletService.StopAsync(); } if (Directory.Exists(blocksFolderPath)) { Directory.Delete(blocksFolderPath, recursive: true); } IoHelpers.EnsureContainingDirectoryExists(addressManagerFilePath); addressManager?.SavePeerFile(addressManagerFilePath, network); Logger.LogInfo($"Saved {nameof(AddressManager)} to `{addressManagerFilePath}`."); await syncer?.StopAsync(); } }
public async Task InitializeNoWalletAsync() { InitializationStarted = true; AddressManager = null; TorManager = 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 blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}"); 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(Config.TorSocks5EndPoint, TorLogsFile); } else { TorManager = TorProcessManager.Mock(); } TorManager.Start(false, DataDir); var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions"); TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri); 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 : $"/GroestlMix:{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 { })
public async Task InitializeNoWalletAsync() { InitializationStarted = true; try { WalletService = null; AddressManager = null; TorManager = null; var cancel = StoppingCts.Token; #region ConfigInitialization Config = new Config(Path.Combine(DataDir, "Config.json")); await Config.LoadOrCreateDefaultFileAsync(); Logger.LogInfo($"{nameof(Config)} is successfully initialized."); #endregion ConfigInitialization cancel.ThrowIfCancellationRequested(); BitcoinStore = new BitcoinStore(); var bstoreInitTask = BitcoinStore.InitializeAsync(Path.Combine(DataDir, "BitcoinStore"), Network); var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager"); AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat"); var addrManTask = InitializeAddressManagerBehaviorAsync(); var blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}"); var connectionParameters = new NodeConnectionParameters { UserAgent = "/Satoshi:0.18.1/" }; if (Config.UseTor) { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint); } else { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null); } HostedServices.Register(new UpdateChecker(TimeSpan.FromMinutes(7), Synchronizer.WasabiClient), "Software Update Checker"); #region ProcessKillSubscription AppDomain.CurrentDomain.ProcessExit += async(s, e) => await TryDesperateDequeueAllCoinsAsync(); Console.CancelKeyPress += async(s, e) => { e.Cancel = true; await StopAndExitAsync(); }; #endregion ProcessKillSubscription cancel.ThrowIfCancellationRequested(); #region TorProcessInitialization if (Config.UseTor) { TorManager = new TorProcessManager(Config.TorSocks5EndPoint, TorLogsFile); } else { TorManager = TorProcessManager.Mock(); } TorManager.Start(false, DataDir); var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions"); TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri); Logger.LogInfo($"{nameof(TorProcessManager)} is initialized."); #endregion TorProcessInitialization cancel.ThrowIfCancellationRequested(); #region BitcoinStoreInitialization await bstoreInitTask; #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, userAgent : $"/WasabiClient:{Constants.ClientVersion.ToString()}/"), 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 { }) { feeProviderList.Insert(0, rpcFeeProvider); } FeeProviders = new FeeProviders(feeProviderList); #endregion BitcoinCoreInitialization cancel.ThrowIfCancellationRequested(); #region MempoolInitialization connectionParameters.TemplateBehaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior()); #endregion MempoolInitialization cancel.ThrowIfCancellationRequested(); #region AddressManagerInitialization AddressManagerBehavior addressManagerBehavior = await addrManTask; 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 is true) { // 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); } Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements); RegTestMempoolServingNode = null; } Nodes.Connect(); Logger.LogInfo("Start connecting to nodes..."); var regTestMempoolServingNode = RegTestMempoolServingNode; if (regTestMempoolServingNode is { })
public async Task InitializeNoWalletAsync() { WalletService = null; ChaumianClient = null; AddressManager = null; TorManager = null; #region ConfigInitialization Config = new Config(Path.Combine(DataDir, "Config.json")); await Config.LoadOrCreateDefaultFileAsync(); Logger.LogInfo <Config>("Config is successfully initialized."); #endregion ConfigInitialization BitcoinStore = new BitcoinStore(); var bstoreInitTask = BitcoinStore.InitializeAsync(Path.Combine(DataDir, "BitcoinStore"), Network); var hwiInitTask = HwiProcessManager.InitializeAsync(DataDir, Network); var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager"); AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat"); var addrManTask = InitializeAddressManagerBehaviorAsync(); var blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}"); var connectionParameters = new NodeConnectionParameters { UserAgent = "/Satoshi:0.18.0/" }; if (Config.UseTor.Value) { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint); } else { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null); } UpdateChecker = new UpdateChecker(Synchronizer.WasabiClient); #region ProcessKillSubscription AppDomain.CurrentDomain.ProcessExit += async(s, e) => await TryDesperateDequeueAllCoinsAsync(); Console.CancelKeyPress += async(s, e) => { e.Cancel = true; Logger.LogWarning("Process was signaled for killing.", nameof(Global)); KillRequested = true; await TryDesperateDequeueAllCoinsAsync(); Dispatcher.UIThread.PostLogException(() => { Application.Current?.MainWindow?.Close(); }); await DisposeAsync(); Logger.LogInfo($"Wasabi stopped gracefully.", Logger.InstanceGuid.ToString()); }; #endregion ProcessKillSubscription #region TorProcessInitialization if (Config.UseTor.Value) { TorManager = new TorProcessManager(Config.TorSocks5EndPoint, TorLogsFile); } else { TorManager = TorProcessManager.Mock(); } TorManager.Start(false, DataDir); var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions"); TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri); Logger.LogInfo <TorProcessManager>($"{nameof(TorProcessManager)} is initialized."); #endregion TorProcessInitialization #region MempoolInitialization MempoolService = new MempoolService(); connectionParameters.TemplateBehaviors.Add(new MempoolBehavior(MempoolService)); #endregion MempoolInitialization #region HwiProcessInitialization try { await hwiInitTask; } catch (Exception ex) { Logger.LogError(ex, nameof(Global)); } #endregion HwiProcessInitialization #region BitcoinStoreInitialization await bstoreInitTask; #endregion BitcoinStoreInitialization #region AddressManagerInitialization AddressManagerBehavior addressManagerBehavior = await addrManTask; connectionParameters.TemplateBehaviors.Add(addressManagerBehavior); #endregion AddressManagerInitialization #region P2PInitialization if (Network == Network.RegTest) { Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements); try { Node node = await Node.ConnectAsync(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444)); Nodes.ConnectedNodes.Add(node); RegTestMempoolServingNode = await Node.ConnectAsync(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444)); RegTestMempoolServingNode.Behaviors.Add(new MempoolBehavior(MempoolService)); } catch (SocketException ex) { Logger.LogError(ex, nameof(Global)); } } else { if (Config.UseTor is true) { // 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); } Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements); RegTestMempoolServingNode = null; } Nodes.Connect(); Logger.LogInfo("Start connecting to nodes..."); if (RegTestMempoolServingNode != null) { RegTestMempoolServingNode.VersionHandshake(); Logger.LogInfo("Start connecting to mempool serving regtest node..."); } #endregion P2PInitialization #region SynchronizerInitialization var requestInterval = TimeSpan.FromSeconds(30); if (Network == Network.RegTest) { requestInterval = TimeSpan.FromSeconds(5); } int maxFiltSyncCount = Network == Network.Main ? 1000 : 10000; // On testnet, filters are empty, so it's faster to query them together Synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), maxFiltSyncCount); Logger.LogInfo("Start synchronizing filters..."); #endregion SynchronizerInitialization Initialized = true; }
public async Task TestServicesAsync(string networkString) { await RuntimeParams.LoadAsync(); var network = Network.GetNetwork(networkString); var blocksToDownload = new HashSet <uint256>(); if (network == Network.Main) { blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0")); blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9")); blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629")); } else if (network == Network.TestNet) { blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524")); blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc")); blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66")); } else { throw new NotSupportedException($"{nameof(Network)} not supported: {network}."); } var addressManagerFolderPath = Path.Combine(Global.Instance.DataDir, "AddressManager"); var addressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat"); var blocksFolderPath = Path.Combine(Global.Instance.DataDir, "Blocks", network.ToString()); var connectionParameters = new NodeConnectionParameters(); AddressManager addressManager = null; try { addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath); Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`."); } catch (DirectoryNotFoundException) { addressManager = new AddressManager(); } catch (FileNotFoundException) { addressManager = new AddressManager(); } catch (OverflowException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } catch (FormatException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager)); var mempoolService = new MempoolService(); connectionParameters.TemplateBehaviors.Add(new MempoolBehavior(mempoolService)); var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements); BitcoinStore bitcoinStore = new BitcoinStore(); await bitcoinStore.InitializeAsync(Path.Combine(Global.Instance.DataDir, nameof(TestServicesAsync)), network); KeyManager keyManager = KeyManager.CreateNew(out _, "password"); WasabiSynchronizer syncer = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint); WalletService walletService = new WalletService( bitcoinStore, keyManager, syncer, new CcjClient(syncer, network, keyManager, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint), mempoolService, nodes, Global.Instance.DataDir, new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(0.0001m))); Assert.True(Directory.Exists(blocksFolderPath)); try { mempoolService.TransactionReceived += MempoolService_TransactionReceived; nodes.Connect(); var times = 0; while (nodes.ConnectedNodes.Count < 3) { if (times > 4200) // 7 minutes { throw new TimeoutException($"Connection test timed out."); } await Task.Delay(100); times++; } times = 0; while (Interlocked.Read(ref _mempoolTransactionCount) < 3) { if (times > 3000) // 3 minutes { throw new TimeoutException($"{nameof(MempoolService)} test timed out."); } await Task.Delay(100); times++; } foreach (var hash in blocksToDownload) { using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3))) { var block = await walletService.GetOrDownloadBlockAsync(hash, cts.Token); Assert.True(File.Exists(Path.Combine(blocksFolderPath, hash.ToString()))); Logger.LogInfo <P2pTests>($"Full block is downloaded: {hash}."); } } } finally { nodes.ConnectedNodes.Added -= ConnectedNodes_Added; nodes.ConnectedNodes.Removed -= ConnectedNodes_Removed; mempoolService.TransactionReceived -= MempoolService_TransactionReceived; // So next test will download the block. foreach (var hash in blocksToDownload) { await walletService?.DeleteBlockAsync(hash); } if (walletService != null) { await walletService.StopAsync(); } if (Directory.Exists(blocksFolderPath)) { Directory.Delete(blocksFolderPath, recursive: true); } IoHelpers.EnsureContainingDirectoryExists(addressManagerFilePath); addressManager?.SavePeerFile(addressManagerFilePath, network); Logger.LogInfo <P2pTests>($"Saved {nameof(AddressManager)} to `{addressManagerFilePath}`."); nodes?.Dispose(); await syncer?.StopAsync(); } }
public async Task MempoolNotifiesAsync() { using var services = new HostedServices(); CoreNode coreNode = await TestNodeBuilder.CreateAsync(services); await services.StartAllAsync(); using var node = await coreNode.CreateNewP2pNodeAsync(); try { string dir = Common.GetWorkDir(); var network = coreNode.Network; var rpc = coreNode.RpcClient; var indexStore = new IndexStore(Path.Combine(dir, "indexStore"), network, new SmartHeaderChain()); var transactionStore = new AllTransactionStore(Path.Combine(dir, "transactionStore"), network); var mempoolService = new MempoolService(); var blocks = new FileSystemBlockRepository(Path.Combine(dir, "blocks"), network); // Construct BitcoinStore. var bitcoinStore = new BitcoinStore(indexStore, transactionStore, mempoolService, blocks); await bitcoinStore.InitializeAsync(); await rpc.GenerateAsync(blockCount : 101); node.Behaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior()); node.VersionHandshake(); BitcoinWitPubKeyAddress address = new Key().PubKey.GetSegwitAddress(network); // Number of transactions to send. const int TransactionsCount = 10; var eventAwaiter = new EventsAwaiter <SmartTransaction>( subscribe: h => mempoolService.TransactionReceived += h, unsubscribe: h => mempoolService.TransactionReceived -= h, count: TransactionsCount); var txHashesList = new List <Task <uint256> >(); IRPCClient rpcBatch = rpc.PrepareBatch(); // Add to the batch 10 RPC commands: Send 1 coin to the same address. for (int i = 0; i < TransactionsCount; i++) { txHashesList.Add(rpcBatch.SendToAddressAsync(address, Money.Coins(1))); } // Publish the RPC batch. Task rpcBatchTask = rpcBatch.SendBatchAsync(); // Wait until the mempool service receives all the sent transactions. IEnumerable <SmartTransaction> mempoolSmartTxs = await eventAwaiter.WaitAsync(TimeSpan.FromSeconds(30)); await rpcBatchTask; // Collect all the transaction hashes of the sent transactions. uint256[] hashes = await Task.WhenAll(txHashesList); // Check that all the received transaction hashes are in the set of sent transaction hashes. foreach (SmartTransaction tx in mempoolSmartTxs) { Assert.Contains(tx.GetHash(), hashes); } } finally { await services.StopAllAsync(); node.Disconnect(); await coreNode.TryStopAsync(); } }
public async Task InitializeNoWalletAsync() { WalletService = null; ChaumianClient = null; AddressManager = null; TorManager = null; #region ConfigInitialization Config = new Config(Path.Combine(DataDir, "Config.json")); await Config.LoadOrCreateDefaultFileAsync(); Logger.LogInfo($"{nameof(Config)} is successfully initialized."); #endregion ConfigInitialization BitcoinStore = new BitcoinStore(); var bstoreInitTask = BitcoinStore.InitializeAsync(Path.Combine(DataDir, "BitcoinStore"), Network); var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager"); Task <CoreNode> bitcoinCoreNodeInitTask; if (Config.StartLocalBitcoinCoreOnStartup) { bitcoinCoreNodeInitTask = CoreNode .CreateAsync(new CoreNodeParams( Network, Config.LocalBitcoinCoreDataDir, tryRestart: false, tryDeleteDataDir: false, EndPointStrategy.Custom(Config.GetBitcoinP2pEndPoint()), EndPointStrategy.Default(Network, EndPointType.Rpc), txIndex: null, prune: null)); } else { bitcoinCoreNodeInitTask = Task.FromResult <CoreNode>(null); } AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat"); var addrManTask = InitializeAddressManagerBehaviorAsync(); var blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}"); var connectionParameters = new NodeConnectionParameters { UserAgent = "/Satoshi:0.18.1/" }; if (Config.UseTor) { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint); } else { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null); } UpdateChecker = new UpdateChecker(TimeSpan.FromMinutes(7), Synchronizer.WasabiClient); #region ProcessKillSubscription AppDomain.CurrentDomain.ProcessExit += async(s, e) => await TryDesperateDequeueAllCoinsAsync(); Console.CancelKeyPress += async(s, e) => { e.Cancel = true; Logger.LogWarning("Process was signaled for killing."); KillRequested = true; await TryDesperateDequeueAllCoinsAsync(); Dispatcher.UIThread.PostLogException(() => { var window = (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow; window?.Close(); }); await DisposeAsync(); Logger.LogSoftwareStopped("Wasabi"); }; #endregion ProcessKillSubscription #region TorProcessInitialization if (Config.UseTor) { TorManager = new TorProcessManager(Config.TorSocks5EndPoint, TorLogsFile); } else { TorManager = TorProcessManager.Mock(); } TorManager.Start(false, DataDir); var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions"); TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri); Logger.LogInfo($"{nameof(TorProcessManager)} is initialized."); #endregion TorProcessInitialization #region BitcoinStoreInitialization await bstoreInitTask; #endregion BitcoinStoreInitialization #region BitcoinCoreInitialization var feeProviderList = new List <IFeeProvider>(); try { BitcoinCoreNode = await bitcoinCoreNodeInitTask.ConfigureAwait(false); if (Config.StartLocalBitcoinCoreOnStartup) { RpcMonitor.RpcClient = BitcoinCoreNode.RpcClient; RpcMonitor.Start(); RpcFeeProvider = new RpcFeeProvider(TimeSpan.FromMinutes(1), BitcoinCoreNode.RpcClient); RpcFeeProvider.Start(); feeProviderList.Add(RpcFeeProvider); } } catch (Exception ex) { Logger.LogError(ex); } feeProviderList.Add(Synchronizer); FeeProviders = new FeeProviders(feeProviderList); #endregion BitcoinCoreInitialization #region MempoolInitialization connectionParameters.TemplateBehaviors.Add(BitcoinStore.CreateMempoolBehavior()); #endregion MempoolInitialization #region AddressManagerInitialization AddressManagerBehavior addressManagerBehavior = await addrManTask; connectionParameters.TemplateBehaviors.Add(addressManagerBehavior); #endregion AddressManagerInitialization #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); Nodes.ConnectedNodes.Add(node); RegTestMempoolServingNode = await Node.ConnectAsync(Network.RegTest, bitcoinCoreEndpoint); RegTestMempoolServingNode.Behaviors.Add(BitcoinStore.CreateMempoolBehavior()); } catch (SocketException ex) { Logger.LogError(ex); } } else { if (Config.UseTor is true) { // 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); } Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements); RegTestMempoolServingNode = null; } Nodes.Connect(); Logger.LogInfo("Start connecting to nodes..."); if (RegTestMempoolServingNode != null) { RegTestMempoolServingNode.VersionHandshake(); Logger.LogInfo("Start connecting to mempool serving regtest node..."); } #endregion P2PInitialization #region SynchronizerInitialization var requestInterval = TimeSpan.FromSeconds(30); if (Network == Network.RegTest) { requestInterval = TimeSpan.FromSeconds(5); } int maxFiltSyncCount = Network == Network.Main ? 1000 : 10000; // On testnet, filters are empty, so it's faster to query them together Synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), maxFiltSyncCount); Logger.LogInfo("Start synchronizing filters..."); #endregion SynchronizerInitialization TransactionBroadcaster = new TransactionBroadcaster(Network, BitcoinStore, Synchronizer, Nodes, BitcoinCoreNode?.RpcClient); Initialized = true; }
public async Task InitializeNoWalletAsync(CancellationToken cancellationToken = default) { AddressManager = null; Logger.LogDebug($"Global.InitializeNoWalletAsync(): Waiting for a lock"); try { InitializationStarted = true; Logger.LogDebug($"Global.InitializeNoWalletAsync(): Got lock"); 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 blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}"); var userAgent = Constants.UserAgents.RandomElement(); var connectionParameters = new NodeConnectionParameters { UserAgent = userAgent }; if (Config.UseTor) { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint); } else { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null); } #region TorProcessInitialization if (Config.UseTor) { await TorManager.StartAsync(ensureRunning : false, DataDir); Logger.LogInfo($"{nameof(TorManager)} is initialized."); } Logger.LogInfo($"Global.InitializeNoWalletAsync():{nameof(TorManager)} is initialized."); #endregion TorProcessInitialization #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 #region FeeProviderInitialization // Mirrors #region BitcoinCoreInitialization in WalletWasabi var feeProviderList = new List <IFeeProvider> { Synchronizer }; FeeProviders = new FeeProviders(feeProviderList); #endregion FeeProviderInitialization #region MempoolInitialization connectionParameters.TemplateBehaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior()); #endregion MempoolInitialization #region AddressManagerInitialization AddressManagerBehavior addressManagerBehavior = await addrManTask.ConfigureAwait(false); connectionParameters.TemplateBehaviors.Add(addressManagerBehavior); #endregion AddressManagerInitialization #region P2PInitialization if (Network == Network.RegTest) { Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements); try { EndPoint bitcoinCoreEndpoint = Config.GetBitcoinP2pEndPoint(); Node node = await Node.ConnectAsync(NBitcoin.Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false); Nodes.ConnectedNodes.Add(node); RegTestMempoolServingNode = await Node.ConnectAsync(NBitcoin.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 don't connect to clearnet IPs at all. // This of course makes the first setting unneccessary, 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("Global.InitializeNoWalletAsync(): Start connecting to nodes..."); var regTestMempoolServingNode = RegTestMempoolServingNode; if (regTestMempoolServingNode != null) { regTestMempoolServingNode.VersionHandshake(); Logger.LogInfo("Global.InitializeNoWalletAsync(): Start connecting to mempool serving regtest node..."); } #endregion P2PInitialization #region SynchronizerInitialization var requestInterval = TimeSpan.FromSeconds(30); if (Network == Network.RegTest) { requestInterval = TimeSpan.FromSeconds(5); } int maxFiltSyncCount = Network == Network.Main ? 1000 : 10000; // On testnet, filters are empty, so it's faster to query them together Synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), maxFiltSyncCount); Logger.LogInfo("Global.InitializeNoWalletAsync(): Start synchronizing filters..."); #endregion SynchronizerInitialization TransactionBroadcaster = new TransactionBroadcaster(Network, BitcoinStore, Synchronizer, Nodes, WalletManager, null); CoinJoinProcessor = new CoinJoinProcessor(Synchronizer, WalletManager, null); #region Blocks provider var blockProvider = new CachedBlockProvider( new SmartBlockProvider( new P2pBlockProvider(Nodes, null, Synchronizer, Config.ServiceConfiguration, Network), Cache), new FileSystemBlockRepository(blocksFolderPath, Network)); #endregion Blocks provider WalletManager.RegisterServices(BitcoinStore, Synchronizer, Nodes, Config.ServiceConfiguration, FeeProviders, blockProvider); Initialized(this, EventArgs.Empty); IsInitialized = true; }
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 { })
public async Task TestServicesAsync(string networkString) { await RuntimeParams.LoadAsync(); var network = Network.GetNetwork(networkString); var blocksToDownload = new List <uint256>(); if (network == Network.Main) { blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0")); blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9")); blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629")); } else if (network == Network.TestNet) { blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524")); blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc")); blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66")); } else { throw new NotSupportedNetworkException(network); } var dataDir = Common.GetWorkDir(); var indexStore = new IndexStore(Path.Combine(dataDir, "indexStore"), network, new SmartHeaderChain()); await using var transactionStore = new AllTransactionStore(Path.Combine(dataDir, "transactionStore"), network); var mempoolService = new MempoolService(); var blocks = new FileSystemBlockRepository(Path.Combine(dataDir, "blocks"), network); await using BitcoinStore bitcoinStore = new BitcoinStore(indexStore, transactionStore, mempoolService, blocks); await bitcoinStore.InitializeAsync(); var addressManagerFolderPath = Path.Combine(dataDir, "AddressManager"); var addressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat"); var connectionParameters = new NodeConnectionParameters(); AddressManager addressManager; try { addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath); Logger.LogInfo($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`."); } catch (DirectoryNotFoundException) { addressManager = new AddressManager(); } catch (FileNotFoundException) { addressManager = new AddressManager(); } catch (OverflowException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } catch (FormatException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager)); connectionParameters.TemplateBehaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior()); using var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements); KeyManager keyManager = KeyManager.CreateNew(out _, "password"); WasabiClientFactory wasabiClientFactory = new WasabiClientFactory(Common.TorSocks5Endpoint, backendUriGetter: () => new Uri("http://localhost:12345")); WasabiSynchronizer syncer = new WasabiSynchronizer(network, bitcoinStore, wasabiClientFactory); ServiceConfiguration serviceConfig = new ServiceConfiguration(MixUntilAnonymitySet.PrivacyLevelStrong.ToString(), 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)); CachedBlockProvider blockProvider = new CachedBlockProvider( new P2pBlockProvider(nodes, null, syncer, serviceConfig, network), bitcoinStore.BlockRepository); using Wallet wallet = Wallet.CreateAndRegisterServices( network, bitcoinStore, keyManager, syncer, nodes, dataDir, new ServiceConfiguration(MixUntilAnonymitySet.PrivacyLevelStrong.ToString(), 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)), syncer, blockProvider); Assert.True(Directory.Exists(blocks.BlocksFolderPath)); try { var mempoolTransactionAwaiter = new EventsAwaiter <SmartTransaction>( h => bitcoinStore.MempoolService.TransactionReceived += h, h => bitcoinStore.MempoolService.TransactionReceived -= h, 3); var nodeConnectionAwaiter = new EventsAwaiter <NodeEventArgs>( h => nodes.ConnectedNodes.Added += h, h => nodes.ConnectedNodes.Added -= h, 3); nodes.Connect(); var downloadTasks = new List <Task <Block> >(); using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(4)); foreach (var hash in blocksToDownload) { downloadTasks.Add(blockProvider.GetBlockAsync(hash, cts.Token)); } await nodeConnectionAwaiter.WaitAsync(TimeSpan.FromMinutes(3)); var i = 0; var hashArray = blocksToDownload.ToArray(); foreach (var block in await Task.WhenAll(downloadTasks)) { Assert.True(File.Exists(Path.Combine(blocks.BlocksFolderPath, hashArray[i].ToString()))); i++; } await mempoolTransactionAwaiter.WaitAsync(TimeSpan.FromMinutes(1)); } finally { // So next test will download the block. foreach (var hash in blocksToDownload) { await blockProvider.BlockRepository.RemoveAsync(hash, CancellationToken.None); } if (wallet is { })