make ReadyToSignAsync parallel and timed
MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -183,14 +183,18 @@ public class CoinJoinClient
// Output registration.
roundState = await RoundStatusUpdater.CreateRoundAwaiter(roundState.Id, Phase.OutputRegistration, cancellationToken).ConfigureAwait(false);
- var outputRegistrationEndTime = DateTimeOffset.UtcNow + roundState.OutputRegistrationTimeout - RoundStatusUpdater.Period;
- Logger.LogDebug($"Round ({roundState.Id}): Output registration phase started - estimated end time: {outputRegistrationEndTime:hh\\:mm\\:ss}");
+ var remainingTime = roundState.OutputRegistrationTimeout - RoundStatusUpdater.Period;
+ var outputRegistrationEndTime = DateTimeOffset.UtcNow + (remainingTime * 0.8);
+ Logger.LogDebug($"Round ({roundState.Id}): Output registration phase started - it will end in: {outputRegistrationEndTime - DateTimeOffset.UtcNow:hh\\:mm\\:ss}");
await scheduler.StartOutputRegistrationsAsync(outputTxOuts, bobClient, KeyChain, outputRegistrationEndTime, cancellationToken).ConfigureAwait(false);
Logger.LogDebug($"Round ({roundState.Id}): Outputs({outputTxOuts.Count()}) successfully registered.");
// ReadyToSign.
- await ReadyToSignAsync(registeredAliceClients, cancellationToken).ConfigureAwait(false);
+ var readyToSignEndTime = outputRegistrationEndTime + remainingTime * 0.2;
+ Logger.LogDebug($"Round ({roundState.Id}): ReadyToSign phase started - it will end in: {readyToSignEndTime - DateTimeOffset.UtcNow:hh\\:mm\\:ss}");
+
+ await ReadyToSignAsync(registeredAliceClients, readyToSignEndTime, cancellationToken).ConfigureAwait(false);
Logger.LogDebug($"Round ({roundState.Id}): Alices({registeredAliceClients.Length}) successfully signalled ready to sign.");
// Signing.
@@ -307,12 +311,24 @@ public class CoinJoinClient
}
}
- private async Task ReadyToSignAsync(IEnumerable<AliceClient> aliceClients, CancellationToken cancellationToken)
+ private async Task ReadyToSignAsync(IEnumerable<AliceClient> aliceClients, DateTimeOffset readyToSignEndTime, CancellationToken cancellationToken)
{
- foreach (var aliceClient in aliceClients)
+ var remainingTime = readyToSignEndTime - DateTimeOffset.UtcNow;
+ if (remainingTime < TimeSpan.FromSeconds(3))
+ {
+ throw new InvalidOperationException("No time to signal ready, aborting.");
+ }
+
+ var delays = remainingTime.SamplePoissonDelays(aliceClients.Count());
+
+ var tasks = Enumerable.Zip(aliceClients, delays,
+ async (aliceClient, delay) =>
{
await aliceClient.ReadyToSignAsync(cancellationToken).ConfigureAwait(false);
}
+ ).ToImmutableArray();
+
+ await Task.WhenAll(tasks).ConfigureAwait(false);
}
private void LogCoinJoinSummary(ImmutableArray<AliceClient> registeredAliceClients, IEnumerable<TxOut> myOutputs, Transaction unsignedCoinJoinTransaction, RoundState roundState)

make ReadyToSignAsync parallel and timed