Skip to content

Commit 7abd2e6

Browse files
committed
wallet/rpc: add maxfeerate parameter to testmempoolaccept
1 parent 6c0a6f7 commit 7abd2e6

File tree

5 files changed

+32
-11
lines changed

5 files changed

+32
-11
lines changed

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
9595
{ "sendrawtransaction", 1, "maxfeerate" },
9696
{ "testmempoolaccept", 0, "rawtxs" },
9797
{ "testmempoolaccept", 1, "allowhighfees" },
98+
{ "testmempoolaccept", 1, "maxfeerate" },
9899
{ "combinerawtransaction", 0, "txs" },
99100
{ "fundrawtransaction", 1, "options" },
100101
{ "fundrawtransaction", 2, "iswitness" },

src/rpc/rawtransaction.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
11081108
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
11091109
},
11101110
},
1111-
{"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"},
1111+
{"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(maxTxFee), "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"},
11121112
},
11131113
RPCResult{
11141114
"[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n"
@@ -1133,7 +1133,11 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
11331133
}.ToString());
11341134
}
11351135

1136-
RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VBOOL});
1136+
RPCTypeCheck(request.params, {
1137+
UniValue::VARR,
1138+
UniValueType(), // NUM or BOOL, checked later
1139+
});
1140+
11371141
if (request.params[0].get_array().size() != 1) {
11381142
throw JSONRPCError(RPC_INVALID_PARAMETER, "Array must contain exactly one raw transaction for now");
11391143
}
@@ -1145,9 +1149,19 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
11451149
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
11461150
const uint256& tx_hash = tx->GetHash();
11471151

1148-
CAmount max_raw_tx_fee = ::maxTxFee;
1149-
if (!request.params[1].isNull() && request.params[1].get_bool()) {
1150-
max_raw_tx_fee = 0;
1152+
CAmount max_raw_tx_fee = maxTxFee;
1153+
// TODO: temporary migration code for old clients. Remove in v0.20
1154+
if (request.params[1].isBool()) {
1155+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Second argument must be numeric (maxfeerate) and no longer supports a boolean. To allow a transaction with high fees, set maxfeerate to 0.");
1156+
} else if (request.params[1].isNum()) {
1157+
size_t weight = GetTransactionWeight(*tx);
1158+
CFeeRate fr(AmountFromValue(request.params[1]));
1159+
// the +3/4 part rounds the value up, and is the same formula used when
1160+
// calculating the fee for a transaction
1161+
// (see GetVirtualTransactionSize)
1162+
max_raw_tx_fee = fr.GetFee((weight+3)/4);
1163+
} else if (!request.params[1].isNull()) {
1164+
throw JSONRPCError(RPC_INVALID_PARAMETER, "second argument (maxfeerate) must be numeric");
11511165
}
11521166

11531167
UniValue result(UniValue::VARR);
@@ -2068,7 +2082,7 @@ static const CRPCCommand commands[] =
20682082
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
20692083
{ "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} },
20702084
{ "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
2071-
{ "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees"} },
2085+
{ "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees|maxfeerate"} },
20722086
{ "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
20732087
{ "rawtransactions", "combinepsbt", &combinepsbt, {"txs"} },
20742088
{ "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },

test/functional/feature_cltv.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def run_test(self):
113113
# rejected from the mempool for exactly that reason.
114114
assert_equal(
115115
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],
116-
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], allowhighfees=True)
116+
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
117117
)
118118

119119
# Now we verify that a block with this transaction is also invalid.

test/functional/feature_dersig.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def run_test(self):
102102
# rejected from the mempool for exactly that reason.
103103
assert_equal(
104104
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Non-canonical DER signature)'}],
105-
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], allowhighfees=True)
105+
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
106106
)
107107

108108
# Now we verify that a block with this transaction is also invalid.

test/functional/rpc_rawtransaction.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ def run_test(self):
426426
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
427427
assert_equal(decrawtx['version'], 0x7fffffff)
428428

429-
self.log.info('sendrawtransaction with maxfeerate')
429+
self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')
430430

431431
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
432432
rawTx = self.nodes[0].getrawtransaction(txId, True)
@@ -439,9 +439,15 @@ def run_test(self):
439439
rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
440440
assert_equal(rawTxSigned['complete'], True)
441441
# 1000 sat fee, ~200 b transaction, fee rate should land around 5 sat/b = 0.00005000 BTC/kB
442-
# Thus, below call should fail
442+
# Thus, testmempoolaccept should reject
443+
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
444+
assert_equal(testres['allowed'], False)
445+
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
446+
# and sendrawtransaction should throw
443447
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
444-
# And below call should succeed
448+
# And below calls should both succeed
449+
testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate=0.00007000)[0]
450+
assert_equal(testres['allowed'], True)
445451
self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate=0.00007000)
446452

447453

0 commit comments

Comments
 (0)