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"); 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 { if (Config.StartLocalBitcoinCoreOnStartup) { BitcoinCoreNode = await CoreNode .CreateAsync( new CoreNodeParams( Network, BitcoinStore.MempoolService, Config.LocalBitcoinCoreDataDir, tryRestart : false, tryDeleteDataDir : false, EndPointStrategy.Custom(Config.GetBitcoinP2pEndPoint()), EndPointStrategy.Default(Network, EndPointType.Rpc), txIndex : null, prune : null, userAgent : $"/WasabiClient:{Constants.ClientVersion.ToString()}/"), CancellationToken.None) .ConfigureAwait(false); 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.CreateUntrustedP2pBehavior()); #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).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 { })
private long _dispose = 0; // To detect redundant calls public async Task DisposeAsync() { var compareRes = Interlocked.CompareExchange(ref _dispose, 1, 0); if (compareRes == 1) { while (Interlocked.Read(ref _dispose) != 2) { await Task.Delay(50); } return; } else if (compareRes == 2) { return; } try { await DisposeInWalletDependentServicesAsync(); if (UpdateChecker != null) { await UpdateChecker?.StopAsync(); Logger.LogInfo($"{nameof(UpdateChecker)} is stopped."); } if (FeeProviders != null) { FeeProviders.Dispose(); Logger.LogInfo($"Disposed {nameof(FeeProviders)}."); } if (Synchronizer != null) { await Synchronizer?.StopAsync(); Logger.LogInfo($"{nameof(Synchronizer)} is stopped."); } if (RpcFeeProvider != null) { await RpcFeeProvider.StopAsync(); Logger.LogInfo("Stopped synching fees through RPC."); } if (AddressManagerFilePath != null) { IoHelpers.EnsureContainingDirectoryExists(AddressManagerFilePath); if (AddressManager != null) { AddressManager?.SavePeerFile(AddressManagerFilePath, Config.Network); Logger.LogInfo($"{nameof(AddressManager)} is saved to `{AddressManagerFilePath}`."); } } if (Nodes != null) { Nodes?.Disconnect(); while (Nodes.ConnectedNodes.Any(x => x.IsConnected)) { await Task.Delay(50); } Nodes?.Dispose(); Logger.LogInfo($"{nameof(Nodes)} are disposed."); } if (RegTestMempoolServingNode != null) { RegTestMempoolServingNode.Disconnect(); Logger.LogInfo($"{nameof(RegTestMempoolServingNode)} is disposed."); } if (RpcMonitor != null) { await RpcMonitor.StopAsync(); Logger.LogInfo("Stopped monitoring RPC."); } if (Config.StopLocalBitcoinCoreOnShutdown && BitcoinCoreNode != null) { await BitcoinCoreNode.TryStopAsync().ConfigureAwait(false); } if (TorManager != null) { await TorManager?.StopAsync(); Logger.LogInfo($"{nameof(TorManager)} is stopped."); } if (AsyncMutex.IsAny) { try { await AsyncMutex.WaitForAllMutexToCloseAsync(); Logger.LogInfo($"{nameof(AsyncMutex)}(es) are stopped."); } catch (Exception ex) { Logger.LogError($"Error during stopping {nameof(AsyncMutex)}: {ex}"); } } } catch (Exception ex) { Logger.LogWarning(ex); } finally { Interlocked.Exchange(ref _dispose, 2); } }