Make sure input registration can be modified runtime.
MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/AliceTimeoutTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/AliceTimeoutTests.cs
@@ -77,7 +77,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
{
// Alice does not time out if input registration timed out,
// even though the deadline is reached and still in input reg.
- WabiSabiConfig cfg = new() { InputRegistrationTimeout = TimeSpan.Zero };
+ WabiSabiConfig cfg = new() { StandardInputRegistrationTimeout = TimeSpan.Zero };
var round = WabiSabiFactory.CreateRound(cfg);
var alice = WabiSabiFactory.CreateAlice();
round.Alices.Add(alice);

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RegisterInputTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/RegisterInputTests.cs
@@ -203,7 +203,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public async Task InputRegistrationTimedoutAsync()
{
- WabiSabiConfig cfg = new() { InputRegistrationTimeout = TimeSpan.Zero };
+ WabiSabiConfig cfg = new() { StandardInputRegistrationTimeout = TimeSpan.Zero };
var round = WabiSabiFactory.CreateRound(cfg);
using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg);
MockRpcClient rpc = new();
@@ -228,6 +228,35 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
await arena.StopAsync(CancellationToken.None);
}
+ [Fact]
+ public async Task InputRegistrationTimeoutCanBeModifiedRuntimeAsync()
+ {
+ WabiSabiConfig cfg = new() { StandardInputRegistrationTimeout = TimeSpan.FromHours(1) };
+
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg);
+ MockRpcClient rpc = new();
+ using Key key = new();
+
+ rpc.OnGetTxOutAsync = (_, _, _) => new()
+ {
+ Confirmations = 1,
+ ScriptPubKeyType = "witness_v0_keyhash",
+ TxOut = new TxOut(Money.Coins(1), key.PubKey.GetSegwitAddress(Network.Main))
+ };
+
+ await using PostRequestHandler handler = new(cfg, new Prison(), arena, rpc);
+ await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));
+ var round = arena.Rounds.First().Value;
+ var req = WabiSabiFactory.CreateInputsRegistrationRequest(key, round);
+
+ cfg.StandardInputRegistrationTimeout = TimeSpan.Zero;
+ var ex = await Assert.ThrowsAsync<WabiSabiProtocolException>(async () => await handler.RegisterInputAsync(req));
+ Assert.Equal(Phase.InputRegistration, round.Phase);
+ Assert.Equal(WabiSabiProtocolErrorCode.WrongPhase, ex.ErrorCode);
+
+ await arena.StopAsync(CancellationToken.None);
+ }
+
[Fact]
public async Task NonUniqueInputsAsync()
{

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/StepInputRegistrationTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/StepInputRegistrationTests.cs
@@ -95,7 +95,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
{
WabiSabiConfig cfg = new()
{
- InputRegistrationTimeout = TimeSpan.Zero,
+ StandardInputRegistrationTimeout = TimeSpan.Zero,
MaxInputCountByRound = 4,
MinInputCountByRoundMultiplier = 0.5
};
@@ -116,7 +116,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
WabiSabiConfig cfg = new()
{
BlameInputRegistrationTimeout = TimeSpan.Zero,
- InputRegistrationTimeout = TimeSpan.FromHours(1), // Test that this is disregarded.
+ StandardInputRegistrationTimeout = TimeSpan.FromHours(1), // Test that this is disregarded.
MaxInputCountByRound = 4,
MinInputCountByRoundMultiplier = 0.5
};
@@ -143,7 +143,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
{
WabiSabiConfig cfg = new()
{
- InputRegistrationTimeout = TimeSpan.Zero,
+ StandardInputRegistrationTimeout = TimeSpan.Zero,
MaxInputCountByRound = 4,
MinInputCountByRoundMultiplier = 0.5
};
@@ -167,7 +167,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
WabiSabiConfig cfg = new()
{
BlameInputRegistrationTimeout = TimeSpan.Zero,
- InputRegistrationTimeout = TimeSpan.FromHours(1), // Test that this is disregarded.
+ StandardInputRegistrationTimeout = TimeSpan.FromHours(1), // Test that this is disregarded.
MaxInputCountByRound = 4,
MinInputCountByRoundMultiplier = 0.5
};
@@ -186,5 +186,30 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
await arena.StopAsync(CancellationToken.None);
}
+
+ [Fact]
+ public async Task InputRegistrationTimeoutCanBeModifiedRuntimeAsync()
+ {
+ WabiSabiConfig cfg = new()
+ {
+ StandardInputRegistrationTimeout = TimeSpan.FromHours(1),
+ MaxInputCountByRound = 4,
+ MinInputCountByRoundMultiplier = 0.5
+ };
+ var round = WabiSabiFactory.CreateRound(cfg);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, round);
+
+ round.Alices.Add(WabiSabiFactory.CreateAlice());
+ round.Alices.Add(WabiSabiFactory.CreateAlice());
+ await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));
+ Assert.Equal(Phase.InputRegistration, round.Phase);
+
+ cfg.StandardInputRegistrationTimeout = TimeSpan.Zero;
+
+ await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));
+ Assert.Equal(Phase.ConnectionConfirmation, round.Phase);
+
+ await arena.StopAsync(CancellationToken.None);
+ }
}
}

MODIFY
WalletWasabi/WabiSabi/Backend/PostRequests/InputRegistrationHandler.cs
WalletWasabi/WabiSabi/Backend/PostRequests/InputRegistrationHandler.cs
@@ -64,13 +64,13 @@ namespace WalletWasabi.WabiSabi.Backend.PostRequests
}
public static InputsRegistrationResponse RegisterInput(
+ WabiSabiConfig config,
Guid roundId,
IDictionary<Coin, byte[]> coinRoundSignaturePairs,
ZeroCredentialsRequest zeroAmountCredentialRequests,
ZeroCredentialsRequest zeroWeightCredentialRequests,
IDictionary<Guid, Round> rounds,
- Network network,
- uint maxInputCountByRound)
+ Network network)
{
if (!rounds.TryGetValue(roundId, out var round))
{
@@ -120,7 +120,7 @@ namespace WalletWasabi.WabiSabi.Backend.PostRequests
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchWeight);
}
- if (round.IsInputRegistrationEnded(maxInputCountByRound))
+ if (round.IsInputRegistrationEnded(config.MaxInputCountByRound, config.GetInputRegistrationTimeout(round)))
{
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
@@ -65,7 +65,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
{
foreach (var round in Rounds.Values.Where(x =>
x.Phase == Phase.InputRegistration
- && x.IsInputRegistrationEnded(Config.MaxInputCountByRound)))
+ && x.IsInputRegistrationEnded(Config.MaxInputCountByRound, Config.GetInputRegistrationTimeout(x))))
{
if (round.InputCount < Config.MinInputCountByRound)
{
@@ -235,7 +235,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
private void TimeoutAlices()
{
- foreach (var round in Rounds.Values.Where(x => !x.IsInputRegistrationEnded(Config.MaxInputCountByRound)))
+ foreach (var round in Rounds.Values.Where(x => !x.IsInputRegistrationEnded(Config.MaxInputCountByRound, Config.GetInputRegistrationTimeout(x))))
{
var removedAliceCount = round.Alices.RemoveAll(x => x.Deadline < DateTimeOffset.UtcNow);
if (removedAliceCount > 0)
@@ -279,13 +279,13 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
using (await AsyncLock.LockAsync().ConfigureAwait(false))
{
return InputRegistrationHandler.RegisterInput(
+ Config,
roundId,
coinRoundSignaturePairs,
zeroAmountCredentialRequests,
zeroWeightCredentialRequests,
Rounds,
- Network,
- Config.MaxInputCountByRound);
+ Network);
}
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
@@ -54,7 +54,6 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
public bool IsBlameRound => RoundParameters.IsBlameRound;
public ISet<OutPoint> BlameWhitelist => RoundParameters.BlameWhitelist;
- public TimeSpan InputRegistrationTimeout => RoundParameters.InputRegistrationTimeout;
public TimeSpan ConnectionConfirmationTimeout => RoundParameters.ConnectionConfirmationTimeout;
public TimeSpan OutputRegistrationTimeout => RoundParameters.OutputRegistrationTimeout;
public TimeSpan TransactionSigningTimeout => RoundParameters.TransactionSigningTimeout;
@@ -91,7 +90,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
}
}
- public bool IsInputRegistrationEnded(uint maxInputCount)
+ public bool IsInputRegistrationEnded(uint maxInputCount, TimeSpan inputRegistrationTimeout)
{
if (Phase > Phase.InputRegistration)
{
@@ -110,7 +109,7 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
return true;
}
- if (InputRegistrationStart + InputRegistrationTimeout < DateTimeOffset.UtcNow)
+ if (InputRegistrationStart + inputRegistrationTimeout < DateTimeOffset.UtcNow)
{
return true;
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/RoundParameters.cs
WalletWasabi/WabiSabi/Backend/Rounds/RoundParameters.cs
@@ -26,6 +26,11 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
MaxRegistrableAmount = wabiSabiConfig.MaxRegistrableAmount;
RegistrableWeightCredentials = wabiSabiConfig.RegistrableWeightCredentials;
+ // Note that input registration timeouts can be modified runtime.
+ ConnectionConfirmationTimeout = wabiSabiConfig.ConnectionConfirmationTimeout;
+ OutputRegistrationTimeout = wabiSabiConfig.OutputRegistrationTimeout;
+ TransactionSigningTimeout = wabiSabiConfig.TransactionSigningTimeout;
+
BlameOf = blameOf;
IsBlameRound = BlameOf is not null;
BlameWhitelist = BlameOf
@@ -34,11 +39,6 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
.Select(x => x.Outpoint)
.ToHashSet()
?? new HashSet<OutPoint>();
-
- InputRegistrationTimeout = IsBlameRound ? wabiSabiConfig.BlameInputRegistrationTimeout : wabiSabiConfig.InputRegistrationTimeout;
- ConnectionConfirmationTimeout = wabiSabiConfig.ConnectionConfirmationTimeout;
- OutputRegistrationTimeout = wabiSabiConfig.OutputRegistrationTimeout;
- TransactionSigningTimeout = wabiSabiConfig.TransactionSigningTimeout;
}
public WasabiRandom Random { get; }
@@ -51,7 +51,6 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
public Round? BlameOf { get; }
public bool IsBlameRound { get; }
public ISet<OutPoint> BlameWhitelist { get; }
- public TimeSpan InputRegistrationTimeout { get; }
public TimeSpan ConnectionConfirmationTimeout { get; }
public TimeSpan OutputRegistrationTimeout { get; }
public TimeSpan TransactionSigningTimeout { get; }

MODIFY
WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
@@ -11,6 +11,7 @@ using WalletWasabi.Helpers;
using WalletWasabi.JsonConverters.Bitcoin;
using WalletWasabi.JsonConverters.Collections;
using WalletWasabi.JsonConverters.Timing;
+using WalletWasabi.WabiSabi.Backend.Rounds;
namespace WalletWasabi.WabiSabi.Backend
{
@@ -66,15 +67,18 @@ namespace WalletWasabi.WabiSabi.Backend
public bool AllowNotedInputRegistration { get; set; } = true;
[DefaultValueTimeSpan("0d 1h 0m 0s")]
- [JsonProperty(PropertyName = "InputRegistrationTimeout", DefaultValueHandling = DefaultValueHandling.Populate)]
+ [JsonProperty(PropertyName = "StandardInputRegistrationTimeout", DefaultValueHandling = DefaultValueHandling.Populate)]
[JsonConverter(typeof(TimeSpanJsonConverter))]
- public TimeSpan InputRegistrationTimeout { get; set; } = TimeSpan.FromHours(1);
+ public TimeSpan StandardInputRegistrationTimeout { get; set; } = TimeSpan.FromHours(1);
[DefaultValueTimeSpan("0d 0h 3m 0s")]
[JsonProperty(PropertyName = "BlameInputRegistrationTimeout", DefaultValueHandling = DefaultValueHandling.Populate)]
[JsonConverter(typeof(TimeSpanJsonConverter))]
public TimeSpan BlameInputRegistrationTimeout { get; set; } = TimeSpan.FromMinutes(3);
+ public TimeSpan GetInputRegistrationTimeout(Round round)
+ => round.IsBlameRound ? BlameInputRegistrationTimeout : StandardInputRegistrationTimeout;
+
[DefaultValueTimeSpan("0d 0h 1m 0s")]
[JsonProperty(PropertyName = "ConnectionConfirmationTimeout", DefaultValueHandling = DefaultValueHandling.Populate)]
[JsonConverter(typeof(TimeSpanJsonConverter))]

Make sure input registration can be modified runtime.