From 37ca98c2b0328438c6ca4f1b35dd356f58679502 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Sun, 24 May 2026 11:23:33 +0200 Subject: [PATCH] implement dust detection for sp wallets on received utxos at a higher default limit --- drongo | 2 +- .../com/sparrowwallet/sparrow/io/Config.java | 7 +++++- .../sparrow/wallet/WalletUtxosEntry.java | 24 +++++++++++++------ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drongo b/drongo index 20670b9b..e96aa0d3 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 20670b9b7db749472b02d7f6f129294c53832390 +Subproject commit e96aa0d3f836b2d035cf5449da010147e56c6354 diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Config.java b/src/main/java/com/sparrowwallet/sparrow/io/Config.java index 0055831e..1dbb24c9 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Config.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Config.java @@ -18,12 +18,12 @@ import org.slf4j.LoggerFactory; import java.io.*; import java.lang.reflect.Type; import java.util.*; -import java.util.stream.Collectors; import static com.sparrowwallet.sparrow.AppServices.ENUMERATE_HW_PERIOD_SECS; import static com.sparrowwallet.sparrow.net.PagedBatchRequestBuilder.DEFAULT_PAGE_SIZE; import static com.sparrowwallet.sparrow.net.TcpTransport.DEFAULT_MAX_TIMEOUT; import static com.sparrowwallet.sparrow.wallet.WalletUtxosEntry.DUST_ATTACK_THRESHOLD_SATS; +import static com.sparrowwallet.sparrow.wallet.WalletUtxosEntry.DUST_ATTACK_THRESHOLD_SP_SATS; public class Config { private static final Logger log = LoggerFactory.getLogger(Config.class); @@ -64,6 +64,7 @@ public class Config { private List recentWalletFiles; private Integer keyDerivationPeriod; private long dustAttackThreshold = DUST_ATTACK_THRESHOLD_SATS; + private long dustAttackThresholdSp = DUST_ATTACK_THRESHOLD_SP_SATS; private int enumerateHwPeriod = ENUMERATE_HW_PERIOD_SECS; private QRDensity qrDensity; private QREncoding qrEncoding; @@ -448,6 +449,10 @@ public class Config { return dustAttackThreshold; } + public long getDustAttackThresholdSp() { + return dustAttackThresholdSp; + } + public int getEnumerateHwPeriod() { return enumerateHwPeriod; } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletUtxosEntry.java b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletUtxosEntry.java index 10d11664..9ca2610b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletUtxosEntry.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletUtxosEntry.java @@ -1,5 +1,6 @@ package com.sparrowwallet.sparrow.wallet; +import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.WalletNode; import com.sparrowwallet.sparrow.io.Config; @@ -9,6 +10,7 @@ import java.util.stream.Collectors; public class WalletUtxosEntry extends Entry { public static final int DUST_ATTACK_THRESHOLD_SATS = 1000; + public static final int DUST_ATTACK_THRESHOLD_SP_SATS = 5000; public WalletUtxosEntry(Wallet wallet) { super(wallet, wallet.getName(), wallet.getWalletUtxos().entrySet().stream().map(entry -> new UtxoEntry(entry.getValue().getWallet(), entry.getKey(), HashIndexEntry.Type.OUTPUT, entry.getValue())).collect(Collectors.toList())); @@ -50,14 +52,22 @@ public class WalletUtxosEntry extends Entry { } protected void calculateDust() { - long dustAttackThreshold = Config.get().getDustAttackThreshold(); - Set duplicateNodes = getWallet().getWalletTxos().values().stream() - .collect(Collectors.groupingBy(e -> e, Collectors.counting())) - .entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toSet()); + if(getWallet().getPolicyType() == PolicyType.SINGLE_SP) { + long dustAttackThreshold = Config.get().getDustAttackThresholdSp(); + for(Entry entry : getChildren()) { + UtxoEntry utxoEntry = (UtxoEntry) entry; + utxoEntry.setDustAttack(utxoEntry.getValue() <= dustAttackThreshold && !utxoEntry.getWallet().allInputsFromWallet(utxoEntry.getHashIndex().getHash())); + } + } else { + long dustAttackThreshold = Config.get().getDustAttackThreshold(); + Set duplicateNodes = getWallet().getWalletTxos().values().stream() + .collect(Collectors.groupingBy(e -> e, Collectors.counting())) + .entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toSet()); - for(Entry entry : getChildren()) { - UtxoEntry utxoEntry = (UtxoEntry) entry; - utxoEntry.setDustAttack(utxoEntry.getValue() <= dustAttackThreshold && duplicateNodes.contains(utxoEntry.getNode()) && !utxoEntry.getWallet().allInputsFromWallet(utxoEntry.getHashIndex().getHash())); + for(Entry entry : getChildren()) { + UtxoEntry utxoEntry = (UtxoEntry) entry; + utxoEntry.setDustAttack(utxoEntry.getValue() <= dustAttackThreshold && duplicateNodes.contains(utxoEntry.getNode()) && !utxoEntry.getWallet().allInputsFromWallet(utxoEntry.getHashIndex().getHash())); + } } }