Deprioritize selecting too large coins
MODIFY
WalletWasabi/Blockchain/Analysis/BlockchainAnalyzer.cs
WalletWasabi/Blockchain/Analysis/BlockchainAnalyzer.cs
@@ -8,7 +8,7 @@ namespace WalletWasabi.Blockchain.Analysis;
public class BlockchainAnalyzer
{
- private static long[] StdDenoms = new[]
+ public static long[] StdDenoms = new[]
{
5000L, 6561L, 8192L, 10000L, 13122L, 16384L, 19683L, 20000L, 32768L, 39366L, 50000L, 59049L, 65536L, 100000L, 118098L,
131072L, 177147L, 200000L, 262144L, 354294L, 500000L, 524288L, 531441L, 1000000L, 1048576L, 1062882L, 1594323L, 2000000L,

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Blockchain.Analysis;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Crypto.Randomness;
using WalletWasabi.Extensions;
@@ -72,6 +73,8 @@ public class CoinJoinClient
public bool ConsolidationMode { get; private set; }
public bool RedCoinIsolation { get; }
private TimeSpan FeeRateMedianTimeFrame { get; }
+ private static Money? LastLargestDenomOutput { get; private set; }
+ private static object LastLargestDenomOutputLock { get; } = new object();
private async Task<RoundState> WaitForRoundAsync(uint256 excludeRound, CancellationToken token)
{
@@ -232,6 +235,15 @@ public class CoinJoinClient
LogCoinJoinSummary(registeredAliceClients, outputTxOuts, unsignedCoinJoin, roundState);
+ lock (LastLargestDenomOutputLock)
+ {
+ LastLargestDenomOutput = unsignedCoinJoin.Outputs
+ .Where(x => BlockchainAnalyzer.StdDenoms.Contains(x.Value.Satoshi))
+ .OrderByDescending(x => x.Value)
+ .First()
+ .Value;
+ }
+
return new CoinJoinResult(
GoForBlameRound: roundState.EndRoundState == EndRoundState.NotAllAlicesSign,
SuccessfulBroadcast: roundState.EndRoundState == EndRoundState.TransactionBroadcasted,
@@ -560,7 +572,22 @@ public class CoinJoinClient
consolidationMode ? MaxInputsRegistrableByWallet : GetInputTarget(allowedNonPrivateCoins.Count, privateCoins.Length, rnd));
// Let's allow only a inputCount - 1 private coins to play.
- var allowedPrivateCoins = AnonScoreBiasedShuffle(privateCoins).Take(inputCount - 1);
+ var biasSuffledPrivateCoins = AnonScoreBiasedShuffle(privateCoins).ToArray();
+ IEnumerable<SmartCoin> allowedPrivateCoins;
+ lock (LastLargestDenomOutputLock)
+ {
+ if (LastLargestDenomOutput is null)
+ {
+ allowedPrivateCoins = biasSuffledPrivateCoins.Take(inputCount - 1);
+ }
+ else
+ {
+ // Deprioritize private coins those are too large.
+ var smallerPrivateCoins = biasSuffledPrivateCoins.Where(x => x.Amount <= LastLargestDenomOutput);
+ var largerPrivateCoins = biasSuffledPrivateCoins.Where(x => x.Amount > LastLargestDenomOutput);
+ allowedPrivateCoins = smallerPrivateCoins.Concat(largerPrivateCoins).Take(inputCount - 1);
+ }
+ }
var allowedCoins = allowedNonPrivateCoins.Concat(allowedPrivateCoins).ToArray();

Deprioritize selecting too large coins