Make sure bans time out
MODIFY
WalletWasabi.Backend/Controllers/ChaumianCoinJoinController.cs
WalletWasabi.Backend/Controllers/ChaumianCoinJoinController.cs
@@ -101,7 +101,7 @@ namespace WalletWasabi.Backend.Controllers
// Do more checks.
try
{
- if (round.ContainsBlindedOutput(request.BlindedOutputHashHex, out List<Alice> _))
+ if (round.ContainsBlindedOutput(request.BlindedOutputHashHex, out _))
{
return BadRequest("Blinded output has already been registered.");
}
@@ -130,9 +130,19 @@ namespace WalletWasabi.Backend.Controllers
}
}
- if(Coordinator.UtxoReferee.BannedUtxos.Keys.Contains(inputProof.Input))
+ var bannedElem = Coordinator.UtxoReferee.BannedUtxos.SingleOrDefault(x=>x.Key == inputProof.Input);
+ if (bannedElem.Key != default)
{
- return BadRequest($"Input is banned from participation: {inputProof.Input.N}:{inputProof.Input.Hash}.");
+ int maxBan = (int)TimeSpan.FromDays(30).TotalMinutes;
+ int banLeft = maxBan - (int)((DateTimeOffset.UtcNow - bannedElem.Value.timeOfBan).TotalMinutes);
+ if (banLeft > 0)
+ {
+ return BadRequest($"Input is banned from participation for {banLeft} minutes: {inputProof.Input.N}:{inputProof.Input.Hash}.");
+ }
+ else
+ {
+ await Coordinator.UtxoReferee.UnbanAsync(bannedElem.Key);
+ }
}
GetTxOutResponse getTxOutResponse = await RpcClient.GetTxOutAsync(inputProof.Input.Hash, (int)inputProof.Input.N, includeMempool: true);

MODIFY
WalletWasabi.Tests/P2pTests.cs
WalletWasabi.Tests/P2pTests.cs
@@ -87,7 +87,7 @@ namespace WalletWasabi.Tests
MinVersion = ProtocolVersion_WITNESS_VERSION
});
WalletService walletService = new WalletService(
- KeyManager.CreateNew(out Mnemonic _, "password"),
+ KeyManager.CreateNew(out _, "password"),
new IndexDownloader(network, Path.Combine(SharedFixture.DataDir, nameof(TestServicesAsync), "IndexDownloader.txt"), new Uri("http://localhost:12345")),
memPoolService,
nodes,
@@ -211,7 +211,7 @@ namespace WalletWasabi.Tests
// Test initial synchronization.
var times = 0;
uint256 firstHash = await rpc.GetBlockHashAsync(0);
- while (indexBuilderService.GetFilterLinesExcluding(firstHash, out bool _).Count() != 101)
+ while (indexBuilderService.GetFilterLinesExcluding(firstHash, out _).Count() != 101)
{
if (times > 500) // 30 sec
{

MODIFY
WalletWasabi.Tests/RegTests.cs
WalletWasabi.Tests/RegTests.cs
@@ -269,7 +269,7 @@ namespace WalletWasabi.Tests
await AssertFiltersInitializedAsync();
var network = Network.RegTest;
- var keyManager = KeyManager.CreateNew(out Mnemonic _, "password");
+ var keyManager = KeyManager.CreateNew(out _, "password");
// Mine some coins, make a few bech32 transactions then make it confirm.
await Global.RpcClient.GenerateAsync(1);
@@ -429,7 +429,7 @@ namespace WalletWasabi.Tests
var indexDownloader = new IndexDownloader(Global.RpcClient.Network, indexFilePath, new Uri(RegTestFixture.BackendEndPoint));
// 4. Create key manager service.
- var keyManager = KeyManager.CreateNew(out Mnemonic _, "password");
+ var keyManager = KeyManager.CreateNew(out _, "password");
// 5. Create wallet service.
var blocksFolderPath = Path.Combine(SharedFixture.DataDir, nameof(WalletTestsAsync), $"Blocks");
@@ -655,7 +655,7 @@ namespace WalletWasabi.Tests
var indexDownloader = new IndexDownloader(Global.RpcClient.Network, indexFilePath, new Uri(RegTestFixture.BackendEndPoint));
// 4. Create key manager service.
- var keyManager = KeyManager.CreateNew(out Mnemonic _, "password");
+ var keyManager = KeyManager.CreateNew(out _, "password");
// 5. Create wallet service.
var blocksFolderPath = Path.Combine(SharedFixture.DataDir, nameof(SendTestsFromHiddenWalletAsync), $"Blocks");
@@ -1033,7 +1033,7 @@ namespace WalletWasabi.Tests
var indexDownloader = new IndexDownloader(Global.RpcClient.Network, indexFilePath, new Uri(RegTestFixture.BackendEndPoint));
// 4. Create key manager service.
- var keyManager = KeyManager.CreateNew(out Mnemonic _, "password");
+ var keyManager = KeyManager.CreateNew(out _, "password");
// 5. Create wallet service.
var blocksFolderPath = Path.Combine(SharedFixture.DataDir, nameof(SendTestsFromHiddenWalletAsync), $"Blocks");
@@ -1193,7 +1193,7 @@ namespace WalletWasabi.Tests
var indexDownloader = new IndexDownloader(Global.RpcClient.Network, indexFilePath, new Uri(RegTestFixture.BackendEndPoint));
// 4. Create key manager service.
- var keyManager = KeyManager.CreateNew(out Mnemonic _, "password");
+ var keyManager = KeyManager.CreateNew(out _, "password");
// 5. Create wallet service.
var blocksFolderPath = Path.Combine(SharedFixture.DataDir, nameof(SendTestsFromHiddenWalletAsync), $"Blocks");
@@ -1357,7 +1357,7 @@ namespace WalletWasabi.Tests
new IndexDownloader(Global.RpcClient.Network, indexFilePath, new Uri(RegTestFixture.BackendEndPoint));
// 4. Create key manager service.
- var keyManager = KeyManager.CreateNew(out Mnemonic _, "password");
+ var keyManager = KeyManager.CreateNew(out _, "password");
// 5. Create wallet service.
var blocksFolderPath = Path.Combine(SharedFixture.DataDir, nameof(SendTestsFromHiddenWalletAsync), $"Blocks");

MODIFY
WalletWasabi/Services/UtxoReferee.cs
WalletWasabi/Services/UtxoReferee.cs
@@ -3,6 +3,7 @@ using NBitcoin.RPC;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
@@ -17,9 +18,9 @@ namespace WalletWasabi.Services
public class UtxoReferee
{
/// <summary>
- /// Key: banned utxo, Value: severity level
+ /// Key: banned utxo, Value: severity level, time of ban
/// </summary>
- public ConcurrentDictionary<OutPoint, int> BannedUtxos { get; }
+ public ConcurrentDictionary<OutPoint, (int severity, DateTimeOffset timeOfBan)> BannedUtxos { get; }
public string BannedUtxosFilePath => Path.Combine(FolderPath, $"BannedUtxos{Network}.txt");
@@ -35,7 +36,7 @@ namespace WalletWasabi.Services
FolderPath = Guard.NotNullOrEmptyOrWhitespace(nameof(folderPath), folderPath, trim: true);
RpcClient = Guard.NotNull(nameof(rpc), rpc);
- BannedUtxos = new ConcurrentDictionary<OutPoint, int>();
+ BannedUtxos = new ConcurrentDictionary<OutPoint, (int severity, DateTimeOffset timeOfBan)>();
Directory.CreateDirectory(FolderPath);
@@ -48,8 +49,9 @@ namespace WalletWasabi.Services
foreach (string line in allLines)
{
var parts = line.Split(':');
- var utxo = new OutPoint(new uint256(parts[2]), int.Parse(parts[1]));
- var severity = int.Parse(parts[0]);
+ var utxo = new OutPoint(new uint256(parts[3]), int.Parse(parts[2]));
+ var severity = int.Parse(parts[1]);
+ var timeOfBan = DateTimeOffset.Parse(parts[0], CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
GetTxOutResponse getTxOutResponse = RpcClient.GetTxOut(utxo.Hash, (int)utxo.N, includeMempool: true);
@@ -60,7 +62,7 @@ namespace WalletWasabi.Services
}
else
{
- BannedUtxos.TryAdd(utxo, severity);
+ BannedUtxos.TryAdd(utxo, (severity, timeOfBan));
}
}
@@ -83,9 +85,10 @@ namespace WalletWasabi.Services
var lines = new List<string>();
foreach(var utxo in alice.Inputs.Select(x=>x.OutPoint))
{
- if (BannedUtxos.TryAdd(utxo, 1))
+ DateTimeOffset utcNow = DateTimeOffset.UtcNow;
+ if (BannedUtxos.TryAdd(utxo, (1, utcNow)))
{
- string line = $"1:{utxo.N}:{utxo.Hash}";
+ string line = $"{utcNow.ToString(CultureInfo.InvariantCulture)}:1:{utxo.N}:{utxo.Hash}";
lines.Add(line);
}
}
@@ -95,5 +98,14 @@ namespace WalletWasabi.Services
await File.AppendAllLinesAsync(BannedUtxosFilePath, lines);
}
}
+
+ public async Task UnbanAsync(OutPoint key)
+ {
+ if(BannedUtxos.TryRemove(key, out _))
+ {
+ IEnumerable<string> lines = BannedUtxos.Select(x => $"{x.Value.timeOfBan.ToString(CultureInfo.InvariantCulture)}:{x.Value.severity}:{x.Key.N}:{x.Key.Hash}");
+ await File.AppendAllLinesAsync(BannedUtxosFilePath, lines);
+ }
+ }
}
}

Make sure bans time out