Skip to content

Commit

Permalink
Remove CoinJoinIdStore (WalletWasabi#13228)
Browse files Browse the repository at this point in the history
This was used mainly to implement the "remixes dont pay" feature, which was added late in the WabiSabi development as an idea to incentivize continue coinjoining, and as a marketing selling point.

It was also used as a trivial optimization for the "friends don't pay" or "one hop don't pay" (what requires a full-index bitcoin node)
  • Loading branch information
lontivero authored Jul 8, 2024
1 parent c9b268b commit 59b908c
Show file tree
Hide file tree
Showing 26 changed files with 30 additions and 506 deletions.
21 changes: 1 addition & 20 deletions WalletWasabi.Backend/Controllers/WabiSabiController.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using System.Threading;
using System.Threading.Tasks;
using NBitcoin;
using WalletWasabi.Backend.Filters;
using WalletWasabi.Cache;
using WalletWasabi.WabiSabi.Backend;
using WalletWasabi.WabiSabi.Backend.PostRequests;
using WalletWasabi.WabiSabi.Backend.Rounds;
using WalletWasabi.WabiSabi.Backend.Statistics;
Expand All @@ -21,18 +19,16 @@ namespace WalletWasabi.Backend.Controllers;
[Produces("application/json")]
public class WabiSabiController : ControllerBase, IWabiSabiApiRequestHandler
{
public WabiSabiController(IdempotencyRequestCache idempotencyRequestCache, Arena arena, CoinJoinFeeRateStatStore coinJoinFeeRateStatStore, CoinJoinMempoolManager coinJoinMempoolManager)
public WabiSabiController(IdempotencyRequestCache idempotencyRequestCache, Arena arena, CoinJoinFeeRateStatStore coinJoinFeeRateStatStore)
{
IdempotencyRequestCache = idempotencyRequestCache;
Arena = arena;
CoinJoinFeeRateStatStore = coinJoinFeeRateStatStore;
CoinJoinMempoolManager = coinJoinMempoolManager;
}

private IdempotencyRequestCache IdempotencyRequestCache { get; }
private Arena Arena { get; }
private CoinJoinFeeRateStatStore CoinJoinFeeRateStatStore { get; }
public CoinJoinMempoolManager CoinJoinMempoolManager { get; }

[HttpPost("status")]
public async Task<RoundStateResponse> GetStatusAsync(RoundStateRequest request, CancellationToken cancellationToken)
Expand Down Expand Up @@ -104,19 +100,4 @@ public HumanMonitorResponse GetHumanMonitor()

return new HumanMonitorResponse(response.ToArray());
}

/// <summary>
/// Gets the list of unconfirmed coinjoin transaction Ids.
/// </summary>
/// <returns>The list of coinjoin transactions in the mempool.</returns>
/// <response code="200">An array of transaction Ids</response>
[HttpGet("unconfirmed-coinjoins")]
[ProducesResponseType(200)]
public IActionResult GetUnconfirmedCoinjoins()
{
IEnumerable<string> unconfirmedCoinJoinString = GetUnconfirmedCoinJoinCollection().Select(x => x.ToString());
return Ok(unconfirmedCoinJoinString);
}

private IEnumerable<uint256> GetUnconfirmedCoinJoinCollection() => CoinJoinMempoolManager.CoinJoinIds;
}
12 changes: 1 addition & 11 deletions WalletWasabi.Backend/Global.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using NBitcoin;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.BitcoinCore;
Expand All @@ -14,8 +13,6 @@
using WalletWasabi.Logging;
using WalletWasabi.Services;
using WalletWasabi.WabiSabi;
using WalletWasabi.WabiSabi.Backend;
using WalletWasabi.WabiSabi.Backend.Rounds.CoinJoinStorage;
using WalletWasabi.WabiSabi.Backend.Statistics;

namespace WalletWasabi.Backend;
Expand All @@ -32,7 +29,6 @@ public Global(string dataDir, IRPCClient rpcClient, Config config)
HostedServices = new();

CoordinatorParameters = new(DataDir);
CoinJoinIdStore = CoinJoinIdStore.Create(CoordinatorParameters.CoinJoinIdStoreFilePath);

// Add Nostr publisher if enabled
if (Config.AnnouncerConfig.IsEnabled && config.Network != Network.RegTest)
Expand All @@ -51,7 +47,6 @@ public Global(string dataDir, IRPCClient rpcClient, Config config)
IndexBuilderService = new(RpcClient, HostedServices.Get<BlockNotifier>(), indexFilePath);

MempoolMirror = new MempoolMirror(TimeSpan.FromSeconds(21), RpcClient, P2pNode);
CoinJoinMempoolManager = new CoinJoinMempoolManager(CoinJoinIdStore, MempoolMirror);
}

public string DataDir { get; }
Expand All @@ -68,10 +63,8 @@ public Global(string dataDir, IRPCClient rpcClient, Config config)

private CoordinatorParameters CoordinatorParameters { get; }

public CoinJoinIdStore CoinJoinIdStore { get; }
public WabiSabiCoordinator? WabiSabiCoordinator { get; private set; }
public MempoolMirror MempoolMirror { get; }
public CoinJoinMempoolManager CoinJoinMempoolManager { get; private set; }

public async Task InitializeAsync(CancellationToken cancel)
{
Expand All @@ -85,10 +78,9 @@ public async Task InitializeAsync(CancellationToken cancel)

var blockNotifier = HostedServices.Get<BlockNotifier>();

var wabiSabiConfig = CoordinatorParameters.RuntimeCoordinatorConfig;
var coinJoinScriptStore = CoinJoinScriptStore.LoadFromFile(CoordinatorParameters.CoinJoinScriptStoreFilePath);

WabiSabiCoordinator = new WabiSabiCoordinator(CoordinatorParameters, RpcClient, CoinJoinIdStore, coinJoinScriptStore);
WabiSabiCoordinator = new WabiSabiCoordinator(CoordinatorParameters, RpcClient, coinJoinScriptStore);
blockNotifier.OnBlock += WabiSabiCoordinator.BanDescendant;
HostedServices.Register<WabiSabiCoordinator>(() => WabiSabiCoordinator, "WabiSabi Coordinator");
P2pNode.OnTransactionArrived += WabiSabiCoordinator.BanDoubleSpenders;
Expand Down Expand Up @@ -163,8 +155,6 @@ protected virtual void Dispose(bool disposing)
P2pNode.OnTransactionArrived -= wabiSabiCoordinator.BanDoubleSpenders;
}

CoinJoinMempoolManager.Dispose();

var stoppingTask = Task.Run(DisposeAsync);

stoppingTask.GetAwaiter().GetResult();
Expand Down
5 changes: 0 additions & 5 deletions WalletWasabi.Backend/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,6 @@ public void ConfigureServices(IServiceCollection services)
var coordinator = global.HostedServices.Get<WabiSabiCoordinator>();
return coordinator.CoinJoinFeeRateStatStore;
});
services.AddSingleton(serviceProvider =>
{
var global = serviceProvider.GetRequiredService<Global>();
return global.CoinJoinMempoolManager;
});
services.AddStartupTask<InitConfigStartupTask>();

services.AddResponseCompression();
Expand Down
10 changes: 1 addition & 9 deletions WalletWasabi.Tests/Helpers/ArenaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public class ArenaBuilder
public IRPCClient? Rpc { get; set; }
public Prison? Prison { get; set; }
public RoundParameterFactory? RoundParameterFactory { get; set; }
public ICoinJoinIdStore? CoinJoinIdStore { get; set; }

/// <param name="rounds">Rounds to initialize <see cref="Arena"/> with.</param>
public Arena Create(params Round[] rounds)
Expand All @@ -33,10 +32,9 @@ public Arena Create(params Round[] rounds)
WabiSabiConfig config = Config ?? new();
IRPCClient rpc = Rpc ?? WabiSabiFactory.CreatePreconfiguredRpcClient();
Network network = Network ?? Network.Main;
ICoinJoinIdStore coinJoinIdStore = CoinJoinIdStore ?? new CoinJoinIdStore();
RoundParameterFactory roundParameterFactory = RoundParameterFactory ?? CreateRoundParameterFactory(config, network);

Arena arena = new(period, config, rpc, prison, coinJoinIdStore, roundParameterFactory);
Arena arena = new(period, config, rpc, prison, roundParameterFactory);

foreach (var round in rounds)
{
Expand Down Expand Up @@ -67,12 +65,6 @@ public async Task<Arena> CreateAndStartAsync(Round[] rounds, CancellationToken c
}
}

public ArenaBuilder With(ICoinJoinIdStore store)
{
CoinJoinIdStore = store;
return this;
}

public ArenaBuilder With(IRPCClient rpc)
{
Rpc = rpc;
Expand Down
11 changes: 1 addition & 10 deletions WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public static MockRpcClient CreatePreconfiguredRpcClient(params Coin[] coins)
}

public static Alice CreateAlice(Coin coin, OwnershipProof ownershipProof, Round round)
=> new(coin, ownershipProof, round, Guid.NewGuid(), false) { Deadline = DateTimeOffset.UtcNow + TimeSpan.FromHours(1) };
=> new(coin, ownershipProof, round, Guid.NewGuid()) { Deadline = DateTimeOffset.UtcNow + TimeSpan.FromHours(1) };

public static Alice CreateAlice(Key key, Money amount, Round round, ScriptPubKeyType scriptPubKeyType = ScriptPubKeyType.Segwit)
=> CreateAlice(CreateCoin(key, amount, scriptPubKeyType), CreateOwnershipProof(key, round.Id, scriptPubKeyType), round);
Expand Down Expand Up @@ -378,10 +378,8 @@ public static RoundParameterFactory CreateRoundParametersFactory(WabiSabiConfig

public static (Prison, ChannelReader<Offender>) CreateObservablePrison()
{
var coinjoinIdStore = CreateCoinJoinIdStore();
var channel = Channel.CreateUnbounded<Offender>();
var prison = new Prison(
coinjoinIdStore,
Enumerable.Empty<Offender>(),
channel.Writer);
return (prison, channel.Reader);
Expand Down Expand Up @@ -411,11 +409,4 @@ internal static WabiSabiConfig CreateWabiSabiConfig()
DoSPenaltyFactorForDisruptingByDoubleSpending = 3.0d
};
}

internal static ICoinJoinIdStore CreateCoinJoinIdStore()
{
var coinjoinIdStore = new Mock<ICoinJoinIdStore>();
coinjoinIdStore.Setup(x => x.Contains(uint256.One)).Returns(true);
return coinjoinIdStore.Object;
}
}
61 changes: 0 additions & 61 deletions WalletWasabi.Tests/UnitTests/CoinjoinIdStoreTests.cs

This file was deleted.

This file was deleted.

3 changes: 1 addition & 2 deletions WalletWasabi.Tests/UnitTests/WabiSabi/Backend/ConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using WalletWasabi.Tests.Helpers;
using WalletWasabi.WabiSabi;
using WalletWasabi.WabiSabi.Backend;
using WalletWasabi.WabiSabi.Backend.Rounds.CoinJoinStorage;
using WalletWasabi.WabiSabi.Backend.Statistics;
using Xunit;

Expand Down Expand Up @@ -144,5 +143,5 @@ private static IRPCClient NewMockRpcClient()
}

private static WabiSabiCoordinator CreateWabiSabiCoordinator(CoordinatorParameters coordinatorParameters)
=> new(coordinatorParameters, NewMockRpcClient(), new CoinJoinIdStore(), new CoinJoinScriptStore());
=> new(coordinatorParameters, NewMockRpcClient(), new CoinJoinScriptStore());
}
19 changes: 2 additions & 17 deletions WalletWasabi.Tests/UnitTests/WabiSabi/Backend/CoordinatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,8 @@ public void BanDoubleSpendersTest()
CoordinatorParameters coordinatorParameters = new(workDir);
WabiSabiConfig cfg = coordinatorParameters.RuntimeCoordinatorConfig;
DoSConfiguration dosConfig = cfg.GetDoSConfiguration() with { MinTimeInPrison = TimeSpan.Zero };
var coinJoinIdStore = new InMemoryCoinJoinIdStore();
var mockRpcClient = new MockRpcClient { Network = Network.Main };
using WabiSabiCoordinator coordinator = new(coordinatorParameters, mockRpcClient, coinJoinIdStore, new CoinJoinScriptStore());
using WabiSabiCoordinator coordinator = new(coordinatorParameters, mockRpcClient, new CoinJoinScriptStore());

// Receive a tx that is not spending coins registered in any round.
{
Expand Down Expand Up @@ -117,20 +116,6 @@ public void BanDoubleSpendersTest()
Assert.True(isOutputBanned); // Banned.
Assert.Contains(round.Id, coordinator.Arena.DisruptedRounds);
}

// Receive a tx that is spending coins registered in a round but the tx is a Wasabi coinjoin
{
tx2.Outputs[0].ScriptPubKey = BitcoinFactory.CreateScript(); // Make it a completely different tx.

// Make the transaction look like a Wasabi coinjoin tx.
Assert.True(coinJoinIdStore.TryAdd(tx2.GetHash()));

// Attempt to ban Wasabi coinjoin tx.
coordinator.BanDoubleSpenders(this, tx2);

var isOutputBanned = coordinator.Warden.Prison.IsBanned(new OutPoint(tx2, 0), dosConfig, DateTimeOffset.UtcNow);
Assert.False(isOutputBanned); // Not banned.
}
}

private static Transaction CreateTransaction(Money amount, OutPoint? outPoint = default)
Expand All @@ -155,5 +140,5 @@ private static IRPCClient NewMockRpcClient()
}

private static WabiSabiCoordinator CreateWabiSabiCoordinator(CoordinatorParameters coordinatorParameters)
=> new(coordinatorParameters, NewMockRpcClient(), new CoinJoinIdStore(), new CoinJoinScriptStore());
=> new(coordinatorParameters, NewMockRpcClient(), new CoinJoinScriptStore());
}
Loading

0 comments on commit 59b908c

Please sign in to comment.