Signal for readiness with all but one alice in case of problems
MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -655,18 +655,34 @@ public class CoinJoinClient
var bobClient = CreateBobClient(roundState);
roundState.LogInfo("Starting reissuances.");
var combinedToken = linkedCts.Token;
- await scheduler.StartReissuancesAsync(registeredAliceClients, bobClient, combinedToken).ConfigureAwait(false);
+ bool wereAllCredentialsReissuedSuccessfully = await scheduler
+ .StartReissuancesAsync(registeredAliceClients, bobClient, combinedToken)
+ .ConfigureAwait(false);
+ bool wereAllOutputsRegistered = false;
+ if (wereAllCredentialsReissuedSuccessfully)
+ {
// Output registration.
- roundState.LogDebug($"Output registration started - it will end in: {outputRegistrationEndTime - DateTimeOffset.UtcNow:hh\\:mm\\:ss}.");
+ roundState.LogDebug(
+ $"Output registration started - it will end in: {outputRegistrationEndTime - DateTimeOffset.UtcNow:hh\\:mm\\:ss}.");
+
+ var outputRegistrationScheduledDates =
+ GetScheduledDates(outputTxOuts.Count(), outputRegistrationEndTime, MaximumRequestDelay);
+ var registeredOutputs = await scheduler
+ .StartOutputRegistrationsAsync(outputTxOuts, bobClient, KeyChain, outputRegistrationScheduledDates, combinedToken)
+ .ConfigureAwait(false);
+ roundState.LogDebug($"{registeredOutputs.Count} out of {outputTxOuts.Count()} outputs were registered.");
+
+ wereAllOutputsRegistered = registeredOutputs.Count == outputTxOuts.Count();
+ }
- var outputRegistrationScheduledDates = GetScheduledDates(outputTxOuts.Count(), outputRegistrationEndTime, MaximumRequestDelay);
- await scheduler.StartOutputRegistrationsAsync(outputTxOuts, bobClient, KeyChain, outputRegistrationScheduledDates, combinedToken).ConfigureAwait(false);
- roundState.LogDebug($"Outputs({outputTxOuts.Count()}) were registered.");
+ var alicesToSignalReadiness = wereAllCredentialsReissuedSuccessfully && wereAllOutputsRegistered
+ ? registeredAliceClients
+ : registeredAliceClients.RemoveAt(SecureRandom.GetInt(0, registeredAliceClients.Length));
// ReadyToSign.
roundState.LogDebug($"ReadyToSign phase started - it will end in: {readyToSignEndTime - DateTimeOffset.UtcNow:hh\\:mm\\:ss}.");
- await ReadyToSignAsync(registeredAliceClients, readyToSignEndTime, combinedToken).ConfigureAwait(false);
+ await ReadyToSignAsync(alicesToSignalReadiness, readyToSignEndTime, combinedToken).ConfigureAwait(false);
roundState.LogDebug($"Alices({registeredAliceClients.Length}) are ready to sign.");
return outputTxOuts;
}

MODIFY
WalletWasabi/WabiSabi/Client/DependencyGraphTaskScheduler.cs
WalletWasabi/WabiSabi/Client/DependencyGraphTaskScheduler.cs
@@ -82,7 +82,7 @@ public class DependencyGraphTaskScheduler
}
}
- public async Task StartReissuancesAsync(IEnumerable<AliceClient> aliceClients, BobClient bobClient, CancellationToken cancellationToken)
+ public async Task<bool> StartReissuancesAsync(IEnumerable<AliceClient> aliceClients, BobClient bobClient, CancellationToken cancellationToken)
{
var aliceNodePairs = PairAliceClientAndRequestNodes(aliceClients, Graph);
@@ -139,11 +139,14 @@ public class DependencyGraphTaskScheduler
// Check if all tasks were finished, otherwise Task.Result will block.
if (!amountEdges.Concat(vsizeEdges).All(edge => DependencyTasks[edge].Task.IsCompletedSuccessfully))
{
- throw new InvalidOperationException("Some Output nodes in-edges failed to complete");
+ Logger.LogInfo("Some output nodes in-edges failed to complete.");
+ return false;
}
+
+ return true;
}
- public async Task StartOutputRegistrationsAsync(IEnumerable<TxOut> txOuts, BobClient bobClient, IKeyChain keyChain, ImmutableList<DateTimeOffset> outputRegistrationScheduledDates, CancellationToken cancellationToken)
+ public async Task<ImmutableList<TxOut>> StartOutputRegistrationsAsync(IEnumerable<TxOut> txOuts, BobClient bobClient, IKeyChain keyChain, ImmutableList<DateTimeOffset> outputRegistrationScheduledDates, CancellationToken cancellationToken)
{
using CancellationTokenSource ctsOnError = new();
using CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ctsOnError.Token);
@@ -172,6 +175,7 @@ public class DependencyGraphTaskScheduler
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
}
await smartRequestNode.StartOutputRegistrationAsync(bobClient, txOut.ScriptPubKey, cancellationToken).ConfigureAwait(false);
+ return txOut;
}
catch (WabiSabiProtocolException ex) when (ex.ErrorCode == WabiSabiProtocolErrorCode.AlreadyRegisteredScript)
{
@@ -181,11 +185,17 @@ public class DependencyGraphTaskScheduler
{
hdPubKey.SetKeyState(KeyState.Used);
}
+
+ throw;
}
}
).ToImmutableArray();
await Task.WhenAll(tasks).ConfigureAwait(false);
+ return tasks
+ .Where(x => x.IsCompletedSuccessfully)
+ .Select(x => x.Result)
+ .ToImmutableList();
}
private IEnumerable<(AliceClient AliceClient, InputNode Node)> PairAliceClientAndRequestNodes(IEnumerable<AliceClient> aliceClients, DependencyGraph graph)

Signal for readiness with all but one alice in case of problems