aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfanquake <fanquake@gmail.com>2020-10-07 10:35:01 +0800
committerfanquake <fanquake@gmail.com>2020-10-07 10:58:30 +0800
commitdb88db47278d2e7208c50d16ab10cb355067d071 (patch)
treed2691df090af42be8c95c9585e6d969ed61dce1b
parentd8cd7b137fb075616f31d2b43b85fa2e27ea7477 (diff)
parentb048b275d9711f70847afaea5450f17a0f7e673a (diff)
downloadbitcoin-db88db47278d2e7208c50d16ab10cb355067d071.tar.xz
Merge #19339: validation: re-delegate absurd fee checking from mempool to clients
b048b275d9711f70847afaea5450f17a0f7e673a [validation] Remove absurdfee from accepttomempool (John Newbery) 932564b9cfda8446a957649c2316a52e868ad5d4 scripted-diff: update max-fee-exceeded error message to include RPC (gzhao408) 8f1290c60159a3171c27250bc95687548c5c1b84 [rpc/node] check for high fee before ATMP in clients (gzhao408) Pull request description: Picked up from #15810. Add separate fee-checking logic for clients that need to enforce max fee rates, then remove the `absurdFee` logic from ATMP. ATMP's `nAbsurdFee` argument is used to enforce user-specific behavior (it is not policy since it isn't applied consistently: it is only ever used in RPC and wallet, and set to 0 everywhere else internally). It should be removed from `AcceptToMemoryPool` because (1) validation results/mempool behavior should not be user-specific and (2) enforcing a max fee rate should be the responsibility of the client instead of the mempool. Note: this PR does not intend to _remove_ protection from high fees, just re-delegate the responsibility to clients. ACKs for top commit: jnewbery: utACK b048b275d9711f70847afaea5450f17a0f7e673a LarryRuane: re-ACK b048b275d9711f70847afaea5450f17a0f7e673a MarcoFalke: re-ACK b048b275d9 , only change is squashing one commit 🏦 instagibbs: utACK https://github.com/bitcoin/bitcoin/pull/19339/commits/b048b275d9711f70847afaea5450f17a0f7e673a Tree-SHA512: 57c17ba16d230a4cae2896dd6a64c924f307757824e35784bf96da7b10aff2d8ea910710edf35e981035623a155f8766209a92a0fdb856549fde78bc3eaae4d2
-rw-r--r--src/bench/block_assemble.cpp2
-rw-r--r--src/net_processing.cpp4
-rw-r--r--src/node/transaction.cpp38
-rw-r--r--src/rpc/rawtransaction.cpp12
-rw-r--r--src/test/txvalidation_tests.cpp3
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/test/validation_block_tests.cpp3
-rw-r--r--src/util/error.cpp2
-rw-r--r--src/validation.cpp18
-rw-r--r--src/validation.h2
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py2
-rwxr-xr-xtest/functional/rpc_psbt.py4
-rwxr-xr-xtest/functional/rpc_rawtransaction.py8
-rwxr-xr-xtest/functional/wallet_bumpfee.py2
-rwxr-xr-xtest/functional/wallet_create_tx.py8
15 files changed, 63 insertions, 47 deletions
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index 3f15f3f856..99a7ad237b 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -49,7 +49,7 @@ static void AssembleBlock(benchmark::Bench& bench)
for (const auto& txr : txs) {
TxValidationState state;
- bool ret{::AcceptToMemoryPool(*test_setup.m_node.mempool, state, txr, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
+ bool ret{::AcceptToMemoryPool(*test_setup.m_node.mempool, state, txr, nullptr /* plTxnReplaced */, false /* bypass_limits */)};
assert(ret);
}
}
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 2634dccd45..41fe1e0298 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2069,7 +2069,7 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
TxValidationState state;
std::list<CTransactionRef> removed_txn;
- if (AcceptToMemoryPool(m_mempool, state, porphanTx, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ if (AcceptToMemoryPool(m_mempool, state, porphanTx, &removed_txn, false /* bypass_limits */)) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanHash, porphanTx->GetWitnessHash(), m_connman);
for (unsigned int i = 0; i < porphanTx->vout.size(); i++) {
@@ -3024,7 +3024,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
// (older than our recency filter) if trying to DoS us, without any need
// for witness malleation.
if (!AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid), m_mempool) &&
- AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */)) {
m_mempool.check(&::ChainstateActive().CoinsTip());
RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 9ae4700743..b72f7b70e9 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -13,6 +13,18 @@
#include <future>
+static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out) {
+ err_string_out = state.ToString();
+ if (state.IsInvalid()) {
+ if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
+ return TransactionError::MISSING_INPUTS;
+ }
+ return TransactionError::MEMPOOL_REJECTED;
+ } else {
+ return TransactionError::MEMPOOL_ERROR;
+ }
+}
+
TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
{
// BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs.
@@ -36,20 +48,24 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
}
if (!node.mempool->exists(hashTx)) {
- // Transaction is not already in the mempool. Submit it.
+ // Transaction is not already in the mempool.
TxValidationState state;
- if (!AcceptToMemoryPool(*node.mempool, state, tx,
- nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
- err_string = state.ToString();
- if (state.IsInvalid()) {
- if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
- return TransactionError::MISSING_INPUTS;
- }
- return TransactionError::MEMPOOL_REJECTED;
- } else {
- return TransactionError::MEMPOOL_ERROR;
+ CAmount fee{0};
+ if (max_tx_fee) {
+ // First, call ATMP with test_accept and check the fee. If ATMP
+ // fails here, return error immediately.
+ if (!AcceptToMemoryPool(*node.mempool, state, tx,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee)) {
+ return HandleATMPError(state, err_string);
+ } else if (fee > max_tx_fee) {
+ return TransactionError::MAX_FEE_EXCEEDED;
}
}
+ // Try to submit the transaction to the mempool.
+ if (!AcceptToMemoryPool(*node.mempool, state, tx,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */)) {
+ return HandleATMPError(state, err_string);
+ }
// Transaction was accepted to the mempool.
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index e60e0a2d90..7a6b605ec3 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -947,11 +947,19 @@ static RPCHelpMan testmempoolaccept()
TxValidationState state;
bool test_accept_res;
- CAmount fee;
+ CAmount fee{0};
{
LOCK(cs_main);
test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx),
- nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true, &fee);
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee);
+ }
+
+ // Check that fee does not exceed maximum fee
+ if (test_accept_res && max_raw_tx_fee && fee > max_raw_tx_fee) {
+ result_0.pushKV("allowed", false);
+ result_0.pushKV("reject-reason", "max-fee-exceeded");
+ result.push_back(std::move(result_0));
+ return result;
}
result_0.pushKV("allowed", test_accept_res);
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
index c3d7af8323..7e6246d68f 100644
--- a/src/test/txvalidation_tests.cpp
+++ b/src/test/txvalidation_tests.cpp
@@ -40,8 +40,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
false,
AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(coinbaseTx),
nullptr /* plTxnReplaced */,
- true /* bypass_limits */,
- 0 /* nAbsurdFee */));
+ true /* bypass_limits */));
// Check that the transaction hasn't been added to mempool.
BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 034577aa2c..bed2ba3608 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
TxValidationState state;
return AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(tx),
- nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */);
+ nullptr /* plTxnReplaced */, true /* bypass_limits */);
};
// Create a double-spend of mature coinbase txn:
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 8e85b7df3e..ea17cb50f1 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -291,8 +291,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
state,
tx,
&plTxnReplaced,
- /* bypass_limits */ false,
- /* nAbsurdFee */ 0));
+ /* bypass_limits */ false));
}
}
diff --git a/src/util/error.cpp b/src/util/error.cpp
index 3e29083712..6c94b80683 100644
--- a/src/util/error.cpp
+++ b/src/util/error.cpp
@@ -30,7 +30,7 @@ bilingual_str TransactionErrorString(const TransactionError err)
case TransactionError::SIGHASH_MISMATCH:
return Untranslated("Specified sighash value does not match value stored in PSBT");
case TransactionError::MAX_FEE_EXCEEDED:
- return Untranslated("Fee exceeds maximum configured by -maxtxfee");
+ return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)");
// no default case, so the compiler can warn about missing cases
}
assert(false);
diff --git a/src/validation.cpp b/src/validation.cpp
index e9c0607ced..06b9b36fca 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -384,7 +384,7 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
TxValidationState stateDummy;
if (!fAddToMempool || (*it)->IsCoinBase() ||
!AcceptToMemoryPool(mempool, stateDummy, *it,
- nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ nullptr /* plTxnReplaced */, true /* bypass_limits */)) {
// If the transaction doesn't make it in to the mempool, remove any
// transactions that depend on it (which would now be orphans).
mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
@@ -463,7 +463,6 @@ public:
const int64_t m_accept_time;
std::list<CTransactionRef>* m_replaced_transactions;
const bool m_bypass_limits;
- const CAmount& m_absurd_fee;
/*
* Return any outpoints which were not previously present in the coins
* cache, but were added as a result of validating the tx for mempool
@@ -558,7 +557,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
TxValidationState &state = args.m_state;
const int64_t nAcceptTime = args.m_accept_time;
const bool bypass_limits = args.m_bypass_limits;
- const CAmount& nAbsurdFee = args.m_absurd_fee;
std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache;
// Alias what we need out of ws
@@ -729,10 +727,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// blocks
if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false;
- if (nAbsurdFee && nFees > nAbsurdFee)
- return state.Invalid(TxValidationResult::TX_NOT_STANDARD,
- "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
-
const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts);
// Calculate in-mempool ancestors, up to a limit.
if (setConflicts.size() == 1) {
@@ -1065,10 +1059,10 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
/** (try to) add transaction to memory pool with a specified acceptance time **/
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ bool bypass_limits, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
std::vector<COutPoint> coins_to_uncache;
- MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept, fee_out };
+ MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, coins_to_uncache, test_accept, fee_out };
bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
if (!res) {
// Remove coins that were not present in the coins cache before calling ATMPW;
@@ -1087,10 +1081,10 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept, CAmount* fee_out)
+ bool bypass_limits, bool test_accept, CAmount* fee_out)
{
const CChainParams& chainparams = Params();
- return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept, fee_out);
+ return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, test_accept, fee_out);
}
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
@@ -5079,7 +5073,7 @@ bool LoadMempool(CTxMemPool& pool)
if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nTime,
- nullptr /* plTxnReplaced */, false /* bypass_limits */, 0 /* nAbsurdFee */,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */,
false /* test_accept */);
if (state.IsValid()) {
++count;
diff --git a/src/validation.h b/src/validation.h
index d88bd07765..3d9fa92c15 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -201,7 +201,7 @@ void PruneBlockFilesManual(int nManualPruneHeight);
* @param[out] fee_out optional argument to return tx fee to the caller **/
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool bypass_limits, bool test_accept=false, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 6dcbec2714..7a729f7bc1 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -667,7 +667,7 @@ class RawTransactionsTest(BitcoinTestFramework):
result = self.nodes[3].fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee})
result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10 * self.min_relay_tx_fee})
- assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[3].fundrawtransaction, rawtx, {"feeRate": 1})
+ assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", self.nodes[3].fundrawtransaction, rawtx, {"feeRate": 1})
result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 2453a947cb..10aebc2b1d 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -192,8 +192,8 @@ class PSBTTest(BitcoinTestFramework):
# feeRate of 10 BTC / KB produces a total fee well above -maxtxfee
# previously this was silently capped at -maxtxfee
- assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10, "add_inputs": True})
- assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():1}, 0, {"feeRate": 10, "add_inputs": False})
+ assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10, "add_inputs": True})
+ assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():1}, 0, {"feeRate": 10, "add_inputs": False})
# partially sign multisig things with node 1
psbtx = wmulti.walletcreatefundedpsbt(inputs=[{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], outputs={self.nodes[1].getnewaddress():29.99}, options={'changeAddress': self.nodes[1].getrawchangeaddress()})['psbt']
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index ab27fdca40..d74128b42d 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -456,9 +456,9 @@ class RawTransactionsTest(BitcoinTestFramework):
# Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
assert_equal(testres['allowed'], False)
- assert_equal(testres['reject-reason'], 'absurdly-high-fee')
+ assert_equal(testres['reject-reason'], 'max-fee-exceeded')
# and sendrawtransaction should throw
- assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
+ assert_raises_rpc_error(-25, 'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)', self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
# and the following calls should both succeed
testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']])[0]
assert_equal(testres['allowed'], True)
@@ -480,9 +480,9 @@ class RawTransactionsTest(BitcoinTestFramework):
# Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
assert_equal(testres['allowed'], False)
- assert_equal(testres['reject-reason'], 'absurdly-high-fee')
+ assert_equal(testres['reject-reason'], 'max-fee-exceeded')
# and sendrawtransaction should throw
- assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
+ assert_raises_rpc_error(-25, 'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)', self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
# and the following calls should both succeed
testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate='0.20000000')[0]
assert_equal(testres['allowed'], True)
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 56d1da60b7..4b29e65b09 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -348,7 +348,7 @@ def test_maxtxfee_fails(self, rbf_node, dest_address):
self.restart_node(1, ['-maxtxfee=0.000025'] + self.extra_args[1])
rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
rbfid = spend_one_input(rbf_node, dest_address)
- assert_raises_rpc_error(-4, "Unable to create transaction. Fee exceeds maximum configured by -maxtxfee", rbf_node.bumpfee, rbfid)
+ assert_raises_rpc_error(-4, "Unable to create transaction. Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", rbf_node.bumpfee, rbfid)
self.restart_node(1, self.extra_args[1])
rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
self.connect_nodes(1, 0)
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index ed9159726a..0f11aca525 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -53,12 +53,12 @@ class CreateTxWalletTest(BitcoinTestFramework):
self.restart_node(0, extra_args=[fee_setting])
assert_raises_rpc_error(
-6,
- "Fee exceeds maximum configured by -maxtxfee",
+ "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
lambda: self.nodes[0].sendmany(dummy="", amounts=outputs),
)
assert_raises_rpc_error(
-4,
- "Fee exceeds maximum configured by -maxtxfee",
+ "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx),
)
@@ -67,12 +67,12 @@ class CreateTxWalletTest(BitcoinTestFramework):
self.nodes[0].settxfee(0.01)
assert_raises_rpc_error(
-6,
- "Fee exceeds maximum configured by -maxtxfee",
+ "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
lambda: self.nodes[0].sendmany(dummy="", amounts=outputs),
)
assert_raises_rpc_error(
-4,
- "Fee exceeds maximum configured by -maxtxfee",
+ "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx),
)
self.nodes[0].settxfee(0)