Gracefully recover on client side
MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -162,7 +162,7 @@ public class CoinJoinClient
roundState = await RoundStatusUpdater.CreateRoundAwaiter(roundState.Id, Phase.OutputRegistration, cancellationToken).ConfigureAwait(false);
Logger.LogDebug($"Round ({roundState.Id}): Output registration phase started.");
- await scheduler.StartOutputRegistrationsAsync(outputTxOuts, bobClient, cancellationToken).ConfigureAwait(false);
+ await scheduler.StartOutputRegistrationsAsync(outputTxOuts, bobClient, KeyChain, cancellationToken).ConfigureAwait(false);
Logger.LogDebug($"Round ({roundState.Id}): Outputs({outputTxOuts.Count()}) successfully registered.");
// ReadyToSign.

MODIFY
WalletWasabi/WabiSabi/Client/DependencyGraphTaskScheduler.cs
WalletWasabi/WabiSabi/Client/DependencyGraphTaskScheduler.cs
@@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Blockchain.Keys;
using WalletWasabi.Crypto.ZeroKnowledge;
+using WalletWasabi.WabiSabi.Backend.Models;
using WalletWasabi.WabiSabi.Client.CredentialDependencies;
namespace WalletWasabi.WabiSabi.Client;
@@ -139,7 +141,7 @@ public class DependencyGraphTaskScheduler
}
}
- public async Task StartOutputRegistrationsAsync(IEnumerable<TxOut> txOuts, BobClient bobClient, CancellationToken cancellationToken)
+ public async Task StartOutputRegistrationsAsync(IEnumerable<TxOut> txOuts, BobClient bobClient, IKeyChain keyChain, CancellationToken cancellationToken)
{
List<Task> outputTasks = new();
@@ -163,8 +165,16 @@ public class DependencyGraphTaskScheduler
{
if (t.IsFaulted && t.Exception is { } exception)
{
- // If one task is failing, cancel all the tasks and throw.
- ctsOnError.Cancel();
+ if (exception.InnerExceptions.Select(e => e.InnerException).Any(x => x is WabiSabiProtocolException wabisabiexc
+ && wabisabiexc.ErrorCode == WabiSabiProtocolErrorCode.AlreadyRegisteredScript))
+ {
+ if (keyChain is KeyChain { KeyManager: var keyManager }
+ && keyManager.TryGetKeyForScriptPubKey(txOut.ScriptPubKey, out var hdPubKey))
+ {
+ hdPubKey.SetKeyState(KeyState.Used);
+ }
+ }
+
throw exception;
}
}, linkedCts.Token);

MODIFY
WalletWasabi/WabiSabi/Client/KeyChain.cs
WalletWasabi/WabiSabi/Client/KeyChain.cs
@@ -18,7 +18,7 @@ public class KeyChain : IKeyChain
Kitchen = kitchen;
}
- private KeyManager KeyManager { get; }
+ public KeyManager KeyManager { get; }
private Kitchen Kitchen { get; }
public OwnershipProof GetOwnershipProof(IDestination destination, CoinJoinInputCommitmentData commitmentData)

Gracefully recover on client side