Add Entering and Leaving critical events
MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/CoinJoinStateViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/CoinJoinStateViewModel.cs
@@ -400,45 +400,57 @@ public partial class CoinJoinStateViewModel : ViewModelBase
private void OnCoinJoinPhaseChanged(CoinJoinProgressEventArgs coinJoinProgress)
{
- IsInCriticalPhase = coinJoinProgress.IsInCriticalPhase;
-
switch (coinJoinProgress)
{
case RoundEnded roundEnded:
CurrentStatus = roundEnded.RoundState.WasTransactionBroadcast ? _roundSucceedMessage : _roundFailedMessage;
StopCountDown();
break;
+
case EnteringOutputRegistrationPhase enteringOutputRegistrationPhase:
StartCountDown(
message: _outputRegistrationMessage,
start: enteringOutputRegistrationPhase.TimeoutAt - enteringOutputRegistrationPhase.RoundState.CoinjoinState.Parameters.OutputRegistrationTimeout,
end: enteringOutputRegistrationPhase.TimeoutAt);
break;
+
case EnteringSigningPhase enteringSigningPhase:
StartCountDown(
message: _transactionSigningMessage,
start: enteringSigningPhase.TimeoutAt - enteringSigningPhase.RoundState.CoinjoinState.Parameters.TransactionSigningTimeout,
end: enteringSigningPhase.TimeoutAt);
break;
+
case EnteringInputRegistrationPhase enteringInputRegistrationPhase:
StartCountDown(
message: _inputRegistrationMessage,
start: enteringInputRegistrationPhase.TimeoutAt - enteringInputRegistrationPhase.RoundState.CoinjoinState.Parameters.StandardInputRegistrationTimeout,
end: enteringInputRegistrationPhase.TimeoutAt);
break;
+
case WaitingForBlameRound waitingForBlameRound:
StartCountDown(message: _waitingForBlameRoundMessage, start: DateTimeOffset.UtcNow, end: waitingForBlameRound.TimeoutAt);
break;
+
case WaitingForRound:
CurrentStatus = _waitingRoundMessage;
StopCountDown();
break;
+
case EnteringConnectionConfirmationPhase enteringConnectionConfirmationPhase:
StartCountDown(
message: _connectionConfirmationMessage,
start: enteringConnectionConfirmationPhase.TimeoutAt - enteringConnectionConfirmationPhase.RoundState.CoinjoinState.Parameters.ConnectionConfirmationTimeout,
end: enteringConnectionConfirmationPhase.TimeoutAt);
break;
+
+ case EnteringCriticalPhase:
+ IsInCriticalPhase = true;
+ break;
+
+ case LeavingCriticalPhase:
+ IsInCriticalPhase = false;
+ break;
}
}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -25,7 +25,6 @@ namespace WalletWasabi.WabiSabi.Client;
public class CoinJoinClient
{
private const int MaxInputsRegistrableByWallet = 10; // how many
- private volatile bool _inCriticalCoinJoinState;
private static readonly Money MinimumOutputAmountSanity = Money.Coins(0.0001m); // ignore rounds with too big minimum denominations
private static readonly TimeSpan ExtraPhaseTimeoutMargin = TimeSpan.FromMinutes(1);
@@ -67,12 +66,6 @@ public class CoinJoinClient
public int MinAnonScoreTarget { get; }
private TimeSpan DoNotRegisterInLastMinuteTimeLimit { get; }
- public bool InCriticalCoinJoinState
- {
- get => _inCriticalCoinJoinState;
- private set => _inCriticalCoinJoinState = value;
- }
-
public bool ConsolidationMode { get; private set; }
private TimeSpan FeeRateMedianTimeFrame { get; }
@@ -205,8 +198,6 @@ public class CoinJoinClient
var registeredAliceClients = registeredAliceClientAndCircuits.Select(x => x.AliceClient).ToImmutableArray();
- InCriticalCoinJoinState = true;
-
var outputTxOuts = await ProceedWithOutputRegistrationPhaseAsync(roundId, registeredAliceClients, cancellationToken).ConfigureAwait(false);
var unsignedCoinJoin = await ProceedWithSigningStateAsync(roundId, registeredAliceClients, outputTxOuts, cancellationToken).ConfigureAwait(false);
@@ -235,12 +226,15 @@ public class CoinJoinClient
aliceClientAndCircuit.AliceClient.Finish();
aliceClientAndCircuit.PersonCircuit.Dispose();
}
- InCriticalCoinJoinState = false;
+ CoinJoinClientProgress.SafeInvoke(this, new LeavingCriticalPhase());
}
}
private async Task<ImmutableArray<(AliceClient AliceClient, PersonCircuit PersonCircuit)>> CreateRegisterAndConfirmCoinsAsync(IEnumerable<SmartCoin> smartCoins, RoundState roundState, CancellationToken cancellationToken)
{
+ bool alreadyEnteredToCritical = false;
+ object alreadyEnteredToCriticalLock = new();
+
async Task<(AliceClient? AliceClient, PersonCircuit? PersonCircuit)> RegisterInputAsync(SmartCoin coin, CancellationToken cancellationToken)
{
PersonCircuit? personCircuit = null;
@@ -258,6 +252,19 @@ public class CoinJoinClient
var aliceClient = await AliceClient.CreateRegisterAndConfirmInputAsync(roundState, aliceArenaClient, coin, KeyChain, RoundStatusUpdater, cancellationToken).ConfigureAwait(false);
+ // Right after the first real-cred confirmation happened we entered into critical phase.
+ if (!alreadyEnteredToCritical)
+ {
+ lock (alreadyEnteredToCriticalLock)
+ {
+ if (!alreadyEnteredToCritical)
+ {
+ CoinJoinClientProgress.SafeInvoke(this, new EnteringCriticalPhase());
+ alreadyEnteredToCritical = true;
+ }
+ }
+ }
+
return (aliceClient, personCircuit);
}
catch (HttpRequestException)

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/CoinJoinProgressEventArgs.cs
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/CoinJoinProgressEventArgs.cs
@@ -2,5 +2,4 @@ namespace WalletWasabi.WabiSabi.Client.CoinJoinProgressEvents;
public class CoinJoinProgressEventArgs : EventArgs
{
- public bool IsInCriticalPhase { get; protected set; }
}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/EnteringConnectionConfirmationPhase.cs
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/EnteringConnectionConfirmationPhase.cs
@@ -6,6 +6,5 @@ public class EnteringConnectionConfirmationPhase : RoundStateChanged
{
public EnteringConnectionConfirmationPhase(RoundState roundState, DateTimeOffset timeoutAt) : base(roundState, timeoutAt)
{
- IsInCriticalPhase = true;
}
}

ADD
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/EnteringCriticalPhase.cs
+namespace WalletWasabi.WabiSabi.Client.CoinJoinProgressEvents;
+
+public class EnteringCriticalPhase : CoinJoinProgressEventArgs
+{
+}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/EnteringOutputRegistrationPhase.cs
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/EnteringOutputRegistrationPhase.cs
@@ -6,6 +6,5 @@ public class EnteringOutputRegistrationPhase : RoundStateChanged
{
public EnteringOutputRegistrationPhase(RoundState roundState, DateTimeOffset timeoutAt) : base(roundState, timeoutAt)
{
- IsInCriticalPhase = true;
}
}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/EnteringSigningPhase.cs
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/EnteringSigningPhase.cs
@@ -6,6 +6,5 @@ public class EnteringSigningPhase : RoundStateChanged
{
public EnteringSigningPhase(RoundState roundState, DateTimeOffset timeoutAt) : base(roundState, timeoutAt)
{
- IsInCriticalPhase = true;
}
}

ADD
WalletWasabi/WabiSabi/Client/CoinJoinProgressEvents/LeavingCriticalPhase.cs
+namespace WalletWasabi.WabiSabi.Client.CoinJoinProgressEvents;
+
+public class LeavingCriticalPhase : CoinJoinProgressEventArgs
+{
+}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinTracker.cs
WalletWasabi/WabiSabi/Client/CoinJoinTracker.cs
@@ -39,7 +39,7 @@ public class CoinJoinTracker : IDisposable
public bool RestartAutomatically { get; }
public bool IsCompleted => CoinJoinTask.IsCompleted;
- public bool InCriticalCoinJoinState => CoinJoinClient.InCriticalCoinJoinState;
+ public bool InCriticalCoinJoinState { get; private set; }
public bool IsStopped { get; private set; }
public void Stop()
@@ -50,6 +50,17 @@ public class CoinJoinTracker : IDisposable
private void CoinJoinClient_CoinJoinClientProgress(object? sender, CoinJoinProgressEventArgs coinJoinProgressEventArgs)
{
+ switch (coinJoinProgressEventArgs)
+ {
+ case EnteringCriticalPhase:
+ InCriticalCoinJoinState = true;
+ break;
+
+ case LeavingCriticalPhase:
+ InCriticalCoinJoinState = false;
+ break;
+ }
+
WalletCoinJoinProgressChanged?.Invoke(Wallet, coinJoinProgressEventArgs);
}

Add Entering and Leaving critical events