Skip to content

Commit dd98f04

Browse files
committed
Merge #9380: Separate different uses of minimum fees
eb30d1a Introduce -dustrelayfee (Alex Morcos) 7b1add3 Introduce -incrementalrelayfee (Alex Morcos) daec955 Introduce -blockmintxfee (Alex Morcos)
2 parents 8a445c5 + eb30d1a commit dd98f04

File tree

12 files changed

+82
-30
lines changed

12 files changed

+82
-30
lines changed

src/init.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,11 @@ std::string HelpMessage(HelpMessageMode mode)
467467
AppendParamsHelpMessages(strUsage, showDebug);
468468

469469
strUsage += HelpMessageGroup(_("Node relay options:"));
470-
if (showDebug)
470+
if (showDebug) {
471471
strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard()));
472+
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)));
473+
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)));
474+
}
472475
strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
473476
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));
474477
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
@@ -478,6 +481,7 @@ std::string HelpMessage(HelpMessageMode mode)
478481
strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT));
479482
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
480483
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
484+
strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));
481485
if (showDebug)
482486
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
483487

@@ -925,6 +929,15 @@ bool AppInitParameterInteraction()
925929
int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
926930
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
927931
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
932+
// incremental relay fee sets the minimimum feerate increase necessary for BIP 125 replacement in the mempool
933+
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
934+
if (IsArgSet("-incrementalrelayfee"))
935+
{
936+
CAmount n = 0;
937+
if (!ParseMoney(GetArg("-incrementalrelayfee", ""), n))
938+
return InitError(AmountErrMsg("incrementalrelayfee", GetArg("-incrementalrelayfee", "")));
939+
incrementalRelayFee = CFeeRate(n);
940+
}
928941

929942
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
930943
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
@@ -975,6 +988,29 @@ bool AppInitParameterInteraction()
975988
return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
976989
// High fee check is done afterward in CWallet::ParameterInteraction()
977990
::minRelayTxFee = CFeeRate(n);
991+
} else if (incrementalRelayFee > ::minRelayTxFee) {
992+
// Allow only setting incrementalRelayFee to control both
993+
::minRelayTxFee = incrementalRelayFee;
994+
LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString());
995+
}
996+
997+
// Sanity check argument for min fee for including tx in block
998+
// TODO: Harmonize which arguments need sanity checking and where that happens
999+
if (IsArgSet("-blockmintxfee"))
1000+
{
1001+
CAmount n = 0;
1002+
if (!ParseMoney(GetArg("-blockmintxfee", ""), n))
1003+
return InitError(AmountErrMsg("blockmintxfee", GetArg("-blockmintxfee", "")));
1004+
}
1005+
1006+
// Feerate used to define dust. Shouldn't be changed lightly as old
1007+
// implementations may inadvertently create non-standard transactions
1008+
if (IsArgSet("-dustrelayfee"))
1009+
{
1010+
CAmount n = 0;
1011+
if (!ParseMoney(GetArg("-dustrelayfee", ""), n) || 0 == n)
1012+
return InitError(AmountErrMsg("dustrelayfee", GetArg("-dustrelayfee", "")));
1013+
dustRelayFee = CFeeRate(n);
9781014
}
9791015

9801016
fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());

src/miner.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,18 @@ BlockAssembler::BlockAssembler(const CChainParams& _chainparams)
9595
nBlockMaxWeight = nBlockMaxSize * WITNESS_SCALE_FACTOR;
9696
}
9797
}
98+
if (IsArgSet("-blockmintxfee")) {
99+
CAmount n = 0;
100+
ParseMoney(GetArg("-blockmintxfee", ""), n);
101+
blockMinFeeRate = CFeeRate(n);
102+
} else {
103+
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
104+
}
98105

99106
// Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
100107
nBlockMaxWeight = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_WEIGHT-4000), nBlockMaxWeight));
101108
// Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
102109
nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SERIALIZED_SIZE-1000), nBlockMaxSize));
103-
104110
// Whether we need to account for byte usage (in addition to weight usage)
105111
fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000);
106112
}
@@ -460,7 +466,7 @@ void BlockAssembler::addPackageTxs()
460466
packageSigOpsCost = modit->nSigOpCostWithAncestors;
461467
}
462468

463-
if (packageFees < ::minRelayTxFee.GetFee(packageSize)) {
469+
if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
464470
// Everything else we might consider has a lower fee rate
465471
return;
466472
}

src/miner.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class BlockAssembler
143143
bool fIncludeWitness;
144144
unsigned int nBlockMaxWeight, nBlockMaxSize;
145145
bool fNeedSizeAccounting;
146+
CFeeRate blockMinFeeRate;
146147

147148
// Information on the current status of the block
148149
uint64_t nBlockWeight;

src/policy/policy.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
105105
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
106106
reason = "bare-multisig";
107107
return false;
108-
} else if (txout.IsDust(::minRelayTxFee)) {
108+
} else if (txout.IsDust(dustRelayFee)) {
109109
reason = "dust";
110110
return false;
111111
}
@@ -206,6 +206,8 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
206206
return true;
207207
}
208208

209+
CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
210+
CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
209211
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
210212

211213
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)

src/policy/policy.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
2020
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 0;
2121
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
2222
static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000;
23+
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
24+
static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;
2325
/** The maximum weight for transactions we're willing to relay/mine */
2426
static const unsigned int MAX_STANDARD_TX_WEIGHT = 400000;
2527
/** Maximum number of signature check operations in an IsStandard() P2SH script */
@@ -28,6 +30,8 @@ static const unsigned int MAX_P2SH_SIGOPS = 15;
2830
static const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5;
2931
/** Default for -maxmempool, maximum megabytes of mempool memory usage */
3032
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
33+
/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/
34+
static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
3135
/** Default for -bytespersigop */
3236
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
3337
/** The maximum number of witness stack items in a standard P2WSH script */
@@ -36,6 +40,12 @@ static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
3640
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
3741
/** The maximum size of a standard witnessScript */
3842
static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
43+
/** Min feerate for defining dust. Historically this has been the same as the
44+
* minRelayTxFee, however changing the dust limit changes which transactions are
45+
* standard and should be done with care and ideally rarely. It makes sense to
46+
* only increase the dust limit after prior releases were already not creating
47+
* outputs below the new threshold */
48+
static const unsigned int DUST_RELAY_TX_FEE = 1000;
3949
/**
4050
* Standard script verification flags that standard transactions will comply
4151
* with. However scripts violating these flags may still be present in valid
@@ -83,6 +93,8 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
8393
*/
8494
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
8595

96+
extern CFeeRate incrementalRelayFee;
97+
extern CFeeRate dustRelayFee;
8698
extern unsigned int nBytesPerSigOp;
8799

88100
/** Compute the virtual transaction size (weight reinterpreted as bytes). */

src/qt/coincontroldialog.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
#include "wallet/coincontrol.h"
1717
#include "init.h"
18-
#include "validation.h" // For minRelayTxFee
18+
#include "policy/policy.h"
19+
#include "validation.h" // For mempool
1920
#include "wallet/wallet.h"
2021

2122
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
@@ -432,7 +433,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
432433
{
433434
CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0));
434435
txDummy.vout.push_back(txout);
435-
if (txout.IsDust(::minRelayTxFee))
436+
if (txout.IsDust(dustRelayFee))
436437
fDust = true;
437438
}
438439
}
@@ -545,10 +546,10 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
545546
if (nChange > 0 && nChange < MIN_CHANGE)
546547
{
547548
CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
548-
if (txout.IsDust(::minRelayTxFee))
549+
if (txout.IsDust(dustRelayFee))
549550
{
550551
if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
551-
nChange = txout.GetDustThreshold(::minRelayTxFee);
552+
nChange = txout.GetDustThreshold(dustRelayFee);
552553
else
553554
{
554555
nPayFee += nChange;

src/qt/guiutil.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
#include "primitives/transaction.h"
1313
#include "init.h"
14-
#include "validation.h" // For minRelayTxFee
14+
#include "policy/policy.h"
1515
#include "protocol.h"
1616
#include "script/script.h"
1717
#include "script/standard.h"
@@ -257,7 +257,7 @@ bool isDust(const QString& address, const CAmount& amount)
257257
CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
258258
CScript script = GetScriptForDestination(dest);
259259
CTxOut txOut(amount, script);
260-
return txOut.IsDust(::minRelayTxFee);
260+
return txOut.IsDust(dustRelayFee);
261261
}
262262

263263
QString HtmlEscape(const QString& str, bool fMultiLine)

src/qt/paymentserver.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#include "base58.h"
1212
#include "chainparams.h"
13-
#include "validation.h" // For minRelayTxFee
13+
#include "policy/policy.h"
1414
#include "ui_interface.h"
1515
#include "util.h"
1616
#include "wallet/wallet.h"
@@ -582,7 +582,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
582582

583583
// Extract and check amounts
584584
CTxOut txOut(sendingTo.second, sendingTo.first);
585-
if (txOut.IsDust(::minRelayTxFee)) {
585+
if (txOut.IsDust(dustRelayFee)) {
586586
Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
587587
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
588588
CClientUIInterface::MSG_ERROR);

src/test/transaction_tests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
690690
BOOST_CHECK(IsStandardTx(t, reason));
691691

692692
// Check dust with default relay fee:
693-
CAmount nDustThreshold = 182 * minRelayTxFee.GetFeePerK()/1000 * 3;
693+
CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000 * 3;
694694
BOOST_CHECK_EQUAL(nDustThreshold, 546);
695695
// dust:
696696
t.vout[0].nValue = nDustThreshold - 1;
@@ -701,14 +701,14 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
701701

702702
// Check dust with odd relay fee to verify rounding:
703703
// nDustThreshold = 182 * 1234 / 1000 * 3
704-
minRelayTxFee = CFeeRate(1234);
704+
dustRelayFee = CFeeRate(1234);
705705
// dust:
706706
t.vout[0].nValue = 672 - 1;
707707
BOOST_CHECK(!IsStandardTx(t, reason));
708708
// not dust:
709709
t.vout[0].nValue = 672;
710710
BOOST_CHECK(IsStandardTx(t, reason));
711-
minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
711+
dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
712712

713713
t.vout[0].scriptPubKey = CScript() << OP_1;
714714
BOOST_CHECK(!IsStandardTx(t, reason));

src/txmempool.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
359359
nCheckFrequency = 0;
360360

361361
minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee);
362-
minReasonableRelayFee = _minReasonableRelayFee;
363362
}
364363

365364
CTxMemPool::~CTxMemPool()
@@ -1076,12 +1075,12 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
10761075
rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
10771076
lastRollingFeeUpdate = time;
10781077

1079-
if (rollingMinimumFeeRate < (double)minReasonableRelayFee.GetFeePerK() / 2) {
1078+
if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {
10801079
rollingMinimumFeeRate = 0;
10811080
return CFeeRate(0);
10821081
}
10831082
}
1084-
return std::max(CFeeRate(rollingMinimumFeeRate), minReasonableRelayFee);
1083+
return std::max(CFeeRate(rollingMinimumFeeRate), incrementalRelayFee);
10851084
}
10861085

10871086
void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
@@ -1105,7 +1104,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
11051104
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
11061105
// equal to txn which were removed with no block in between.
11071106
CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
1108-
removed += minReasonableRelayFee;
1107+
removed += incrementalRelayFee;
11091108
trackPackageRemoved(removed);
11101109
maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
11111110

0 commit comments

Comments
 (0)