Bring non-concurrent code to the arena
MODIFY
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.Crypto;
using WalletWasabi.Crypto.Randomness;
@@ -59,6 +60,17 @@ namespace WalletWasabi.Tests.Helpers
new InsecureRandom(),
new(100m)));
+ public static async Task<Arena> CreateAndStartArenaAsync(params Round[] rounds)
+ {
+ Arena arena = new(TimeSpan.FromSeconds(1), rounds.FirstOrDefault()?.Network ?? Network.Main);
+ foreach (var round in rounds)
+ {
+ arena.Rounds.Add(round.Id, round);
+ }
+ await arena.StartAsync(CancellationToken.None).ConfigureAwait(false);
+ return arena;
+ }
+
public static Alice CreateAlice(InputRoundSignaturePair inputSigPairs, Key? key = null, Money? value = null) => CreateAlice(new[] { inputSigPairs }, key, value);
public static Alice CreateAlice(IEnumerable<InputRoundSignaturePair>? inputSigPairs = null, Key? key = null, Money? value = null)

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/ConfirmConnectionTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/ConfirmConnectionTests.cs
@@ -21,16 +21,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task SuccessInInputRegistrationPhaseAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
var alice = WabiSabiFactory.CreateAlice();
var preDeadline = alice.Deadline;
round.Alices.Add(alice);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
var minAliceDeadline = DateTimeOffset.UtcNow + cfg.ConnectionConfirmationTimeout * 0.9;
@@ -50,17 +46,13 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task SuccessInConnectionConfirmationPhaseAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.ConnectionConfirmation;
var alice = WabiSabiFactory.CreateAlice();
var preDeadline = alice.Deadline;
round.Alices.Add(alice);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
@@ -78,9 +70,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task RoundNotFoundAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();
await using PostRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient());
var req = WabiSabiFactory.CreateConnectionConfirmationRequest();
var ex = Assert.Throws<WabiSabiProtocolException>(() => handler.ConfirmConnection(req));
@@ -92,16 +82,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task WrongPhaseAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
var alice = WabiSabiFactory.CreateAlice();
var preDeadline = alice.Deadline;
round.Alices.Add(alice);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
foreach (Phase phase in Enum.GetValues(typeof(Phase)))
@@ -122,13 +108,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task AliceNotFoundAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
@@ -141,16 +123,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task IncorrectRequestedWeightCredentialsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.ConnectionConfirmation;
var alice = WabiSabiFactory.CreateAlice();
round.Alices.Add(alice);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
req = new(
@@ -170,16 +148,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task IncorrectRequestedAmountCredentialsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.ConnectionConfirmation;
var alice = WabiSabiFactory.CreateAlice();
round.Alices.Add(alice);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
req = new(

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RegisterInputTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RegisterInputTests.cs
@@ -22,13 +22,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task SuccessAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();
@@ -56,9 +52,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task RoundNotFoundAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();
MockRpcClient rpc = new();
using Key key = new();
@@ -80,13 +74,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task WrongPhaseAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();
@@ -115,13 +105,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task NonUniqueInputsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var inputSigPair = WabiSabiFactory.CreateInputRoundSignaturePair();
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
@@ -135,14 +121,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task TooManyInputsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new() { MaxInputCountByAlice = 3 };
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
-
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();
@@ -164,17 +145,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputBannedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
Prison prison = new();
var pair = WabiSabiFactory.CreateInputRoundSignaturePair();
prison.Punish(pair.Input, Punishment.Banned, Guid.NewGuid());
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
-
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, prison, arena, new MockRpcClient());
var req = WabiSabiFactory.CreateInputsRegistrationRequest(pair, round);
var ex = await Assert.ThrowsAsync<WabiSabiProtocolException>(async () => await handler.RegisterInputAsync(req));
@@ -186,16 +162,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputCanBeNotedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
Prison prison = new();
var pair = WabiSabiFactory.CreateInputRoundSignaturePair();
prison.Punish(pair.Input, Punishment.Noted, Guid.NewGuid());
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, prison, arena, new MockRpcClient());
var req = WabiSabiFactory.CreateInputsRegistrationRequest(pair, round);
@@ -211,16 +183,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputCantBeNotedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
Prison prison = new();
var pair = WabiSabiFactory.CreateInputRoundSignaturePair();
prison.Punish(pair.Input, Punishment.Noted, Guid.NewGuid());
WabiSabiConfig cfg = new() { AllowNotedInputRegistration = false };
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, prison, arena, new MockRpcClient());
var req = WabiSabiFactory.CreateInputsRegistrationRequest(pair, round);
@@ -233,16 +201,11 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputNotWhitelistedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Alices.Add(WabiSabiFactory.CreateAlice());
Round blameRound = new(round);
-
- arena.Rounds.Add(round.Id, round);
- arena.Rounds.Add(blameRound.Id, blameRound);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round, blameRound);
MockRpcClient rpc = new();
using Key key = new();
@@ -264,17 +227,12 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputWhitelistedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
var pair = WabiSabiFactory.CreateInputRoundSignaturePair();
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Alices.Add(WabiSabiFactory.CreateAlice(pair));
Round blameRound = new(round);
-
- arena.Rounds.Add(round.Id, round);
- arena.Rounds.Add(blameRound.Id, blameRound);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round, blameRound);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
var req = WabiSabiFactory.CreateInputsRegistrationRequest(pair, blameRound);
@@ -291,9 +249,6 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputWhitelistedButBannedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
Prison prison = new();
var pair = WabiSabiFactory.CreateInputRoundSignaturePair();
prison.Punish(pair.Input, Punishment.Banned, Guid.NewGuid());
@@ -301,9 +256,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
var round = WabiSabiFactory.CreateRound(cfg);
round.Alices.Add(WabiSabiFactory.CreateAlice(pair));
Round blameRound = new(round);
-
- arena.Rounds.Add(round.Id, round);
- arena.Rounds.Add(blameRound.Id, blameRound);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round, blameRound);
await using PostRequestHandler handler = new(cfg, prison, arena, new MockRpcClient());
var req = WabiSabiFactory.CreateInputsRegistrationRequest(pair, blameRound);
@@ -316,13 +269,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputSpentAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
rpc.OnGetTxOutAsync = (_, _, _) => null;
@@ -337,13 +286,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputUnconfirmedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
rpc.OnGetTxOutAsync = (_, _, _) => new GetTxOutResponse { Confirmations = 0 };
@@ -358,13 +303,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputImmatureAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
var req = WabiSabiFactory.CreateInputsRegistrationRequest(round);
@@ -383,13 +324,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task ScriptNotAllowedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();
@@ -410,13 +347,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task WrongRoundSignatureAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();
@@ -438,13 +371,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task NotEnoughFundsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new() { MinRegistrableAmount = Money.Coins(2) };
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();
@@ -466,13 +395,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task TooMuchFundsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new() { MaxRegistrableAmount = Money.Coins(0.9m) };
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();
@@ -494,13 +419,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task TooMuchWeightAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new() { RegistrableWeightCredentials = 1 };
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
MockRpcClient rpc = new();
using Key key = new();

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RegisterOutputTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RegisterOutputTests.cs
@@ -21,15 +21,11 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task SuccessAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.OutputRegistration;
round.Alices.Add(WabiSabiFactory.CreateAlice());
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
var req = WabiSabiFactory.CreateOutputRegistrationRequest(round);
@@ -46,9 +42,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task RoundNotFoundAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();
await using PostRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient());
var req = WabiSabiFactory.CreateOutputRegistrationRequest();
var ex = Assert.Throws<WabiSabiProtocolException>(() => handler.RegisterOutput(req));
@@ -60,13 +54,10 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task ScriptNotAllowedAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.OutputRegistration;
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
using Key key = new();
var req = WabiSabiFactory.CreateOutputRegistrationRequest(round, key.PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main).ScriptPubKey);
@@ -80,14 +71,11 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task NotEnoughFundsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new() { MinRegistrableAmount = Money.Coins(2) };
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.OutputRegistration;
round.Alices.Add(WabiSabiFactory.CreateAlice(value: Money.Coins(1)));
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
var req = WabiSabiFactory.CreateOutputRegistrationRequest(round);
@@ -101,14 +89,11 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task TooMuchFundsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new() { MaxRegistrableAmount = Money.Coins(1.999m) };
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.OutputRegistration;
round.Alices.Add(WabiSabiFactory.CreateAlice(value: Money.Coins(2)));
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
var req = WabiSabiFactory.CreateOutputRegistrationRequest(round);
@@ -122,14 +107,11 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task IncorrectRequestedWeightCredentialsAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Phase = Phase.OutputRegistration;
round.Alices.Add(WabiSabiFactory.CreateAlice());
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
var req = WabiSabiFactory.CreateOutputRegistrationRequest(round, weight: 30);
@@ -143,13 +125,10 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task WrongPhaseAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
round.Alices.Add(WabiSabiFactory.CreateAlice());
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
foreach (Phase phase in Enum.GetValues(typeof(Phase)))

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RemoveInputTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RemoveInputTests.cs
@@ -20,14 +20,11 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task SuccessAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
var alice = WabiSabiFactory.CreateAlice();
round.Alices.Add(alice);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
@@ -45,8 +42,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task RoundNotFoundAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();
await using PostRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient());
var req = new InputsRemovalRequest(Guid.NewGuid(), Guid.NewGuid());
@@ -59,12 +55,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task WrongPhaseAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = new InputsRemovalRequest(round.Id, Guid.NewGuid());
foreach (Phase phase in Enum.GetValues(typeof(Phase)))

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RequestHandlerDisposeTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RequestHandlerDisposeTests.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Tests.Helpers;
using WalletWasabi.WabiSabi.Backend;
using WalletWasabi.WabiSabi.Backend.Banning;
using WalletWasabi.WabiSabi.Backend.PostRequests;
@@ -18,8 +19,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task DisposeGuardAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();
PostRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient());
await handler.DisposeAsync();
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await handler.RegisterInputAsync(null!));

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/SignTransactionTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/SignTransactionTests.cs
@@ -21,8 +21,6 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task SuccessAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
using Key key = new();
@@ -31,8 +29,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
var coinjoin = round.Coinjoin;
coinjoin.Inputs.Add(alice.Coins.First().Outpoint);
round.Phase = Phase.TransactionSigning;
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var signedCoinJoin = coinjoin.Clone();
signedCoinJoin.Sign(key.GetBitcoinSecret(Network.Main), alice.Coins.First());
@@ -47,9 +44,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task RoundNotFoundAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
-
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();
await using PostRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient());
var req = new TransactionSignaturesRequest(Guid.NewGuid(), null!);
var ex = Assert.Throws<WabiSabiProtocolException>(() => handler.SignTransaction(req));
@@ -60,12 +55,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task WrongPhaseAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
var req = new TransactionSignaturesRequest(round.Id, null!);
foreach (Phase phase in Enum.GetValues(typeof(Phase)))
@@ -84,8 +76,6 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task WrongCoinjoinSignatureAsync()
{
- using Arena arena = new(TimeSpan.FromSeconds(1));
- await arena.StartAsync(CancellationToken.None);
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
using Key key1 = new();
@@ -98,8 +88,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
coinjoin.Inputs.Add(alice1.Coins.First().Outpoint);
coinjoin.Inputs.Add(alice2.Coins.First().Outpoint);
round.Phase = Phase.TransactionSigning;
-
- arena.Rounds.Add(round.Id, round);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(round);
// Submit the signature for the second alice to the first alice's input.
var signedCoinJoin = coinjoin.Clone();

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
@@ -15,12 +15,14 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
{
public class Arena : PeriodicRunner
{
- public Arena(TimeSpan period) : base(period)
+ public Arena(TimeSpan period, Network network) : base(period)
{
+ Network = network;
}
public Dictionary<Guid, Round> Rounds { get; } = new();
private object Lock { get; } = new();
+ public Network Network { get; }
public bool TryGetRound(Guid roundId, [NotNullWhen(true)] out Round? round)
{
@@ -46,8 +48,51 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.RoundNotFound);
}
+ var alice = new Alice(coinRoundSignaturePairs);
+
+ var coins = alice.Coins;
+ if (round.MaxInputCountByAlice < coins.Count())
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooManyInputs);
+ }
+ if (round.IsBlameRound && coins.Select(x => x.Outpoint).Any(x => !round.BlameWhitelist.Contains(x)))
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputNotWhitelisted);
+ }
+
+ var inputValueSum = Money.Zero;
+ var inputWeightSum = 0;
+ foreach (var coinRoundSignaturePair in alice.CoinRoundSignaturePairs)
+ {
+ var coin = coinRoundSignaturePair.Key;
+ var signature = coinRoundSignaturePair.Value;
+ var address = (BitcoinWitPubKeyAddress)coin.TxOut.ScriptPubKey.GetDestinationAddress(Network);
+ if (!address.VerifyMessage(round.Hash, signature))
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongRoundSignature);
+ }
+ inputValueSum += coin.TxOut.Value;
+
+ // Convert conservative P2WPKH size in virtual bytes to weight units.
+ inputWeightSum += coin.TxOut.ScriptPubKey.EstimateInputVsize() * 4;
+ }
+
+ if (inputValueSum < round.MinRegistrableAmount)
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.NotEnoughFunds);
+ }
+ if (inputValueSum > round.MaxRegistrableAmount)
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchFunds);
+ }
+
+ if (inputWeightSum > round.RegistrableWeightCredentials)
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchWeight);
+ }
+
return round.RegisterAlice(
- new Alice(coinRoundSignaturePairs),
+ alice,
zeroAmountCredentialRequests,
zeroWeightCredentialRequests);
}
@@ -79,12 +124,26 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
}
var credentialAmount = -request.AmountCredentialRequests.Delta;
- return round.RegisterBob(
- new Bob(
- request.Script,
- credentialAmount),
- request.AmountCredentialRequests,
- request.WeightCredentialRequests);
+
+ var bob = new Bob(request.Script, credentialAmount);
+
+ var outputValue = bob.CalculateOutputAmount(round.FeeRate);
+ if (outputValue < round.MinRegistrableAmount)
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.NotEnoughFunds);
+ }
+ if (outputValue > round.MaxRegistrableAmount)
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchFunds);
+ }
+
+ var weightCredentialRequests = request.WeightCredentialRequests;
+ if (-weightCredentialRequests.Delta != bob.CalculateWeight())
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.IncorrectRequestedWeightCredentials);
+ }
+
+ return round.RegisterBob(bob, request.AmountCredentialRequests, weightCredentialRequests);
}
public void SignTransaction(TransactionSignaturesRequest request)

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
@@ -74,68 +74,25 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
ZeroCredentialsRequest zeroAmountCredentialRequests,
ZeroCredentialsRequest zeroWeightCredentialRequests)
{
- var coins = alice.Coins;
- if (MaxInputCountByAlice < coins.Count())
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooManyInputs);
- }
- if (IsBlameRound && coins.Select(x => x.Outpoint).Any(x => !BlameWhitelist.Contains(x)))
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputNotWhitelisted);
- }
-
- var inputValueSum = Money.Zero;
- var inputWeightSum = 0;
- foreach (var coinRoundSignaturePair in alice.CoinRoundSignaturePairs)
- {
- var coin = coinRoundSignaturePair.Key;
- var signature = coinRoundSignaturePair.Value;
- var address = (BitcoinWitPubKeyAddress)coin.TxOut.ScriptPubKey.GetDestinationAddress(Network);
- if (!address.VerifyMessage(Hash, signature))
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongRoundSignature);
- }
- inputValueSum += coin.TxOut.Value;
-
- // Convert conservative P2WPKH size in virtual bytes to weight units.
- inputWeightSum += coin.TxOut.ScriptPubKey.EstimateInputVsize() * 4;
- }
-
- if (inputValueSum < MinRegistrableAmount)
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.NotEnoughFunds);
- }
- if (inputValueSum > MaxRegistrableAmount)
+ lock (Lock)
{
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchFunds);
- }
-
- if (inputWeightSum > RegistrableWeightCredentials)
+ if (Phase != Phase.InputRegistration)
{
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchWeight);
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
}
var amountCredentialResponse = AmountCredentialIssuer.HandleRequest(zeroAmountCredentialRequests);
var weightCredentialResponse = WeightCredentialIssuer.HandleRequest(zeroWeightCredentialRequests);
- lock (Lock)
- {
- if (Phase != Phase.InputRegistration)
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
- }
alice.SetDeadlineRelativeTo(ConnectionConfirmationTimeout);
Alices.Add(alice);
- }
return new(alice.Id, amountCredentialResponse, weightCredentialResponse);
}
+ }
public ConnectionConfirmationResponse ConfirmAlice(ConnectionConfirmationRequest request)
{
- var amountZeroCredentialResponse = AmountCredentialIssuer.HandleRequest(request.ZeroAmountCredentialRequests);
- var weightZeroCredentialResponse = WeightCredentialIssuer.HandleRequest(request.ZeroWeightCredentialRequests);
-
lock (Lock)
{
var alice = Alices.FirstOrDefault(x => x.Id == request.AliceId);
@@ -144,6 +101,9 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.AliceNotFound);
}
+ var amountZeroCredentialResponse = AmountCredentialIssuer.HandleRequest(request.ZeroAmountCredentialRequests);
+ var weightZeroCredentialResponse = WeightCredentialIssuer.HandleRequest(request.ZeroWeightCredentialRequests);
+
var realAmountCredentialRequests = request.RealAmountCredentialRequests;
var realWeightCredentialRequests = request.RealWeightCredentialRequests;
@@ -195,24 +155,6 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
public OutputRegistrationResponse RegisterBob(Bob bob, RealCredentialsRequest amountCredentialRequests, RealCredentialsRequest weightCredentialRequests)
{
- var outputValue = bob.CalculateOutputAmount(FeeRate);
- if (outputValue < MinRegistrableAmount)
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.NotEnoughFunds);
- }
- if (outputValue > MaxRegistrableAmount)
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchFunds);
- }
-
- var amountCredentialResponse = AmountCredentialIssuer.HandleRequest(amountCredentialRequests);
- var weightCredentialResponse = WeightCredentialIssuer.HandleRequest(weightCredentialRequests);
-
- if (-weightCredentialRequests.Delta != bob.CalculateWeight())
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.IncorrectRequestedWeightCredentials);
- }
-
lock (Lock)
{
if (Phase != Phase.OutputRegistration)
@@ -220,6 +162,9 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
}
+ var amountCredentialResponse = AmountCredentialIssuer.HandleRequest(amountCredentialRequests);
+ var weightCredentialResponse = WeightCredentialIssuer.HandleRequest(weightCredentialRequests);
+
Bobs.Add(bob);
return new(

MODIFY
WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
@@ -26,7 +26,7 @@ namespace WalletWasabi.WabiSabi
Warden = new(parameters.UtxoWardenPeriod, parameters.PrisonFilePath, Config);
ConfigWatcher = new(parameters.ConfigChangeMonitoringPeriod, Config, () => Logger.LogInfo("WabiSabi configuration has changed."));
- Arena = new(parameters.RoundProgressSteppingPeriod);
+ Arena = new(parameters.RoundProgressSteppingPeriod, rpc.Network);
Postman = new(Config, Prison, Arena, Rpc);
}

Bring non-concurrent code to the arena