Use a cancellation token to
MODIFY
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
@@ -146,10 +146,12 @@ namespace WalletWasabi.Tests.Helpers
var alice = round?.Alices.FirstOrDefault();
var (realAmountCredentialRequest, _) = amClient.CreateRequest(
new[] { amount?.Satoshi ?? alice?.CalculateRemainingAmountCredentials(round!.FeeRate).Satoshi ?? ProtocolConstants.MaxVsizePerAlice },
- zeroPresentables.amountCredentials);
+ zeroPresentables.amountCredentials,
+ CancellationToken.None);
var (realVsizeCredentialRequest, _) = vsClient.CreateRequest(
new[] { vsize ?? alice?.CalculateRemainingVsizeCredentials(round!.PerAliceVsizeAllocation) ?? ProtocolConstants.MaxVsizePerAlice },
- zeroPresentables.vsizeCredentials);
+ zeroPresentables.vsizeCredentials,
+ CancellationToken.None);
return (realAmountCredentialRequest, realVsizeCredentialRequest);
}
@@ -162,10 +164,12 @@ namespace WalletWasabi.Tests.Helpers
var alice = round?.Alices.FirstOrDefault();
var (realAmountCredentialRequest, _) = amClient.CreateRequest(
new[] { alice?.CalculateRemainingAmountCredentials(round!.FeeRate).Satoshi ?? ProtocolConstants.MaxVsizePerAlice },
- zeroPresentables.amountCredentials);
+ zeroPresentables.amountCredentials,
+ CancellationToken.None);
var (realVsizeCredentialRequest, _) = vsClient.CreateRequest(
new[] { alice?.CalculateRemainingVsizeCredentials(round!.PerAliceVsizeAllocation) ?? ProtocolConstants.MaxVsizePerAlice },
- zeroPresentables.vsizeCredentials);
+ zeroPresentables.vsizeCredentials,
+ CancellationToken.None);
var (zeroAmountCredentialRequest, _) = amClient.CreateRequestForZeroAmount();
var (zeroVsizeCredentialRequest, _) = vsClient.CreateRequestForZeroAmount();
@@ -198,10 +202,12 @@ namespace WalletWasabi.Tests.Helpers
var alice = round.Alices.First(x => x.Id == response.AliceId);
var (realAmountCredentialRequest, amVal) = amClient.CreateRequest(
new[] { alice.CalculateRemainingAmountCredentials(round.FeeRate).Satoshi },
- zeroPresentables.amountCredentials);
+ zeroPresentables.amountCredentials,
+ CancellationToken.None);
var (realVsizeCredentialRequest, weVal) = vsClient.CreateRequest(
new[] { alice.CalculateRemainingVsizeCredentials(round.PerAliceVsizeAllocation) },
- zeroPresentables.vsizeCredentials);
+ zeroPresentables.vsizeCredentials,
+ CancellationToken.None);
var (zeroAmountCredentialRequest, _) = amClient.CreateRequestForZeroAmount();
var (zeroVsizeCredentialRequest, _) = vsClient.CreateRequestForZeroAmount();
@@ -228,11 +234,13 @@ namespace WalletWasabi.Tests.Helpers
var alice = round?.Alices.FirstOrDefault();
var (amCredentialRequest, amValid) = amClient.CreateRequest(
new[] { alice?.CalculateRemainingAmountCredentials(round!.FeeRate).Satoshi ?? ProtocolConstants.MaxVsizePerAlice },
- zeroPresentables.amountCredentials);
+ zeroPresentables.amountCredentials,
+ CancellationToken.None);
long startingVsizeCredentialAmount = alice?.CalculateRemainingVsizeCredentials(round!.PerAliceVsizeAllocation) ?? ProtocolConstants.MaxVsizePerAlice;
var (vsCredentialRequest, weValid) = vsClient.CreateRequest(
new[] { startingVsizeCredentialAmount },
- zeroPresentables.vsizeCredentials);
+ zeroPresentables.vsizeCredentials,
+ CancellationToken.None);
var amResp = amIssuer.HandleRequest(amCredentialRequest);
var weResp = vsIssuer.HandleRequest(vsCredentialRequest);
@@ -242,7 +250,8 @@ namespace WalletWasabi.Tests.Helpers
script ??= BitcoinFactory.CreateScript();
var (realAmountCredentialRequest, _) = amClient.CreateRequest(
Array.Empty<long>(),
- amountCredentials);
+ amountCredentials,
+ CancellationToken.None);
try
{
@@ -255,7 +264,8 @@ namespace WalletWasabi.Tests.Helpers
var (realVsizeCredentialRequest, _) = vsClient.CreateRequest(
new[] { startingVsizeCredentialAmount - (long)vsize },
- vsizeCredentials);
+ vsizeCredentials,
+ CancellationToken.None);
return new OutputRegistrationRequest(
round?.Id ?? uint256.Zero,
@@ -274,11 +284,13 @@ namespace WalletWasabi.Tests.Helpers
var startingVsizeCredentialAmount = alice.CalculateRemainingVsizeCredentials(round!.PerAliceVsizeAllocation);
var script = BitcoinFactory.CreateScript();
var vsize = script.EstimateOutputVsize();
+ var amountCredentialRequestData = ccresp.amountClient.CreateRequest(Array.Empty<long>(), ccresp.amountCredentials, CancellationToken.None);
+ var vsizeCredentialRequestData = ccresp.vsizeClient.CreateRequest(new[] { startingVsizeCredentialAmount - vsize }, ccresp.vsizeCredentials, CancellationToken.None);
ret.Add(new OutputRegistrationRequest(
round.Id,
script,
- ccresp.amountClient.CreateRequest(Array.Empty<long>(), ccresp.amountCredentials).CredentialsRequest,
- ccresp.vsizeClient.CreateRequest(new[] { startingVsizeCredentialAmount - vsize }, ccresp.vsizeCredentials).CredentialsRequest));
+ amountCredentialRequestData.CredentialsRequest,
+ vsizeCredentialRequestData.CredentialsRequest));
}
return ret;

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/SerializationTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/SerializationTests.cs
using System;
using System.Linq;
+using System.Threading;
using NBitcoin.Secp256k1;
using Newtonsoft.Json;
using WalletWasabi.Crypto;
@@ -159,7 +160,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi
(CredentialsRequest credentialRequest, CredentialsResponseValidation validationData) = client.CreateRequestForZeroAmount();
var credentialResponse = issuer.HandleRequest(credentialRequest);
var present = client.HandleResponse(credentialResponse, validationData);
- (credentialRequest, _) = client.CreateRequest(new[] { 1L }, present);
+ (credentialRequest, _) = client.CreateRequest(new[] { 1L }, present, CancellationToken.None);
// Registration request message.
var serializedRequestMessage = JsonConvert.SerializeObject(credentialRequest, converters);

MODIFY
WalletWasabi/WabiSabi/Client/ArenaClient.cs
WalletWasabi/WabiSabi/Client/ArenaClient.cs
@@ -88,12 +88,14 @@ namespace WalletWasabi.WabiSabi.Client
var presentedAmount = amountCredentialsToPresent.Sum(x => (long)x.Amount.ToUlong());
var (realAmountCredentialRequest, realAmountCredentialResponseValidation) = AmountCredentialClient.CreateRequest(
new[] { presentedAmount - value },
- amountCredentialsToPresent);
+ amountCredentialsToPresent,
+ cancellationToken);
var presentedVsize = vsizeCredentialsToPresent.Sum(x => (long)x.Amount.ToUlong());
var (realVsizeCredentialRequest, realVsizeCredentialResponseValidation) = VsizeCredentialClient.CreateRequest(
new[] { presentedVsize - scriptPubKey.EstimateOutputVsize() },
- vsizeCredentialsToPresent);
+ vsizeCredentialsToPresent,
+ cancellationToken);
var outputRegistrationResponse = await RequestHandler.RegisterOutputAsync(
new OutputRegistrationRequest(
@@ -130,11 +132,13 @@ namespace WalletWasabi.WabiSabi.Client
var presentedVsize = vsizeCredentialsToPresent.Sum(x => (long)x.Amount.ToUlong());
var (realVsizeCredentialRequest, realVsizeCredentialResponseValidation) = VsizeCredentialClient.CreateRequest(
new[] { (long)scriptPubKey1.EstimateOutputVsize(), scriptPubKey2.EstimateOutputVsize() },
- vsizeCredentialsToPresent);
+ vsizeCredentialsToPresent,
+ cancellationToken);
var (realAmountCredentialRequest, realAmountCredentialResponseValidation) = AmountCredentialClient.CreateRequest(
new[] { value1, value2 },
- amountCredentialsToPresent);
+ amountCredentialsToPresent,
+ cancellationToken);
var zeroAmountCredentialRequestData = AmountCredentialClient.CreateRequestForZeroAmount();
var zeroVsizeCredentialRequestData = VsizeCredentialClient.CreateRequestForZeroAmount();
@@ -172,11 +176,13 @@ namespace WalletWasabi.WabiSabi.Client
var realAmountCredentialRequestData = AmountCredentialClient.CreateRequest(
newAmount.Select(x => x.Satoshi),
- amountCredentialsToPresent);
+ amountCredentialsToPresent,
+ cancellationToken);
var realVsizeCredentialRequestData = VsizeCredentialClient.CreateRequest(
inputsRegistrationVsize,
- vsizeCredentialsToPresent);
+ vsizeCredentialsToPresent,
+ cancellationToken);
var zeroAmountCredentialRequestData = AmountCredentialClient.CreateRequestForZeroAmount();
var zeroVsizeCredentialRequestData = VsizeCredentialClient.CreateRequestForZeroAmount();

MODIFY
WalletWasabi/WabiSabi/Crypto/WabiSabiClient.cs
WalletWasabi/WabiSabi/Crypto/WabiSabiClient.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Threading;
using NBitcoin;
using NBitcoin.Secp256k1;
using WalletWasabi.Crypto;
@@ -90,13 +91,15 @@ namespace WalletWasabi.WabiSabi.Crypto
/// </summary>
/// <param name="amountsToRequest">List of amounts requested in credentials.</param>
/// <param name="credentialsToPresent">List of credentials to be presented to the coordinator.</param>
+ /// <param name="cancellationToken">The cancellation token to be used in case shut down is in progress..</param>
/// <returns>
/// A tuple containing the registration request message instance and the registration validation data
/// to be used to validate the coordinator response message (the issued credentials).
/// </returns>
public RealCredentialsRequestData CreateRequest(
IEnumerable<long> amountsToRequest,
- IEnumerable<Credential> credentialsToPresent)
+ IEnumerable<Credential> credentialsToPresent,
+ CancellationToken cancellationToken)
{
// Make sure we request always the same number of credentials
var credentialAmountsToRequest = amountsToRequest.ToList();
@@ -106,7 +109,7 @@ namespace WalletWasabi.WabiSabi.Crypto
credentialAmountsToRequest.Add(0);
}
- credentialsToPresent = ZeroCredentialPool.FillOutWithZeroCredentials(credentialsToPresent);
+ credentialsToPresent = ZeroCredentialPool.FillOutWithZeroCredentials(credentialsToPresent, cancellationToken);
var macsToPresent = credentialsToPresent.Select(x => x.Mac);
if (macsToPresent.Distinct().Count() < macsToPresent.Count())

MODIFY
WalletWasabi/WabiSabi/Crypto/ZeroCredentialPool.cs
WalletWasabi/WabiSabi/Crypto/ZeroCredentialPool.cs
@@ -2,6 +2,8 @@ using System;
using System.Linq;
using System.Collections.Generic;
using WalletWasabi.Crypto.ZeroKnowledge;
+using System.Collections.Concurrent;
+using System.Threading;
namespace WalletWasabi.WabiSabi.Crypto
{
@@ -10,8 +12,7 @@ namespace WalletWasabi.WabiSabi.Crypto
/// </summary>
public class ZeroCredentialPool
{
- private readonly object syncObject = new();
- private readonly Queue<Credential> _zeroValueCredentials = new ();
+ private readonly ConcurrentQueue<Credential> _zeroValueCredentials = new ();
internal ZeroCredentialPool()
{
@@ -26,12 +27,9 @@ namespace WalletWasabi.WabiSabi.Crypto
foreach (var credential in credentials)
{
if (credential.Amount.IsZero)
- {
- lock (syncObject)
{
_zeroValueCredentials.Enqueue(credential);
}
- }
else
{
yield return credential;
@@ -39,7 +37,11 @@ namespace WalletWasabi.WabiSabi.Crypto
}
}
- public Credential[] FillOutWithZeroCredentials(IEnumerable<Credential> credentials)
+ /// <summary>
+ /// Given `c` credentials returns `k` credentials taking `k-c` null credentials from the pool.
+ /// </summary>
+ /// <param name="credentials">Credentials received from the coordinator.</param>
+ public Credential[] FillOutWithZeroCredentials(IEnumerable<Credential> credentials, CancellationToken cancellationToken)
{
var n = ProtocolConstants.CredentialNumber;
var credentialsToReturn = new Credential[ProtocolConstants.CredentialNumber];
@@ -49,14 +51,11 @@ namespace WalletWasabi.WabiSabi.Crypto
credentialsToReturn[n] = credential;
}
- lock (syncObject)
- {
while (n > 0)
{
- if (!_zeroValueCredentials.TryDequeue(out var credential))
+ cancellationToken.ThrowIfCancellationRequested();
+ if (_zeroValueCredentials.TryDequeue(out var credential))
{
- throw new InvalidOperationException("There are not enough null credentials.");
- }
n--;
credentialsToReturn[n] = credential;
}

Use a cancellation token to