Separate spent and confirmed events
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabViewModel.cs
@@ -64,7 +64,8 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged))
.Merge(Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.NewBlockProcessed)))
- .Merge(Observable.FromEventPattern(Global.WalletService.TransactionProcessor, nameof(Global.WalletService.TransactionProcessor.CoinSpentOrSpenderConfirmed)))
+ .Merge(Observable.FromEventPattern(Global.WalletService.TransactionProcessor, nameof(Global.WalletService.TransactionProcessor.CoinSpent)))
+ .Merge(Observable.FromEventPattern(Global.WalletService.TransactionProcessor, nameof(Global.WalletService.TransactionProcessor.SpenderConfirmed)))
.Throttle(TimeSpan.FromSeconds(5))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async _ => await TryRewriteTableAsync())

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/WalletViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/WalletViewModel.cs
@@ -33,8 +33,6 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
var keyManager = WalletService.KeyManager;
Name = Path.GetFileNameWithoutExtension(keyManager.FilePath);
- SetBalance(Name);
-
Actions = new ObservableCollection<WalletActionViewModel>();
SendTabViewModel sendTab = null;
@@ -95,16 +93,22 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
{
Disposables = Disposables is null ? new CompositeDisposable() : throw new NotSupportedException($"Cannot open {GetType().Name} before closing it.");
- Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged))
- .Merge(Observable.FromEventPattern(Global.WalletService.TransactionProcessor, nameof(Global.WalletService.TransactionProcessor.CoinSpentOrSpenderConfirmed)))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(o => SetBalance(Name))
- .DisposeWith(Disposables);
+ var observed = Observable.Merge(
+ Global.UiConfig.WhenAnyValue(x => x.LurkingWifeMode).Select(_ => Unit.Default),
+ Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged)).Select(_ => Unit.Default),
+ Observable.FromEventPattern(Global.WalletService.TransactionProcessor, nameof(Global.WalletService.TransactionProcessor.CoinSpent)).Select(_ => Unit.Default))
+ .Throttle(TimeSpan.FromSeconds(1))
+ .ObserveOn(RxApp.MainThreadScheduler);
- Global.UiConfig.WhenAnyValue(x => x.LurkingWifeMode).Subscribe(x =>
+ observed.Subscribe(_ =>
{
- SetBalance(Name);
- }).DisposeWith(Disposables);
+ Money balance = Enumerable.Where(WalletService.Coins, c => c.Unspent && !c.SpentAccordingToBackend).Sum(c => (long?)c.Amount) ?? 0;
+
+ Title = $"{Name} ({(Global.UiConfig.LurkingWifeMode ? "#########" : balance.ToString(false, true))} BTC)";
+ })
+ .DisposeWith(Disposables);
+
+ observed.Next();
IsExpanded = true;
}
@@ -125,12 +129,5 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
get => _actions;
set => this.RaiseAndSetIfChanged(ref _actions, value);
}
-
- private void SetBalance(string walletName)
- {
- Money balance = Enumerable.Where(WalletService.Coins, c => c.Unspent && !c.SpentAccordingToBackend).Sum(c => (long?)c.Amount) ?? 0;
-
- Title = $"{walletName} ({(Global.UiConfig.LurkingWifeMode ? "#########" : balance.ToString(false, true))} BTC)";
- }
}
}

MODIFY
WalletWasabi.Tests/TransactionProcessorTests.cs
WalletWasabi.Tests/TransactionProcessorTests.cs
@@ -209,7 +209,7 @@ namespace WalletWasabi.Tests
{
var transactionProcessor = CreateTransactionProcessor();
SmartCoin spentCoin = null;
- transactionProcessor.CoinSpentOrSpenderConfirmed += (s, theCoin) => spentCoin = theCoin;
+ transactionProcessor.CoinSpent += (s, theCoin) => spentCoin = theCoin;
var keys = transactionProcessor.KeyManager.GetKeys();
var tx = CreateCreditingTransaction(keys.First().P2wpkhScript, Money.Coins(1.0m));
transactionProcessor.Process(tx);
@@ -327,6 +327,7 @@ namespace WalletWasabi.Tests
tx.Outputs.Add(amount, scriptPubKey);
return new SmartTransaction(tx, isConfirmed ? new Height(9999) : Height.Mempool);
}
+
private static OutPoint GetRandomOutPoint()
{
return new OutPoint(RandomUtils.GetUInt256(), 0);

MODIFY
WalletWasabi/Services/TransactionProcessor.cs
WalletWasabi/Services/TransactionProcessor.cs
@@ -14,7 +14,11 @@ namespace WalletWasabi.Services
public ConcurrentHashSet<SmartTransaction> TransactionCache { get; }
public ObservableConcurrentHashSet<SmartCoin> Coins { get; }
public Money DustThreshold { get; }
- public event EventHandler<SmartCoin> CoinSpentOrSpenderConfirmed;
+
+ public event EventHandler<SmartCoin> CoinSpent;
+
+ public event EventHandler<SmartCoin> SpenderConfirmed;
+
public event EventHandler<SmartCoin> CoinReceived;
public TransactionProcessor(KeyManager keyManager,
@@ -203,9 +207,19 @@ namespace WalletWasabi.Services
if (foundCoin != null)
{
walletRelevant = true;
+ var alreadyKnown = foundCoin.SpenderTransactionId == txId;
foundCoin.SpenderTransactionId = txId;
TransactionCache.TryAdd(tx);
- CoinSpentOrSpenderConfirmed?.Invoke(this, foundCoin);
+
+ if (!alreadyKnown)
+ {
+ CoinSpent?.Invoke(this, foundCoin);
+ }
+
+ if (tx.Confirmed)
+ {
+ SpenderConfirmed?.Invoke(this, foundCoin);
+ }
}
}

MODIFY
WalletWasabi/Services/WalletService.cs
WalletWasabi/Services/WalletService.cs
@@ -115,8 +115,8 @@ namespace WalletWasabi.Services
KeyManager.AssertLockedInternalKeysIndexed(14);
TransactionProcessor = new TransactionProcessor(KeyManager, Mempool.TransactionHashes, Coins, ServiceConfiguration.DustThreshold);
- TransactionProcessor.CoinSpentOrSpenderConfirmed += OnNewSpendindCoinFound;
- TransactionProcessor.CoinReceived += OnNewCoinFound;
+ TransactionProcessor.CoinSpent += TransactionProcessor_CoinSpent;
+ TransactionProcessor.CoinReceived += OnNewCoinFoundAsync;
if (Directory.Exists(BlocksFolderPath))
{
@@ -156,12 +156,12 @@ namespace WalletWasabi.Services
Mempool.TransactionReceived += Mempool_TransactionReceivedAsync;
}
- private void OnNewSpendindCoinFound(object sender, SmartCoin spentCoin)
+ private void TransactionProcessor_CoinSpent(object sender, SmartCoin spentCoin)
{
ChaumianClient.ExposedLinks.TryRemove(spentCoin.GetTxoRef(), out _);
}
- private async void OnNewCoinFound(object sender, SmartCoin newCoin)
+ private async void OnNewCoinFoundAsync(object sender, SmartCoin newCoin)
{
// If it's being mixed and anonset is not sufficient, then queue it.
if (newCoin.Unspent && ChaumianClient.HasIngredients
@@ -198,7 +198,6 @@ namespace WalletWasabi.Services
{
TransactionProcessor.TransactionCache.TryRemove(txToRemove);
}
-
}
RefreshCoinHistories();

Separate spent and confirmed events