This commit is contained in:
Pol Espinasa 2025-01-08 23:48:08 +05:30 committed by GitHub
commit 4540cd4c61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 152 additions and 4 deletions

View file

@ -48,6 +48,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendtoaddress", 9, "fee_rate"},
{ "sendtoaddress", 10, "verbose"},
{ "settxfee", 0, "amount" },
{ "settxfeerate", 0, "amount" },
{ "sethdseed", 0, "newkeypool" },
{ "getreceivedbyaddress", 1, "minconf" },
{ "getreceivedbyaddress", 2, "include_immature_coinbase" },

View file

@ -418,7 +418,7 @@ RPCHelpMan sendmany()
RPCHelpMan settxfee()
{
return RPCHelpMan{"settxfee",
"\nSet the transaction fee rate in " + CURRENCY_UNIT + "/kvB for this wallet. Overrides the global -paytxfee command line parameter.\n"
"\n(DEPRECATED)Set the transaction fee rate in " + CURRENCY_UNIT + "/kvB for this wallet. Overrides the global -paytxfee command line parameter.\n"
"Can be deactivated by passing 0 as the fee. In that case automatic fee selection will be used by default.\n",
{
{"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee rate in " + CURRENCY_UNIT + "/kvB"},
@ -437,6 +437,10 @@ RPCHelpMan settxfee()
LOCK(pwallet->cs_wallet);
if (!pwallet->chain().rpcEnableDeprecated("settxfee")) {
throw JSONRPCError(RPC_METHOD_DEPRECATED, "Using settxfee is deprecated. Use settxfeerate instead or restart bitcoind with -deprecatedrpc=settxfee. This functionality will be removed in x.xx");
}
CAmount nAmount = AmountFromValue(request.params[0]);
CFeeRate tx_fee_rate(nAmount, 1000);
CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
@ -456,6 +460,53 @@ RPCHelpMan settxfee()
};
}
RPCHelpMan settxfeerate()
{
return RPCHelpMan{"settxfeerate",
"\nSet the transaction fee rate in " + CURRENCY_ATOM + "/vB for this wallet. Overrides the global -paytxfee command line parameter.\n"
"Can be deactivated by passing 0 as the fee. In that case automatic fee selection will be used by default.\n",
{
{"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee rate in " + CURRENCY_ATOM + "/vB"},
},
RPCResult{
RPCResult::Type::BOOL, "", "Returns true if successful"
},
RPCExamples{
HelpExampleCli("settxfeerate", "1")
+ HelpExampleRpc("settxfeerate", "1")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
CAmount test = AmountFromValue(request.params[0]);
double conv_ammount = (static_cast<double>(test) / COIN) / 100000; // Convert to BTC/kvB
CAmount nAmount = AmountFromValue(UniValue(conv_ammount));
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
CFeeRate tx_fee_rate(nAmount, 1000);
CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
if (tx_fee_rate == CFeeRate(0)) {
// automatic selection
} else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString(FeeEstimateMode::SAT_VB)));
} else if (tx_fee_rate < pwallet->m_min_fee) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString(FeeEstimateMode::SAT_VB)));
} else if (tx_fee_rate > max_tx_fee_rate) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be more than wallet max tx fee (%s)", max_tx_fee_rate.ToString(FeeEstimateMode::SAT_VB)));
}
pwallet->m_pay_tx_fee = tx_fee_rate;
return true;
},
};
}
// Only includes key documentation where the key is snake_case in all RPC methods. MixedCase keys can be added later.
static std::vector<RPCArg> FundTxDoc(bool solving_data = true)

View file

@ -1076,6 +1076,7 @@ RPCHelpMan encryptwallet();
RPCHelpMan sendtoaddress();
RPCHelpMan sendmany();
RPCHelpMan settxfee();
RPCHelpMan settxfeerate();
RPCHelpMan fundrawtransaction();
RPCHelpMan bumpfee();
RPCHelpMan psbtbumpfee();
@ -1156,7 +1157,8 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &sendtoaddress},
{"wallet", &sethdseed},
{"wallet", &setlabel},
{"wallet", &settxfee},
{"hidden", &settxfee},
{"wallet", &settxfeerate},
{"wallet", &setwalletflag},
{"wallet", &signmessage},
{"wallet", &signrawtransactionwithwallet},

View file

@ -0,0 +1,83 @@
#!/usr/bin/env python3
# Copyright (c) 2024 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet changes the feerate configured properly when settxfee and settxfeerate is set."""
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error
)
class RPCSetTxFeeTest(BitcoinTestFramework):
def add_options(self, parser):
self.add_wallet_options(parser)
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [["-deprecatedrpc=settxfee"], []]
self.supports_cli = False
def run_test(self):
node = self.nodes[0]
self.log.debug("Test that settxfee is a hidden RPC")
# It is hidden from general help, but its detailed help may be called directly.
assert "settxfee " not in node.help() # An empty space is left after settxfee as if not would return True because of settxfeerate
assert "settxfeerate" in node.help()
assert "unknown command: settxfeerate" not in node.help("settxfeerate")
assert "unknown command: settxfee" not in node.help("settxfee")
self.log.debug("Test that settxfee set the feerate in B/kvB")
assert_equal(node.settxfee(0.001), True)
assert_equal(str(node.getwalletinfo()['paytxfee']), "0.00100000")
self.log.debug("Test that settxfeerate set the feerate in sat/vB")
assert_equal(node.settxfeerate(6), True)
assert_equal(str(node.getwalletinfo()['paytxfee']), "0.00006000")
self.log.debug("Test that settxfee limit (0.1 B/kvB) can not be surpassed")
assert_raises_rpc_error(-8, "txfee cannot be more than wallet max tx fee (0.10000000 BTC/kvB)", node.settxfee, 1)
self.log.debug("Test that settxfeerate limit (10000 sat/vB) can not be surpassed")
assert_raises_rpc_error(-8, "txfee cannot be more than wallet max tx fee (10000.000 sat/vB)", node.settxfeerate, 10001)
self.log.debug("Test that settxfee minimum (0.00001 B/kvB) can not be ignored")
assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee (0.00001000 BTC/kvB)", node.settxfee, 0.000009)
self.log.debug("Test that settxfeerate minimum (1 sat/vB) can not be ignored")
assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee (1.000 sat/vB)", node.settxfeerate, 0.99)
self.log.debug("Test that the feerate set using settxfee is used when creating transactions")
expected_feerate = 0.001
node.settxfee(expected_feerate)
txid = node.sendtoaddress(node.getnewaddress(), 10)
fee = Decimal(node.gettransaction(txid)['fee'] * -1)
vsize = Decimal(node.getrawtransaction(txid, 1)['vsize']/1000)
feerate = Decimal(fee/vsize)
feerate = feerate.quantize(Decimal("0.00000001"))
expected_feerate = Decimal(expected_feerate).quantize(Decimal("0.00000001"))
assert_equal(feerate, expected_feerate)
self.log.debug("Test that the feerate set using settxfeerate is used when creating transactions")
expected_feerate = 6
node.settxfeerate(expected_feerate)
txid = node.sendtoaddress(node.getnewaddress(), 10)
fee = Decimal(node.gettransaction(txid)['fee'] * -100000000)
vsize = Decimal(node.getrawtransaction(txid, 1)['vsize'])
feerate = Decimal(fee/vsize)
feerate = feerate.quantize(Decimal("0.00000001"))
expected_feerate = Decimal(expected_feerate).quantize(Decimal("0.00000001"))
self.log.debug("Test that settxfee is deprecated")
assert_raises_rpc_error(-32, "Using settxfee is deprecated. Use settxfeerate instead or restart bitcoind with -deprecatedrpc=settxfee. This functionality will be removed in x.xx", self.nodes[1].settxfee, 0.05)
if __name__ == '__main__':
RPCSetTxFeeTest(__file__).main()

View file

@ -166,6 +166,7 @@ BASE_SCRIPTS = [
'mempool_limit.py',
'rpc_txoutproof.py',
'rpc_orphans.py',
'rpc_settxfeerate.py',
'wallet_listreceivedby.py --legacy-wallet',
'wallet_listreceivedby.py --descriptors',
'wallet_abandonconflict.py --legacy-wallet',

View file

@ -35,7 +35,7 @@ class WalletTest(BitcoinTestFramework):
# whitelist peers to speed up tx relay / mempool sync
self.noban_tx_relay = True
self.extra_args = [[
"-dustrelayfee=0", "-walletrejectlongchains=0"
"-dustrelayfee=0", "-walletrejectlongchains=0", "-deprecatedrpc=settxfee"
]] * self.num_nodes
self.setup_clean_chain = True
self.supports_cli = False

View file

@ -61,6 +61,7 @@ class BumpFeeTest(BitcoinTestFramework):
"-walletrbf={}".format(i),
"-mintxfee=0.00002",
"-addresstype=bech32",
"-deprecatedrpc=settxfee"
] for i in range(self.num_nodes)]
def skip_test_if_missing_module(self):

View file

@ -23,6 +23,9 @@ class CreateTxWalletTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [[
"-deprecatedrpc=settxfee"
] for i in range(self.num_nodes)]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

View file

@ -44,6 +44,9 @@ class RawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.extra_args = [[
"-deprecatedrpc=settxfee"
] for i in range(self.num_nodes)]
self.setup_clean_chain = True
# whitelist peers to speed up tx relay / mempool sync
self.noban_tx_relay = True

View file

@ -46,7 +46,7 @@ class MultiWalletTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 2
self.rpc_timeout = 120
self.extra_args = [["-nowallet"], []]
self.extra_args = [["-nowallet", "-deprecatedrpc=settxfee"], ["-deprecatedrpc=settxfee"]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

View file

@ -18,6 +18,9 @@ class TxnMallTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
self.supports_cli = False
self.extra_args = [[
"-deprecatedrpc=settxfee"
] for i in range(self.num_nodes)]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()