Wire up CoinJoinIdStore
MODIFY
WalletWasabi.Backend/Global.cs
WalletWasabi.Backend/Global.cs
@@ -14,6 +14,7 @@ using WalletWasabi.Helpers;
using WalletWasabi.Logging;
using WalletWasabi.Services;
using WalletWasabi.WabiSabi;
+using WalletWasabi.WabiSabi.Backend.Rounds.CoinJoinStorage;
namespace WalletWasabi.Backend;
@@ -42,6 +43,7 @@ public class Global : IDisposable
public Config Config { get; private set; }
public CoordinatorRoundConfig RoundConfig { get; private set; }
+ public CoinJoinIdStore CoinJoinIdStore { get; private set; }
public async Task InitializeAsync(Config config, CoordinatorRoundConfig roundConfig, IRPCClient rpc, CancellationToken cancel)
{
@@ -57,9 +59,6 @@ public class Global : IDisposable
HostedServices.Register<MempoolMirror>(() => new MempoolMirror(TimeSpan.FromSeconds(21), RpcClient, P2pNode), "Full Node Mempool Mirror");
- CoordinatorParameters coordinatorParameters = new(DataDir);
- HostedServices.Register<WabiSabiCoordinator>(() => new WabiSabiCoordinator(coordinatorParameters, RpcClient), "WabiSabi Coordinator");
-
if (roundConfig.FilePath is { })
{
HostedServices.Register<ConfigWatcher>(() =>
@@ -86,7 +85,15 @@ public class Global : IDisposable
var indexBuilderServiceDir = Path.Combine(DataDir, "IndexBuilderService");
var indexFilePath = Path.Combine(indexBuilderServiceDir, $"Index{RpcClient.Network}.dat");
var blockNotifier = HostedServices.Get<BlockNotifier>();
+
+ CoordinatorParameters coordinatorParameters = new(DataDir);
Coordinator = new(RpcClient.Network, blockNotifier, Path.Combine(DataDir, "CcjCoordinator"), RpcClient, roundConfig);
+ Coordinator.CoinJoinBroadcasted += Coordinator_CoinJoinBroadcasted;
+
+ CoinJoinIdStore = new(coordinatorParameters.CoinJoinIdStoreFilePath);
+ CoinJoinIdStore.InMemoryCoinJoinIdStore.ImportWW1CoinJoinsToWW2(Coordinator.CoinJoinsFilePath, coordinatorParameters.CoinJoinIdStoreFilePath);
+
+ HostedServices.Register<WabiSabiCoordinator>(() => new WabiSabiCoordinator(coordinatorParameters, RpcClient, CoinJoinIdStore), "WabiSabi Coordinator");
HostedServices.Register<RoundBootstrapper>(() => new RoundBootstrapper(TimeSpan.FromMilliseconds(100), Coordinator), "Round Bootstrapper");
await HostedServices.StartAllAsync(cancel);
@@ -96,6 +103,11 @@ public class Global : IDisposable
Logger.LogInfo($"{nameof(IndexBuilderService)} is successfully initialized and started synchronization.");
}
+ private void Coordinator_CoinJoinBroadcasted(object? sender, Transaction transaction)
+ {
+ CoinJoinIdStore.Append(transaction.GetHash());
+ }
+
private async Task InitializeP2pAsync(Network network, EndPoint endPoint, CancellationToken cancel)
{
Guard.NotNull(nameof(network), network);
@@ -165,6 +177,8 @@ public class Global : IDisposable
{
if (disposing)
{
+ Coordinator.CoinJoinBroadcasted -= Coordinator_CoinJoinBroadcasted;
+
if (Coordinator is { } coordinator)
{
coordinator.Dispose();

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.Partial.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.Partial.cs
@@ -73,14 +73,14 @@ public partial class Arena : IWabiSabiApiRequestHandler
// only that the probability of duplicates is very low).
var id = new Guid(Random.GetBytes(16));
- var isPayingZeroCoordinationFee = InMemoryCoinJoinIdStore.Contains(coin.Outpoint.Hash);
+ var isPayingZeroCoordinationFee = CoinJoinIdStore.Contains(coin.Outpoint.Hash);
if (!isPayingZeroCoordinationFee)
{
// If the coin comes from a tx that all of the tx inputs are coming from a CJ (1 hop - no pay).
Transaction tx = await Rpc.GetRawTransactionAsync(coin.Outpoint.Hash, true, cancellationToken).ConfigureAwait(false);
- if (tx.Inputs.All(input => InMemoryCoinJoinIdStore.Contains(input.PrevOut.Hash)))
+ if (tx.Inputs.All(input => CoinJoinIdStore.Contains(input.PrevOut.Hash)))
{
isPayingZeroCoordinationFee = true;
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
@@ -25,7 +25,7 @@ public partial class Arena : PeriodicRunner
WabiSabiConfig config,
IRPCClient rpc,
Prison prison,
- InMemoryCoinJoinIdStore inMemoryCoinJoinIdStore,
+ ICoinJoinIdStore coinJoinIdStore,
CoinJoinTransactionArchiver? archiver = null,
CoinJoinScriptStore? coinJoinScriptStore = null) : base(period)
{
@@ -35,7 +35,7 @@ public partial class Arena : PeriodicRunner
Prison = prison;
TransactionArchiver = archiver;
Random = new SecureRandom();
- InMemoryCoinJoinIdStore = inMemoryCoinJoinIdStore;
+ CoinJoinIdStore = coinJoinIdStore;
CoinJoinScriptStore = coinJoinScriptStore;
}
@@ -48,7 +48,7 @@ public partial class Arena : PeriodicRunner
private SecureRandom Random { get; }
private CoinJoinTransactionArchiver? TransactionArchiver { get; }
public CoinJoinScriptStore? CoinJoinScriptStore { get; }
- private InMemoryCoinJoinIdStore InMemoryCoinJoinIdStore { get; }
+ public ICoinJoinIdStore CoinJoinIdStore { get; private set; }
public event EventHandler<Transaction>? CoinJoinBroadcast;
@@ -265,7 +265,6 @@ public partial class Arena : PeriodicRunner
round.SetPhase(Phase.Ended);
round.LogInfo($"Successfully broadcast the CoinJoin: {coinjoin.GetHash()}.");
- InMemoryCoinJoinIdStore.Add(coinjoin.GetHash());
CoinJoinScriptStore?.AddRange(coinjoin.Outputs.Select(x => x.ScriptPubKey));
CoinJoinBroadcast?.Invoke(this, coinjoin);
}

MODIFY
WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
@@ -17,21 +17,19 @@ namespace WalletWasabi.WabiSabi;
public class WabiSabiCoordinator : BackgroundService
{
- public WabiSabiCoordinator(CoordinatorParameters parameters, IRPCClient rpc)
+ public WabiSabiCoordinator(CoordinatorParameters parameters, IRPCClient rpc, ICoinJoinIdStore coinJoinIdStore)
{
Parameters = parameters;
Warden = new(parameters.UtxoWardenPeriod, parameters.PrisonFilePath, Config);
ConfigWatcher = new(parameters.ConfigChangeMonitoringPeriod, Config, () => Logger.LogInfo("WabiSabi configuration has changed."));
-
+ CoinJoinIdStore = coinJoinIdStore;
CoinJoinTransactionArchiver transactionArchiver = new(Path.Combine(parameters.CoordinatorDataDir, "CoinJoinTransactions"));
CoinJoinFeeRateStatStore = CoinJoinFeeRateStatStore.LoadFromFile(parameters.CoinJoinFeeRateStatStoreFilePath, Config, rpc);
IoHelpers.EnsureContainingDirectoryExists(Parameters.CoinJoinFeeRateStatStoreFilePath);
CoinJoinFeeRateStatStore.NewStat += FeeRateStatStore_NewStat;
- var inMemoryCoinJoinIdStore = InMemoryCoinJoinIdStore.LoadFromFile(parameters.CoinJoinIdStoreFilePath);
-
var coinJoinScriptStore = CoinJoinScriptStore.LoadFromFile(parameters.CoinJoinScriptStoreFilePath);
IoHelpers.EnsureContainingDirectoryExists(Parameters.CoinJoinScriptStoreFilePath);
@@ -41,7 +39,7 @@ public class WabiSabiCoordinator : BackgroundService
Config,
rpc,
Warden.Prison,
- inMemoryCoinJoinIdStore,
+ coinJoinIdStore,
transactionArchiver,
coinJoinScriptStore);
@@ -50,6 +48,7 @@ public class WabiSabiCoordinator : BackgroundService
}
public ConfigWatcher ConfigWatcher { get; }
+ public ICoinJoinIdStore CoinJoinIdStore { get; private set; }
public Warden Warden { get; }
public CoordinatorParameters Parameters { get; }
@@ -59,22 +58,14 @@ public class WabiSabiCoordinator : BackgroundService
public WabiSabiConfig Config => Parameters.RuntimeCoordinatorConfig;
- private void Arena_CoinJoinBroadcast(object? sender, Transaction e)
- {
- var coinJoinIdStoreFilePath = Parameters.CoinJoinIdStoreFilePath;
- try
+ private void Arena_CoinJoinBroadcast(object? sender, Transaction transaction)
{
- File.AppendAllLines(coinJoinIdStoreFilePath, new[] { e.GetHash().ToString() });
- }
- catch (Exception ex)
- {
- Logger.LogError($"Could not write file {coinJoinIdStoreFilePath}.", ex);
- }
+ CoinJoinIdStore.Append(transaction.GetHash());
var coinJoinScriptStoreFilePath = Parameters.CoinJoinScriptStoreFilePath;
try
{
- File.AppendAllLines(coinJoinScriptStoreFilePath, e.Outputs.Select(x => x.ScriptPubKey.ToHex()));
+ File.AppendAllLines(coinJoinScriptStoreFilePath, transaction.Outputs.Select(x => x.ScriptPubKey.ToHex()));
}
catch (Exception ex)
{

Wire up CoinJoinIdStore