Make `AliceClient` aware of `SmartCoin`
MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/AliceTimeoutTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/AliceTimeoutTests.cs
using NBitcoin;
using System;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Blockchain.Analysis.Clustering;
+using WalletWasabi.Blockchain.Keys;
using WalletWasabi.Tests.Helpers;
using WalletWasabi.WabiSabi.Backend;
using WalletWasabi.WabiSabi.Backend.Banning;
@@ -21,9 +24,10 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
// Alice times out when its deadline is reached.
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
- using Key key = new();
- var coin = WabiSabiFactory.CreateCoin(key);
- var rpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin);
+ var km = ServiceFactory.CreateKeyManager("");
+ var key = BitcoinFactory.CreateHdPubKey(km);
+ var smartCoin = BitcoinFactory.CreateSmartCoin(key, 10m);
+ var rpc = WabiSabiFactory.CreatePreconfiguredRpcClient(smartCoin.Coin);
using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, rpc, round);
var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
@@ -32,7 +36,8 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
await roundStateUpdater.StartAsync(CancellationToken.None);
// Register Alices.
- var aliceClient = new AliceClient(RoundState.FromRound(round), arenaClient, coin, key.GetBitcoinSecret(round.Network));
+ var esk = km.GetSecrets("", smartCoin.ScriptPubKey).Single();
+ var aliceClient = new AliceClient(RoundState.FromRound(round), arenaClient, smartCoin, esk.PrivateKey.GetBitcoinSecret(round.Network));
using CancellationTokenSource cancellationTokenSource = new();
var task = aliceClient.RegisterAndConfirmInputAsync(roundStateUpdater, cancellationTokenSource.Token);

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs
@@ -3,6 +3,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Helpers;
using WalletWasabi.Tests.Helpers;
using WalletWasabi.WabiSabi;
@@ -25,12 +26,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MaxInputCountByRound = 2,
MinInputCountByRoundMultiplier = 0.5
};
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, mockRpc);
var (round, arenaClient, alices) = await CreateRoundWithTwoConfirmedConnectionsAsync(arena, key1, coin1, key2, coin2);
var (amountCredentials1, vsizeCredentials1) = (alices[0].IssuedAmountCredentials, alices[0].IssuedVsizeCredentials);
@@ -75,12 +73,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MinInputCountByRoundMultiplier = 0.5,
OutputRegistrationTimeout = TimeSpan.Zero
};
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, mockRpc);
var (round, arenaClient, alices) = await CreateRoundWithTwoConfirmedConnectionsAsync(arena, key1, coin1, key2, coin2);
var (amountCredentials1, vsizeCredentials1) = (alices[0].IssuedAmountCredentials, alices[0].IssuedVsizeCredentials);
@@ -114,12 +109,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MinInputCountByRoundMultiplier = 0.5,
OutputRegistrationTimeout = TimeSpan.Zero
};
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, mockRpc);
var (round, arenaClient, alices) = await CreateRoundWithTwoConfirmedConnectionsAsync(arena, key1, coin1, key2, coin2);
var (amountCredentials1, vsizeCredentials1) = (alices[0].IssuedAmountCredentials, alices[0].IssuedVsizeCredentials);
@@ -167,12 +159,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MaxInputCountByRound = 2,
MinInputCountByRoundMultiplier = 0.5
};
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, mockRpc);
var (round, arenaClient, alices) = await CreateRoundWithTwoConfirmedConnectionsAsync(arena, key1, coin1, key2, coin2);
var (amountCredentials1, vsizeCredentials1) = (alices[0].IssuedAmountCredentials, alices[0].IssuedVsizeCredentials);
@@ -194,7 +183,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
}
private async Task<(Round Round, ArenaClient ArenaClient, AliceClient[] alices)>
- CreateRoundWithTwoConfirmedConnectionsAsync(Arena arena, Key key1, Coin coin1, Key key2, Coin coin2)
+ CreateRoundWithTwoConfirmedConnectionsAsync(Arena arena, Key key1, SmartCoin coin1, Key key2, SmartCoin coin2)
{
// Create the round.
await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Tests.Helpers;
using WalletWasabi.WabiSabi;
using WalletWasabi.WabiSabi.Backend;
@@ -27,12 +28,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MaxInputCountByRound = 2,
MinInputCountByRoundMultiplier = 0.5
};
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, mockRpc);
var (round, aliceClient1, aliceClient2) = await CreateRoundWithOutputsReadyToSignAsync(arena, key1, coin1, key2, coin2);
@@ -61,12 +59,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MaxInputCountByRound = 2,
MinInputCountByRoundMultiplier = 0.5
};
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
mockRpc.Setup(rpc => rpc.SendRawTransactionAsync(It.IsAny<Transaction>()))
.ThrowsAsync(new RPCException(RPCErrorCode.RPC_TRANSACTION_REJECTED, "", null));
@@ -101,12 +96,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MinInputCountByRoundMultiplier = 0.5
};
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
mockRpc.Setup(rpc => rpc.SendRawTransactionAsync(It.IsAny<Transaction>()))
.ThrowsAsync(new RPCException(RPCErrorCode.RPC_TRANSACTION_REJECTED, "", null));
@@ -145,13 +137,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
MinInputCountByRoundMultiplier = 1,
TransactionSigningTimeout = TimeSpan.Zero
};
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
-
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
mockRpc.Setup(rpc => rpc.SendRawTransactionAsync(It.IsAny<Transaction>()))
.ThrowsAsync(new RPCException(RPCErrorCode.RPC_TRANSACTION_REJECTED, "", null));
@@ -171,7 +159,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
Assert.Equal(Phase.Ended, round.Phase);
Assert.False(round.WasTransactionBroadcast);
Assert.Empty(arena.Rounds.Where(x => x.IsBlameRound));
- Assert.Contains(aliceClient2.Coin.Outpoint, arena.Prison.GetInmates().Select(x => x.Utxo));
+ Assert.Contains(aliceClient2.SmartCoin.OutPoint, arena.Prison.GetInmates().Select(x => x.Utxo));
await arena.StopAsync(CancellationToken.None);
}
@@ -186,13 +174,9 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
TransactionSigningTimeout = TimeSpan.Zero,
OutputRegistrationTimeout = TimeSpan.Zero
};
+ var (key1, coin1, key2, coin2) = WabiSabiFactory.CreateCoinKeyPairs();
- using Key key1 = new();
- using Key key2 = new();
- var coin1 = WabiSabiFactory.CreateCoin(key1);
- var coin2 = WabiSabiFactory.CreateCoin(key2);
-
- var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1, coin2);
+ var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin, coin2.Coin);
mockRpc.Setup(rpc => rpc.SendRawTransactionAsync(It.IsAny<Transaction>()))
.ThrowsAsync(new RPCException(RPCErrorCode.RPC_TRANSACTION_REJECTED, "", null));
@@ -222,15 +206,15 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PhaseStepping
Assert.Equal(round.Id, blameRound.BlameOf?.Id);
var whitelist = blameRound.BlameWhitelist;
- Assert.Contains(aliceClient1.Coin.Outpoint, whitelist);
- Assert.Contains(aliceClient2.Coin.Outpoint, whitelist);
+ Assert.Contains(aliceClient1.SmartCoin.OutPoint, whitelist);
+ Assert.Contains(aliceClient2.SmartCoin.OutPoint, whitelist);
Assert.DoesNotContain(badOutpoint, whitelist);
await arena.StopAsync(CancellationToken.None);
}
private async Task<(Round Round, AliceClient AliceClient1, AliceClient AliceClient2)>
- CreateRoundWithOutputsReadyToSignAsync(Arena arena, Key key1, Coin coin1, Key key2, Coin coin2)
+ CreateRoundWithOutputsReadyToSignAsync(Arena arena, Key key1, SmartCoin coin1, Key key2, SmartCoin coin2)
{
// Create the round.
await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs
@@ -49,7 +49,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Client
var bitcoinSecret = km.GetSecrets("", coin1.ScriptPubKey).Single().PrivateKey.GetBitcoinSecret(Network.Main);
- var aliceClient = new AliceClient(RoundState.FromRound(round), aliceArenaClient, coin1.Coin, bitcoinSecret);
+ var aliceClient = new AliceClient(RoundState.FromRound(round), aliceArenaClient, coin1, bitcoinSecret);
using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), wabiSabiApi);
await roundStateUpdater.StartAsync(CancellationToken.None);

MODIFY
WalletWasabi/WabiSabi/Client/AliceClient.cs
WalletWasabi/WabiSabi/Client/AliceClient.cs
@@ -9,17 +9,18 @@ using WalletWasabi.Logging;
using WalletWasabi.WabiSabi.Backend.Models;
using WalletWasabi.WabiSabi.Backend.Rounds;
using WalletWasabi.WabiSabi.Models;
+using WalletWasabi.Blockchain.TransactionOutputs;
namespace WalletWasabi.WabiSabi.Client
{
public class AliceClient
{
- public AliceClient(RoundState roundState, ArenaClient arenaClient, Coin coin, BitcoinSecret bitcoinSecret)
+ public AliceClient(RoundState roundState, ArenaClient arenaClient, SmartCoin coin, BitcoinSecret bitcoinSecret)
{
- AliceId = CalculateHash(coin, bitcoinSecret, roundState.Id);
+ AliceId = CalculateHash(coin.Coin, bitcoinSecret, roundState.Id);
RoundId = roundState.Id;
ArenaClient = arenaClient;
- Coin = coin;
+ SmartCoin = coin;
FeeRate = roundState.FeeRate;
BitcoinSecret = bitcoinSecret;
IssuedAmountCredentials = Array.Empty<Credential>();
@@ -31,7 +32,7 @@ namespace WalletWasabi.WabiSabi.Client
public uint256 AliceId { get; }
public uint256 RoundId { get; }
private ArenaClient ArenaClient { get; }
- public Coin Coin { get; }
+ public SmartCoin SmartCoin { get; }
private FeeRate FeeRate { get; }
private BitcoinSecret BitcoinSecret { get; }
public IEnumerable<Credential> IssuedAmountCredentials { get; private set; }
@@ -41,18 +42,64 @@ namespace WalletWasabi.WabiSabi.Client
public async Task RegisterAndConfirmInputAsync(RoundStateUpdater roundStatusUpdater, CancellationToken cancellationToken)
{
- var response = await ArenaClient.RegisterInputAsync(RoundId, Coin.Outpoint, BitcoinSecret.PrivateKey, cancellationToken).ConfigureAwait(false);
+ await RegisterInputAsync(cancellationToken).ConfigureAwait(false);
+ await ConfirmConnectionAsync(roundStatusUpdater, cancellationToken).ConfigureAwait(false);
+ }
+
+ private async Task RegisterInputAsync(CancellationToken cancellationToken)
+ {
+ try
+ {
+ var response = await ArenaClient.RegisterInputAsync(RoundId, SmartCoin.Coin.Outpoint, BitcoinSecret.PrivateKey, cancellationToken).ConfigureAwait(false);
var remoteAliceId = response.Value;
if (AliceId != remoteAliceId)
{
throw new InvalidOperationException($"Round ({RoundId}), Local Alice ({AliceId}) was computed as {remoteAliceId}");
}
+ SmartCoin.CoinJoinInProgress = true;
+
IssuedAmountCredentials = response.IssuedAmountCredentials;
IssuedVsizeCredentials = response.IssuedVsizeCredentials;
Logger.LogInfo($"Round ({RoundId}), Alice ({AliceId}): Registered an input.");
+ }
+ catch (System.Net.Http.HttpRequestException ex)
+ {
+ if (ex.InnerException is not WabiSabiProtocolException wpe)
+ {
+ Logger.LogInfo($"{SmartCoin.Coin.Outpoint} registration failed with {ex}.");
+ throw;
+ }
+
+ switch (wpe.ErrorCode)
+ {
+ case WabiSabiProtocolErrorCode.InputSpent:
+ SmartCoin.SpentAccordingToBackend = true;
+ Logger.LogInfo($"{SmartCoin.Coin.Outpoint} is spent according to the backend. The wallet is not fully synchronized or corrupted.");
+ break;
+
+ case WabiSabiProtocolErrorCode.InputBanned:
+ SmartCoin.BannedUntilUtc = DateTimeOffset.UtcNow.AddDays(1);
+ SmartCoin.SetIsBanned();
+ Logger.LogInfo($"{SmartCoin.Coin.Outpoint} is banned.");
+ break;
+
+ case WabiSabiProtocolErrorCode.InputNotWhitelisted:
+ SmartCoin.SpentAccordingToBackend = false;
+ Logger.LogInfo($"{SmartCoin.Coin.Outpoint} cannot be registered in the blame round.");
+ break;
+
+ case WabiSabiProtocolErrorCode.AliceAlreadyRegistered:
+ Logger.LogInfo($"{SmartCoin.Coin.Outpoint} was already registered.");
+ break;
+ }
+ throw;
+ }
+ }
- long[] amountsToRequest = { Coin.EffectiveValue(FeeRate).Satoshi };
- long[] vsizesToRequest = { MaxVsizeAllocationPerAlice - Coin.ScriptPubKey.EstimateInputVsize() };
+ private async Task ConfirmConnectionAsync(RoundStateUpdater roundStatusUpdater, CancellationToken cancellationToken)
+ {
+ long[] amountsToRequest = { SmartCoin.EffectiveValue(FeeRate).Satoshi };
+ long[] vsizesToRequest = { MaxVsizeAllocationPerAlice - SmartCoin.ScriptPubKey.EstimateInputVsize() };
do
{
@@ -113,7 +160,7 @@ namespace WalletWasabi.WabiSabi.Client
public async Task SignTransactionAsync(Transaction unsignedCoinJoin, CancellationToken cancellationToken)
{
- await ArenaClient.SignTransactionAsync(RoundId, Coin, BitcoinSecret, unsignedCoinJoin, cancellationToken).ConfigureAwait(false);
+ await ArenaClient.SignTransactionAsync(RoundId, SmartCoin.Coin, BitcoinSecret, unsignedCoinJoin, cancellationToken).ConfigureAwait(false);
Logger.LogInfo($"Round ({RoundId}), Alice ({AliceId}): Posted a signature.");
}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -79,7 +79,7 @@ namespace WalletWasabi.WabiSabi.Client
var constructionState = roundState.Assert<ConstructionState>();
var coinCandidates = SelectCoinsForRound(smartCoins, constructionState.Parameters);
- var aliceClientsToRegister = coinCandidates.Select(x => (SmartCoin: x, AliceClient: CreateAliceClient(x.Coin, roundState))).ToImmutableArray();
+ var aliceClientsToRegister = coinCandidates.Select(x => CreateAliceClient(x, roundState)).ToImmutableArray();
// Register coins.
var registeredAliceClients = await RegisterAndConfirmCoinsAsync(aliceClientsToRegister, cancellationToken).ConfigureAwait(false);
@@ -89,8 +89,7 @@ namespace WalletWasabi.WabiSabi.Client
}
// Calculate outputs values
- var registeredCoins = registeredAliceClients.Select(x => x.Coin);
-
+ var registeredCoins = registeredAliceClients.Select(x => x.SmartCoin.Coin);
var availableVsize = registeredAliceClients.SelectMany(x => x.IssuedVsizeCredentials).Sum(x => x.Value);
var outputValues = DecomposeAmounts(registeredCoins, roundState.FeeRate, constructionState.Parameters.AllowedOutputAmounts.Min, (int)availableVsize);
@@ -131,7 +130,7 @@ namespace WalletWasabi.WabiSabi.Client
return finalRoundState.WasTransactionBroadcast;
}
- private AliceClient CreateAliceClient(Coin coin, RoundState roundState)
+ private AliceClient CreateAliceClient(SmartCoin coin, RoundState roundState)
{
var aliceArenaClient = new ArenaClient(
roundState.CreateAmountCredentialClient(SecureRandom),
@@ -148,52 +147,22 @@ namespace WalletWasabi.WabiSabi.Client
}
private async Task<ImmutableArray<AliceClient>> RegisterAndConfirmCoinsAsync(
- IEnumerable<(SmartCoin SmartCoin, AliceClient AliceClient)> aliceClients, CancellationToken cancellationToken)
+ IEnumerable<AliceClient> aliceClients, CancellationToken cancellationToken)
{
- async Task<AliceClient?> RegisterInputTask(SmartCoin smartCoin, AliceClient aliceClient)
+ async Task<AliceClient?> RegisterInputTask(AliceClient aliceClient)
{
try
{
await aliceClient.RegisterAndConfirmInputAsync(RoundStatusUpdater, cancellationToken).ConfigureAwait(false);
- smartCoin.CoinJoinInProgress = true;
return aliceClient;
}
catch (System.Net.Http.HttpRequestException ex)
{
- if (ex.InnerException is WabiSabiProtocolException wpe)
- {
- switch (wpe.ErrorCode)
- {
- case WabiSabiProtocolErrorCode.InputSpent:
- smartCoin.SpentAccordingToBackend = true;
- Logger.LogInfo($"{smartCoin.Coin.Outpoint} is spent according to the backend. The wallet is not fully synchronized or corrupted.");
- break;
-
- case WabiSabiProtocolErrorCode.InputBanned:
- smartCoin.BannedUntilUtc = DateTimeOffset.UtcNow.AddDays(1);
- smartCoin.SetIsBanned();
- Logger.LogInfo($"{smartCoin.Coin.Outpoint} is banned.");
- break;
-
- case WabiSabiProtocolErrorCode.InputNotWhitelisted:
- smartCoin.SpentAccordingToBackend = false;
- Logger.LogInfo($"{smartCoin.Coin.Outpoint} cannot be registered in the blame round.");
- break;
-
- case WabiSabiProtocolErrorCode.AliceAlreadyRegistered:
- Logger.LogInfo($"{smartCoin.Coin.Outpoint} was already registered.");
- return aliceClient;
-
- case WabiSabiProtocolErrorCode.WrongPhase:
- return null; // The coin didn't get it and arrived too late to the party.
- }
- }
- Logger.LogInfo($"{smartCoin.Coin.Outpoint} registration failed with {ex}.");
return null;
}
}
- var registerRequests = aliceClients.Select(x => RegisterInputTask(x.SmartCoin, x.AliceClient)).ToImmutableArray();
+ var registerRequests = aliceClients.Select(RegisterInputTask).ToImmutableArray();
await Task.WhenAll(registerRequests).ConfigureAwait(false);
return registerRequests

Make `AliceClient` aware of `SmartCoin`