diff --git a/src/config.h b/src/config.h --- a/src/config.h +++ b/src/config.h @@ -33,6 +33,14 @@ virtual void SetMinFeePerKB(CFeeRate amt) = 0; virtual CFeeRate GetMinFeePerKB() const = 0; + /** + * Absolute maximum transaction fee per kb (in satoshis) used by wallet and + * mempool + * (rejects high fee in sendrawtransaction) + */ + virtual bool SetMaxFee(Amount amt) = 0; + virtual Amount GetMaxFee() const = 0; + virtual void SetRPCUserAndPassword(std::string userAndPassword) = 0; virtual std::string GetRPCUserAndPassword() const = 0; virtual void SetRPCCORSDomain(std::string corsDomain) = 0; @@ -56,6 +64,9 @@ void SetMinFeePerKB(CFeeRate amt) override; CFeeRate GetMinFeePerKB() const override; + bool SetMaxFee(Amount amt) override; + Amount GetMaxFee() const override; + void SetRPCUserAndPassword(std::string userAndPassword) override; std::string GetRPCUserAndPassword() const override; void SetRPCCORSDomain(std::string corsDomain) override; @@ -77,6 +88,9 @@ /** The largest block size this node will accept. */ uint64_t nMaxBlockSize; uint64_t nBlockPriorityPercentage; + + CFeeRate minFeePerKB; + Amount maxFee; }; // Dummy for subclassing in unittests @@ -105,6 +119,9 @@ return CFeeRate(Amount::zero()); } + bool SetMaxFee(Amount amt) override; + Amount GetMaxFee() const override; + void SetRPCUserAndPassword(std::string userAndPassword) override{}; std::string GetRPCUserAndPassword() const override { return ""; }; void SetRPCCORSDomain(std::string corsDomain) override{}; diff --git a/src/config.cpp b/src/config.cpp --- a/src/config.cpp +++ b/src/config.cpp @@ -7,10 +7,12 @@ #include "consensus/consensus.h" // DEFAULT_MAX_BLOCK_SIZE #include "globals.h" #include "policy/policy.h" // DEFAULT_BLOCK_PRIORITY_PERCENTAGE +#include "validation.h" // DEFAULT_TRANSACTION_MAXFEE GlobalConfig::GlobalConfig() : useCashAddr(false), nMaxBlockSize(DEFAULT_MAX_BLOCK_SIZE), - nBlockPriorityPercentage(DEFAULT_BLOCK_PRIORITY_PERCENTAGE) {} + nBlockPriorityPercentage(DEFAULT_BLOCK_PRIORITY_PERCENTAGE), + maxFee(DEFAULT_TRANSACTION_MAXFEE) {} bool GlobalConfig::SetMaxBlockSize(uint64_t maxBlockSize) { // Do not allow maxBlockSize to be set below historic 1MB limit @@ -76,11 +78,23 @@ } void GlobalConfig::SetMinFeePerKB(CFeeRate fee) { - feePerKB = fee; + minFeePerKB = fee; } CFeeRate GlobalConfig::GetMinFeePerKB() const { - return feePerKB; + return minFeePerKB; +} + +bool GlobalConfig::SetMaxFee(Amount fee) { + if (minFeePerKB.GetFeePerK() >= fee) { + return false; + } + maxFee = fee; + return true; +} + +Amount GlobalConfig::GetMaxFee() const { + return maxFee; } void GlobalConfig::SetRPCUserAndPassword(std::string userAndPassword) { @@ -98,3 +112,11 @@ std::string GlobalConfig::GetRPCCORSDomain() const { return rpcCORSDomain; } + +bool DummyConfig::SetMaxFee(Amount amt) { + return false; +}; + +Amount DummyConfig::GetMaxFee() const { + return DEFAULT_TRANSACTION_MAXFEE; +} diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -1652,7 +1652,7 @@ nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp); #ifdef ENABLE_WALLET - if (!WalletParameterInteraction()) { + if (!WalletParameterInteraction(config)) { return false; } #endif diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -9,6 +9,7 @@ #include "bitcoinunits.h" #include "clientmodel.h" #include "coincontroldialog.h" +#include "config.h" #include "guiutil.h" #include "optionsmodel.h" #include "platformstyle.h" @@ -604,7 +605,8 @@ msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.") .arg(BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), maxTxFee)); + model->getOptionsModel()->getDisplayUnit(), + GetConfig().GetMaxFee())); break; case WalletModel::PaymentRequestExpired: msgParams.first = tr("Payment request expired."); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -288,13 +288,6 @@ CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } - - // reject absurdly high fee. (This can never happen because the wallet - // caps the fee at maxTxFee. This merely serves as a belt-and-suspenders - // check) - if (nFeeRequired > Amount(maxTxFee)) { - return AbsurdFee; - } } return SendCoinsReturn(OK); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1209,7 +1209,7 @@ const uint256 &txid = tx->GetId(); bool fLimitFree = false; - Amount nMaxRawTxFee = maxTxFee; + Amount nMaxRawTxFee = config.GetMaxFee(); if (request.params.size() > 1 && request.params[1].get_bool()) { nMaxRawTxFee = Amount::zero(); } diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -215,11 +215,6 @@ extern bool fCheckpointsEnabled; extern size_t nCoinCacheUsage; -/** - * Absolute maximum transaction fee (in satoshis) used by wallet and mempool - * (rejects high fee in sendrawtransaction) - */ -extern Amount maxTxFee; /** * If the tip is older than this (in seconds), the node is considered to be in * initial block download. diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -84,8 +84,6 @@ uint256 hashAssumeValid; arith_uint256 nMinimumChainWork; -Amount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; - CTxMemPool mempool; static void CheckBlockIndex(const Consensus::Params &consensusParams); diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -33,8 +33,9 @@ std::max(nFeeNeeded, GetConfig().GetMinFeePerKB().GetFee(nTxBytes)); // But always obey the maximum. - if (nFeeNeeded > maxTxFee) { - nFeeNeeded = maxTxFee; + Amount maxFee = GetConfig().GetMaxFee(); + if (nFeeNeeded > maxFee) { + nFeeNeeded = maxFee; } return nFeeNeeded; diff --git a/src/wallet/init.h b/src/wallet/init.h --- a/src/wallet/init.h +++ b/src/wallet/init.h @@ -19,7 +19,7 @@ /** * Wallets parameter interaction */ -bool WalletParameterInteraction(); +bool WalletParameterInteraction(Config &config); /** * Responsible for reading and validating the -wallet arguments and verifying diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -100,8 +100,8 @@ return strUsage; } -bool WalletParameterInteraction() { - CFeeRate minRelayTxFee = GetConfig().GetMinFeePerKB(); +bool WalletParameterInteraction(Config &config) { + CFeeRate minRelayTxFee = config.GetMinFeePerKB(); gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT); const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1; @@ -231,8 +231,7 @@ "be paid on a single transaction.")); } - maxTxFee = nMaxFee; - if (CFeeRate(maxTxFee, 1000) < minRelayTxFee) { + if (!config.SetMaxFee(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.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -262,7 +262,7 @@ * Pass this transaction to the mempool. Fails if absolute fee exceeds * absurd fee. */ - bool AcceptToMemoryPool(const Amount nAbsurdFee, CValidationState &state); + bool AcceptToMemoryPool(CValidationState &state); bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1763,7 +1763,7 @@ LOCK(mempool.cs); CValidationState state; - wtx.AcceptToMemoryPool(maxTxFee, state); + wtx.AcceptToMemoryPool(state); } } @@ -1775,7 +1775,7 @@ CValidationState state; // GetDepthInMainChain already catches known conflicts. - if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) { + if (InMempool() || AcceptToMemoryPool(state)) { LogPrintf("Relaying wtx %s\n", GetId().ToString()); if (connman) { CInv inv(MSG_TX, GetId()); @@ -3096,7 +3096,7 @@ if (fBroadcastTransactions) { // Broadcast - if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) { + if (!wtxNew.AcceptToMemoryPool(state)) { LogPrintf("CommitTransaction(): Transaction cannot be " "broadcast immediately, %s\n", state.GetRejectReason()); @@ -4264,8 +4264,8 @@ return GetBlocksToMaturity() > 0; } -bool CMerkleTx::AcceptToMemoryPool(const Amount nAbsurdFee, - CValidationState &state) { - return ::AcceptToMemoryPool(GetConfig(), mempool, state, tx, true, nullptr, - false, nAbsurdFee); +bool CMerkleTx::AcceptToMemoryPool(CValidationState &state) { + const Config &config = GetConfig(); + return ::AcceptToMemoryPool(config, mempool, state, tx, true, nullptr, + false, config.GetMaxFee()); }