Skip to content

Wallet: Add maxfeerate wallet startup option #29278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

ismaelsadeeq
Copy link
Member

@ismaelsadeeq ismaelsadeeq commented Jan 18, 2024

This PR fixes #29220

  • The PR adds a wallet -maxfeerate startup option, as the upper limit of wallet transactions fee rate.

  • This fixes the ambiguity of using maxtxfee value to check the upper limit of transactions fee rate.

  • Wallet will not create a transaction with fee rate above maxfeerate value. And you can not set wallet fee rate with settxfee RPC above maxfeerate value.

  • This PR adds a functional test that ensure the behavior is enforced.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jan 18, 2024

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/29278.

Reviews

See the guideline for information on the review process.

Type Reviewers
Stale ACK josibake, murchandamus

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #32636 (Split CWallet::Create() into CreateNew and LoadExisting by davidgumberg)
  • #27865 (wallet: Track no-longer-spendable TXOs separately by achow101)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

LLM Linter (✨ experimental)

Possible typos and grammar issues:

  • “for a wallet transactions” → “for wallet transactions” [“a” makes the noun plural ‘transactions’ ungrammatical]

drahtbot_id_4_m

Copy link
Member

@glozow glozow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned adding a maxfeerate option in #29220, but I was more imagining it as a wallet-only option. I don't think that wallet configurations should bleed into how the node RPCs function. Instead, the interaction there should be for wallet to pass it as a param to BroadcastTransaction when the it submits a tx to the node.

I'm also not sure about maxburnamount being a node-wide config (#29217 (comment))

@ismaelsadeeq
Copy link
Member Author

Thanks @glozow for your review.
Will put this PR in draft while addressing Approach feedback

@ismaelsadeeq ismaelsadeeq marked this pull request as draft January 19, 2024 16:12
@luke-jr
Copy link
Member

luke-jr commented Jan 23, 2024

I agree this feels more like it should be a wallet option.

@ismaelsadeeq ismaelsadeeq force-pushed the 01-2024-maxfeerate-fix branch 2 times, most recently from b9f2ddc to 0c9e0c5 Compare January 25, 2024 21:53
@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the
documentation.

Possibly this is due to a silent merge conflict (the changes in this pull request being
incompatible with the current code in the target branch). If so, make sure to rebase on the latest
commit of the target branch.

Leave a comment here, if you need help tracking down a confusing failure.

Debug: https://github.com/bitcoin/bitcoin/runs/20878506397

@ismaelsadeeq ismaelsadeeq changed the title RPC: Wallet: Add maxfeerate and maxburnamount startup option Wallet: Add maxfeerate wallet startup option Jan 25, 2024
@DrahtBot DrahtBot changed the title Wallet: Add maxfeerate wallet startup option Wallet: Add maxfeerate wallet startup option Jan 25, 2024
@ismaelsadeeq
Copy link
Member Author

Forced pushed from 2576efc to 0c9e0c5 Compare the diff

  • All review comments are addressed
  • Removed maxburnamount option
  • Made maxfeerate wallet option
  • Added a check in CreateTransactionInternal that makes sure we don't make transactions above this -maxfeerate.
  • Fixed ambiguity between -maxtxfee and maxfeerate
  • Prevent setting wallet feerate above maxfeerate from settxfee RPC
  • Added a functional test case
  • Updated PR OP

@ismaelsadeeq ismaelsadeeq marked this pull request as ready for review January 25, 2024 22:19
Copy link
Member

@josibake josibake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems odd to me that we would ever have maxtxfee and maxfeerate set together as they seem to cover entirely different scenarios.

For maxtxfee, a user is expressing "I don't or care what my transaction size is but I know I never want to spend more than X in total fees."

For maxfeerate as user is expressing "I know that my transactions will vary a lot in size, so I don't know what the total fees will be, but I do know that I don't want to pay more than X sats/per vbyte."

I am struggling to think of a scenario where it makes sense to combine them. On the other hand, if I set a maxtxfee of Y and a maxfeerate of X, there input sets that are valid for Y but not valid for X and also inputs that are valid for X but not for Y.

What do you think about only letting the user set one or the other? Or is there a use case for caring about the total fees you pay AND caring about the sats per vbyte you pay that I'm not understanding?

@achow101
Copy link
Member

Or is there a use case for caring about the total fees you pay AND caring about the sats per vbyte you pay that I'm not understanding?

I think it makes sense to have both. I could have a maxtxfee of the upper bound of what I'm willing to pay ever, and also set maxfeerate to something reasonable just to make sure I don't typo a feerate and accidentally pay a feerate orders of magnitude higher than intended. At maxfeerate, a small transaction can still pay a smaller fee than maxtxfee, but a large transaction could exceed maxtxfee.

@josibake
Copy link
Member

I think it makes sense to have both. I could have a maxtxfee of the upper bound of what I'm willing to pay ever, and also set maxfeerate to something reasonable just to make sure I don't typo a feerate and accidentally pay a feerate orders of magnitude higher than intended. At maxfeerate, a small transaction can still pay a smaller fee than maxtxfee, but a large transaction could exceed maxtxfee.

But in this example, if you typo'd a feerate orders of magnitude higher, your maxtxfee should get hit. If you accidentally typo a higher fee rate than intended but it's below the maxtxfee you're willing to pay, that doesn't seem like a big problem to me.

Seems less footgunny to only let the user set one or the other (and then as a belt and suspenders still check the defaults for both, regardless of what is set?). But I might be overthinking this.. just seems really gross to have to now consider both of these in coin selection, especially if a user sets wonky values.

@ismaelsadeeq
Copy link
Member Author

Thank you for your comments @josibake @glozow @achow101 , will address review comments shortly.

if you typo'd a feerate orders of magnitude higher, your maxtxfee should get hit.

I don't think this is true; it depends on what your maxtxfee is. Going by the default value of 0.10 BTC.

This is not likely to occur.

I did a manual test on master.

When I set maxtxfee to 0.10 BTC on master, if you mistakenly type 10,000 as the fee rate, the max fee exceed error will not be hit.

However, in some cases where you set a low maxtxfeeit may be hit or not depending on the transaction size.
It's uncertain.

abubakarismail@Abubakars-MacBook-Pro bitcoin % ./src/bitcoind -regtest -maxtxfee=0.10  -daemon                                                                                          
Bitcoin Core starting

abubakarismail@Abubakars-MacBook-Pro bitcoin % ./src/bitcoin-cli -regtest loadwallet abubakar-test                                                                          
{
  "name": "abubakar-test"
}

abubakarismail@Abubakars-MacBook-Pro bitcoin % ./src/bitcoin-cli -regtest -named sendtoaddress address="bcrt1qt3fvqww6reduq287nhl59cu05hmyrj7achar44" fee_rate=10000 amount=1
22a92fdfa68581ba1d3da4aeedaeb20c7570b8c8eff9c29699c846aa1dacd73d


On this branch, if I set my -maxtxfee as 0.10 absolute fee and -maxfeerate as (0.010 which is 1000s/vb), and make a typo in a sendtoaddress call with a fee_rate of 10,000 s/vb instead of 100, the maxfeerate check will be hit.

 ./src/bitcoind -regtest -maxfeerate=0.01 -maxtxfee=0.10 -daemon                                                                         
Bitcoin Core starting
abubakarismail@Abubakars-MacBook-Pro bitcoin % ./src/bitcoin-cli -regtest loadwallet abubakar-test                                                                         
{
  "name": "abubakar-test"
}

abubakarismail@Abubakars-MacBook-Pro bitcoin % ./src/bitcoin-cli -regtest -named sendtoaddress address="bcrt1qt3fvqww6reduq287nhl59cu05hmyrj7achar44" fee_rate=10000 amount=1
error code: -6
error message:
Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)

IIUC -maxtxfee should generally be high as the maximum absolute fee you think you can ever pay, and -maxfeerate as a cautionary check against an absurd fee rate for a transaction based on current fee estimates.

Maybe I should differentiate between the two error messages and make it more verbose, so that users can know which one is hit and adjust if its not intentional.

@ismaelsadeeq
Copy link
Member Author

Rebased to fix merge conflict.

@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed.
Task lint: https://github.com/bitcoin/bitcoin/runs/47890704383
LLM reason (✨ experimental): The CI failure is caused by a lint error due to missing a trailing newline in a markdown file.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@ismaelsadeeq ismaelsadeeq force-pushed the 01-2024-maxfeerate-fix branch from 29db50d to b592d27 Compare August 12, 2025 09:21
-BEGIN VERIFY SCRIPT-
git grep -l "m_default_max_tx_fee" src | xargs sed -i "s/m_default_max_tx_fee/m_max_tx_fee/g"
-END VERIFY SCRIPT-

- The value is not always the default but can be configured
  during startup so `m_max_tx_fee` is the right name not
  `m_default_max_tx_fee`.
- Also update `-maxapsfee` option from `max_fee` to `max_aps_fee`.
  This fixes the ambiguity in the variable name.
- 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.
- `BroadcastTransaction` now accepts a fee rate limit as an additional
  input parameter. It ensures that the transaction with fee rate exceeding
  the specified limit are not added to mempool and not broadcasted
  to peers.

- This will allow differentiating between the error messages
  when either `-maxtxfee` or `maxfeerate` is hit.

- `TestSimpleSpend` creates transaction with base fee of
  `DEFAULT_TRANSACTION_MAXFEE`, since we now also check fee rate
  limit in broadcastTransaction, creating transaction with the base fee of
  `DEFAULT_TRANSACTION_MAXFEE` will prevent the transaction from being
  broadcasted because its fee rate will be above
  `DEFAULT_MAX_TRANSACTION_FEERATE`, hence update the maximum during broadcast
  to be the expected fee rate of the transaction.
- This distinguishes maxfeerate and maxtxfee error messages.
- This commit prevents the wallet from creating transactions
  above `maxfeerate`, and tests the new functionality.
… less than `minrelaytxfee`

- Wallet prevents creating transactions with fee rates lower than `-minrelaytxfee`.
  Also prevents creating a transaction with a base fee above `-maxtxfee`.

- Warn user if a 1kvb transaction, with a base fee set to `-maxtxfee`, has a fee rate less than
  `-minrelaytxfee`. It is likely that some transactions with fee rates greater than or equal
  to the `-minrelaytxfee` will also likely exceed `-maxtxfee`, the wallet won't be able to create
  transactions.
@ismaelsadeeq ismaelsadeeq force-pushed the 01-2024-maxfeerate-fix branch from b592d27 to 4d6de3c Compare August 13, 2025 10:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

-maxtxfee is used as a fee and a feerate
10 participants