0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-08 10:31:50 -05:00

[wallet]: add maxfeerate wallet startup option

- The commits adds a new wallet startup option `-maxfeerate`

- The value will be used as the upper limit of wallet transaction fee rate.

- The commit updates all instances where `-maxtxfee` value is utilized to check
  wallet transactions fee rate upper limit to now use `-maxfeerate` value.

- `settxfee` RPC now only check if the fee rate user set is less `minrelaytxfee`,
   less than wallet min fee, or whether it exceed `maxfeerate`.
   We should not check whether `settxfee` RPC respects `maxtxfee` limit in
   in the functional test because its not enforced.
   We now only check if `settxfee` respects `maxfeerate` limit.
This commit is contained in:
ismaelsadeeq 2025-01-23 12:11:35 -05:00
parent d3600accf9
commit 832d468c34
6 changed files with 23 additions and 9 deletions

View file

@ -37,6 +37,7 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
"-keypool=<n>",
"-maxapsfee=<n>",
"-maxtxfee=<amt>",
"-maxfeerate=<amt>",
"-mintxfee=<amt>",
"-paytxfee=<amt>",
"-signer=<cmd>",

View file

@ -64,6 +64,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
argsman.AddArg("-maxapsfee=<n>", strprintf("Spend up to this amount in additional (absolute) fees (in %s) if it allows the use of partial spend avoidance (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MAX_AVOIDPARTIALSPEND_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-maxfeerate=<amt>", strprintf("Maximum fee rate (in %s/kvB) for a wallet transactions (default: %s %s/kvB)", CURRENCY_UNIT, FormatMoney(DEFAULT_MAX_TRANSACTION_FEERATE.GetFeePerK()), CURRENCY_UNIT), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-mintxfee=<amt>", strprintf("Fee rates (in %s/kvB) smaller than this are considered zero fee for transaction creation (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-paytxfee=<amt>", strprintf("Fee rate (in %s/kvB) to add to transactions you send (default: %s)",

View file

@ -439,15 +439,14 @@ RPCHelpMan settxfee()
CAmount nAmount = AmountFromValue(request.params[0]);
CFeeRate tx_fee_rate(nAmount, 1000);
CFeeRate max_tx_fee_rate(pwallet->m_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()));
} 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()));
} 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()));
} else if (tx_fee_rate > pwallet->m_max_tx_fee_rate) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("fee rate cannot be more than wallet max tx fee rate (%s)", pwallet->m_max_tx_fee_rate.ToString()));
}
pwallet->m_pay_tx_fee = tx_fee_rate;

View file

@ -3194,13 +3194,22 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
warnings.push_back(strprintf(_("%s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));
}
if (chain && CFeeRate{max_tx_fee.value(), 1000} < chain->relayMinFee()) {
walletInstance->m_max_tx_fee = max_tx_fee.value();
}
if (args.IsArgSet("-maxfeerate")) {
std::optional<CAmount> max_tx_fee_rate = ParseMoney(args.GetArg("-maxfeerate", ""));
if (!max_tx_fee_rate) {
error = AmountErrMsg("maxfeerate", args.GetArg("-maxfeerate", ""));
return nullptr;
}
if (chain && CFeeRate(max_tx_fee_rate.value()) < chain->relayMinFee()) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
"-maxtxfee", args.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString());
"-maxfeerate", args.GetArg("-maxfeerate", ""), chain->relayMinFee().ToString());
return nullptr;
}
walletInstance->m_max_tx_fee = max_tx_fee.value();
walletInstance->m_max_tx_fee_rate = CFeeRate(max_tx_fee_rate.value());
}
if (args.IsArgSet("-consolidatefeerate")) {

View file

@ -135,6 +135,8 @@ static const bool DEFAULT_DISABLE_WALLET = false;
static const bool DEFAULT_WALLETCROSSCHAIN = false;
//! -maxtxfee default
constexpr CAmount DEFAULT_TRANSACTION_MAXFEE{COIN / 10};
//! maxfeerate default
const CFeeRate DEFAULT_MAX_TRANSACTION_FEERATE(CFeeRate(COIN / 10));
//! Discourage users to set fees higher than this amount (in satoshis) per kB
constexpr CAmount HIGH_TX_FEE_PER_KB{COIN / 100};
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
@ -730,6 +732,8 @@ public:
/** Absolute maximum transaction fee (in satoshis) used by default for the wallet */
CAmount m_max_tx_fee{DEFAULT_TRANSACTION_MAXFEE};
/** Maximum transaction fee rate used for the wallet */
CFeeRate m_max_tx_fee_rate{DEFAULT_MAX_TRANSACTION_FEERATE};
/** Number of pre-generated keys/scripts by each spkm (part of the look-ahead process, used to detect payments) */
int64_t m_keypool_size{DEFAULT_KEYPOOL_SIZE};

View file

@ -547,9 +547,9 @@ def test_settxfee(self, rbf_node, dest_address):
assert_greater_than(Decimal("0.00001000"), abs(requested_feerate - actual_feerate))
rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee
# check that settxfee respects -maxtxfee
self.restart_node(1, ['-maxtxfee=0.000025'] + self.extra_args[1])
assert_raises_rpc_error(-8, "txfee cannot be more than wallet max tx fee", rbf_node.settxfee, Decimal('0.00003'))
# check that settxfee respects -maxfeerate
self.restart_node(1, ['-maxfeerate=0.000025'] + self.extra_args[1])
assert_raises_rpc_error(-8, "fee rate cannot be more than wallet max tx fee rate", rbf_node.settxfee, Decimal('0.00003'))
self.restart_node(1, self.extra_args[1])
rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
self.connect_nodes(1, 0)