-
Notifications
You must be signed in to change notification settings - Fork 1.2k
qt: Add dust attack protection feature #7095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
c74e16b
ef2058d
9877a6e
addb56e
f8487af
14f1090
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,6 +24,9 @@ class Node; | |||||||
| extern const char *DEFAULT_GUI_PROXY_HOST; | ||||||||
| static constexpr uint16_t DEFAULT_GUI_PROXY_PORT = 9050; | ||||||||
|
|
||||||||
| /** Default threshold for dust attack protection (in duffs) */ | ||||||||
| static constexpr qint64 DEFAULT_DUST_PROTECTION_THRESHOLD = 10000; | ||||||||
|
|
||||||||
| /** | ||||||||
| * Convert configured prune target MiB to displayed GB. Round up to avoid underestimating max disk usage. | ||||||||
| */ | ||||||||
|
|
@@ -95,6 +98,8 @@ class OptionsModel : public QAbstractListModel | |||||||
| Server, // bool | ||||||||
| EnablePSBTControls, // bool | ||||||||
| MaskValues, // bool | ||||||||
| DustProtection, // bool | ||||||||
| DustProtectionThreshold, // CAmount (in duffs) | ||||||||
|
Comment on lines
+101
to
+102
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: consider
Suggested change
|
||||||||
| OptionIDRowCount, | ||||||||
| }; | ||||||||
|
|
||||||||
|
|
@@ -130,6 +135,8 @@ class OptionsModel : public QAbstractListModel | |||||||
| bool getEnablePSBTControls() const { return m_enable_psbt_controls; } | ||||||||
| bool getKeepChangeAddress() const { return fKeepChangeAddress; } | ||||||||
| bool getShowAdvancedCJUI() { return fShowAdvancedCJUI; } | ||||||||
| bool getDustProtection() const { return fDustProtection; } | ||||||||
| qint64 getDustProtectionThreshold() const { return nDustProtectionThreshold; } | ||||||||
| const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; } | ||||||||
| bool isOptionOverridden(const QString& option) const { return strOverriddenByCommandLine.contains(option); } | ||||||||
| void emitCoinJoinEnabledChanged(); | ||||||||
|
|
@@ -160,6 +167,8 @@ class OptionsModel : public QAbstractListModel | |||||||
| bool m_mask_values; | ||||||||
| bool fKeepChangeAddress; | ||||||||
| bool fShowAdvancedCJUI; | ||||||||
| bool fDustProtection{false}; | ||||||||
| qint64 nDustProtectionThreshold{DEFAULT_DUST_PROTECTION_THRESHOLD}; | ||||||||
|
|
||||||||
| /* settings that were overridden by command-line */ | ||||||||
| QString strOverriddenByCommandLine; | ||||||||
|
|
@@ -183,6 +192,7 @@ class OptionsModel : public QAbstractListModel | |||||||
| void keepChangeAddressChanged(bool); | ||||||||
| void showTrayIconChanged(bool); | ||||||||
| void fontForMoneyChanged(const QFont&); | ||||||||
| void dustProtectionChanged(); | ||||||||
| }; | ||||||||
|
|
||||||||
| Q_DECLARE_METATYPE(OptionsModel::FontChoice) | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,7 +29,8 @@ bool TransactionRecord::showTransaction() | |
| /* | ||
| * Decompose CWallet transaction to model transaction records. | ||
| */ | ||
| QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Node& node, interfaces::Wallet& wallet, const interfaces::WalletTx& wtx) | ||
| QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Node& node, interfaces::Wallet& wallet, const interfaces::WalletTx& wtx, | ||
| bool dustProtectionEnabled, CAmount dustThreshold) | ||
| { | ||
| QList<TransactionRecord> parts; | ||
| int64_t nTime = wtx.time; | ||
|
|
@@ -40,6 +41,15 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Nod | |
| std::map<std::string, std::string> mapValue = wtx.value_map; | ||
| auto& coinJoinOptions = node.coinJoinOptions(); | ||
|
|
||
| // Check if any inputs belong to this wallet (for dust detection) | ||
| bool isFromMe = false; | ||
| for (const isminetype mine : wtx.txin_is_mine) { | ||
| if (mine) { | ||
| isFromMe = true; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (nNet > 0 || wtx.is_coinbase || wtx.is_platform_transfer) | ||
| { | ||
| // | ||
|
|
@@ -81,6 +91,15 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Nod | |
| sub.type = TransactionRecord::PlatformTransfer; | ||
| } | ||
|
|
||
| // Check for dust attack: external receive with small amount | ||
| // Only override if not already a special type (coinbase, platform transfer) | ||
| if (dustProtectionEnabled && !isFromMe && !wtx.is_coinbase && !wtx.is_platform_transfer && | ||
| sub.credit > 0 && sub.credit <= dustThreshold && | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: consider refactoring: move |
||
| (sub.type == TransactionRecord::RecvWithAddress || sub.type == TransactionRecord::RecvFromOther)) | ||
| { | ||
| sub.type = TransactionRecord::DustReceive; | ||
| } | ||
|
|
||
| parts.append(sub); | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
rg -nC3 'dustProtectionThresholdUnitLabel' --type=cppRepository: dashpay/dash
Length of output: 551
Fix hardcoded unit label to be network-aware.
The unit label is hardcoded to "duffs" in both the UI file (line 446-453) and at runtime in
src/qt/optionsdialog.cpp:78viaBitcoinUnits::name(BitcoinUnits::Unit::duffs). This conflicts with the PR objective to use a network-aware label (duffs/tduffs). On testnet, the label should display "tduffs" instead of "duffs".🤖 Prompt for AI Agents