Solve problem with small denominations in change.
MODIFY
WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs
WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
+using WalletWasabi.Blockchain.Analysis.Clustering;
using WalletWasabi.Blockchain.Keys;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Blockchain.TransactionProcessing;
@@ -871,6 +872,34 @@ public class TransactionProcessorTests
Assert.All(keys.Skip(5), key => Assert.Equal(KeyState.Clean, key.KeyState));
}
+ [Fact]
+ public async Task ReceiveTransactionWithDustFromOurselvesAsync()
+ {
+ await using var txStore = await CreateTransactionStoreAsync();
+ var transactionProcessor = CreateTransactionProcessor(txStore);
+
+ // The dust coin should raise an event, but it shouldn't be fully processed.
+ transactionProcessor.WalletRelevantTransactionProcessed += (s, e)
+ => Assert.Empty(e.ReceivedDusts); // small coins received from us are not an attack.
+
+ var keys = transactionProcessor.KeyManager.GetKeys();
+ var creditingTx = CreateCreditingTransaction(keys.First().P2wpkhScript, Money.Coins(0.0001001m));
+ var relevant = transactionProcessor.Process(creditingTx);
+ var receivedCoin = Assert.Single(relevant.ReceivedCoins);
+
+ using var destinationKey = new Key();
+ var spendingTx = CreateSpendingTransaction(
+ Enumerable.Repeat(receivedCoin.Coin, 1),
+ destinationKey.GetScriptPubKey(ScriptPubKeyType.Legacy),
+ transactionProcessor.KeyManager.GetNextReceiveKey(new SmartLabel("someone"), out _).P2wpkhScript);
+ relevant = transactionProcessor.Process(spendingTx);
+ Assert.True(relevant.IsNews);
+
+ // There is one coin (the change of the payment) under dust.
+ var underDustThresholdCoin = Assert.Single(transactionProcessor.Coins);
+ Assert.True(underDustThresholdCoin.Amount < transactionProcessor.DustThreshold);
+ }
+
[Fact]
public async Task ReceiveCoinJoinTransactionAsync()
{

MODIFY
WalletWasabi/Blockchain/TransactionProcessing/TransactionProcessor.cs
WalletWasabi/Blockchain/TransactionProcessing/TransactionProcessor.cs
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Linq;
using NBitcoin;
using WalletWasabi.Blockchain.Analysis;
@@ -206,6 +207,7 @@ public class TransactionProcessor
}
}
+ var myInputs = Coins.AsAllCoinsView().OutPoints(tx.Transaction.Inputs.Select(x => x.PrevOut).ToHashSet()).ToImmutableList();
for (var i = 0U; i < tx.Transaction.Outputs.Count; i++)
{
// If transaction received to any of the wallet keys:
@@ -218,7 +220,8 @@ public class TransactionProcessor
}
foundKey.SetKeyState(KeyState.Used, KeyManager);
- if (output.Value < DustThreshold)
+ var areWeSending = myInputs.Any();
+ if (output.Value <= DustThreshold && !areWeSending)
{
result.ReceivedDusts.Add(output);
continue;
@@ -257,7 +260,7 @@ public class TransactionProcessor
}
// If spends any of our coin
- foreach (var coin in Coins.AsAllCoinsView().OutPoints(tx.Transaction.Inputs.Select(x => x.PrevOut).ToHashSet()))
+ foreach (var coin in myInputs)
{
var alreadyKnown = coin.SpenderTransaction == tx;
result.SpentCoins.Add(coin);

Solve problem with small denominations in change. (#8256)