Skip to content

Commit 8f1290c

Browse files
committed
[rpc/node] check for high fee before ATMP in clients
Check absurd fee in BroadcastTransaction and RPC, return TransactionError::MAX_FEE_EXCEEDED instead of TxValidationResult::TX_NOT_STANDARD because this is client preference, not a node-wide policy.
1 parent 3487e42 commit 8f1290c

File tree

4 files changed

+41
-18
lines changed

4 files changed

+41
-18
lines changed

src/node/transaction.cpp

+27-11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@
1313

1414
#include <future>
1515

16+
static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out) {
17+
err_string_out = state.ToString();
18+
if (state.IsInvalid()) {
19+
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
20+
return TransactionError::MISSING_INPUTS;
21+
}
22+
return TransactionError::MEMPOOL_REJECTED;
23+
} else {
24+
return TransactionError::MEMPOOL_ERROR;
25+
}
26+
}
27+
1628
TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
1729
{
1830
// BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs.
@@ -36,20 +48,24 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
3648
if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
3749
}
3850
if (!node.mempool->exists(hashTx)) {
39-
// Transaction is not already in the mempool. Submit it.
51+
// Transaction is not already in the mempool.
4052
TxValidationState state;
41-
if (!AcceptToMemoryPool(*node.mempool, state, tx,
42-
nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
43-
err_string = state.ToString();
44-
if (state.IsInvalid()) {
45-
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
46-
return TransactionError::MISSING_INPUTS;
47-
}
48-
return TransactionError::MEMPOOL_REJECTED;
49-
} else {
50-
return TransactionError::MEMPOOL_ERROR;
53+
CAmount fee{0};
54+
if (max_tx_fee) {
55+
// First, call ATMP with test_accept and check the fee. If ATMP
56+
// fails here, return error immediately.
57+
if (!AcceptToMemoryPool(*node.mempool, state, tx,
58+
nullptr /* plTxnReplaced */, false /* bypass_limits */, /* absurdfee*/ 0, /* test_accept */ true, &fee)) {
59+
return HandleATMPError(state, err_string);
60+
} else if (fee > max_tx_fee) {
61+
return TransactionError::MAX_FEE_EXCEEDED;
5162
}
5263
}
64+
// Try to submit the transaction to the mempool.
65+
if (!AcceptToMemoryPool(*node.mempool, state, tx,
66+
nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
67+
return HandleATMPError(state, err_string);
68+
}
5369

5470
// Transaction was accepted to the mempool.
5571

src/rpc/rawtransaction.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -947,12 +947,20 @@ static RPCHelpMan testmempoolaccept()
947947

948948
TxValidationState state;
949949
bool test_accept_res;
950-
CAmount fee;
950+
CAmount fee{0};
951951
{
952952
LOCK(cs_main);
953953
test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx),
954954
nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true, &fee);
955955
}
956+
957+
// Check that fee does not exceed maximum fee
958+
if (test_accept_res && max_raw_tx_fee && fee > max_raw_tx_fee) {
959+
result_0.pushKV("allowed", false);
960+
result_0.pushKV("reject-reason", "max-fee-exceeded");
961+
result.push_back(std::move(result_0));
962+
return result;
963+
}
956964
result_0.pushKV("allowed", test_accept_res);
957965

958966
// Only return the fee and vsize if the transaction would pass ATMP.

src/validation.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
730730
if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false;
731731

732732
if (nAbsurdFee && nFees > nAbsurdFee)
733-
return state.Invalid(TxValidationResult::TX_NOT_STANDARD,
734-
"absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
733+
LogPrintf("Ignoring Absurdfee\n");
735734

736735
const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts);
737736
// Calculate in-mempool ancestors, up to a limit.

test/functional/rpc_rawtransaction.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -456,9 +456,9 @@ def run_test(self):
456456
# Thus, testmempoolaccept should reject
457457
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
458458
assert_equal(testres['allowed'], False)
459-
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
459+
assert_equal(testres['reject-reason'], 'max-fee-exceeded')
460460
# and sendrawtransaction should throw
461-
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
461+
assert_raises_rpc_error(-25, 'Fee exceeds maximum configured by -maxtxfee', self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
462462
# and the following calls should both succeed
463463
testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']])[0]
464464
assert_equal(testres['allowed'], True)
@@ -480,9 +480,9 @@ def run_test(self):
480480
# Thus, testmempoolaccept should reject
481481
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
482482
assert_equal(testres['allowed'], False)
483-
assert_equal(testres['reject-reason'], 'absurdly-high-fee')
483+
assert_equal(testres['reject-reason'], 'max-fee-exceeded')
484484
# and sendrawtransaction should throw
485-
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
485+
assert_raises_rpc_error(-25, 'Fee exceeds maximum configured by -maxtxfee', self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
486486
# and the following calls should both succeed
487487
testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate='0.20000000')[0]
488488
assert_equal(testres['allowed'], True)

0 commit comments

Comments
 (0)