diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -12,3 +12,6 @@ - Deprecated estimatefee RPC command - Improved help message for backup wallet RPC - Various bug fixes that improve node stability and performance + +Backwards-incompatible or otherwise breaking changes: + - Change `-maxtxfee` from a total fee to a fee per kb. diff --git a/src/config.h b/src/config.h --- a/src/config.h +++ b/src/config.h @@ -38,8 +38,8 @@ * mempool * (rejects high fee in sendrawtransaction) */ - virtual bool SetMaxFee(Amount amt) = 0; - virtual Amount GetMaxFee() const = 0; + virtual bool SetMaxFeePerKB(CFeeRate amt) = 0; + virtual CFeeRate GetMaxFeePerKB() const = 0; virtual void SetRPCUserAndPassword(std::string userAndPassword) = 0; virtual std::string GetRPCUserAndPassword() const = 0; @@ -64,8 +64,8 @@ void SetMinFeePerKB(CFeeRate amt) override; CFeeRate GetMinFeePerKB() const override; - bool SetMaxFee(Amount amt) override; - Amount GetMaxFee() const override; + bool SetMaxFeePerKB(CFeeRate amt) override; + CFeeRate GetMaxFeePerKB() const override; void SetRPCUserAndPassword(std::string userAndPassword) override; std::string GetRPCUserAndPassword() const override; @@ -76,7 +76,7 @@ bool useCashAddr; Amount excessUTXOCharge; CFeeRate minFeePerKB; - Amount maxFee; + CFeeRate maxFeePerKB; }; // Dummy for subclassing in unittests @@ -105,8 +105,8 @@ return CFeeRate(Amount::zero()); } - bool SetMaxFee(Amount amt) override { return false; }; - Amount GetMaxFee() const override { return MAX_MONEY; } + bool SetMaxFeePerKB(CFeeRate amt) override { return false; }; + CFeeRate GetMaxFeePerKB() const override { return CFeeRate(MAX_MONEY); } void SetRPCUserAndPassword(std::string userAndPassword) override{}; std::string GetRPCUserAndPassword() const override { return ""; }; diff --git a/src/config.cpp b/src/config.cpp --- a/src/config.cpp +++ b/src/config.cpp @@ -80,16 +80,16 @@ return minFeePerKB; } -bool GlobalConfig::SetMaxFee(Amount fee) { - if (minFeePerKB.GetFeePerK() > fee) { +bool GlobalConfig::SetMaxFeePerKB(CFeeRate fee) { + if (minFeePerKB >= fee) { return false; } - maxFee = fee; + maxFeePerKB = fee; return true; } -Amount GlobalConfig::GetMaxFee() const { - return maxFee; +CFeeRate GlobalConfig::GetMaxFeePerKB() const { + return maxFeePerKB; } void GlobalConfig::SetRPCUserAndPassword(std::string userAndPassword) { diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -769,10 +769,11 @@ CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE_PER_KB))); strUsage += HelpMessageOpt( "-maxtxfee=", - strprintf(_("Maximum total fees (in %s) to use in a single wallet " + strprintf(_("Maximum total fees (in %s/kB) to use in a single wallet " "transaction or raw transaction; setting this too low may " "abort large transactions (default: %s)"), - CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE))); + CURRENCY_UNIT, + FormatMoney(DEFAULT_TRANSACTION_MAXFEE_PER_KB))); strUsage += HelpMessageOpt( "-printtoconsole", _("Send trace/debug info to console instead of debug.log file")); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -606,7 +606,7 @@ tr("A fee higher than %1 is considered an absurdly high fee.") .arg(BitcoinUnits::formatWithUnit( model->getOptionsModel()->getDisplayUnit(), - GetConfig().GetMaxFee())); + GetConfig().GetMaxFeePerKB())); break; case WalletModel::PaymentRequestExpired: msgParams.first = tr("Payment request expired."); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1133,9 +1133,9 @@ const uint256 &txid = tx->GetId(); bool fLimitFree = false; - Amount nMaxRawTxFee = config.GetMaxFee(); + CFeeRate nMaxRawTxFee = config.GetMaxFeePerKB(); if (request.params.size() > 1 && request.params[1].get_bool()) { - nMaxRawTxFee = Amount::zero(); + nMaxRawTxFee = CFeeRate(Amount::zero()); } CCoinsViewCache &view = *pcoinsTip; diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -63,12 +63,13 @@ /** Default for -excessutxocharge for transactions transactions */ static const Amount DEFAULT_UTXO_FEE = Amount::zero(); //! -maxtxfee default -static const Amount DEFAULT_TRANSACTION_MAXFEE(COIN / 10); +static const Amount DEFAULT_TRANSACTION_MAXFEE_PER_KB = + 10000 * DEFAULT_MIN_RELAY_TX_FEE_PER_KB; //! Discourage users to set fees higher than this amount (in satoshis) per kB static const Amount HIGH_TX_FEE_PER_KB(COIN / 100); /** -maxtxfee will warn if called with a higher fee than this amount (in * satoshis */ -static const Amount HIGH_MAX_TX_FEE(100 * HIGH_TX_FEE_PER_KB); +static const Amount HIGH_MAX_TX_FEE(10 * DEFAULT_TRANSACTION_MAXFEE_PER_KB); /** Default for -limitancestorcount, max number of in-mempool ancestors */ static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25; /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool @@ -444,7 +445,7 @@ CValidationState &state, const CTransactionRef &tx, bool fLimitFree, bool *pfMissingInputs, bool fOverrideMempoolLimit = false, - const Amount nAbsurdFee = Amount::zero()); + const CFeeRate nAbsurdFee = CFeeRate(Amount::zero())); /** Convert CValidationState to a human-readable message for logging */ std::string FormatStateMessage(const CValidationState &state); diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -370,7 +370,7 @@ static bool AcceptToMemoryPoolWorker( const Config &config, CTxMemPool &pool, CValidationState &state, const CTransactionRef &ptx, bool fLimitFree, bool *pfMissingInputs, - int64_t nAcceptTime, bool fOverrideMempoolLimit, const Amount nAbsurdFee, + int64_t nAcceptTime, bool fOverrideMempoolLimit, const CFeeRate nAbsurdFee, std::vector &coins_to_uncache) { AssertLockHeld(cs_main); @@ -588,9 +588,11 @@ dFreeCount += nSize; } - if (nAbsurdFee != Amount::zero() && nFees > nAbsurdFee) { - return state.Invalid(false, REJECT_HIGHFEE, "absurdly-high-fee", - strprintf("%d > %d", nFees, nAbsurdFee)); + if (nAbsurdFee != CFeeRate(Amount::zero()) && + nFees > nAbsurdFee.GetFee(nSize)) { + return state.Invalid( + false, REJECT_HIGHFEE, "absurdly-high-fee", + strprintf("%d > %d", nFees, nAbsurdFee.GetFee(nSize))); } // Calculate in-mempool ancestors, up to a limit. @@ -722,7 +724,7 @@ const Config &config, CTxMemPool &pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree, bool *pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit = false, - const Amount nAbsurdFee = Amount::zero()) { + const CFeeRate nAbsurdFee = CFeeRate(Amount::zero())) { std::vector coins_to_uncache; bool res = AcceptToMemoryPoolWorker( config, pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, @@ -743,7 +745,7 @@ bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree, bool *pfMissingInputs, - bool fOverrideMempoolLimit, const Amount nAbsurdFee) { + bool fOverrideMempoolLimit, const CFeeRate nAbsurdFee) { return AcceptToMemoryPoolWithTime(config, pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), fOverrideMempoolLimit, nAbsurdFee); diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -33,7 +33,7 @@ std::max(nFeeNeeded, GetConfig().GetMinFeePerKB().GetFee(nTxBytes)); // But always obey the maximum. - Amount maxFee = GetConfig().GetMaxFee(); + Amount maxFee = GetConfig().GetMaxFeePerKB().GetFee(nTxBytes); if (nFeeNeeded > maxFee) { nFeeNeeded = maxFee; } diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -219,7 +219,7 @@ } } - config.SetMaxFee(DEFAULT_TRANSACTION_MAXFEE); + config.SetMaxFeePerKB(CFeeRate(DEFAULT_TRANSACTION_MAXFEE_PER_KB)); if (gArgs.IsArgSet("-maxtxfee")) { Amount nMaxFee = Amount::zero(); if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) { @@ -232,7 +232,7 @@ "be paid on a single transaction.")); } - if (!config.SetMaxFee(nMaxFee)) { + if (!config.SetMaxFeePerKB(CFeeRate(nMaxFee))) { return InitError(strprintf( _("Invalid amount for -maxtxfee=: '%s' (must " "be at least the minrelay fee of %s to prevent " diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4257,5 +4257,5 @@ bool CMerkleTx::AcceptToMemoryPool(CValidationState &state) { const Config &config = GetConfig(); return ::AcceptToMemoryPool(config, mempool, state, tx, true, nullptr, - false, config.GetMaxFee()); + false, config.GetMaxFeePerKB()); }