wallet/rpc: add maxfeerate parameter to testmempoolaccept
This commit is contained in:
parent
6c0a6f73e3
commit
7abd2e697c
5 changed files with 32 additions and 11 deletions
|
@ -95,6 +95,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "sendrawtransaction", 1, "maxfeerate" },
|
{ "sendrawtransaction", 1, "maxfeerate" },
|
||||||
{ "testmempoolaccept", 0, "rawtxs" },
|
{ "testmempoolaccept", 0, "rawtxs" },
|
||||||
{ "testmempoolaccept", 1, "allowhighfees" },
|
{ "testmempoolaccept", 1, "allowhighfees" },
|
||||||
|
{ "testmempoolaccept", 1, "maxfeerate" },
|
||||||
{ "combinerawtransaction", 0, "txs" },
|
{ "combinerawtransaction", 0, "txs" },
|
||||||
{ "fundrawtransaction", 1, "options" },
|
{ "fundrawtransaction", 1, "options" },
|
||||||
{ "fundrawtransaction", 2, "iswitness" },
|
{ "fundrawtransaction", 2, "iswitness" },
|
||||||
|
|
|
@ -1108,7 +1108,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
||||||
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
|
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"},
|
{"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(maxTxFee), "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"},
|
||||||
},
|
},
|
||||||
RPCResult{
|
RPCResult{
|
||||||
"[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n"
|
"[ (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)
|
||||||
}.ToString());
|
}.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VBOOL});
|
RPCTypeCheck(request.params, {
|
||||||
|
UniValue::VARR,
|
||||||
|
UniValueType(), // NUM or BOOL, checked later
|
||||||
|
});
|
||||||
|
|
||||||
if (request.params[0].get_array().size() != 1) {
|
if (request.params[0].get_array().size() != 1) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Array must contain exactly one raw transaction for now");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Array must contain exactly one raw transaction for now");
|
||||||
}
|
}
|
||||||
|
@ -1145,9 +1149,19 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
||||||
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
|
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
|
||||||
const uint256& tx_hash = tx->GetHash();
|
const uint256& tx_hash = tx->GetHash();
|
||||||
|
|
||||||
CAmount max_raw_tx_fee = ::maxTxFee;
|
CAmount max_raw_tx_fee = maxTxFee;
|
||||||
if (!request.params[1].isNull() && request.params[1].get_bool()) {
|
// TODO: temporary migration code for old clients. Remove in v0.20
|
||||||
max_raw_tx_fee = 0;
|
if (request.params[1].isBool()) {
|
||||||
|
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.");
|
||||||
|
} else if (request.params[1].isNum()) {
|
||||||
|
size_t weight = GetTransactionWeight(*tx);
|
||||||
|
CFeeRate fr(AmountFromValue(request.params[1]));
|
||||||
|
// the +3/4 part rounds the value up, and is the same formula used when
|
||||||
|
// calculating the fee for a transaction
|
||||||
|
// (see GetVirtualTransactionSize)
|
||||||
|
max_raw_tx_fee = fr.GetFee((weight+3)/4);
|
||||||
|
} else if (!request.params[1].isNull()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "second argument (maxfeerate) must be numeric");
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue result(UniValue::VARR);
|
UniValue result(UniValue::VARR);
|
||||||
|
@ -2068,7 +2082,7 @@ static const CRPCCommand commands[] =
|
||||||
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
|
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
|
||||||
{ "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} },
|
{ "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} },
|
||||||
{ "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
|
{ "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
|
||||||
{ "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees"} },
|
{ "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees|maxfeerate"} },
|
||||||
{ "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
|
{ "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
|
||||||
{ "rawtransactions", "combinepsbt", &combinepsbt, {"txs"} },
|
{ "rawtransactions", "combinepsbt", &combinepsbt, {"txs"} },
|
||||||
{ "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },
|
{ "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },
|
||||||
|
|
|
@ -113,7 +113,7 @@ class BIP65Test(BitcoinTestFramework):
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_equal(
|
assert_equal(
|
||||||
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],
|
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],
|
||||||
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], allowhighfees=True)
|
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
|
|
|
@ -102,7 +102,7 @@ class BIP66Test(BitcoinTestFramework):
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_equal(
|
assert_equal(
|
||||||
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Non-canonical DER signature)'}],
|
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Non-canonical DER signature)'}],
|
||||||
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], allowhighfees=True)
|
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
|
|
|
@ -426,7 +426,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||||
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
|
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
|
||||||
assert_equal(decrawtx['version'], 0x7fffffff)
|
assert_equal(decrawtx['version'], 0x7fffffff)
|
||||||
|
|
||||||
self.log.info('sendrawtransaction with maxfeerate')
|
self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')
|
||||||
|
|
||||||
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
|
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
|
||||||
rawTx = self.nodes[0].getrawtransaction(txId, True)
|
rawTx = self.nodes[0].getrawtransaction(txId, True)
|
||||||
|
@ -439,9 +439,15 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||||
rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
|
rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
|
||||||
assert_equal(rawTxSigned['complete'], True)
|
assert_equal(rawTxSigned['complete'], True)
|
||||||
# 1000 sat fee, ~200 b transaction, fee rate should land around 5 sat/b = 0.00005000 BTC/kB
|
# 1000 sat fee, ~200 b transaction, fee rate should land around 5 sat/b = 0.00005000 BTC/kB
|
||||||
# Thus, below call should fail
|
# Thus, testmempoolaccept should reject
|
||||||
|
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
|
||||||
|
assert_equal(testres['allowed'], False)
|
||||||
|
assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
|
||||||
|
# and sendrawtransaction should throw
|
||||||
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
|
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
|
||||||
# And below call should succeed
|
# And below calls should both succeed
|
||||||
|
testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate=0.00007000)[0]
|
||||||
|
assert_equal(testres['allowed'], True)
|
||||||
self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate=0.00007000)
|
self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate=0.00007000)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue