Skip to content

Commit 9022aa3

Browse files
committed
Merge #10817: Redefine Dust and add a discard_rate
f4d00e6 Add a discard_rate (Alex Morcos) b138585 Remove factor of 3 from definition of dust. (Alex Morcos) Pull request description: The definition of dust is redefined to remove the factor of 3. Dust is redefined to be the value of an output such that it would cost that value in fees to (create and) spend the output at the dust relay rate. The previous definition was that it would cost 1/3 of the value. The default dust relay rate is correspondingly increased to 3000 sat/kB so the actual default dust output value of 546 satoshis for a non-segwit output remains unchanged. This commit is a refactor only unless a dustrelayfee is passed on the commandline in which case that number now needs to be increased by a factor of 3 to get the same behavior. -dustrelayfee is a hidden command line option. Note: It's not exactly a refactor due to edge case changes in rounding as evidenced by the required change to the unit test. A discard_rate is added which defaults to 10,000 sat/kB Any change output which would be dust at the discard_rate you are willing to discard completely and add to fee (as well as continuing to pay the fee that would have been needed for creating the change) This would be a nice addition for 0.15 and I think will remain useful for 0.16 with the new coin selection algorithms in discussion, but its not crucial. It does add translation strings, but we could (should?) avoid that by hiding the option Tree-SHA512: 5b6f655354d0ab6b8b6cac1e8d1fe3136d10beb15c6d948fb15bfb105155a9d03684c6240624039b3eed6428b7e60e54216cc8b2f90c4600701e39f646284a9b
2 parents a6ec580 + f4d00e6 commit 9022aa3

File tree

6 files changed

+46
-14
lines changed

6 files changed

+46
-14
lines changed

src/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ std::string HelpMessage(HelpMessageMode mode)
479479
if (showDebug) {
480480
strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->RequireStandard()));
481481
strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));
482-
strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
482+
strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
483483
}
484484
strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
485485
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));

src/policy/policy.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
1919
{
2020
// "Dust" is defined in terms of dustRelayFee,
2121
// which has units satoshis-per-kilobyte.
22-
// If you'd pay more than 1/3 in fees
22+
// If you'd pay more in fees than the value of the output
2323
// to spend something, then we consider it dust.
2424
// A typical spendable non-segwit txout is 34 bytes big, and will
2525
// need a CTxIn of at least 148 bytes to spend:
2626
// so dust is a spendable txout less than
27-
// 546*dustRelayFee/1000 (in satoshis).
27+
// 182*dustRelayFee/1000 (in satoshis).
28+
// 546 satoshis at the default rate of 3000 sat/kB.
2829
// A typical spendable segwit txout is 31 bytes big, and will
2930
// need a CTxIn of at least 67 bytes to spend:
3031
// so dust is a spendable txout less than
31-
// 294*dustRelayFee/1000 (in satoshis).
32+
// 98*dustRelayFee/1000 (in satoshis).
33+
// 294 satoshis at the default rate of 3000 sat/kB.
3234
if (txout.scriptPubKey.IsUnspendable())
3335
return 0;
3436

@@ -44,7 +46,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
4446
nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
4547
}
4648

47-
return 3 * dustRelayFeeIn.GetFee(nSize);
49+
return dustRelayFeeIn.GetFee(nSize);
4850
}
4951

5052
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)

src/policy/policy.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
4040
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
4141
/** The maximum size of a standard witnessScript */
4242
static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
43-
/** Min feerate for defining dust. Historically this has been the same as the
43+
/** Min feerate for defining dust. Historically this has been based on the
4444
* minRelayTxFee, however changing the dust limit changes which transactions are
4545
* standard and should be done with care and ideally rarely. It makes sense to
4646
* only increase the dust limit after prior releases were already not creating
4747
* outputs below the new threshold */
48-
static const unsigned int DUST_RELAY_TX_FEE = 1000;
48+
static const unsigned int DUST_RELAY_TX_FEE = 3000;
4949
/**
5050
* Standard script verification flags that standard transactions will comply
5151
* with. However scripts violating these flags may still be present in valid

src/test/transaction_tests.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
692692
BOOST_CHECK(IsStandardTx(t, reason));
693693

694694
// Check dust with default relay fee:
695-
CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000 * 3;
695+
CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000;
696696
BOOST_CHECK_EQUAL(nDustThreshold, 546);
697697
// dust:
698698
t.vout[0].nValue = nDustThreshold - 1;
@@ -702,13 +702,13 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
702702
BOOST_CHECK(IsStandardTx(t, reason));
703703

704704
// Check dust with odd relay fee to verify rounding:
705-
// nDustThreshold = 182 * 1234 / 1000 * 3
706-
dustRelayFee = CFeeRate(1234);
705+
// nDustThreshold = 182 * 3702 / 1000
706+
dustRelayFee = CFeeRate(3702);
707707
// dust:
708-
t.vout[0].nValue = 672 - 1;
708+
t.vout[0].nValue = 673 - 1;
709709
BOOST_CHECK(!IsStandardTx(t, reason));
710710
// not dust:
711-
t.vout[0].nValue = 672;
711+
t.vout[0].nValue = 673;
712712
BOOST_CHECK(IsStandardTx(t, reason));
713713
dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
714714

src/wallet/wallet.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
5757
*/
5858
CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);
5959

60+
CFeeRate CWallet::m_discard_rate = CFeeRate(DEFAULT_DISCARD_FEE);
61+
6062
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
6163

6264
/** @defgroup mapWallet
@@ -2524,6 +2526,17 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
25242526
return true;
25252527
}
25262528

2529+
static CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator)
2530+
{
2531+
unsigned int highest_target = estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
2532+
CFeeRate discard_rate = estimator.estimateSmartFee(highest_target, nullptr /* FeeCalculation */, false /* conservative */);
2533+
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
2534+
discard_rate = (discard_rate == CFeeRate(0)) ? CWallet::m_discard_rate : std::min(discard_rate, CWallet::m_discard_rate);
2535+
// Discard rate must be at least dustRelayFee
2536+
discard_rate = std::max(discard_rate, ::dustRelayFee);
2537+
return discard_rate;
2538+
}
2539+
25272540
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
25282541
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
25292542
{
@@ -2623,6 +2636,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
26232636
CTxOut change_prototype_txout(0, scriptChange);
26242637
size_t change_prototype_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0);
26252638

2639+
CFeeRate discard_rate = GetDiscardRate(::feeEstimator);
26262640
nFeeRet = 0;
26272641
bool pick_new_inputs = true;
26282642
CAmount nValueIn = 0;
@@ -2690,7 +2704,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
26902704

26912705
// Never create dust outputs; if we would, just
26922706
// add the dust to the fee.
2693-
if (IsDust(newTxOut, ::dustRelayFee))
2707+
if (IsDust(newTxOut, discard_rate))
26942708
{
26952709
nChangePosInOut = -1;
26962710
nFeeRet += nChange;
@@ -2770,7 +2784,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
27702784
// (because of reduced tx size) and so we should add a
27712785
// change output. Only try this once.
27722786
CAmount fee_needed_for_change = GetMinimumFee(change_prototype_size, coin_control, ::mempool, ::feeEstimator, nullptr);
2773-
CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, ::dustRelayFee);
2787+
CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate);
27742788
CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change;
27752789
if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
27762790
pick_new_inputs = false;
@@ -3811,6 +3825,9 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
38113825
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
38123826
strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
38133827
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
3828+
strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) used to discard change (to fee) if it would be dust at this fee rate (default: %s) "
3829+
"Note: We will always discard up to the dust relay fee and a discard fee above that is limited by the longest target fee estimate"),
3830+
CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)));
38143831
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
38153832
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
38163833
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
@@ -4136,6 +4153,16 @@ bool CWallet::ParameterInteraction()
41364153
_("This is the transaction fee you may pay when fee estimates are not available."));
41374154
CWallet::fallbackFee = CFeeRate(nFeePerK);
41384155
}
4156+
if (IsArgSet("-discardfee"))
4157+
{
4158+
CAmount nFeePerK = 0;
4159+
if (!ParseMoney(GetArg("-discardfee", ""), nFeePerK))
4160+
return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), GetArg("-discardfee", "")));
4161+
if (nFeePerK > HIGH_TX_FEE_PER_KB)
4162+
InitWarning(AmountHighWarn("-discardfee") + " " +
4163+
_("This is the transaction fee you may discard if change is smaller than dust at this level"));
4164+
CWallet::m_discard_rate = CFeeRate(nFeePerK);
4165+
}
41394166
if (IsArgSet("-paytxfee"))
41404167
{
41414168
CAmount nFeePerK = 0;

src/wallet/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
4545
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
4646
//! -fallbackfee default
4747
static const CAmount DEFAULT_FALLBACK_FEE = 20000;
48+
//! -m_discard_rate default
49+
static const CAmount DEFAULT_DISCARD_FEE = 10000;
4850
//! -mintxfee default
4951
static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
5052
//! minimum recommended increment for BIP 125 replacement txs
@@ -969,6 +971,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
969971

970972
static CFeeRate minTxFee;
971973
static CFeeRate fallbackFee;
974+
static CFeeRate m_discard_rate;
972975
/**
973976
* Estimate the minimum fee considering user set parameters
974977
* and the required fee

0 commit comments

Comments
 (0)