Remove SpentOutputs (can be now accessed from tx directly) and add back islikelycoinjoin
MODIFY
WalletWasabi.Gui/Rpc/WasabiJsonRpcService.cs
WalletWasabi.Gui/Rpc/WasabiJsonRpcService.cs
@@ -182,7 +182,8 @@ namespace WalletWasabi.Gui.Rpc
height = x.Height.Value,
amount = x.Amount.Satoshi,
label = x.Label,
- tx = x.TransactionId
+ tx = x.TransactionId,
+ islikelycoinjoin = x.IsLikelyCoinJoinOutput
}).ToArray();
}

MODIFY
WalletWasabi.Tests/RegressionTests/SendTests.cs
WalletWasabi.Tests/RegressionTests/SendTests.cs
@@ -603,7 +603,7 @@ namespace WalletWasabi.Tests.RegressionTests
Assert.Equal(1, allCoins.Count(x => !x.IsAvailable() && x.SpenderTransaction?.GetHash() == tx1Res.Transaction.GetHash()));
// There is at least one coin created from the destruction of the first coin
- Assert.Contains(wallet.Coins, x => x.SpentOutputs.Any(o => o.Hash == tx0Id));
+ Assert.Contains(wallet.Coins, x => x.Transaction.Transaction.Inputs.Any(o => o.PrevOut.Hash == tx0Id));
var totalWallet = wallet.Coins.Where(c => c.IsAvailable()).Sum(c => c.Amount);
Assert.Equal((1 * Money.COIN) - tx1Res.Fee.Satoshi, totalWallet);
@@ -632,7 +632,7 @@ namespace WalletWasabi.Tests.RegressionTests
Assert.Equal(2, allCoins.Count(x => !x.IsAvailable() && x.SpenderTransaction?.GetHash() == tx2Hash));
// There is at least one coin created from the destruction of the first coin
- Assert.Contains(wallet.Coins, x => x.SpentOutputs.Any(o => o.Hash == tx1Res.Transaction.GetHash()));
+ Assert.Contains(wallet.Coins, x => x.Transaction.Transaction.Inputs.Any(o => o.PrevOut.Hash == tx1Res.Transaction.GetHash()));
totalWallet = wallet.Coins.Where(c => c.IsAvailable()).Sum(c => c.Amount);
Assert.Equal((1 * Money.COIN) - tx1Res.Fee.Satoshi - tx2Res.Fee.Satoshi, totalWallet);

MODIFY
WalletWasabi.Tests/RegressionTests/WalletTests.cs
WalletWasabi.Tests/RegressionTests/WalletTests.cs
@@ -290,8 +290,6 @@ namespace WalletWasabi.Tests.RegressionTests
Assert.Equal("foo label", firstCoin.Label);
Assert.Equal(key.P2wpkhScript, firstCoin.ScriptPubKey);
Assert.Null(firstCoin.SpenderTransaction);
- Assert.NotNull(firstCoin.SpentOutputs);
- Assert.NotEmpty(firstCoin.SpentOutputs);
Assert.Equal(txId, firstCoin.TransactionId);
Assert.Single(keyManager.GetKeys(KeyState.Used, false));
Assert.Equal("foo label", keyManager.GetKeys(KeyState.Used, false).Single().Label);
@@ -324,12 +322,6 @@ namespace WalletWasabi.Tests.RegressionTests
Assert.Equal(key2.P2wpkhScript, secondCoin.ScriptPubKey);
Assert.Equal(key2.P2wpkhScript, thirdCoin.ScriptPubKey);
Assert.Null(thirdCoin.SpenderTransaction);
- Assert.NotNull(firstCoin.SpentOutputs);
- Assert.NotNull(secondCoin.SpentOutputs);
- Assert.NotNull(thirdCoin.SpentOutputs);
- Assert.NotEmpty(firstCoin.SpentOutputs);
- Assert.NotEmpty(secondCoin.SpentOutputs);
- Assert.NotEmpty(thirdCoin.SpentOutputs);
Assert.Equal(txId, firstCoin.TransactionId);
Assert.Equal(txId2, secondCoin.TransactionId);
Assert.Equal(txId3, thirdCoin.TransactionId);
@@ -376,8 +368,6 @@ namespace WalletWasabi.Tests.RegressionTests
Assert.Equal("bar label", rbfCoin.Label);
Assert.Equal(key2.P2wpkhScript, rbfCoin.ScriptPubKey);
Assert.Null(rbfCoin.SpenderTransaction);
- Assert.NotNull(rbfCoin.SpentOutputs);
- Assert.NotEmpty(rbfCoin.SpentOutputs);
Assert.Equal(tx4bumpRes.TransactionId, rbfCoin.TransactionId);
Assert.Equal(2, keyManager.GetKeys(KeyState.Used, false).Count());

MODIFY
WalletWasabi/Blockchain/TransactionOutputs/CoinsRegistry.cs
WalletWasabi/Blockchain/TransactionOutputs/CoinsRegistry.cs
@@ -95,9 +95,8 @@ namespace WalletWasabi.Blockchain.TransactionOutputs
ClustersByScriptPubKey.Add(coin.ScriptPubKey, coin.Cluster);
}
- foreach (var spentOutPoint in coin.SpentOutputs)
+ foreach (var outPoint in coin.Transaction.Transaction.Inputs.Select(x => x.PrevOut))
{
- var outPoint = spentOutPoint;
var newCoinSet = new HashSet<SmartCoin> { coin };
// If we don't succeed to add a new entry to the dictionary.

MODIFY
WalletWasabi/Blockchain/TransactionOutputs/SmartCoin.cs
WalletWasabi/Blockchain/TransactionOutputs/SmartCoin.cs
@@ -42,7 +42,6 @@ namespace WalletWasabi.Blockchain.TransactionOutputs
Coin = new Coin(transaction.Transaction, outputIndex);
HashCode = (TransactionId, Index).GetHashCode();
Height = transaction.Height;
- SpentOutputs = Transaction.Transaction.Inputs.ToOutPoints().ToArray();
WasReplaceable = Transaction.IsRBF;
AnonymitySet = Guard.InRangeAndNotNull(nameof(anonymitySet), anonymitySet, 1, int.MaxValue);
@@ -99,8 +98,6 @@ namespace WalletWasabi.Blockchain.TransactionOutputs
set => RaiseAndSetIfChanged(ref _label, value);
}
- public OutPoint[] SpentOutputs { get; }
-
public bool WasReplaceable { get; }
public int AnonymitySet
@@ -199,6 +196,8 @@ namespace WalletWasabi.Blockchain.TransactionOutputs
public bool IsReplaceable() => WasReplaceable && !Confirmed;
+ public bool IsLikelyCoinjoinOutput() => Transaction.Transaction.IsLikelyCoinjoin();
+
#endregion Methods
#region EqualityAndComparison

MODIFY
WalletWasabi/Blockchain/TransactionProcessing/TransactionProcessor.cs
WalletWasabi/Blockchain/TransactionProcessing/TransactionProcessor.cs
@@ -233,12 +233,7 @@ namespace WalletWasabi.Blockchain.TransactionProcessing
}
}
- var isLikelyCj = false;
- if (tx.Transaction.Inputs.Count > 1 // The tx must have more than one input in order to be a coinjoin.
- && tx.Transaction.HasIndistinguishableOutputs()) // The tx must have more than one equal output in order to be a coinjoin.
- {
- isLikelyCj = true;
- }
+ var isLikelyCj = tx.Transaction.IsLikelyCoinjoin();
var prevOutSet = tx.Transaction.Inputs.Select(x => x.PrevOut).ToHashSet();
foreach (var coin in Coins.AsAllCoinsView())

MODIFY
WalletWasabi/Blockchain/Transactions/TransactionHistoryBuilder.cs
WalletWasabi/Blockchain/Transactions/TransactionHistoryBuilder.cs
@@ -49,7 +49,8 @@ namespace WalletWasabi.Blockchain.Transactions
Amount = coin.Amount,
Label = foundTransaction.Label,
TransactionId = coin.TransactionId,
- BlockIndex = foundTransaction.BlockIndex
+ BlockIndex = foundTransaction.BlockIndex,
+ IsLikelyCoinJoinOutput = coin.IsLikelyCoinjoinOutput()
});
}
@@ -73,7 +74,8 @@ namespace WalletWasabi.Blockchain.Transactions
Amount = Money.Zero - coin.Amount,
Label = foundSpenderTransaction.Label,
TransactionId = spenderTxId,
- BlockIndex = foundSpenderTransaction.BlockIndex
+ BlockIndex = foundSpenderTransaction.BlockIndex,
+ IsLikelyCoinJoinOutput = coin.IsLikelyCoinjoinOutput()
});
}
}

MODIFY
WalletWasabi/Blockchain/Transactions/TransactionSummary.cs
WalletWasabi/Blockchain/Transactions/TransactionSummary.cs
@@ -13,5 +13,6 @@ namespace WalletWasabi.Blockchain.Transactions
public SmartLabel Label { get; set; }
public uint256 TransactionId { get; set; }
public int BlockIndex { get; set; }
+ public bool IsLikelyCoinJoinOutput { get; set; }
}
}

MODIFY
WalletWasabi/Extensions/NBitcoinExtensions.cs
WalletWasabi/Extensions/NBitcoinExtensions.cs
@@ -136,6 +136,10 @@ namespace NBitcoin
public static int GetAnonymitySet(this Transaction me, uint outputIndex) => GetAnonymitySet(me, (int)outputIndex);
+ public static bool IsLikelyCoinjoin(this Transaction me)
+ => me.Inputs.Count > 1 // The tx must have more than one input in order to be a coinjoin.
+ && me.HasIndistinguishableOutputs(); // The tx must have more than one equal output in order to be a coinjoin.
+
/// <summary>
/// Careful, if it's in a legacy block then this won't work.
/// </summary>

Remove SpentOutputs (can be now accessed from tx directly) and add back islikelycoinjoin