Only calculate anonsets once.
MODIFY
WalletWasabi/Blockchain/Analysis/BlockchainAnalyzer.cs
WalletWasabi/Blockchain/Analysis/BlockchainAnalyzer.cs
@@ -59,10 +59,12 @@ namespace WalletWasabi.Blockchain.Analysis
.WalletOutputs.GroupBy(x => x.Amount)
.ToDictionary(x => x.Key, y => y.Count());
+ var anonsets = tx.Transaction.GetAnonymitySets(tx.WalletOutputs.Select(x => x.Index));
+
foreach (var newCoin in tx.WalletOutputs.ToArray())
{
// Get the anonymity set of i-th output in the transaction.
- int anonset = tx.Transaction.GetAnonymitySet(newCoin.Index);
+ int anonset = anonsets[newCoin.Index];
// Don't count our own equivalent outputs in the anonset.
anonset -= indistinguishableWalletOutputs[newCoin.Amount] - 1;

MODIFY
WalletWasabi/Extensions/NBitcoinExtensions.cs
WalletWasabi/Extensions/NBitcoinExtensions.cs
@@ -123,15 +123,32 @@ namespace NBitcoin
}
public static int GetAnonymitySet(this Transaction me, uint outputIndex)
+ => me.GetAnonymitySets(new[] { outputIndex }).First().Value;
+
+ public static IDictionary<uint, int> GetAnonymitySets(this Transaction me, IEnumerable<uint> outputIndices)
+ {
+ var anonsets = new Dictionary<uint, int>();
+ var inputCount = me.Inputs.Count;
+
+ var indistinguishableOutputs = me.Outputs
+ .GroupBy(x => x.Value)
+ .ToDictionary(x => x.Key, y => y.Count());
+
+ foreach (var outputIndex in outputIndices)
{
// 1. Get the output corresponting to the output index.
var output = me.Outputs[outputIndex];
+
// 2. Get the number of equal outputs.
- int equalOutputs = me.GetIndistinguishableOutputs(includeSingle: true).Single(x => x.value == output.Value).count;
+ int equalOutputs = indistinguishableOutputs[output.Value];
+
// 3. Anonymity set cannot be larger than the number of inputs.
- var inputCount = me.Inputs.Count;
var anonSet = Math.Min(equalOutputs, inputCount);
- return anonSet;
+
+ anonsets.Add(outputIndex, anonSet);
+ }
+
+ return anonsets;
}
public static bool IsLikelyCoinjoin(this Transaction me)

Only calculate anonsets once.