From b7c7ca42b8f5b64bc630af2736e9672f9d108954 Mon Sep 17 00:00:00 2001 From: Turbolay Date: Tue, 27 Aug 2024 23:07:19 +0200 Subject: [PATCH] Remove default coordinator and help to find one (#13317) --- WalletWasabi.Daemon/Config.cs | 4 +- WalletWasabi.Daemon/Global.cs | 27 +++++---- WalletWasabi.Daemon/PersistentConfig.cs | 12 ++-- .../Styles/HyperlinkMenuItem.axaml | 6 ++ WalletWasabi.Fluent/Styles/Styles.axaml | 1 + .../FindCoordinatorViewModel.cs | 25 +++++++++ .../ViewModels/MainViewModelExtensions.cs | 1 + .../Wallets/CoinJoinStateViewModel.cs | 8 +++ .../Views/Wallets/MusicControlsView.axaml | 5 ++ .../UnitTests/Bases/ConfigManagerNgTests.cs | 4 +- .../SuggestionLabelsViewModelTests.cs | 1 - .../LiveServerTestsFixture.cs | 4 +- WalletWasabi/Helpers/Constants.cs | 10 +++- .../IWabiSabiApiRequestHandler.cs | 17 +++++- .../WabiSabi/Client/Banning/CoinPrison.cs | 7 ++- .../CoinJoin/Manager/CoinJoinManager.cs | 55 +++++++++++++++++-- .../StatusChangedEventArgs.cs | 3 +- .../RoundStateAwaiters/RoundStateUpdater.cs | 8 +-- WalletWasabi/Wallets/Wallet.cs | 1 - 19 files changed, 158 insertions(+), 41 deletions(-) create mode 100644 WalletWasabi.Fluent/Styles/HyperlinkMenuItem.axaml create mode 100644 WalletWasabi.Fluent/ViewModels/HelpAndSupport/FindCoordinatorViewModel.cs diff --git a/WalletWasabi.Daemon/Config.cs b/WalletWasabi.Daemon/Config.cs index 3330b06e2f6..1d2bec1abe1 100644 --- a/WalletWasabi.Daemon/Config.cs +++ b/WalletWasabi.Daemon/Config.cs @@ -250,7 +250,7 @@ public Uri GetBackendUri() throw new NotSupportedNetworkException(Network); } - public Uri GetCoordinatorUri() + public Uri? GetCoordinatorUri() { var result = Network switch { @@ -260,7 +260,7 @@ public Uri GetCoordinatorUri() _ => throw new NotSupportedNetworkException(Network) }; - return new Uri(result); + return result is "" ? null : new Uri(result); } public IEnumerable<(string ParameterName, string Hint)> GetConfigOptionsMetadata() => diff --git a/WalletWasabi.Daemon/Global.cs b/WalletWasabi.Daemon/Global.cs index aff53abe701..49b211cc8e8 100644 --- a/WalletWasabi.Daemon/Global.cs +++ b/WalletWasabi.Daemon/Global.cs @@ -74,7 +74,16 @@ public Global(string dataDir, string configFilePath, Config config) BitcoinStore = new BitcoinStore(IndexStore, AllTransactionStore, mempoolService, smartHeaderChain, blocks); HttpClientFactory = BuildHttpClientFactory(() => Config.GetBackendUri()); - CoordinatorHttpClientFactory = BuildHttpClientFactory(() => Config.GetCoordinatorUri()); + + if (Config.GetCoordinatorUri() is { } coordinatorUri) + { + CoordinatorHttpClientFactory = BuildHttpClientFactory(() => coordinatorUri); + CoinPrison = CoinPrison.CreateOrLoadFromFile(Path.Combine(DataDir, coordinatorUri.Host)); + } + else + { + CoinPrison = CoinPrison.CreateDummyPrison(); + } HostedServices.Register(() => new UpdateManager(TimeSpan.FromDays(1), DataDir, Config.DownloadNewVersion, HttpClientFactory.NewHttpClient(Mode.DefaultCircuit, maximumRedirects: 10), HttpClientFactory.SharedWasabiClient), "Update Manager"); UpdateManager = HostedServices.Get(); @@ -146,8 +155,6 @@ public Global(string dataDir, string configFilePath, Config config) WalletManager = new WalletManager(config.Network, DataDir, new WalletDirectories(Config.Network, DataDir), walletFactory); TransactionBroadcaster = new TransactionBroadcaster(Network, BitcoinStore, HttpClientFactory, WalletManager); - var prisonForCoordinator = Path.Combine(DataDir, config.GetCoordinatorUri().Host); - CoinPrison = CoinPrison.CreateOrLoadFromFile(prisonForCoordinator); WalletManager.WalletStateChanged += WalletManager_WalletStateChanged; } @@ -167,7 +174,7 @@ public Global(string dataDir, string configFilePath, Config config) /// HTTP client factory for sending HTTP requests. public WasabiHttpClientFactory HttpClientFactory { get; } - public WasabiHttpClientFactory CoordinatorHttpClientFactory { get; } + public WasabiHttpClientFactory? CoordinatorHttpClientFactory { get; } public string ConfigFilePath { get; } public Config Config { get; } @@ -186,7 +193,7 @@ public Global(string dataDir, string configFilePath, Config config) public Network Network => Config.Network; public IMemoryCache Cache { get; private set; } - public CoinPrison CoinPrison { get; } + private CoinPrison CoinPrison { get; } public JsonRpcServer? RpcServer { get; private set; } public Uri? OnionServiceUri { get; private set; } @@ -404,11 +411,8 @@ private void RegisterFeeRateProviders() private void RegisterCoinJoinComponents() { - Tor.Http.IHttpClient roundStateUpdaterHttpClient = CoordinatorHttpClientFactory.NewHttpClient(Mode.SingleCircuitPerLifetime, RoundStateUpdaterCircuit); - HostedServices.Register(() => new RoundStateUpdater(TimeSpan.FromSeconds(10), new WabiSabiHttpApiClient(roundStateUpdaterHttpClient)), "Round info updater"); - var coinJoinConfiguration = new CoinJoinConfiguration(Config.CoordinatorIdentifier, Config.MaxCoinjoinMiningFeeRate, Config.AbsoluteMinInputCount, AllowSoloCoinjoining: false); - HostedServices.Register(() => new CoinJoinManager(WalletManager, HostedServices.Get(), CoordinatorHttpClientFactory, HostedServices.Get(), coinJoinConfiguration, CoinPrison), "CoinJoin Manager"); + HostedServices.Register(() => new CoinJoinManager(WalletManager, CoordinatorHttpClientFactory, HostedServices.Get(), coinJoinConfiguration, CoinPrison), "CoinJoin Manager"); } private void WalletManager_WalletStateChanged(object? sender, WalletState e) @@ -499,7 +503,10 @@ public async Task DisposeAsync() Logger.LogInfo($"{nameof(HttpClientFactory)} is disposed."); } - await CoordinatorHttpClientFactory.DisposeAsync().ConfigureAwait(false); + if (CoordinatorHttpClientFactory is not null) + { + await CoordinatorHttpClientFactory.DisposeAsync().ConfigureAwait(false); + } Logger.LogInfo($"{nameof(CoordinatorHttpClientFactory)} is disposed."); if (BitcoinCoreNode is { } bitcoinCoreNode) diff --git a/WalletWasabi.Daemon/PersistentConfig.cs b/WalletWasabi.Daemon/PersistentConfig.cs index d34a4193ac5..8724baa2160 100644 --- a/WalletWasabi.Daemon/PersistentConfig.cs +++ b/WalletWasabi.Daemon/PersistentConfig.cs @@ -11,17 +11,17 @@ public record PersistentConfig { public Network Network { get; init; } = Network.Main; - public string MainNetBackendUri { get; init; } = Constants.BackendUri; + public string MainNetBackendUri { get; init; } = Constants.DefaultBackendUri; - public string TestNetBackendUri { get; init; } = Constants.TestnetBackendUri; + public string TestNetBackendUri { get; init; } = Constants.DefaultTestnetBackendUri; - public string RegTestBackendUri { get; init; } = "http://localhost:37127/"; + public string RegTestBackendUri { get; init; } = Constants.DefaultRegtestBackendUri; - public string MainNetCoordinatorUri { get; init; } = Constants.BackendUri; + public string MainNetCoordinatorUri { get; init; } = Constants.DefaultCoordinatorUri; - public string TestNetCoordinatorUri { get; init; } = Constants.TestnetBackendUri; + public string TestNetCoordinatorUri { get; init; } = Constants.DefaultTestnetCoordinatorUri; - public string RegTestCoordinatorUri { get; init; } = "http://localhost:37127/"; + public string RegTestCoordinatorUri { get; init; } = Constants.DefaultRegtestCoordinatorUri; /// /// For backward compatibility this was changed to an object. diff --git a/WalletWasabi.Fluent/Styles/HyperlinkMenuItem.axaml b/WalletWasabi.Fluent/Styles/HyperlinkMenuItem.axaml new file mode 100644 index 00000000000..d8da0a1a2df --- /dev/null +++ b/WalletWasabi.Fluent/Styles/HyperlinkMenuItem.axaml @@ -0,0 +1,6 @@ + + + diff --git a/WalletWasabi.Fluent/Styles/Styles.axaml b/WalletWasabi.Fluent/Styles/Styles.axaml index 9aa94cf7893..ca7506d72e8 100644 --- a/WalletWasabi.Fluent/Styles/Styles.axaml +++ b/WalletWasabi.Fluent/Styles/Styles.axaml @@ -28,6 +28,7 @@ + diff --git a/WalletWasabi.Fluent/ViewModels/HelpAndSupport/FindCoordinatorViewModel.cs b/WalletWasabi.Fluent/ViewModels/HelpAndSupport/FindCoordinatorViewModel.cs new file mode 100644 index 00000000000..3f630d33687 --- /dev/null +++ b/WalletWasabi.Fluent/ViewModels/HelpAndSupport/FindCoordinatorViewModel.cs @@ -0,0 +1,25 @@ +using System.Windows.Input; +using ReactiveUI; +using WalletWasabi.Fluent.ViewModels.Wallets; + +namespace WalletWasabi.Fluent.ViewModels.HelpAndSupport; + +[NavigationMetaData( + Title = "Find a Coordinator", + Caption = "Open Wasabi's documentation website", + Order = 3, + Category = "Help & Support", + Keywords = + [ + "Find", "Coordinator", "Docs", "Documentation", "Guide" + ], + IconName = "book_question_mark_regular")] +public partial class FindCoordinatorViewModel : TriggerCommandViewModel +{ + private FindCoordinatorViewModel() + { + TargetCommand = ReactiveCommand.CreateFromTask(async () => await UiContext.FileSystem.OpenBrowserAsync(CoinJoinStateViewModel.FindCoordinatorLink)); + } + + public override ICommand TargetCommand { get; } +} diff --git a/WalletWasabi.Fluent/ViewModels/MainViewModelExtensions.cs b/WalletWasabi.Fluent/ViewModels/MainViewModelExtensions.cs index 6e08d778bb7..5beaff5b0d9 100644 --- a/WalletWasabi.Fluent/ViewModels/MainViewModelExtensions.cs +++ b/WalletWasabi.Fluent/ViewModels/MainViewModelExtensions.cs @@ -45,6 +45,7 @@ public static void RegisterAllViewModels(this MainViewModel mainViewModel, UiCon UserSupportViewModel.RegisterLazy(() => new UserSupportViewModel(uiContext)); BugReportLinkViewModel.RegisterLazy(() => new BugReportLinkViewModel(uiContext)); DocsLinkViewModel.RegisterLazy(() => new DocsLinkViewModel(uiContext)); + FindCoordinatorViewModel.RegisterLazy(() => new FindCoordinatorViewModel(uiContext)); OpenDataFolderViewModel.RegisterLazy(() => new OpenDataFolderViewModel(uiContext)); OpenWalletsFolderViewModel.RegisterLazy(() => new OpenWalletsFolderViewModel(uiContext)); OpenLogsViewModel.RegisterLazy(() => new OpenLogsViewModel(uiContext)); diff --git a/WalletWasabi.Fluent/ViewModels/Wallets/CoinJoinStateViewModel.cs b/WalletWasabi.Fluent/ViewModels/Wallets/CoinJoinStateViewModel.cs index e52e8f38e92..bef6c8718e8 100644 --- a/WalletWasabi.Fluent/ViewModels/Wallets/CoinJoinStateViewModel.cs +++ b/WalletWasabi.Fluent/ViewModels/Wallets/CoinJoinStateViewModel.cs @@ -10,6 +10,7 @@ using WalletWasabi.Fluent.State; using WalletWasabi.Fluent.ViewModels.Wallets.Settings; using WalletWasabi.WabiSabi.Backend.Rounds; +using WalletWasabi.WabiSabi.Client; using WalletWasabi.WabiSabi.Client.CoinJoinProgressEvents; using WalletWasabi.WabiSabi.Client.StatusChangedEvents; @@ -45,6 +46,7 @@ public partial class CoinJoinStateViewModel : ViewModelBase private const string CoinsRejectedMessage = "Some funds are rejected from coinjoining"; private const string OnlyImmatureCoinsAvailableMessage = "Only immature funds are available"; private const string OnlyExcludedCoinsAvailableMessage = "Only excluded funds are available"; + private const string NoCoordinatorConfiguredMessage = "Configure a coordinator to start coinjoin"; private readonly IWalletModel _wallet; private readonly StateMachine _stateMachine; @@ -165,6 +167,7 @@ public CoinJoinStateViewModel(UiContext uiContext, IWalletModel wallet, WalletSe }, Observable.Return(!_wallet.IsWatchOnlyWallet)); + OpenFindCoordinatorLinkCommand = ReactiveCommand.CreateFromTask(() => UiContext.FileSystem.OpenBrowserAsync(FindCoordinatorLink)); NavigateToSettingsCommand = coinJoinSettingsCommand; CanNavigateToCoinjoinSettings = coinJoinSettingsCommand.CanExecute; NavigateToExcludedCoinsCommand = ReactiveCommand.Create(() => UiContext.Navigate().To().ExcludedCoins(_wallet)); @@ -201,14 +204,18 @@ private enum Trigger AreAllCoinsPrivateChanged } + public static string FindCoordinatorLink { get; } = "https://docs.wasabiwallet.io/FAQ/FAQ-UseWasabi.html#how-do-i-find-a-coordinator"; + public IObservable CanNavigateToCoinjoinSettings { get; } + public ICommand OpenFindCoordinatorLinkCommand { get; } public ICommand NavigateToSettingsCommand { get; } public ICommand NavigateToExcludedCoinsCommand { get; } public ICommand NavigateToCoordinatorSettingsCommand { get; } + public bool NoCoordinatorConfigured => !Services.HostedServices.Get().HasCoordinatorConfigured; public bool IsAutoCoinJoinEnabled => _wallet.Settings.AutoCoinjoin; public IObservable AutoCoinJoinObservable { get; } @@ -386,6 +393,7 @@ private void ProcessStatusChange(StatusChangedEventArgs e) CoinjoinError.RandomlySkippedRound => RandomlySkippedRoundMessage, CoinjoinError.MiningFeeRateTooHigh => CoinjoinMiningFeeRateTooHighMessage, CoinjoinError.MinInputCountTooLow => MinInputCountTooLowMessage, + CoinjoinError.NoCoordinatorConfigured => NoCoordinatorConfiguredMessage, _ => GeneralErrorMessage }; diff --git a/WalletWasabi.Fluent/Views/Wallets/MusicControlsView.axaml b/WalletWasabi.Fluent/Views/Wallets/MusicControlsView.axaml index 73aea958885..f51bca426c1 100644 --- a/WalletWasabi.Fluent/Views/Wallets/MusicControlsView.axaml +++ b/WalletWasabi.Fluent/Views/Wallets/MusicControlsView.axaml @@ -109,6 +109,11 @@