Take cancellation logic into walletmanager
MODIFY
WalletWasabi.Gui/CommandLine/Daemon.cs
WalletWasabi.Gui/CommandLine/Daemon.cs
@@ -78,7 +78,7 @@ namespace WalletWasabi.Gui.CommandLine
return;
}
- WalletService = await Global.CreateWalletServiceAsync(keyManager);
+ WalletService = await Global.WalletManager.CreateAndStartWalletServiceAsync(keyManager);
if (Global.KillRequested)
{
return;

MODIFY
WalletWasabi.Gui/Global.cs
WalletWasabi.Gui/Global.cs
@@ -398,6 +398,8 @@ namespace WalletWasabi.Gui
}
#endregion JsonRpcServerInitialization
+
+ WalletManager.Initialize(BitcoinStore, Synchronizer, Nodes, DataDir, Config.ServiceConfiguration, FeeProviders, BitcoinCoreNode);
}
catch (Exception ex)
{
@@ -515,23 +517,6 @@ namespace WalletWasabi.Gui
}
}
- private CancellationTokenSource _cancelWalletServiceInitialization = null;
-
- public async Task<WalletService> CreateWalletServiceAsync(KeyManager keyManager)
- {
- WalletService walletService;
-
- using (_cancelWalletServiceInitialization = new CancellationTokenSource())
- {
- walletService = new WalletService(BitcoinStore, keyManager, Synchronizer, Nodes, DataDir, Config.ServiceConfiguration, FeeProviders, BitcoinCoreNode);
- await WalletManager.AddAndStartAsync(walletService, _cancelWalletServiceInitialization.Token).ConfigureAwait(false);
- }
-
- _cancelWalletServiceInitialization = null; // Must make it null explicitly, because dispose won't make it null.
-
- return walletService;
- }
-
private void WalletManager_OnDequeue(object sender, DequeueResult e)
{
try
@@ -735,21 +720,6 @@ namespace WalletWasabi.Gui
return keyManager;
}
- public async Task DisposeInWalletDependentServicesAsync()
- {
- try
- {
- _cancelWalletServiceInitialization?.Cancel();
- }
- catch (ObjectDisposedException)
- {
- Logger.LogWarning($"{nameof(_cancelWalletServiceInitialization)} is disposed. This can occur due to an error while processing the wallet.");
- }
- _cancelWalletServiceInitialization = null;
-
- await WalletManager.RemoveAndStopAllAsync().ConfigureAwait(false);
- }
-
/// <summary>
/// 0: nobody called
/// 1: somebody called
@@ -787,7 +757,7 @@ namespace WalletWasabi.Gui
await Task.Delay(100);
}
- await DisposeInWalletDependentServicesAsync();
+ await WalletManager.RemoveAndStopAllAsync().ConfigureAwait(false);
WalletManager.OnDequeue -= WalletManager_OnDequeue;
WalletManager.WalletRelevantTransactionProcessed -= WalletManager_WalletRelevantTransactionProcessed;

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/LoadWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/LoadWalletViewModel.cs
@@ -640,7 +640,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
await Task.Delay(100);
}
- var walletService = await Task.Run(async () => await Global.CreateWalletServiceAsync(keyManager));
+ var walletService = await Task.Run(async () => await Global.WalletManager.CreateAndStartWalletServiceAsync(keyManager));
// Successfully initialized.
Owner.OnClose();
// Open Wallet Explorer tabs
@@ -662,7 +662,8 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
{
Logger.LogError(ex);
}
- await Global.DisposeInWalletDependentServicesAsync();
+
+ await Global.WalletManager.RemoveAndStopAllAsync().ConfigureAwait(false);
}
}
finally

MODIFY
WalletWasabi.Tests/IntegrationTests/RegTests.cs
WalletWasabi.Tests/IntegrationTests/RegTests.cs
@@ -759,10 +759,8 @@ namespace WalletWasabi.Tests.IntegrationTests
// 5. Create wallet service.
var workDir = GetWorkDir();
- var wallet = new WalletService(bitcoinStore, keyManager, synchronizer, nodes, workDir, serviceConfiguration, synchronizer);
- wallet.NewFilterProcessed += Wallet_NewFilterProcessed;
-
var walletManager = new WalletManager(null);
+ walletManager.Initialize(bitcoinStore, synchronizer, nodes, workDir, serviceConfiguration, synchronizer, null);
// Get some money, make it confirm.
var key = keyManager.GetNextReceiveKey("foo label", out _);
@@ -785,10 +783,8 @@ namespace WalletWasabi.Tests.IntegrationTests
var blockCount = await rpc.GetBlockCountAsync();
await WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), blockCount);
- using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
- {
- await walletManager.AddAndStartAsync(wallet, cts.Token);
- }
+ var wallet = await walletManager.CreateAndStartWalletServiceAsync(keyManager);
+ wallet.NewFilterProcessed += Wallet_NewFilterProcessed;
var broadcaster = new TransactionBroadcaster(network, bitcoinStore, synchronizer, nodes, walletManager, rpc);
var waitCount = 0;
@@ -1201,7 +1197,6 @@ namespace WalletWasabi.Tests.IntegrationTests
}
finally
{
- wallet.NewFilterProcessed -= Wallet_NewFilterProcessed;
await walletManager.RemoveAndStopAllAsync();
// Dispose wasabi synchronizer service.
if (synchronizer is { })
@@ -1397,12 +1392,10 @@ namespace WalletWasabi.Tests.IntegrationTests
// 5. Create wallet service.
var workDir = GetWorkDir();
- var wallet = new WalletService(bitcoinStore, keyManager, synchronizer, nodes, workDir, serviceConfiguration, synchronizer);
- wallet.NewFilterProcessed += Wallet_NewFilterProcessed;
var walletManager = new WalletManager(null);
+ walletManager.Initialize(bitcoinStore, synchronizer, nodes, workDir, serviceConfiguration, synchronizer, null);
- Assert.Empty(wallet.Coins);
var baseTip = await rpc.GetBestBlockHashAsync();
// Generate script
@@ -1425,10 +1418,8 @@ namespace WalletWasabi.Tests.IntegrationTests
var blockCount = await rpc.GetBlockCountAsync();
await WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), blockCount);
- using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
- {
- await walletManager.AddAndStartAsync(wallet, cts.Token);
- }
+ var wallet = await walletManager.CreateAndStartWalletServiceAsync(keyManager);
+ wallet.NewFilterProcessed += Wallet_NewFilterProcessed;
var coin = Assert.Single(wallet.Coins);
Assert.True(coin.Confirmed);
@@ -1617,12 +1608,9 @@ namespace WalletWasabi.Tests.IntegrationTests
// 5. Create wallet service.
var workDir = GetWorkDir();
- var wallet = new WalletService(bitcoinStore, keyManager, synchronizer, nodes, workDir, serviceConfiguration, synchronizer);
- wallet.NewFilterProcessed += Wallet_NewFilterProcessed;
var walletManager = new WalletManager(null);
-
- Assert.Empty(wallet.Coins);
+ walletManager.Initialize(bitcoinStore, synchronizer, nodes, workDir, serviceConfiguration, synchronizer, null);
// Get some money, make it confirm.
var key = keyManager.GetNextReceiveKey("foo label", out _);
@@ -1637,10 +1625,8 @@ namespace WalletWasabi.Tests.IntegrationTests
var blockCount = await rpc.GetBlockCountAsync();
await WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), blockCount);
- using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
- {
- await walletManager.AddAndStartAsync(wallet, cts.Token);
- }
+ var wallet = await walletManager.CreateAndStartWalletServiceAsync(keyManager);
+ wallet.NewFilterProcessed += Wallet_NewFilterProcessed;
Assert.Empty(wallet.Coins);

MODIFY
WalletWasabi/Wallets/WalletManager.cs
WalletWasabi/Wallets/WalletManager.cs
using NBitcoin;
+using NBitcoin.Protocol;
using Nito.AsyncEx;
using System;
using System.Collections.Generic;
@@ -7,13 +8,18 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.BitcoinCore;
+using WalletWasabi.Blockchain.Analysis.FeesEstimation;
+using WalletWasabi.Blockchain.Keys;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Blockchain.TransactionProcessing;
using WalletWasabi.Blockchain.Transactions;
using WalletWasabi.CoinJoin.Client.Clients.Queuing;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
+using WalletWasabi.Models;
using WalletWasabi.Services;
+using WalletWasabi.Stores;
namespace WalletWasabi.Wallets
{
@@ -27,6 +33,8 @@ namespace WalletWasabi.Wallets
AddRemoveLock = new AsyncLock();
}
+ private CancellationTokenSource CancelWalletServiceInitialization { get; set; } = null;
+
public event EventHandler<ProcessedResult> WalletRelevantTransactionProcessed;
public event EventHandler<DequeueResult> OnDequeue;
@@ -38,6 +46,14 @@ namespace WalletWasabi.Wallets
private IEnumerable<KeyValuePair<WalletService, HashSet<uint256>>> AliveWalletsNoLock => Wallets.Where(x => x.Key is { IsStoppingOrStopped: var isDisposed } && !isDisposed);
+ private BitcoinStore BitcoinStore { get; set; }
+ private WasabiSynchronizer Synchronizer { get; set; }
+ private NodesGroup Nodes { get; set; }
+ private string DataDir { get; set; }
+ private ServiceConfiguration ServiceConfiguration { get; set; }
+ private IFeeProvider FeeProvider { get; set; }
+ private CoreNode BitcoinCoreNode { get; set; }
+
public WalletService GetFirstOrDefaultWallet()
{
lock (Lock)
@@ -46,10 +62,13 @@ namespace WalletWasabi.Wallets
}
}
- public async Task AddAndStartAsync(WalletService walletService, CancellationToken cancel)
+ public async Task<WalletService> CreateAndStartWalletServiceAsync(KeyManager keyManager)
{
+ WalletService walletService = new WalletService(BitcoinStore, keyManager, Synchronizer, Nodes, DataDir, ServiceConfiguration, FeeProvider, BitcoinCoreNode);
+ using (CancelWalletServiceInitialization = new CancellationTokenSource())
using (await AddRemoveLock.LockAsync().ConfigureAwait(false))
{
+ var cancel = CancelWalletServiceInitialization.Token;
lock (Lock)
{
Wallets.Add(walletService, new HashSet<uint256>());
@@ -64,6 +83,10 @@ namespace WalletWasabi.Wallets
walletService.TransactionProcessor.WalletRelevantTransactionProcessed += TransactionProcessor_WalletRelevantTransactionProcessed;
walletService.ChaumianClient.OnDequeue += ChaumianClient_OnDequeue;
}
+
+ CancelWalletServiceInitialization = null; // Must make it null explicitly, because dispose won't make it null.
+
+ return walletService;
}
private void ChaumianClient_OnDequeue(object sender, DequeueResult e)
@@ -80,6 +103,16 @@ namespace WalletWasabi.Wallets
public async Task RemoveAndStopAllAsync()
{
+ try
+ {
+ CancelWalletServiceInitialization?.Cancel();
+ }
+ catch (ObjectDisposedException)
+ {
+ Logger.LogWarning($"{nameof(CancelWalletServiceInitialization)} is disposed. This can occur due to an error while processing the wallet.");
+ }
+ CancelWalletServiceInitialization = null;
+
using (await AddRemoveLock.LockAsync().ConfigureAwait(false))
{
List<WalletService> walletsListClone;
@@ -168,5 +201,16 @@ namespace WalletWasabi.Wallets
return unknowns;
}
}
+
+ public void Initialize(BitcoinStore bitcoinStore, WasabiSynchronizer synchronizer, NodesGroup nodes, string dataDir, ServiceConfiguration serviceConfiguration, IFeeProvider feeProvider, CoreNode bitcoinCoreNode)
+ {
+ BitcoinStore = bitcoinStore;
+ Synchronizer = synchronizer;
+ Nodes = nodes;
+ DataDir = dataDir;
+ ServiceConfiguration = serviceConfiguration;
+ FeeProvider = feeProvider;
+ BitcoinCoreNode = bitcoinCoreNode;
+ }
}
}

Take cancellation logic into walletmanager