private async Task <TransactionProcessor> CreateTransactionProcessorAsync([CallerMemberName] string callerName = "") { var datadir = EnvironmentHelpers.GetDataDir(Path.Combine("WalletWasabi", "Bench")); var dir = Path.Combine(datadir, callerName, "TransactionStore"); Console.WriteLine(dir); await IoHelpers.DeleteRecursivelyWithMagicDustAsync(dir); // Create the services. // 1. Create connection service. var nodes = new NodesGroup(Network.Main); var bitcoinStore = new BitcoinStore(); var serviceConfiguration = new ServiceConfiguration(2, 2, 21, 50, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 45678), Money.Coins(0.0001m)); // 2. Create wasabi synchronizer service. var synchronizer = new WasabiSynchronizer(Network.Main, bitcoinStore, () => new Uri("http://localhost:35474"), null); synchronizer.Start(requestInterval: TimeSpan.FromDays(1), TimeSpan.FromDays(1), 1000); // 3. Create key manager service. var keyManager = KeyManager.CreateNew(out _, "password"); // 4. Create chaumian coinjoin client. var chaumianClient = new CoinJoinClient(synchronizer, Network.Main, keyManager); // 5. Create wallet service. await bitcoinStore.InitializeAsync(dir, Network.Main); var workDir = Path.Combine(datadir, EnvironmentHelpers.GetMethodName()); var feeProviders = new FeeProviders(new[] { synchronizer }); var wallet = new WalletService(bitcoinStore, keyManager, synchronizer, nodes, workDir, serviceConfiguration, feeProviders); return(wallet.TransactionProcessor); }
public void RegisterServices( BitcoinStore bitcoinStore, WasabiSynchronizer syncer, NodesGroup nodes, ServiceConfiguration serviceConfiguration, IFeeProvider feeProvider, CoreNode coreNode = null) { if (State != WalletState.Uninitialized) { throw new InvalidOperationException($"{nameof(State)} must be {WalletState.Uninitialized}. Current state: {State}."); } BitcoinStore = Guard.NotNull(nameof(bitcoinStore), bitcoinStore); Nodes = Guard.NotNull(nameof(nodes), nodes); Synchronizer = Guard.NotNull(nameof(syncer), syncer); ServiceConfiguration = Guard.NotNull(nameof(serviceConfiguration), serviceConfiguration); FeeProvider = Guard.NotNull(nameof(feeProvider), feeProvider); CoreNode = coreNode; ChaumianClient = new CoinJoinClient(Synchronizer, Network, KeyManager); TransactionProcessor = new TransactionProcessor(BitcoinStore.TransactionStore, KeyManager, ServiceConfiguration.DustThreshold, ServiceConfiguration.PrivacyLevelStrong); Coins = TransactionProcessor.Coins; TransactionProcessor.WalletRelevantTransactionProcessed += TransactionProcessor_WalletRelevantTransactionProcessedAsync; ChaumianClient.OnDequeue += ChaumianClient_OnDequeue; BitcoinStore.IndexStore.NewFilter += IndexDownloader_NewFilterAsync; BitcoinStore.IndexStore.Reorged += IndexDownloader_ReorgedAsync; BitcoinStore.MempoolService.TransactionReceived += Mempool_TransactionReceived; State = WalletState.Initialized; }
public CoinJoinClient( WasabiSynchronizer synchronizer, Network network, KeyManager keyManager, Kitchen kitchen) { Network = Guard.NotNull(nameof(network), network); KeyManager = Guard.NotNull(nameof(keyManager), keyManager); DestinationKeyManager = KeyManager; Synchronizer = Guard.NotNull(nameof(synchronizer), synchronizer); CcjHostUriAction = Synchronizer.HttpClientFactory.BackendUriGetter; CoordinatorFeepercentToCheck = null; Kitchen = Guard.NotNull(nameof(kitchen), kitchen); ExposedLinks = new ConcurrentDictionary <OutPoint, IEnumerable <HdPubKeyBlindedPair> >(); _running = StateNotStarted; Cancel = new CancellationTokenSource(); _frequentStatusProcessingIfNotMixing = 0; State = new ClientState(); MixLock = new AsyncLock(); _statusProcessing = 0; DelayedRoundRegistration = null; Synchronizer.ResponseArrived += Synchronizer_ResponseArrivedAsync; var lastResponse = Synchronizer.LastResponse; if (lastResponse is { })
public void Initialize(NodesCollection nodes, WasabiSynchronizer synchronizer) { Nodes = nodes; Synchronizer = synchronizer; HashChain = synchronizer.BitcoinStore.HashChain; UseTor = Global.Config.UseTor; // Do not make it dynamic, because if you change this config settings only next time will it activate. UseBitcoinCore = Global.Config.StartLocalBitcoinCoreOnStartup; var hostedServices = Global.HostedServices; var updateChecker = hostedServices.FirstOrDefault <UpdateChecker>(); Guard.NotNull(nameof(updateChecker), updateChecker); UpdateStatus = updateChecker.UpdateStatus; var rpcMonitor = hostedServices.FirstOrDefault <RpcMonitor>(); BitcoinCoreStatus = rpcMonitor?.RpcStatus ?? RpcStatus.Unresponsive; _status = ActiveStatuses.WhenAnyValue(x => x.CurrentStatus) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.Status) .DisposeWith(Disposables); Observable .Merge(Observable.FromEventPattern <NodeEventArgs>(nodes, nameof(nodes.Added)).Select(x => true) .Merge(Observable.FromEventPattern <NodeEventArgs>(nodes, nameof(nodes.Removed)).Select(x => true) .Merge(Synchronizer.WhenAnyValue(x => x.TorStatus).Select(x => true)))) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => Peers = Synchronizer.TorStatus == TorStatus.NotRunning ? 0 : Nodes.Count) // Set peers to 0 if Tor is not running, because we get Tor status from backend answer so it seems to the user that peers are connected over clearnet, while they are not. .DisposeWith(Disposables); Peers = Tor == TorStatus.NotRunning ? 0 : Nodes.Count; Observable.FromEventPattern <bool>(typeof(WalletService), nameof(WalletService.DownloadingBlockChanged)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => DownloadingBlock = x.EventArgs) .DisposeWith(Disposables); Synchronizer.WhenAnyValue(x => x.TorStatus) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(status => Tor = UseTor ? status : TorStatus.TurnedOff) .DisposeWith(Disposables); Synchronizer.WhenAnyValue(x => x.BackendStatus) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => Backend = Synchronizer.BackendStatus) .DisposeWith(Disposables); _filtersLeft = HashChain.WhenAnyValue(x => x.HashesLeft) .Throttle(TimeSpan.FromMilliseconds(100)) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.FiltersLeft) .DisposeWith(Disposables); Synchronizer.WhenAnyValue(x => x.UsdExchangeRate) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(usd => BtcPrice = $"${(long)usd}") .DisposeWith(Disposables); if (rpcMonitor is { })
protected CoinJoinClientBase( WasabiSynchronizer synchronizer, Network network, KeyManager keyManager) { Network = Guard.NotNull(nameof(network), network); KeyManager = Guard.NotNull(nameof(keyManager), keyManager); DestinationKeyManager = KeyManager; Synchronizer = Guard.NotNull(nameof(synchronizer), synchronizer); CcjHostUriAction = Synchronizer.WasabiClient.TorClient.DestinationUriAction; TorSocks5EndPoint = Synchronizer.WasabiClient.TorClient.TorSocks5EndPoint; CoordinatorFeepercentToCheck = null; ExposedLinks = new ConcurrentDictionary <OutPoint, IEnumerable <HdPubKeyBlindedPair> >(); _running = 0; Cancel = new CancellationTokenSource(); _frequentStatusProcessingIfNotMixing = 0; State = new ClientState(); MixLock = new AsyncLock(); _statusProcessing = 0; DelayedRoundRegistration = null; Synchronizer.ResponseArrived += Synchronizer_ResponseArrivedAsync; var lastResponse = Synchronizer.LastResponse; if (lastResponse != null) { _ = TryProcessStatusAsync(Synchronizer.LastResponse.CcjRoundStates); } }
public Global(string dataDir, string torLogsFile, Config config, UiConfig uiConfig, WalletManager walletManager) { using (BenchmarkLogger.Measure()) { StoppingCts = new CancellationTokenSource(); DataDir = dataDir; Config = config; UiConfig = uiConfig; TorSettings = new TorSettings(DataDir, torLogsFile, distributionFolderPath: EnvironmentHelpers.GetFullBaseDirectory()); Logger.InitializeDefaults(Path.Combine(DataDir, "Logs.txt")); HostedServices = new HostedServices(); WalletManager = walletManager; LegalDocuments = LegalDocuments.TryLoadAgreed(DataDir); WalletManager.OnDequeue += WalletManager_OnDequeue; WalletManager.WalletRelevantTransactionProcessed += WalletManager_WalletRelevantTransactionProcessed; var networkWorkFolderPath = Path.Combine(DataDir, "BitcoinStore", Network.ToString()); var transactionStore = new AllTransactionStore(networkWorkFolderPath, Network); var indexStore = new IndexStore(Path.Combine(networkWorkFolderPath, "IndexStore"), Network, new SmartHeaderChain()); var mempoolService = new MempoolService(); var blocks = new FileSystemBlockRepository(Path.Combine(networkWorkFolderPath, "Blocks"), Network); BitcoinStore = new BitcoinStore(indexStore, transactionStore, mempoolService, blocks); WasabiClientFactory wasabiClientFactory = Config.UseTor ? new WasabiClientFactory(Config.TorSocks5EndPoint, backendUriGetter: () => Config.GetCurrentBackendUri()) : new WasabiClientFactory(torEndPoint: null, backendUriGetter: () => Config.GetFallbackBackendUri()); Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, wasabiClientFactory); } }
private void Create(WasabiSynchronizer synchronizer, Network network, KeyManager keyManager, Func <Uri> ccjHostUriAction, EndPoint torSocks5EndPoint) { Network = Guard.NotNull(nameof(network), network); KeyManager = Guard.NotNull(nameof(keyManager), keyManager); CcjHostUriAction = Guard.NotNull(nameof(ccjHostUriAction), ccjHostUriAction); Synchronizer = Guard.NotNull(nameof(synchronizer), synchronizer); TorSocks5EndPoint = torSocks5EndPoint; CoordinatorFeepercentToCheck = null; ExposedLinks = new ConcurrentDictionary <TxoRef, IEnumerable <HdPubKeyBlindedPair> >(); _running = 0; Cancel = new CancellationTokenSource(); _frequentStatusProcessingIfNotMixing = 0; State = new ClientState(); MixLock = new AsyncLock(); _statusProcessing = 0; DelayedRoundRegistration = null; Synchronizer.ResponseArrived += Synchronizer_ResponseArrivedAsync; var lastResponse = Synchronizer.LastResponse; if (lastResponse != null) { _ = TryProcessStatusAsync(Synchronizer.LastResponse.CcjRoundStates); } }
public UpdateChecker(TimeSpan period, WasabiSynchronizer synchronizer) : base(period) { Synchronizer = synchronizer; UpdateStatus = new UpdateStatus(true, true, new Version(), 0, new Version()); WasabiClient = Synchronizer.HttpClientFactory.SharedWasabiClient; Synchronizer.PropertyChanged += Synchronizer_PropertyChanged; }
public TransactionBroadcaster(Network network, BitcoinStore bitcoinStore, WasabiSynchronizer synchronizer, WalletManager walletManager) { Network = Guard.NotNull(nameof(network), network); BitcoinStore = Guard.NotNull(nameof(bitcoinStore), bitcoinStore); Synchronizer = Guard.NotNull(nameof(synchronizer), synchronizer); WalletManager = Guard.NotNull(nameof(walletManager), walletManager); }
private volatile bool _disposedValue = false; // To detect redundant calls public CoinJoinProcessor(WasabiSynchronizer synchronizer, WalletManager walletManager, IRPCClient rpc) { Synchronizer = Guard.NotNull(nameof(synchronizer), synchronizer); WalletManager = Guard.NotNull(nameof(walletManager), walletManager); RpcClient = rpc; ProcessLock = new AsyncLock(); Synchronizer.ResponseArrived += Synchronizer_ResponseArrivedAsync; }
public P2pBlockProvider(NodesGroup nodes, CoreNode coreNode, WasabiSynchronizer syncer, ServiceConfiguration serviceConfiguration, Network network) { Nodes = nodes; CoreNode = coreNode; Synchronizer = syncer; ServiceConfiguration = serviceConfiguration; Network = network; }
public CoinJoinClient( WasabiSynchronizer synchronizer, Network network, KeyManager keyManager, Func <Uri> ccjHostUriAction, EndPoint torSocks5EndPoint) { Create(synchronizer, network, keyManager, ccjHostUriAction, torSocks5EndPoint); }
public CoinJoinClient( WasabiSynchronizer synchronizer, Network network, KeyManager keyManager, Uri ccjHostUri, EndPoint torSocks5EndPoint) { Create(synchronizer, network, keyManager, () => ccjHostUri, torSocks5EndPoint); }
public TransactionBroadcaster(Network network, BitcoinStore bitcoinStore, WasabiSynchronizer synchronizer, NodesGroup nodes, WalletManager walletManager, IRPCClient rpc) { Nodes = Guard.NotNull(nameof(nodes), nodes); Network = Guard.NotNull(nameof(network), network); BitcoinStore = Guard.NotNull(nameof(bitcoinStore), bitcoinStore); Synchronizer = Guard.NotNull(nameof(synchronizer), synchronizer); WalletManager = Guard.NotNull(nameof(walletManager), walletManager); RpcClient = rpc; }
public Wallet( Network network, BitcoinStore bitcoinStore, KeyManager keyManager, WasabiSynchronizer syncer, NodesGroup nodes, string workFolderDir, ServiceConfiguration serviceConfiguration, IFeeProvider feeProvider, CoreNode coreNode = null) { Network = Guard.NotNull(nameof(network), network); BitcoinStore = Guard.NotNull(nameof(bitcoinStore), bitcoinStore); KeyManager = Guard.NotNull(nameof(keyManager), keyManager); Nodes = Guard.NotNull(nameof(nodes), nodes); Synchronizer = Guard.NotNull(nameof(syncer), syncer); ServiceConfiguration = Guard.NotNull(nameof(serviceConfiguration), serviceConfiguration); FeeProvider = Guard.NotNull(nameof(feeProvider), feeProvider); CoreNode = coreNode; ChaumianClient = new CoinJoinClient(Synchronizer, Network, keyManager); HandleFiltersLock = new AsyncLock(); BlocksFolderPath = Path.Combine(workFolderDir, "Blocks", Network.ToString()); RuntimeParams.SetDataDir(workFolderDir); BlockFolderLock = new AsyncLock(); KeyManager.AssertCleanKeysIndexed(); KeyManager.AssertLockedInternalKeysIndexed(14); TransactionProcessor = new TransactionProcessor(BitcoinStore.TransactionStore, KeyManager, ServiceConfiguration.DustThreshold, ServiceConfiguration.PrivacyLevelStrong); Coins = TransactionProcessor.Coins; TransactionProcessor.WalletRelevantTransactionProcessed += TransactionProcessor_WalletRelevantTransactionProcessedAsync; ChaumianClient.OnDequeue += ChaumianClient_OnDequeue; if (Directory.Exists(BlocksFolderPath)) { if (Network == Network.RegTest) { Directory.Delete(BlocksFolderPath, true); Directory.CreateDirectory(BlocksFolderPath); } } else { Directory.CreateDirectory(BlocksFolderPath); } BitcoinStore.IndexStore.NewFilter += IndexDownloader_NewFilterAsync; BitcoinStore.IndexStore.Reorged += IndexDownloader_ReorgedAsync; BitcoinStore.MempoolService.TransactionReceived += Mempool_TransactionReceived; State = WalletState.Initialized; }
public TransactionBroadcaster(Network network, BitcoinStore bitcoinStore, WasabiSynchronizer synchronizer, NodesGroup nodes, RPCClient rpc) { Nodes = Guard.NotNull(nameof(nodes), nodes); Network = Guard.NotNull(nameof(network), network); BitcoinStore = Guard.NotNull(nameof(bitcoinStore), bitcoinStore); Synchronizer = Guard.NotNull(nameof(synchronizer), synchronizer); WalletServices = new List <WalletService>(); WalletServicesLock = new object(); RpcClient = rpc; }
public async Task GetFiltersAsync(NetworkType networkType) { using (var client = new WasabiClient(LiveServerTestsFixture.UriMappings[networkType], SharedFixture.TorSocks5Endpoint)) { var filterModel = WasabiSynchronizer.GetStartingFilter(Network.GetNetwork(networkType.ToString())); FiltersResponse filtersResponse = await client.GetFiltersAsync(filterModel.BlockHash, 2); Assert.NotNull(filtersResponse); Assert.True(filtersResponse.Filters.Count() == 2); } }
private volatile bool _disposedValue = false; // To detect redundant calls public StatusBarViewModel(string dataDir, Network network, Config config, HostedServices hostedServices, SmartHeaderChain smartHeaderChain, WasabiSynchronizer synchronizer) { DataDir = dataDir; Network = network; Config = config; HostedServices = hostedServices; SmartHeaderChain = smartHeaderChain; Synchronizer = synchronizer; Backend = BackendStatus.NotConnected; UseTor = false; Tor = TorStatus.NotRunning; Peers = 0; _exchangeRate = ""; IsExchangeRateAvailable = false; ActiveStatuses = new StatusSet(); }
private volatile bool _disposedValue = false; // To detect redundant calls public StatusBarViewModel(string dataDir, Network network, Config config, HostedServices hostedServices, SmartHeaderChain smartHeaderChain, WasabiSynchronizer synchronizer, LegalDocuments?legalDocuments) { DataDir = dataDir; Network = network; Config = config; HostedServices = hostedServices; SmartHeaderChain = smartHeaderChain; Synchronizer = synchronizer; LegalDocuments = legalDocuments; Backend = BackendStatus.NotConnected; UseTor = false; Tor = TorStatus.NotRunning; Peers = 0; BtcPrice = "$0"; ActiveStatuses = new StatusSet(); }
public Global(string dataDir, Config config, UiConfig uiConfig, WalletManager walletManager) { using (BenchmarkLogger.Measure()) { DataDir = dataDir; Config = config; UiConfig = uiConfig; TorSettings = new TorSettings(DataDir, distributionFolderPath: EnvironmentHelpers.GetFullBaseDirectory(), Config.TerminateTorOnExit, Environment.ProcessId); HostedServices = new HostedServices(); WalletManager = walletManager; var networkWorkFolderPath = Path.Combine(DataDir, "BitcoinStore", Network.ToString()); AllTransactionStore = new AllTransactionStore(networkWorkFolderPath, Network); SmartHeaderChain smartHeaderChain = new(maxChainSize : 20_000); IndexStore = new IndexStore(Path.Combine(networkWorkFolderPath, "IndexStore"), Network, smartHeaderChain); var mempoolService = new MempoolService(); var blocks = new FileSystemBlockRepository(Path.Combine(networkWorkFolderPath, "Blocks"), Network); BitcoinStore = new BitcoinStore(IndexStore, AllTransactionStore, mempoolService, blocks); if (Config.UseTor) { BackendHttpClientFactory = new HttpClientFactory(TorSettings.SocksEndpoint, backendUriGetter: () => Config.GetCurrentBackendUri()); ExternalHttpClientFactory = new HttpClientFactory(TorSettings.SocksEndpoint, backendUriGetter: null); } else { BackendHttpClientFactory = new HttpClientFactory(torEndPoint: null, backendUriGetter: () => Config.GetFallbackBackendUri()); ExternalHttpClientFactory = new HttpClientFactory(torEndPoint: null, backendUriGetter: null); } Synchronizer = new WasabiSynchronizer(BitcoinStore, BackendHttpClientFactory); LegalChecker = new(DataDir); TransactionBroadcaster = new TransactionBroadcaster(Network, BitcoinStore, BackendHttpClientFactory, WalletManager); RoundStateUpdaterCircuit = new PersonCircuit(); Cache = new MemoryCache(new MemoryCacheOptions { SizeLimit = 1_000, ExpirationScanFrequency = TimeSpan.FromSeconds(30) });
private volatile bool _disposedValue = false; // To detect redundant calls public HybridFeeProvider(WasabiSynchronizer synchronizer, RpcFeeProvider?rpcFeeProvider) { Synchronizer = synchronizer; RpcFeeProvider = rpcFeeProvider; Synchronizer.AllFeeEstimateArrived += OnAllFeeEstimateArrived; if (RpcFeeProvider is not null) { RpcFeeProvider.AllFeeEstimateArrived += OnAllFeeEstimateArrived; } var syncerEstimate = Synchronizer.LastResponse?.AllFeeEstimate; var rpcEstimate = RpcFeeProvider?.LastAllFeeEstimate; var betterEstimate = rpcEstimate?.IsAccurate is true ? rpcEstimate : syncerEstimate; if (betterEstimate is not null) { SetAllFeeEstimate(betterEstimate); } }
public Global(string dataDir, string torLogsFile, Config config, UiConfig uiConfig, WalletManager walletManager) { using (BenchmarkLogger.Measure()) { CrashReporter = new CrashReporter(); StoppingCts = new CancellationTokenSource(); DataDir = dataDir; Config = config; UiConfig = uiConfig; TorLogsFile = torLogsFile; Logger.InitializeDefaults(Path.Combine(DataDir, "Logs.txt")); HostedServices = new HostedServices(); WalletManager = walletManager; LegalDocuments = LegalDocuments.TryLoadAgreed(DataDir); WalletManager.OnDequeue += WalletManager_OnDequeue; WalletManager.WalletRelevantTransactionProcessed += WalletManager_WalletRelevantTransactionProcessed; var networkWorkFolderPath = Path.Combine(DataDir, "BitcoinStore", Network.ToString()); var transactionStore = new AllTransactionStore(networkWorkFolderPath, Network); var indexStore = new IndexStore(Path.Combine(networkWorkFolderPath, "IndexStore"), Network, new SmartHeaderChain()); var mempoolService = new MempoolService(); BitcoinStore = new BitcoinStore(indexStore, transactionStore, mempoolService); SingleInstanceChecker = new SingleInstanceChecker(Network); if (Config.UseTor) { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint); } else { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null); } } }
public Global(string dataDir, Config config, UiConfig uiConfig, WalletManager walletManager) { using (BenchmarkLogger.Measure()) { StoppingCts = new CancellationTokenSource(); DataDir = dataDir; Config = config; UiConfig = uiConfig; TorSettings = new TorSettings(DataDir, distributionFolderPath: EnvironmentHelpers.GetFullBaseDirectory(), Config.TerminateTorOnExit, Environment.ProcessId); HostedServices = new HostedServices(); WalletManager = walletManager; WalletManager.OnDequeue += WalletManager_OnDequeue; WalletManager.WalletRelevantTransactionProcessed += WalletManager_WalletRelevantTransactionProcessed; var networkWorkFolderPath = Path.Combine(DataDir, "BitcoinStore", Network.ToString()); var transactionStore = new AllTransactionStore(networkWorkFolderPath, Network); var indexStore = new IndexStore(Path.Combine(networkWorkFolderPath, "IndexStore"), Network, new SmartHeaderChain()); var mempoolService = new MempoolService(); var blocks = new FileSystemBlockRepository(Path.Combine(networkWorkFolderPath, "Blocks"), Network); BitcoinStore = new BitcoinStore(indexStore, transactionStore, mempoolService, blocks); if (Config.UseTor) { BackendHttpClientFactory = new HttpClientFactory(TorSettings.SocksEndpoint, backendUriGetter: () => Config.GetCurrentBackendUri()); ExternalHttpClientFactory = new HttpClientFactory(TorSettings.SocksEndpoint, backendUriGetter: null); } else { BackendHttpClientFactory = new HttpClientFactory(torEndPoint: null, backendUriGetter: () => Config.GetFallbackBackendUri()); ExternalHttpClientFactory = new HttpClientFactory(torEndPoint: null, backendUriGetter: null); } Synchronizer = new WasabiSynchronizer(BitcoinStore, BackendHttpClientFactory); LegalChecker = new(DataDir); TransactionBroadcaster = new TransactionBroadcaster(Network, BitcoinStore, BackendHttpClientFactory, WalletManager); } }
public static 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 blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}"); var connectionParameters = new NodeConnectionParameters(); if (Config.UseTor.Value) { Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.GetTorSocks5EndPoint()); } 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(); }); }; #endregion ProcessKillSubscription #region TorProcessInitialization if (Config.UseTor.Value) { TorManager = new TorProcessManager(Config.GetTorSocks5EndPoint(), 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 AddressManagerInitialization var needsToDiscoverPeers = true; if (Network == Network.RegTest) { AddressManager = new AddressManager(); Logger.LogInfo <AddressManager>($"Fake {nameof(AddressManager)} is initialized on the RegTest."); } else { try { AddressManager = AddressManager.LoadPeerFile(AddressManagerFilePath); // The most of the times we don't need to discover new peers. Instead, we can connect to // some of those that we already discovered in the past. In this case we assume that we // assume that discovering new peers could be necessary if out address manager has less // than 500 addresses. A 500 addresses could be okay because previously we tried with // 200 and only one user reported he/she was not able to connect (there could be many others, // of course). // On the other side, increasing this number forces users that do not need to discover more peers // to spend resources (CPU/bandwith) to discover new peers. needsToDiscoverPeers = Config.UseTor == true || AddressManager.Count < 500; Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{AddressManagerFilePath}`."); } catch (DirectoryNotFoundException ex) { Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one."); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); } catch (FileNotFoundException ex) { Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one."); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); } catch (OverflowException ex) { // https://github.com/zkSNACKs/WalletWasabi/issues/712 Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(OverflowException)}`. Attempting to autocorrect."); File.Delete(AddressManagerFilePath); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful."); } catch (FormatException ex) { // https://github.com/zkSNACKs/WalletWasabi/issues/880 Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(FormatException)}`. Attempting to autocorrect."); File.Delete(AddressManagerFilePath); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful."); } } var addressManagerBehavior = new AddressManagerBehavior(AddressManager) { Mode = needsToDiscoverPeers ? AddressManagerBehaviorMode.Discover : AddressManagerBehaviorMode.None }; connectionParameters.TemplateBehaviors.Add(addressManagerBehavior); #endregion AddressManagerInitialization #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 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.GetTorSocks5EndPoint(), 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); } 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 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 = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName()); BitcoinStore bitcoinStore = new BitcoinStore(); await bitcoinStore.InitializeAsync(Path.Combine(dataDir, EnvironmentHelpers.GetMethodName()), network); var addressManagerFolderPath = Path.Combine(dataDir, "AddressManager"); var addressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat"); var blocksFolderPath = Path.Combine(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.CreateUntrustedP2pBehavior()); 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); ServiceConfiguration serviceConfig = new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)); CachedBlockProvider blockProvider = new CachedBlockProvider( new P2pBlockProvider(nodes, null, syncer, serviceConfig, network), new FileSystemBlockRepository(blocksFolderPath, network)); using Wallet wallet = Wallet.CreateAndRegisterServices( network, bitcoinStore, keyManager, syncer, nodes, dataDir, new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)), syncer, blockProvider); 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(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(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 { })
public StatusBarViewModel(NodesCollection nodes, WasabiSynchronizer synchronizer, UpdateChecker updateChecker) { UpdateStatus = UpdateStatus.Latest; Nodes = nodes; Synchronizer = synchronizer; BlocksLeft = 0; FiltersLeft = synchronizer.GetFiltersLeft(); UseTor = Global.Config.UseTor.Value; // Don't make it dynamic, because if you change this config settings only next time will it activate. Observable.FromEventPattern <NodeEventArgs>(nodes, nameof(nodes.Added)) .Subscribe(x => { SetPeers(Nodes.Count); }).DisposeWith(Disposables); Observable.FromEventPattern <NodeEventArgs>(nodes, nameof(nodes.Removed)) .Subscribe(x => { SetPeers(Nodes.Count); }).DisposeWith(Disposables); SetPeers(Nodes.Count); Observable.FromEventPattern <int>(typeof(WalletService), nameof(WalletService.ConcurrentBlockDownloadNumberChanged)) .Subscribe(x => { BlocksLeft = x.EventArgs; }).DisposeWith(Disposables); Observable.FromEventPattern(synchronizer, nameof(synchronizer.NewFilter)).Subscribe(x => { FiltersLeft = Synchronizer.GetFiltersLeft(); }).DisposeWith(Disposables); synchronizer.WhenAnyValue(x => x.TorStatus).Subscribe(status => { SetTor(status); SetPeers(Nodes.Count); }).DisposeWith(Disposables); synchronizer.WhenAnyValue(x => x.BackendStatus).Subscribe(_ => { Backend = Synchronizer.BackendStatus; }).DisposeWith(Disposables); synchronizer.WhenAnyValue(x => x.BestBlockchainHeight).Subscribe(_ => { FiltersLeft = Synchronizer.GetFiltersLeft(); }).DisposeWith(Disposables); synchronizer.WhenAnyValue(x => x.UsdExchangeRate).Subscribe(usd => { BtcPrice = $"${(long)usd}"; }).DisposeWith(Disposables); Observable.FromEventPattern <bool>(synchronizer, nameof(synchronizer.ResponseArrivedIsGenSocksServFail)) .Subscribe(e => { OnResponseArrivedIsGenSocksServFail(e.EventArgs); }).DisposeWith(Disposables); this.WhenAnyValue(x => x.BlocksLeft).Subscribe(blocks => { SetStatusAndDoUpdateActions(); }); this.WhenAnyValue(x => x.FiltersLeft).Subscribe(filters => { SetStatusAndDoUpdateActions(); }); this.WhenAnyValue(x => x.Tor).Subscribe(tor => { SetStatusAndDoUpdateActions(); }); this.WhenAnyValue(x => x.Backend).Subscribe(backend => { SetStatusAndDoUpdateActions(); }); this.WhenAnyValue(x => x.Peers).Subscribe(peers => { SetStatusAndDoUpdateActions(); }); this.WhenAnyValue(x => x.UpdateStatus).Subscribe(_ => { SetStatusAndDoUpdateActions(); }); this.WhenAnyValue(x => x.Status).Subscribe(async status => { if (status.EndsWith(".")) // Then do animation. { string nextAnimation = null; if (status.EndsWith("...")) { nextAnimation = status.TrimEnd("..", StringComparison.Ordinal); } else if (status.EndsWith("..") || status.EndsWith(".")) { nextAnimation = $"{status}."; } if (nextAnimation != null) { await Task.Delay(1000); if (Status == status) // If still the same. { Status = nextAnimation; } } } }); UpdateCommand = ReactiveCommand.Create(() => { try { IoHelpers.OpenBrowser("https://wasabiwallet.io/#download"); } catch (Exception ex) { Logging.Logger.LogWarning <StatusBarViewModel>(ex); IoC.Get <IShell>().AddOrSelectDocument(() => new AboutViewModel()); } }, this.WhenAnyValue(x => x.UpdateStatus).Select(x => x != UpdateStatus.Latest)); updateChecker.Start(TimeSpan.FromMinutes(7), () => { UpdateStatus = UpdateStatus.Critical; return(Task.CompletedTask); }, () => { if (UpdateStatus != UpdateStatus.Critical) { UpdateStatus = UpdateStatus.Optional; } return(Task.CompletedTask); }); }
public static void InitializeNoWallet() { WalletService = null; ChaumianClient = null; 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)); await TryDesperateDequeueAllCoinsAsync(); Dispatcher.UIThread.Post(() => { Application.Current.MainWindow.Close(); }); }; var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager"); AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat"); var blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}"); var connectionParameters = new NodeConnectionParameters(); AddressManager = null; TorManager = null; TorManager = new TorProcessManager(Config.GetTorSocks5EndPoint(), TorLogsFile); 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."); var needsToDiscoverPeers = true; if (Network == Network.RegTest) { AddressManager = new AddressManager(); Logger.LogInfo <AddressManager>($"Fake {nameof(AddressManager)} is initialized on the RegTest."); } else { try { AddressManager = AddressManager.LoadPeerFile(AddressManagerFilePath); // The most of the times we don't need to discover new peers. Instead, we can connect to // some of those that we already discovered in the past. In this case we assume that we // assume that discovering new peers could be necessary if out address manager has less // than 500 addresses. A 500 addresses could be okay because previously we tried with // 200 and only one user reported he/she was not able to connect (there could be many others, // of course). // On the other side, increasing this number forces users that do not need to discover more peers // to spend resources (CPU/bandwith) to discover new peers. needsToDiscoverPeers = AddressManager.Count < 500; Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{AddressManagerFilePath}`."); } catch (DirectoryNotFoundException ex) { Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one."); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); } catch (FileNotFoundException ex) { Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one."); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); } catch (OverflowException ex) { // https://github.com/zkSNACKs/WalletWasabi/issues/712 Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(OverflowException)}`. Attempting to autocorrect."); File.Delete(AddressManagerFilePath); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful."); } catch (FormatException ex) { // https://github.com/zkSNACKs/WalletWasabi/issues/880 Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(FormatException)}`. Attempting to autocorrect."); File.Delete(AddressManagerFilePath); Logger.LogTrace <AddressManager>(ex); AddressManager = new AddressManager(); Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful."); } } var addressManagerBehavior = new AddressManagerBehavior(AddressManager) { Mode = needsToDiscoverPeers ? AddressManagerBehaviorMode.Discover : AddressManagerBehaviorMode.None }; connectionParameters.TemplateBehaviors.Add(addressManagerBehavior); MemPoolService = new MemPoolService(); connectionParameters.TemplateBehaviors.Add(new MemPoolBehavior(MemPoolService)); if (Network == Network.RegTest) { Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements); try { Node node = Node.Connect(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444)); Nodes.ConnectedNodes.Add(node); RegTestMemPoolServingNode = Node.Connect(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444)); RegTestMemPoolServingNode.Behaviors.Add(new MemPoolBehavior(MemPoolService)); } catch (SocketException ex) { Logger.LogError(ex, nameof(Global)); } } else { Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements); RegTestMemPoolServingNode = null; } Synchronizer = new WasabiSynchronizer(Network, IndexFilePath, Config.GetCurrentBackendUri(), Config.GetTorSocks5EndPoint()); UpdateChecker = new UpdateChecker(Synchronizer.WasabiClient); Nodes.Connect(); Logger.LogInfo("Start connecting to nodes..."); if (!(RegTestMemPoolServingNode is null)) { RegTestMemPoolServingNode.VersionHandshake(); Logger.LogInfo("Start connecting to mempool serving regtest node..."); } var requestInterval = TimeSpan.FromSeconds(30); if (Network == Network.RegTest) { requestInterval = TimeSpan.FromSeconds(5); } Synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), 1000); Logger.LogInfo("Start synchronizing filters..."); }
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 }; 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), "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, userAgent : $"/WasabiClient:{Constants.ClientVersion}/", 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 SendTestsAsync() { (string password, IRPCClient rpc, Network network, _, ServiceConfiguration serviceConfiguration, BitcoinStore bitcoinStore, Backend.Global global) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1); bitcoinStore.IndexStore.NewFilter += Common.Wallet_NewFilterProcessed; // Create the services. // 1. Create connection service. var nodes = new NodesGroup(global.Config.Network, requirements: Constants.NodeRequirements); nodes.ConnectedNodes.Add(await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync()); // 2. Create mempool service. Node node = await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync(); node.Behaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior()); // 3. Create wasabi synchronizer service. var synchronizer = new WasabiSynchronizer(rpc.Network, bitcoinStore, new Uri(RegTestFixture.BackendEndPoint), null); // 4. Create key manager service. var keyManager = KeyManager.CreateNew(out _, password); // 5. Create wallet service. var workDir = Tests.Common.GetWorkDir(); CachedBlockProvider blockProvider = new CachedBlockProvider( new P2pBlockProvider(nodes, null, synchronizer, serviceConfiguration, network), bitcoinStore.BlockRepository); var walletManager = new WalletManager(network, new WalletDirectories(workDir)); walletManager.RegisterServices(bitcoinStore, synchronizer, nodes, serviceConfiguration, synchronizer, blockProvider); // Get some money, make it confirm. var key = keyManager.GetNextReceiveKey("foo label", out _); var key2 = keyManager.GetNextReceiveKey("foo label", out _); var txId = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(1m)); Assert.NotNull(txId); await rpc.GenerateAsync(1); var txId2 = await rpc.SendToAddressAsync(key2.GetP2wpkhAddress(network), Money.Coins(1m)); Assert.NotNull(txId2); await rpc.GenerateAsync(1); try { Interlocked.Exchange(ref Common.FiltersProcessedByWalletCount, 0); nodes.Connect(); // Start connection service. node.VersionHandshake(); // Start mempool service. synchronizer.Start(requestInterval: TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), 10000); // Start wasabi synchronizer service. // Wait until the filter our previous transaction is present. var blockCount = await rpc.GetBlockCountAsync(); await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), blockCount); var wallet = await walletManager.AddAndStartWalletAsync(keyManager); var broadcaster = new TransactionBroadcaster(network, bitcoinStore, synchronizer, nodes, walletManager, rpc); var waitCount = 0; while (wallet.Coins.Sum(x => x.Amount) == Money.Zero) { await Task.Delay(1000); waitCount++; if (waitCount >= 21) { Logger.LogInfo("Funding transaction to the wallet did not arrive."); return; // Very rarely this test fails. I have no clue why. Probably because all these RegTests are interconnected, anyway let's not bother the CI with it. } } var scp = new Key().ScriptPubKey; var res2 = wallet.BuildTransaction(password, new PaymentIntent(scp, Money.Coins(0.05m), label: "foo"), FeeStrategy.CreateFromConfirmationTarget(5), allowUnconfirmed: false); Assert.NotNull(res2.Transaction); Assert.Single(res2.OuterWalletOutputs); Assert.Equal(scp, res2.OuterWalletOutputs.Single().ScriptPubKey); Assert.Single(res2.InnerWalletOutputs); Assert.True(res2.Fee > Money.Satoshis(2 * 100)); // since there is a sanity check of 2sat/vb in the server Assert.InRange(res2.FeePercentOfSent, 0, 1); Assert.Single(res2.SpentCoins); var spentCoin = Assert.Single(res2.SpentCoins); Assert.Contains(new[] { key.P2wpkhScript, key2.P2wpkhScript }, x => x == spentCoin.ScriptPubKey); Assert.Equal(Money.Coins(1m), res2.SpentCoins.Single().Amount); Assert.False(res2.SpendsUnconfirmed); await broadcaster.SendTransactionAsync(res2.Transaction); Assert.Contains(res2.InnerWalletOutputs.Single(), wallet.Coins); #region Basic Script receive = keyManager.GetNextReceiveKey("Basic", out _).P2wpkhScript; Money amountToSend = wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) / 2; var res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true); foreach (SmartCoin coin in res.SpentCoins) { Assert.False(coin.CoinJoinInProgress); Assert.True(coin.Confirmed); Assert.Null(coin.SpenderTransactionId); Assert.True(coin.Unspent); } Assert.Equal(2, res.InnerWalletOutputs.Count()); Assert.Empty(res.OuterWalletOutputs); var activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); var changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive); Assert.Equal(receive, activeOutput.ScriptPubKey); Assert.Equal(amountToSend, activeOutput.Amount); if (res.SpentCoins.Sum(x => x.Amount) - activeOutput.Amount == res.Fee) // this happens when change is too small { Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == activeOutput.Amount); Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}"); } Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}"); Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %"); Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}"); Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"TxId: {res.Transaction.GetHash()}"); var foundReceive = false; Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); await broadcaster.SendTransactionAsync(res.Transaction); #endregion Basic #region SubtractFeeFromAmount receive = keyManager.GetNextReceiveKey("SubtractFeeFromAmount", out _).P2wpkhScript; amountToSend = wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) / 3; res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, subtractFee: true, label: "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true); Assert.Equal(2, res.InnerWalletOutputs.Count()); Assert.Empty(res.OuterWalletOutputs); activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive); Assert.Equal(receive, activeOutput.ScriptPubKey); Assert.Equal(amountToSend - res.Fee, activeOutput.Amount); Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount); Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}"); Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %"); Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}"); Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend - res.Fee, output.Value); } } Assert.True(foundReceive); #endregion SubtractFeeFromAmount #region LowFee res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true); Assert.Equal(2, res.InnerWalletOutputs.Count()); Assert.Empty(res.OuterWalletOutputs); activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive); Assert.Equal(receive, activeOutput.ScriptPubKey); Assert.Equal(amountToSend, activeOutput.Amount); Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount); Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}"); Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %"); Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}"); Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); #endregion LowFee #region MediumFee res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.OneDayConfirmationTargetStrategy, allowUnconfirmed: true); Assert.Equal(2, res.InnerWalletOutputs.Count()); Assert.Empty(res.OuterWalletOutputs); activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive); Assert.Equal(receive, activeOutput.ScriptPubKey); Assert.Equal(amountToSend, activeOutput.Amount); Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount); Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}"); Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %"); Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}"); Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); #endregion MediumFee #region HighFee res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.TwentyMinutesConfirmationTargetStrategy, allowUnconfirmed: true); Assert.Equal(2, res.InnerWalletOutputs.Count()); Assert.Empty(res.OuterWalletOutputs); activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive); Assert.Equal(receive, activeOutput.ScriptPubKey); Assert.Equal(amountToSend, activeOutput.Amount); Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount); Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}"); Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %"); Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}"); Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); Assert.InRange(res.Fee, Money.Zero, res.Fee); Assert.InRange(res.Fee, res.Fee, res.Fee); await broadcaster.SendTransactionAsync(res.Transaction); #endregion HighFee #region MaxAmount receive = keyManager.GetNextReceiveKey("MaxAmount", out _).P2wpkhScript; res = wallet.BuildTransaction(password, new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true); Assert.Single(res.InnerWalletOutputs); Assert.Empty(res.OuterWalletOutputs); activeOutput = res.InnerWalletOutputs.Single(); Assert.Equal(receive, activeOutput.ScriptPubKey); Assert.Single(res.Transaction.Transaction.Outputs); var maxBuiltTxOutput = res.Transaction.Transaction.Outputs.Single(); Assert.Equal(receive, maxBuiltTxOutput.ScriptPubKey); Assert.Equal(wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) - res.Fee, maxBuiltTxOutput.Value); await broadcaster.SendTransactionAsync(res.Transaction); #endregion MaxAmount #region InputSelection receive = keyManager.GetNextReceiveKey("InputSelection", out _).P2wpkhScript; var inputCountBefore = res.SpentCoins.Count(); res = wallet.BuildTransaction(password, new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true, allowedInputs: wallet.Coins.Where(x => !x.Unavailable).Select(x => x.OutPoint).Take(1)); Assert.Single(res.InnerWalletOutputs); Assert.Empty(res.OuterWalletOutputs); activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); Assert.True(inputCountBefore >= res.SpentCoins.Count()); Assert.Equal(res.SpentCoins.Count(), res.Transaction.Transaction.Inputs.Count); Assert.Equal(receive, activeOutput.ScriptPubKey); Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}"); Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %"); Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}"); Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogInfo($"TxId: {res.Transaction.GetHash()}"); Assert.Single(res.Transaction.Transaction.Outputs); res = wallet.BuildTransaction(password, new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true, allowedInputs: new[] { res.SpentCoins.Select(x => x.OutPoint).First() }); Assert.Single(res.InnerWalletOutputs); Assert.Empty(res.OuterWalletOutputs); activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); Assert.Single(res.Transaction.Transaction.Inputs); Assert.Single(res.Transaction.Transaction.Outputs); Assert.Single(res.SpentCoins); #endregion InputSelection #region Labeling Script receive2 = keyManager.GetNextReceiveKey("foo", out _).P2wpkhScript; res = wallet.BuildTransaction(password, new PaymentIntent(receive2, MoneyRequest.CreateAllRemaining(), "my label"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true); Assert.Single(res.InnerWalletOutputs); Assert.Equal("foo, my label", res.InnerWalletOutputs.Single().Label); amountToSend = wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) / 3; res = wallet.BuildTransaction( password, new PaymentIntent( new DestinationRequest(new Key(), amountToSend, label: "outgoing"), new DestinationRequest(new Key(), amountToSend, label: "outgoing2")), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true); Assert.Single(res.InnerWalletOutputs); Assert.Equal(2, res.OuterWalletOutputs.Count()); IEnumerable <string> change = res.InnerWalletOutputs.Single().Label.Labels; Assert.Contains("outgoing", change); Assert.Contains("outgoing2", change); await broadcaster.SendTransactionAsync(res.Transaction); IEnumerable <SmartCoin> unconfirmedCoins = wallet.Coins.Where(x => x.Height == Height.Mempool).ToArray(); IEnumerable <string> unconfirmedCoinLabels = unconfirmedCoins.SelectMany(x => x.Label.Labels).ToArray(); Assert.Contains("outgoing", unconfirmedCoinLabels); Assert.Contains("outgoing2", unconfirmedCoinLabels); IEnumerable <string> allKeyLabels = keyManager.GetKeys().SelectMany(x => x.Label.Labels); Assert.Contains("outgoing", allKeyLabels); Assert.Contains("outgoing2", allKeyLabels); Interlocked.Exchange(ref Common.FiltersProcessedByWalletCount, 0); await rpc.GenerateAsync(1); await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), 1); var bestHeight = new Height(bitcoinStore.SmartHeaderChain.TipHeight); IEnumerable <string> confirmedCoinLabels = wallet.Coins.Where(x => x.Height == bestHeight).SelectMany(x => x.Label.Labels); Assert.Contains("outgoing", confirmedCoinLabels); Assert.Contains("outgoing2", confirmedCoinLabels); allKeyLabels = keyManager.GetKeys().SelectMany(x => x.Label.Labels); Assert.Contains("outgoing", allKeyLabels); Assert.Contains("outgoing2", allKeyLabels); #endregion Labeling #region AllowedInputsDisallowUnconfirmed inputCountBefore = res.SpentCoins.Count(); receive = keyManager.GetNextReceiveKey("AllowedInputsDisallowUnconfirmed", out _).P2wpkhScript; var allowedInputs = wallet.Coins.Where(x => !x.Unavailable).Select(x => x.OutPoint).Take(1); var toSend = new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "fizz"); // covers: // disallow unconfirmed with allowed inputs res = wallet.BuildTransaction(password, toSend, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, false, allowedInputs: allowedInputs); activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive); Assert.Single(res.InnerWalletOutputs); Assert.Empty(res.OuterWalletOutputs); Assert.Equal(receive, activeOutput.ScriptPubKey); Logger.LogDebug($"{nameof(res.Fee)}: {res.Fee}"); Logger.LogDebug($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %"); Logger.LogDebug($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}"); Logger.LogDebug($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Logger.LogDebug($"TxId: {res.Transaction.GetHash()}"); Assert.True(inputCountBefore >= res.SpentCoins.Count()); Assert.False(res.SpendsUnconfirmed); Assert.Single(res.Transaction.Transaction.Inputs); Assert.Single(res.Transaction.Transaction.Outputs); Assert.Single(res.SpentCoins); Assert.True(inputCountBefore >= res.SpentCoins.Count()); Assert.Equal(res.SpentCoins.Count(), res.Transaction.Transaction.Inputs.Count); #endregion AllowedInputsDisallowUnconfirmed #region CustomChange // covers: // customchange // feePc > 1 var k1 = new Key(); var k2 = new Key(); res = wallet.BuildTransaction( password, new PaymentIntent( new DestinationRequest(k1, MoneyRequest.CreateChange()), new DestinationRequest(k2, Money.Coins(0.0003m), label: "outgoing")), FeeStrategy.TwentyMinutesConfirmationTargetStrategy); Assert.Contains(k1.ScriptPubKey, res.OuterWalletOutputs.Select(x => x.ScriptPubKey)); Assert.Contains(k2.ScriptPubKey, res.OuterWalletOutputs.Select(x => x.ScriptPubKey)); #endregion CustomChange #region FeePcHigh res = wallet.BuildTransaction( password, new PaymentIntent(new Key(), Money.Coins(0.0003m), label: "outgoing"), FeeStrategy.TwentyMinutesConfirmationTargetStrategy); Assert.True(res.FeePercentOfSent > 1); var newChangeK = keyManager.GenerateNewKey("foo", KeyState.Clean, isInternal: true); res = wallet.BuildTransaction( password, new PaymentIntent( new DestinationRequest(newChangeK.P2wpkhScript, MoneyRequest.CreateChange(), "boo"), new DestinationRequest(new Key(), Money.Coins(0.0003m), label: "outgoing")), FeeStrategy.TwentyMinutesConfirmationTargetStrategy); Assert.True(res.FeePercentOfSent > 1); Assert.Single(res.OuterWalletOutputs); Assert.Single(res.InnerWalletOutputs); SmartCoin changeRes = res.InnerWalletOutputs.Single(); Assert.Equal(newChangeK.P2wpkhScript, changeRes.ScriptPubKey); Assert.Equal(newChangeK.Label, changeRes.Label); Assert.Equal(KeyState.Clean, newChangeK.KeyState); // Still clean, because the tx wasn't yet propagated. #endregion FeePcHigh } finally { bitcoinStore.IndexStore.NewFilter -= Common.Wallet_NewFilterProcessed; await walletManager.RemoveAndStopAllAsync(CancellationToken.None); // Dispose wasabi synchronizer service. if (synchronizer is { })
public async Task FilterDownloaderTestAsync() { (_, IRPCClient rpc, _, _, _, BitcoinStore bitcoinStore, _) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1); var httpClientFactory = new HttpClientFactory(torEndPoint: null, backendUriGetter: () => new Uri(RegTestFixture.BackendEndPoint)); var synchronizer = new WasabiSynchronizer(rpc.Network, bitcoinStore, httpClientFactory); try { synchronizer.Start(requestInterval: TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), 1000); var blockCount = await rpc.GetBlockCountAsync() + 1; // Plus one because of the zeroth. // Test initial synchronization. var times = 0; int filterCount; while ((filterCount = bitcoinStore.SmartHeaderChain.HashCount) < blockCount) { if (times > 500) // 30 sec { throw new TimeoutException($"{nameof(WasabiSynchronizer)} test timed out. Needed filters: {blockCount}, got only: {filterCount}."); } await Task.Delay(100); times++; } Assert.Equal(blockCount, bitcoinStore.SmartHeaderChain.HashCount); // Test later synchronization. await RegTestFixture.BackendRegTestNode.GenerateAsync(10); times = 0; while ((filterCount = bitcoinStore.SmartHeaderChain.HashCount) < blockCount + 10) { if (times > 500) // 30 sec { throw new TimeoutException($"{nameof(WasabiSynchronizer)} test timed out. Needed filters: {blockCount + 10}, got only: {filterCount}."); } await Task.Delay(100); times++; } // Test correct number of filters is received. Assert.Equal(blockCount + 10, bitcoinStore.SmartHeaderChain.HashCount); // Test filter block hashes are correct. var filterList = new List <FilterModel>(); await bitcoinStore.IndexStore.ForeachFiltersAsync(async x => { filterList.Add(x); await Task.CompletedTask; }, new Height(0)); FilterModel[] filters = filterList.ToArray(); for (int i = 0; i < 101; i++) { var expectedHash = await rpc.GetBlockHashAsync(i); var filter = filters[i]; Assert.Equal(i, (int)filter.Header.Height); Assert.Equal(expectedHash, filter.Header.BlockHash); Assert.Equal(IndexBuilderService.CreateDummyEmptyFilter(expectedHash).ToString(), filter.Filter.ToString()); } } finally { if (synchronizer is { })