Interleave Output Registrations
MODIFY
WalletWasabi/Crypto/Extensions.cs
WalletWasabi/Crypto/Extensions.cs
@@ -25,6 +25,11 @@ namespace System.Linq
public static long ToLong(this Scalar scalar) =>
checked((long)scalar.ToUlong());
+ public static IEnumerable<(TFirst, TSecond, TThird)> Zip<TFirst, TSecond, TThird>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, IEnumerable<TThird> third)
+ {
+ return first.Zip(second, third, (fst, snd, trd) => (fst, snd, trd));
+ }
+
public static IEnumerable<TResult> Zip<TFirst, TSecond, TThird, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, IEnumerable<TThird> third, Func<TFirst, TSecond, TThird, TResult> resultSelector)
{
Guard.NotNull(nameof(first), first);

MODIFY
WalletWasabi/Extensions/TaskExtensions.cs
WalletWasabi/Extensions/TaskExtensions.cs
@@ -78,12 +78,23 @@ namespace System.Threading.Tasks
=> await me.WithAwaitCancellationAsync(ThreadingHelpers.Cancelled, (int)timeout.TotalMilliseconds).ConfigureAwait(false);
public static async Task<TResult> RunAsScheduledAsync<TResult>(this Task<TResult> task, DateTimeOffset when, CancellationToken cancellationToken)
+ {
+ await WaitUntilAsync(when, cancellationToken).ConfigureAwait(false);
+ return await task.ConfigureAwait(false);
+ }
+
+ public static async Task RunAsScheduledAsync(this Task task, DateTimeOffset when, CancellationToken cancellationToken)
+ {
+ await WaitUntilAsync(when, cancellationToken).ConfigureAwait(false);
+ await task.ConfigureAwait(false);
+ }
+
+ private static async Task WaitUntilAsync(DateTimeOffset when, CancellationToken cancellationToken)
{
var timeToWait = when - DateTimeOffset.UtcNow;
var fixedTimeToWait = timeToWait < TimeSpan.Zero ? TimeSpan.Zero : timeToWait;
await Task.Delay(fixedTimeToWait, cancellationToken).ConfigureAwait(false);
- return await task.ConfigureAwait(false);
}
}
}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -124,7 +124,8 @@ namespace WalletWasabi.WabiSabi.Client
// Output registration.
roundState = await RoundStatusUpdater.CreateRoundAwaiter(roundState.Id, rs => rs.Phase == Phase.OutputRegistration, cancellationToken).ConfigureAwait(false);
- await scheduler.StartOutputRegistrationsAsync(outputTxOuts, bobClient, cancellationToken).ConfigureAwait(false);
+ var remainingTimeForOutputRegistration = roundState.OutputRegistrationTimeout - RoundStatusUpdater.Period;
+ await scheduler.StartOutputRegistrationsAsync(outputTxOuts, bobClient, remainingTimeForOutputRegistration, cancellationToken).ConfigureAwait(false);
// ReadyToSign.
await ReadyToSignAsync(registeredAliceClients, cancellationToken).ConfigureAwait(false);

MODIFY
WalletWasabi/WabiSabi/Client/DependencyGraphTaskScheduler.cs
WalletWasabi/WabiSabi/Client/DependencyGraphTaskScheduler.cs
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using WalletWasabi.Crypto.ZeroKnowledge;
using WalletWasabi.WabiSabi.Client.CredentialDependencies;
using WalletWasabi.WabiSabi.Crypto;
+using WalletWasabi.WabiSabi.Models;
namespace WalletWasabi.WabiSabi.Client
{
@@ -142,14 +143,17 @@ namespace WalletWasabi.WabiSabi.Client
}
}
- public async Task StartOutputRegistrationsAsync(IEnumerable<TxOut> txOuts, BobClient bobClient, CancellationToken cancellationToken)
+ public async Task StartOutputRegistrationsAsync(IEnumerable<TxOut> txOuts, BobClient bobClient, TimeSpan remainingTimeForOutputRegistration, CancellationToken cancellationToken)
{
List<Task> outputTasks = new();
using CancellationTokenSource ctsOnError = new();
using CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ctsOnError.Token);
- foreach (var (node, txOut) in Enumerable.Zip(Graph.Outputs, txOuts))
+ // Gets the list of scheduled dates/time in the remaining available time frame when each alice has to be registered.
+ var scheduledDates = remainingTimeForOutputRegistration.SamplePoisson(txOuts.Count());
+
+ foreach (var (node, txOut, when) in Graph.Outputs.Zip(txOuts, scheduledDates))
{
var amountCredsToPresentTasks = Graph.InEdges(node, CredentialType.Amount).Select(edge => DependencyTasks[edge].Task);
var vsizeCredsToPresentTasks = Graph.InEdges(node, CredentialType.Vsize).Select(edge => DependencyTasks[edge].Task);
@@ -171,7 +175,7 @@ namespace WalletWasabi.WabiSabi.Client
throw exception;
}
}, linkedCts.Token);
- outputTasks.Add(task);
+ outputTasks.Add(task.RunAsScheduledAsync(when, cancellationToken));
}
await Task.WhenAll(outputTasks).ConfigureAwait(false);

Interleave Output Registrations