Do more accurate status display
Automaticlally dequeue coins on status processing if we it doesn't have enough
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
@@ -10,6 +10,7 @@ using NBitcoin;
using ReactiveUI;
using WalletWasabi.Gui.ViewModels;
using WalletWasabi.Logging;
+using WalletWasabi.Models;
using WalletWasabi.Models.ChaumianCoinJoin;
namespace WalletWasabi.Gui.Controls.WalletExplorer
@@ -48,15 +49,16 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
QueuedCoinsList = new CoinListViewModel(queued);
- AmountQueued = QueuedCoinsList.Coins.Sum(x => x.Amount);
+ AmountQueued = Global.ChaumianClient.State.SumAllQueuedCoinAmounts();
- QueuedCoinsList.Coins.CollectionChanged += Coins_CollectionChanged;
+ Global.ChaumianClient.CoinQueued += ChaumianClient_CoinQueued;
+ Global.ChaumianClient.CoinDequeued += ChaumianClient_CoinDequeued;
var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault();
if (registrableRound != default)
{
CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString();
- RequiredBTC = registrableRound.State.Denomination + registrableRound.State.Denomination.Percentange(0.3m) + registrableRound.State.FeePerInputs * registrableRound.State.MaximumInputCountPerPeer + registrableRound.State.FeePerOutputs * 2;
+ RequiredBTC = registrableRound.State.CalculateRequiredAmount(Global.ChaumianClient.State.GetAllQueuedCoinAmounts().ToArray());
}
else
{
@@ -150,20 +152,31 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
});
}
- private void Coins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ private void ChaumianClient_CoinDequeued(object sender, SmartCoin e)
{
- AmountQueued = QueuedCoinsList.Coins.Sum(x => x.Amount);
+ UpdateStates();
+ }
- MainWindowViewModel.Instance.CanClose = !QueuedCoinsList.Coins.Any();
+ private void ChaumianClient_CoinQueued(object sender, SmartCoin e)
+ {
+ UpdateStates();
}
private void ChaumianClient_StateUpdated(object sender, EventArgs e)
{
+ UpdateStates();
+ }
+
+ private void UpdateStates()
+ {
+ AmountQueued = Global.ChaumianClient.State.SumAllQueuedCoinAmounts();
+ MainWindowViewModel.Instance.CanClose = AmountQueued == Money.Zero;
+
var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault();
if (registrableRound != default)
{
CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString();
- RequiredBTC = registrableRound.State.Denomination + registrableRound.State.Denomination.Percentange(0.3m) + registrableRound.State.FeePerInputs * registrableRound.State.MaximumInputCountPerPeer + registrableRound.State.FeePerOutputs * 2;
+ RequiredBTC = registrableRound.State.CalculateRequiredAmount(Global.ChaumianClient.State.GetAllQueuedCoinAmounts().ToArray());
}
var mostAdvancedRound = Global.ChaumianClient.State.GetMostAdvancedRoundOrDefault();
if (mostAdvancedRound != default)

MODIFY
WalletWasabi/Models/ChaumianCoinJoin/CcjClientState.cs
WalletWasabi/Models/ChaumianCoinJoin/CcjClientState.cs
@@ -103,6 +103,30 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
}
}
+ public Money SumAllQueuedCoinAmounts()
+ {
+ lock (StateLock)
+ {
+ return WaitingList.Concat(Rounds.SelectMany(x => x.CoinsRegistered)).Sum(x => x.Amount);
+ }
+ }
+
+ public int CountAllQueuedCoins()
+ {
+ lock (StateLock)
+ {
+ return WaitingList.Count + Rounds.Sum(x => x.CoinsRegistered.Count);
+ }
+ }
+
+ public IEnumerable<Money> GetAllQueuedCoinAmounts()
+ {
+ lock (StateLock)
+ {
+ return WaitingList.Concat(Rounds.SelectMany(x => x.CoinsRegistered)).Select(x => x.Amount).ToArray();
+ }
+ }
+
public IEnumerable<(uint256 txid, uint index)> GetAllWaitingCoins()
{
lock (StateLock)

MODIFY
WalletWasabi/Services/CcjClient.cs
WalletWasabi/Services/CcjClient.cs
@@ -39,6 +39,10 @@ namespace WalletWasabi.Services
public event EventHandler StateUpdated;
+ public event EventHandler<SmartCoin> CoinQueued;
+
+ public event EventHandler<SmartCoin> CoinDequeued;
+
private long _frequentStatusProcessingIfNotMixing;
/// <summary>
@@ -160,6 +164,17 @@ namespace WalletWasabi.Services
states = await SatoshiClient.GetAllRoundStatesAsync();
State.UpdateRoundsByStates(states.ToArray());
+ // If we don't have enough coin queued to register a round, then dequeue all.
+ CcjClientRound registrableRound = State.GetRegistrableRoundOrDefault();
+ if (registrableRound != default)
+ {
+ if (!registrableRound.State.HaveEnoughQueued(State.GetAllQueuedCoinAmounts().ToArray()))
+ {
+ await DequeueAllCoinsFromMixNoLockAsync();
+ }
+ }
+
+ StateUpdated?.Invoke(this, null);
if (maxDelayReplySeconds == minDelayReplySeconds)
{
delay = minDelayReplySeconds;
@@ -557,6 +572,7 @@ namespace WalletWasabi.Services
State.AddCoinToWaitingList(coin);
successful.Add(coin);
+ CoinQueued?.Invoke(this, coin);
Logger.LogInfo<CcjClient>($"Coin queued: {coin.Index}:{coin.TransactionId}.");
}
@@ -592,6 +608,11 @@ namespace WalletWasabi.Services
}
}
+ private async Task DequeueAllCoinsFromMixNoLockAsync()
+ {
+ await DequeueCoinsFromMixNoLockAsync(State.GetAllCoins().ToArray());
+ }
+
private async Task DequeueCoinsFromMixNoLockAsync(params (uint256 txid, uint index)[] coins)
{
List<Exception> exceptions = new List<Exception>();
@@ -671,6 +692,7 @@ namespace WalletWasabi.Services
key.SetLabel(coinWaitingForMix.Label, KeyManager);
}
}
+ CoinDequeued?.Invoke(this, coinWaitingForMix);
Logger.LogInfo<CcjClient>($"Coin dequeued: {coinWaitingForMix.Index}:{coinWaitingForMix.TransactionId}.");
}

Do more accurate status display
Automaticlally dequeue coins on status processing if we it doesn't have enough