Move phase to connection confirmation
MODIFY
WalletWasabi/WabiSabi/Backend/PostRequests/InputRegistrationHandler.cs
WalletWasabi/WabiSabi/Backend/PostRequests/InputRegistrationHandler.cs
@@ -69,7 +69,9 @@ namespace WalletWasabi.WabiSabi.Backend.PostRequests
ZeroCredentialsRequest zeroAmountCredentialRequests,
ZeroCredentialsRequest zeroWeightCredentialRequests,
IDictionary<Guid, Round> rounds,
- Network network)
+ Network network,
+ uint maxInputCount,
+ TimeSpan inputRegistrationTimeout)
{
if (!rounds.TryGetValue(roundId, out var round))
{
@@ -119,7 +121,7 @@ namespace WalletWasabi.WabiSabi.Backend.PostRequests
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchWeight);
}
- if (round.Phase != Phase.InputRegistration)
+ if (round.IsInputRegistrationEnded(maxInputCount, inputRegistrationTimeout))
{
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
@@ -43,11 +43,23 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
// Remove timed out alices.
TimeoutAlices();
+ StepInputRegistrationPhase();
+
// Ensure there's at least one non-blame round in input registration.
await CreateRoundsAsync().ConfigureAwait(false);
}
}
+ private void StepInputRegistrationPhase()
+ {
+ foreach (var round in Rounds.Values.Where(x =>
+ x.Phase == Phase.InputRegistration
+ && x.IsInputRegistrationEnded(Config.MaxInputCount, Config.InputRegistrationTimeout)))
+ {
+ round.Phase = Phase.ConnectionConfirmation;
+ }
+ }
+
private async Task CreateRoundsAsync()
{
if (!Rounds.Values.Any(x => !x.IsBlameRound && x.Phase == Phase.InputRegistration))
@@ -62,7 +74,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
private void TimeoutAlices()
{
- foreach (var round in Rounds.Values.Where(x => x.Phase == Phase.InputRegistration))
+ foreach (var round in Rounds.Values.Where(x => !x.IsInputRegistrationEnded(Config.MaxInputCount, Config.InputRegistrationTimeout)))
{
var removedAliceCount = round.RemoveAlices(x => x.Deadline < DateTimeOffset.UtcNow);
if (removedAliceCount > 0)
@@ -86,7 +98,9 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
zeroAmountCredentialRequests,
zeroWeightCredentialRequests,
Rounds,
- Network);
+ Network,
+ Config.MaxInputCount,
+ Config.InputRegistrationTimeout);
}
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
@@ -30,6 +30,8 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
Coinjoin = Transaction.Create(Network);
+ CreationTime = DateTimeOffset.UtcNow;
+
Hash = new(HashHelpers.GenerateSha256Hash($"{Id}{MaxInputCountByAlice}{MinRegistrableAmount}{MaxRegistrableAmount}{RegistrableWeightCredentials}{AmountCredentialIssuerParameters}{WeightCredentialIssuerParameters}{FeeRate.SatoshiPerByte}"));
}
@@ -43,6 +45,26 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
.ToHashSet();
}
+ public bool IsInputRegistrationEnded(uint maxInputCount, TimeSpan inputRegistrationTimeout)
+ {
+ if (Phase != Phase.InputRegistration)
+ {
+ return true;
+ }
+
+ if (Alices.Sum(x => x.Coins.Count()) >= maxInputCount)
+ {
+ return true;
+ }
+
+ if (CreationTime + inputRegistrationTimeout < DateTimeOffset.UtcNow)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
public uint256 Hash { get; }
public Network Network => RoundParameters.Network;
public uint MaxInputCountByAlice => RoundParameters.MaxInputCountByAlice;
@@ -67,7 +89,8 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
public ISet<OutPoint> BlameWhitelist { get; } = new HashSet<OutPoint>();
public byte[] UnsignedTxSecret { get; }
public Transaction Coinjoin { get; }
- public RoundParameters RoundParameters { get; }
+ public DateTimeOffset CreationTime { get; }
+ private RoundParameters RoundParameters { get; }
public int RemoveAlices(Predicate<Alice> match)
{

MODIFY
WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
@@ -65,6 +65,15 @@ namespace WalletWasabi.WabiSabi.Backend
[JsonProperty(PropertyName = "AllowNotedInputRegistration", DefaultValueHandling = DefaultValueHandling.Populate)]
public bool AllowNotedInputRegistration { get; set; } = true;
+ [DefaultValueTimeSpan("0d 1h 0m 0s")]
+ [JsonProperty(PropertyName = "InputRegistrationTimeout", DefaultValueHandling = DefaultValueHandling.Populate)]
+ [JsonConverter(typeof(TimeSpanJsonConverter))]
+ public TimeSpan InputRegistrationTimeout { get; set; } = TimeSpan.FromHours(1);
+
+ [DefaultValue(100)]
+ [JsonProperty(PropertyName = "MaxInputCount", DefaultValueHandling = DefaultValueHandling.Populate)]
+ public uint MaxInputCount { get; set; } = 100;
+
[DefaultValueTimeSpan("0d 0h 1m 0s")]
[JsonProperty(PropertyName = "ConnectionConfirmationTimeout", DefaultValueHandling = DefaultValueHandling.Populate)]
[JsonConverter(typeof(TimeSpanJsonConverter))]

Move phase to connection confirmation