Improve logs and unreg logic
MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/AliceTimeoutTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/AliceTimeoutTests.cs
@@ -37,7 +37,7 @@ public class AliceTimeoutTests
KeyChain keyChain = new(km, new Kitchen(ingredients: ""));
using CancellationTokenSource registrationCts = new();
- Task<AliceClient> task = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, smartCoin, keyChain, roundStateUpdater, registrationCts.Token, confirmationCancellationToken: testDeadlineCts.Token);
+ Task<AliceClient> task = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, smartCoin, keyChain, roundStateUpdater, registrationCts.Token, registrationCts.Token, confirmationCancellationToken: testDeadlineCts.Token);
while (round.Alices.Count == 0)
{

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs
@@ -197,8 +197,8 @@ public class StepOutputRegistrationTests
using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), arena);
await roundStateUpdater.StartAsync(CancellationToken.None);
- var task1 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin1, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None);
- var task2 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin2, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None);
+ var task1 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin1, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None, CancellationToken.None);
+ var task2 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin2, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None, CancellationToken.None);
while (Phase.ConnectionConfirmation != round.Phase)
{

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
@@ -240,8 +240,8 @@ public class StepTransactionSigningTests
using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), arena);
await roundStateUpdater.StartAsync(CancellationToken.None);
- var task1 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin1, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None);
- var task2 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin2, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None);
+ var task1 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin1, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None, CancellationToken.None);
+ var task2 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin2, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None, CancellationToken.None);
while (Phase.OutputRegistration != round.Phase)
{

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs
@@ -57,7 +57,7 @@ public class BobClientTests
await roundStateUpdater.StartAsync(CancellationToken.None);
var keyChain = new KeyChain(km, new Kitchen(""));
- var task = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), aliceArenaClient, coin1, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None);
+ var task = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), aliceArenaClient, coin1, keyChain, roundStateUpdater, CancellationToken.None, CancellationToken.None, CancellationToken.None);
do
{

MODIFY
WalletWasabi/WabiSabi/Client/AliceClient.cs
WalletWasabi/WabiSabi/Client/AliceClient.cs
@@ -10,6 +10,8 @@ using WalletWasabi.WabiSabi.Backend.Rounds;
using WalletWasabi.WabiSabi.Models;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.WabiSabi.Client.RoundStateAwaiters;
+using System.Linq;
+using System.Net.Http;
namespace WalletWasabi.WabiSabi.Client;
@@ -59,6 +61,7 @@ public class AliceClient
SmartCoin coin,
IKeyChain keyChain,
RoundStateUpdater roundStatusUpdater,
+ CancellationToken unregisterCancellationToken,
CancellationToken registrationCancellationToken,
CancellationToken confirmationCancellationToken)
{
@@ -70,12 +73,12 @@ public class AliceClient
Logger.LogInfo($"Round ({aliceClient.RoundId}), Alice ({aliceClient.AliceId}): Connection was confirmed.");
}
- catch (OperationCanceledException)
+ catch (Exception e) when (e is OperationCanceledException || (e is AggregateException ae && ae.InnerExceptions.Last() is OperationCanceledException))
{
if (aliceClient is { })
{
// Unregistering coins is only possible before connection confirmation phase.
- await aliceClient.TryToUnregisterAlicesAsync(registrationCancellationToken).ConfigureAwait(false);
+ await aliceClient.TryToUnregisterAlicesAsync(unregisterCancellationToken).ConfigureAwait(false);
}
throw;
@@ -195,13 +198,16 @@ public class AliceClient
{
try
{
- await RemoveInputAsync(cancellationToken).ConfigureAwait(false);
+ using var unregCts = new CancellationTokenSource(TimeSpan.FromSeconds(7));
+ using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(unregCts.Token, cancellationToken);
+
+ await RemoveInputAsync(linkedCts.Token).ConfigureAwait(false);
SmartCoin.CoinJoinInProgress = false;
Logger.LogInfo($"Round ({RoundId}), Alice ({AliceId}): Unregistered {SmartCoin.OutPoint}.");
}
- catch (System.Net.Http.HttpRequestException ex)
+ catch (Exception ex)
{
- if (ex.InnerException is WabiSabiProtocolException wpe)
+ if (ex is HttpRequestException && ex.InnerException is WabiSabiProtocolException wpe)
{
switch (wpe.ErrorCode)
{

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -253,15 +253,22 @@ public class CoinJoinClient
}
}
- private async Task<ImmutableArray<(AliceClient AliceClient, PersonCircuit PersonCircuit)>> CreateRegisterAndConfirmCoinsAsync(IEnumerable<SmartCoin> smartCoins, RoundState roundState, CancellationToken inputRegTimeoutCancel, CancellationToken connConfTimeoutCancel, CancellationToken cancel)
+ private async Task<ImmutableArray<(AliceClient AliceClient, PersonCircuit PersonCircuit)>> CreateRegisterAndConfirmCoinsAsync(IEnumerable<SmartCoin> smartCoins, RoundState roundState, CancellationToken cancel)
{
int eventInvokedAlready = 0;
+ var remainingInputRegTime = roundState.InputRegistrationEnd - DateTimeOffset.UtcNow;
+
+ using CancellationTokenSource strictInputRegTimeoutCts = new(remainingInputRegTime);
+ using CancellationTokenSource inputRegTimeoutCts = new(remainingInputRegTime + ExtraPhaseTimeoutMargin);
+ using CancellationTokenSource connConfTimeoutCts = new(remainingInputRegTime + roundState.CoinjoinState.Parameters.ConnectionConfirmationTimeout + ExtraPhaseTimeoutMargin);
using CancellationTokenSource registrationsCts = new();
using CancellationTokenSource confirmationsCts = new();
- using CancellationTokenSource linkedRegistrationsCts = CancellationTokenSource.CreateLinkedTokenSource(inputRegTimeoutCancel, registrationsCts.Token, cancel);
- using CancellationTokenSource linkedConfirmationsCts = CancellationTokenSource.CreateLinkedTokenSource(connConfTimeoutCancel, confirmationsCts.Token, cancel);
- using CancellationTokenSource timeoutAndGlobalCts = CancellationTokenSource.CreateLinkedTokenSource(inputRegTimeoutCancel, connConfTimeoutCancel, cancel);
+
+ using CancellationTokenSource linkedUnregisterCts = CancellationTokenSource.CreateLinkedTokenSource(strictInputRegTimeoutCts.Token, registrationsCts.Token);
+ using CancellationTokenSource linkedRegistrationsCts = CancellationTokenSource.CreateLinkedTokenSource(inputRegTimeoutCts.Token, registrationsCts.Token, cancel);
+ using CancellationTokenSource linkedConfirmationsCts = CancellationTokenSource.CreateLinkedTokenSource(connConfTimeoutCts.Token, confirmationsCts.Token, cancel);
+ using CancellationTokenSource timeoutAndGlobalCts = CancellationTokenSource.CreateLinkedTokenSource(inputRegTimeoutCts.Token, connConfTimeoutCts.Token, cancel);
async Task<(AliceClient? AliceClient, PersonCircuit? PersonCircuit)> RegisterInputAsync(SmartCoin coin)
{
@@ -278,7 +285,7 @@ public class CoinJoinClient
roundState.CreateVsizeCredentialClient(SecureRandom),
arenaRequestHandler);
- var aliceClient = await AliceClient.CreateRegisterAndConfirmInputAsync(roundState, aliceArenaClient, coin, KeyChain, RoundStatusUpdater, linkedRegistrationsCts.Token, linkedConfirmationsCts.Token).ConfigureAwait(false);
+ var aliceClient = await AliceClient.CreateRegisterAndConfirmInputAsync(roundState, aliceArenaClient, coin, KeyChain, RoundStatusUpdater, linkedUnregisterCts.Token, linkedRegistrationsCts.Token, linkedConfirmationsCts.Token).ConfigureAwait(false);
// Right after the first real-cred confirmation happened we entered into critical phase.
if (Interlocked.Exchange(ref eventInvokedAlready, 1) == 0)
@@ -710,8 +717,8 @@ public class CoinJoinClient
}
catch (Exception e)
{
- roundState.LogDebug(e.ToString());
roundState.LogInfo($"Failed to register outputs with message {e.Message}. Ignoring...");
+ roundState.LogDebug(e.ToString());
}
// ReadyToSign.
@@ -764,14 +771,10 @@ public class CoinJoinClient
private async Task<ImmutableArray<(AliceClient, PersonCircuit)>> ProceedWithInputRegAndConfirmAsync(IEnumerable<SmartCoin> smartCoins, RoundState roundState, CancellationToken cancellationToken)
{
- var remainingInputRegTime = roundState.InputRegistrationEnd - DateTimeOffset.UtcNow;
- using CancellationTokenSource inputRegTimeoutCts = new(remainingInputRegTime + ExtraPhaseTimeoutMargin);
- using CancellationTokenSource connConfTimeoutCts = new(remainingInputRegTime + roundState.CoinjoinState.Parameters.ConnectionConfirmationTimeout + ExtraPhaseTimeoutMargin);
-
CoinJoinClientProgress.SafeInvoke(this, new EnteringInputRegistrationPhase(roundState, roundState.InputRegistrationEnd));
// Register coins.
- var result = await CreateRegisterAndConfirmCoinsAsync(smartCoins, roundState, inputRegTimeoutCts.Token, connConfTimeoutCts.Token, cancellationToken).ConfigureAwait(false);
+ var result = await CreateRegisterAndConfirmCoinsAsync(smartCoins, roundState, cancellationToken).ConfigureAwait(false);
if (!RoundStatusUpdater.TryGetRoundState(roundState.Id, out var newRoundState))
{

MODIFY
WalletWasabi/WabiSabi/Client/WabiSabiHttpApiClient.cs
WalletWasabi/WabiSabi/Client/WabiSabiHttpApiClient.cs
@@ -108,16 +108,14 @@ public class WabiSabiHttpApiClient : IWabiSabiApiRequestHandler
Logger.LogTrace($"Attempt {attempt} failed with {nameof(TorException)}: {e.Message}.");
exceptions.Add(e);
}
- catch (Exception e)
- {
- if (e is OperationCanceledException)
+ catch (OperationCanceledException e)
{
Logger.LogTrace($"Attempt {attempt} failed with {nameof(OperationCanceledException)}: {e.Message}.");
+ exceptions.Add(e);
}
- else
+ catch (Exception e)
{
Logger.LogDebug($"Attempt {attempt} failed with exception {e}.");
- }
if (exceptions.Any())
{
@@ -130,8 +128,15 @@ public class WabiSabiHttpApiClient : IWabiSabiApiRequestHandler
}
}
+ try
+ {
// Wait before the next try.
await Task.Delay(250, combinedToken).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ exceptions.Add(e);
+ }
attempt++;
} while (!combinedToken.IsCancellationRequested);

Improve logs and unreg logic