Simplify `Round` by extracting `BlameRound`
MODIFY
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
@@ -266,8 +266,8 @@ namespace WalletWasabi.Tests.Helpers
realVsizeCredentialRequest);
}
- public static Round CreateBlameRound(Round round, WabiSabiConfig cfg)
- => new(new(cfg, round.Network, new InsecureRandom(), round.FeeRate, blameOf: round));
+ public static BlameRound CreateBlameRound(Round round, WabiSabiConfig cfg)
+ => new(new(cfg, round.Network, new InsecureRandom(), round.FeeRate), round, round.Alices.Select(x => x.Coin.Outpoint).ToHashSet());
public static (Key, SmartCoin, Key, SmartCoin) CreateCoinKeyPairs()
{

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
@@ -164,7 +164,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
Assert.DoesNotContain(round, arena.ActiveRounds);
Assert.Equal(Phase.Ended, round.Phase);
Assert.False(round.WasTransactionBroadcast);
- Assert.Empty(arena.Rounds.Where(x => x.IsBlameRound));
+ Assert.Empty(arena.Rounds.Where(x => x is BlameRound));
Assert.Contains(aliceClient2.SmartCoin.OutPoint, prison.GetInmates().Select(x => x.Utxo));
await arena.StopAsync(CancellationToken.None);
@@ -204,14 +204,14 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
await aliceClient2.SignTransactionAsync(signedCoinJoin, CancellationToken.None);
await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));
Assert.DoesNotContain(round, arena.ActiveRounds);
- Assert.Single(arena.Rounds.Where(x => x.IsBlameRound));
+ Assert.Single(arena.Rounds.Where(x => x is BlameRound));
var badOutpoint = alice3.Coin.Outpoint;
Assert.Contains(badOutpoint, prison.GetInmates().Select(x => x.Utxo));
- var blameRound = arena.Rounds.Single(x => x.IsBlameRound);
- Assert.True(blameRound.IsBlameRound);
+ var onlyRound = arena.Rounds.Single(x => x is BlameRound);
+ var blameRound = Assert.IsType<BlameRound>(onlyRound);
Assert.NotNull(blameRound.BlameOf);
- Assert.Equal(round.Id, blameRound.BlameOf?.Id);
+ Assert.Equal(round.Id, blameRound.BlameOf.Id);
var whitelist = blameRound.BlameWhitelist;
Assert.Contains(aliceClient1.SmartCoin.OutPoint, whitelist);

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
@@ -281,14 +281,19 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
private async Task CreateBlameRoundAsync(Round round, CancellationToken cancellationToken)
{
var feeRate = (await Rpc.EstimateSmartFeeAsync((int)Config.ConfirmationTarget, EstimateSmartFeeMode.Conservative, simulateIfRegTest: true, cancellationToken).ConfigureAwait(false)).FeeRate;
- RoundParameters parameters = new(Config, Network, Random, feeRate, blameOf: round, Prison);
- Round blameRound = new(parameters);
+ RoundParameters parameters = new(Config, Network, Random, feeRate);
+ var blameWhitelist = round.Alices
+ .Select(x => x.Coin.Outpoint)
+ .Where(x => !Prison.IsBanned(x))
+ .ToHashSet();
+
+ BlameRound blameRound = new(parameters, round, blameWhitelist);
Rounds.Add(blameRound);
}
private async Task CreateRoundsAsync(CancellationToken cancellationToken)
{
- if (!Rounds.Any(x => !x.IsBlameRound && x.Phase == Phase.InputRegistration))
+ if (!Rounds.Any(x => x is not BlameRound && x.Phase == Phase.InputRegistration))
{
var feeRate = (await Rpc.EstimateSmartFeeAsync((int)Config.ConfirmationTarget, EstimateSmartFeeMode.Conservative, simulateIfRegTest: true, cancellationToken).ConfigureAwait(false)).FeeRate;
@@ -353,7 +358,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
}
- if (round.IsBlameRound && !round.BlameWhitelist.Contains(coin.Outpoint))
+ if (round is BlameRound blameRound && !blameRound.BlameWhitelist.Contains(coin.Outpoint))
{
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputNotWhitelisted);
}

ADD
WalletWasabi/WabiSabi/Backend/Rounds/BlameRound.cs
+using NBitcoin;
+using System.Collections.Generic;
+
+namespace WalletWasabi.WabiSabi.Backend.Rounds
+{
+ public class BlameRound : Round
+ {
+ public BlameRound(RoundParameters roundParameters, Round blameOf, ISet<OutPoint> blameWhitelist)
+ : base(roundParameters)
+ {
+ BlameOf = blameOf;
+ BlameWhitelist = blameWhitelist;
+ InputRegistrationTimeFrame = TimeFrame.Create(RoundParameters.BlameInputRegistrationTimeout).StartNow();
+ }
+
+ public Round BlameOf { get; }
+ public ISet<OutPoint> BlameWhitelist { get; }
+
+ public override bool IsInputRegistrationEnded(int maxInputCount)
+ {
+ return base.IsInputRegistrationEnded(BlameWhitelist.Count);
+ }
+ }
+}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
@@ -2,7 +2,6 @@ using NBitcoin;
using System;
using System.Collections.Generic;
using WalletWasabi.Crypto;
-using WalletWasabi.Crypto.StrobeProtocol;
using WalletWasabi.WabiSabi.Backend.Models;
using WalletWasabi.WabiSabi.Crypto;
using WalletWasabi.WabiSabi.Models;
@@ -30,7 +29,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
AmountCredentialIssuerParameters = AmountCredentialIssuer.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters();
VsizeCredentialIssuerParameters = VsizeCredentialIssuer.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters();
- InputRegistrationTimeFrame = TimeFrame.Create(IsBlameRound ? RoundParameters.BlameInputRegistrationTimeout : RoundParameters.StandardInputRegistrationTimeout).StartNow();
+ InputRegistrationTimeFrame = TimeFrame.Create(RoundParameters.StandardInputRegistrationTimeout).StartNow();
ConnectionConfirmationTimeFrame = TimeFrame.Create(RoundParameters.ConnectionConfirmationTimeout);
OutputRegistrationTimeFrame = TimeFrame.Create(RoundParameters.OutputRegistrationTimeout);
TransactionSigningTimeFrame = TimeFrame.Create(RoundParameters.TransactionSigningTimeout);
@@ -52,10 +51,6 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
public int InputCount => Alices.Count;
public List<Bob> Bobs { get; } = new();
- public Round? BlameOf => RoundParameters.BlameOf;
- public bool IsBlameRound => RoundParameters.IsBlameRound;
- public ISet<OutPoint> BlameWhitelist => RoundParameters.BlameWhitelist;
-
public Phase Phase { get; private set; } = Phase.InputRegistration;
public TimeFrame InputRegistrationTimeFrame { get; internal set; }
public TimeFrame ConnectionConfirmationTimeFrame { get; private set; }
@@ -64,9 +59,9 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
public DateTimeOffset End { get; private set; }
public bool WasTransactionBroadcast { get; set; }
public int InitialInputVsizeAllocation { get; internal set; }
- public int RemainingInputVsizeAllocation => InitialInputVsizeAllocation - InputCount * MaxVsizeAllocationPerAlice;
+ public int RemainingInputVsizeAllocation => InitialInputVsizeAllocation - (InputCount * MaxVsizeAllocationPerAlice);
- private RoundParameters RoundParameters { get; }
+ protected RoundParameters RoundParameters { get; }
public TState Assert<TState>() where TState : MultipartyTransactionState =>
CoinjoinState switch
@@ -103,21 +98,14 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
}
}
- public bool IsInputRegistrationEnded(int maxInputCount)
+ public virtual bool IsInputRegistrationEnded(int maxInputCount)
{
if (Phase > Phase.InputRegistration)
{
return true;
}
- if (IsBlameRound)
- {
- if (BlameWhitelist.Count <= InputCount)
- {
- return true;
- }
- }
- else if (InputCount >= maxInputCount)
+ if (InputCount >= maxInputCount)
{
return true;
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/RoundParameters.cs
WalletWasabi/WabiSabi/Backend/Rounds/RoundParameters.cs
using NBitcoin;
using System;
-using System.Collections.Generic;
-using System.Linq;
using WalletWasabi.Crypto.Randomness;
-using WalletWasabi.WabiSabi.Backend.Banning;
namespace WalletWasabi.WabiSabi.Backend.Rounds
{
@@ -13,9 +10,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
WabiSabiConfig wabiSabiConfig,
Network network,
WasabiRandom random,
- FeeRate feeRate,
- Round? blameOf = null,
- Prison? prison = null)
+ FeeRate feeRate)
{
Network = network;
Random = random;
@@ -32,15 +27,6 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
OutputRegistrationTimeout = wabiSabiConfig.OutputRegistrationTimeout;
TransactionSigningTimeout = wabiSabiConfig.TransactionSigningTimeout;
BlameInputRegistrationTimeout = wabiSabiConfig.BlameInputRegistrationTimeout;
-
- BlameOf = blameOf;
- IsBlameRound = BlameOf is not null;
- BlameWhitelist = BlameOf
- ?.Alices
- .Select(x => x.Coin.Outpoint)
- .Where(x => prison is null || !prison.IsBanned(x))
- .ToHashSet()
- ?? new HashSet<OutPoint>();
}
public WasabiRandom Random { get; }
@@ -50,9 +36,6 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
public int MaxInputCountByRound { get; }
public Money MinRegistrableAmount { get; }
public Money MaxRegistrableAmount { get; }
- public Round? BlameOf { get; }
- public bool IsBlameRound { get; }
- public ISet<OutPoint> BlameWhitelist { get; }
public TimeSpan StandardInputRegistrationTimeout { get; }
public TimeSpan ConnectionConfirmationTimeout { get; }
public TimeSpan OutputRegistrationTimeout { get; }

MODIFY
WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
@@ -93,8 +93,5 @@ namespace WalletWasabi.WabiSabi.Backend
[JsonProperty(PropertyName = "BlameScript", DefaultValueHandling = DefaultValueHandling.Populate)]
[JsonConverter(typeof(ScriptJsonConverter))]
public Script BlameScript { get; set; } = new Script("0 1251dec2e6a6694a789f0cca6c2a9cfb4c74fb4e");
-
- public TimeSpan GetInputRegistrationTimeout(Round round)
- => round.IsBlameRound ? BlameInputRegistrationTimeout : StandardInputRegistrationTimeout;
}
}

MODIFY
WalletWasabi/WabiSabi/Models/RoundState.cs
WalletWasabi/WabiSabi/Models/RoundState.cs
@@ -9,7 +9,7 @@ using WalletWasabi.WabiSabi.Models.MultipartyTransaction;
namespace WalletWasabi.WabiSabi.Models
{
public record RoundState(
- uint256? BlameOf,
+ uint256 BlameOf,
CredentialIssuerParameters AmountCredentialIssuerParameters,
CredentialIssuerParameters VsizeCredentialIssuerParameters,
FeeRate FeeRate,
@@ -33,7 +33,7 @@ namespace WalletWasabi.WabiSabi.Models
public static RoundState FromRound(Round round) =>
new(
- round.BlameOf?.Id,
+ round is BlameRound blameRound ? blameRound.BlameOf.Id : uint256.Zero,
round.AmountCredentialIssuerParameters,
round.VsizeCredentialIssuerParameters,
round.FeeRate,

Simplify `Round` by extracting `BlameRound`