Fee Estimation via Fee rate Forecasters #30157

pull ismaelsadeeq wants to merge 16 commits into bitcoin:master from ismaelsadeeq:new-fee-estimator changing 37 files +1485 −50
  1. ismaelsadeeq commented at 11:44 am on May 23, 2024: member

    This PR aims at improving Bitcoin Core fee estimation

    The objectives of this improvement are to:

    • Reduce overestimation done by the current CBlockPolicyEstimator
    • Make the fee estimator aware of the state of the mempool, allowing it to respond to changing conditions immediately.
    • Empower node users to be self-sovereign and use their node’s estimates, as is now, the majority rely on third parties for fee estimation.
    • Simplify the process of adding new fee estimation strategies in the future.

    The PR creates a new FeeEstimator class which is responsible for getting estimates from one or more subscribed Forcaster’s.

    A Forcaster will register with the FeeEstimator as being able to provide estimates, and when an estimate is requested, should return two fee rate estimates (high and low) and a confidence level.

    The estimator will then take (currently undecided):

    1. the lowest estimated rate, or
    2. the weighted average of all the estimated rates

    …and return the two ‘high’ and ’low’ estimations to the user.

    The FeeEstimator also owns access to the legacy estimator, accessible via a pointer.

    This PR deliberately does not try to modify existing fee estimation code, but instead uses new modules with cleaner seperation. This will make new code and interfaces much easier to introduce, and also make it easier to, if desired in the future, drop legacy estimation code.

    Currently, this PR implements two forecasters:

    1. Mempool-based forecaster (MemPoolForecaster): It estimates fees simply by generating a block template from the node’s mempool and returns the 25th and 50th percentile mining scores as low-priority and high-priority fee estimates, respectively.

    2. Last 6 Blocks forecaster (BlockForecaster): Uses the transactions from the previous six blocks which were also seen in the node’s mempool, to make an estimate.

      It listens to the validation interface notifications for removed mempool transactions, linearizes the transactions using a mini miner, and saves the 25th and 50th percentile mining scores. When estimating fees, it averages the mining scores of the percentiles from the last six mined blocks.

      NB. As this excludes transactions that never entered the node’s mempool, it’s likely to undershoot slightly

    These two forecasters both estimate fees for (1, 2) block confirmation targets, referred to as “as soon as possible (ASAP)” fee rate estimates.

    For both forcasters use of RBF is strongly recommended in order that transactions can be fee-bumped if desired.

    Next steps:

    • Give some statistics of estimates “missing the block” (~percentage of estimates below the 5th percentile mining score of the confirmed block) and “over paying” (~percentage of estimates above the 25th 50th and 75th percentiles mining score)

    • Extend the feature to the wallet; currently it’s only exposed in an RPC estimatefee.

    • Update forecasters to return confidence levels in their estimates.

    Confidence levels

    Confidence levels are determined by heuristics.

    For the mempool-based forecaster:

    • Suspected high mining score transactions should be confirmed but aren’t.
    • Most transactions in previously mined blocks were in our node’s mempool.
    • High mining score mempool transactions are confirmed.

    For the last 6 blocks forecaster:

    • Presence of empty blocks in the last 6 blocks.
    • Most of the last 6 blocks’ transactions were seen in the node’s mempool or not.

    The fee estimator will select the fee rate from the forecasters based on confidence level instead of just taking the lowest fee rate estimate.

    How does this fit in with CBlockPolicyEstimator?

    This fee estimator owns the legacy CBlockPolicyEstimator and does not change any of its interfaces. The wallet still uses estimatesmartfee, and RPCs also access it through the Fee Estimator. However, this will change when we switch to using estimates from GetFeeEstimateFromForecasters, which works much better than the estimatesmartfee in (1, 2) confirmation target scenarios.

    Moreover, when we have another forecaster that supports confirmation targets beyond (1, 2) and works better than estimatesmartfee, we will eventually phase out CBlockPolicyEstimator as the new Fee Estimator module makes it easy to do so.

    This PR addresses two open issues and has been requested by users in the past.

    #27995 #30009

    FAQ

    1. Will miners broadcast high fee rate transactions, and then evict them with a conflicting transaction in the next block, trick users of this fee estimator into making transactions with high fees? https://delvingbitcoin.org/t/mempool-based-fee-estimation-on-bitcoin-core/703/6?u=ismaelsadeeq

      This PR addresses this concern by ensuring that the fee estimate does not surge immediately whenever this happens the mempool based forecaster estimate will be higher than last 6 block forecaster estimate. As such the last six blocks forecaster estimate will be returned, preventing users to be victims of this attack.

    2. In times of high confirmation times or high block space demand, fee estimates tend to rise. If the mempool-based forecaster estimate rises, the fee estimator will fall back to the last six blocks fee estimate, if it’s low, will that make transactions constructed with the estimate get stuck in the mempool? The ASAP fee estimate provides an estimate for transactions to confirm in the next one or two blocks. During periods of high confirmation times, fee rates rise due to congestion. Once a block is mined, the mempool clears high mining score transactions, making room for lower fee rate transactions. If congestion recurs and the transaction is time-sensitive, users can safely fee bump assuming it’s an RBF-enabled transaction. In times of immediate high block demand, if the mempool-based fee estimate surges while the last six blocks fee estimate is low, users can fee bump their transactions if they take longer to confirm. As more blocks are mined, the last six blocks forecaster will adjust and reflect the higher fee rates. When demand decreases, the mempool forecaster will immediately respond to the new conditions by providing a lower fee estimate and the fee estimator will return it instead.

    3. Currently, getting a block template is expensive. How do you tackle that in the mempool-based forecaster? The forecaster cache the recently generated fee rate estimates and only generate a new block template when the time delta between the recent estimate and the current time exceeds 30 seconds.


    This is a collaborative work with @willcl-ark and a result of collecting insight from other contributors.

  2. DrahtBot commented at 11:44 am on May 23, 2024: contributor

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

    Code Coverage

    For detailed information about the code coverage, see the test coverage report.

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #30162 (test: MiniWallet: respect passed feerate for padded txs (using target_weight) by theStack)
    • #30141 (kernel: De-globalize validation caches by TheCharlatan)
    • #30079 (Fee Estimation: Ignore all transactions that are CPFP’d by ismaelsadeeq)
    • #30058 (Encapsulate warnings in generalized node::Warnings and remove globals by stickies-v)
    • #29432 (Stratum v2 Template Provider (take 3) by Sjors)
    • #29415 (Broadcast own transactions only via short-lived Tor or I2P connections by vasild)
    • #29015 (kernel: Streamline util library by ryanofsky)
    • #28843 ([refactor] Remove BlockAssembler m_mempool member by TheCharlatan)
    • #28830 ([refactor] Check CTxMemPool options in ctor by TheCharlatan)
    • #28676 ([WIP] Cluster mempool implementation by sdaftuar)

    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.

  3. DrahtBot added the label CI failed on May 23, 2024
  4. DrahtBot commented at 3:18 pm on May 23, 2024: 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/25327260112

  5. luke-jr commented at 5:20 pm on May 23, 2024: member

    Make the fee estimator aware of the state of the mempool, allowing it to respond to changing conditions immediately.

    The state of the node’s mempool may not accurately reflect the state of others’ mempools, and not even its own mempool when the block is found in the future. It isn’t a good single source of information. Perhaps it is a good idea to use it as a secondary source, but probably it should only ever adjust fee estimations upward, not down.

  6. willcl-ark commented at 8:41 am on May 24, 2024: member

    The state of the node’s mempool may not accurately reflect the state of others’ mempools, and not even its own mempool when the block is found in the future. It isn’t a good single source of information.

    Correct. The rationale behind this set of changes can be summed up briefly as follows:

    • Add a new standalone modular fee estimation manager to which (many) Forcasters can be trivially added or removed (vs modifying BlockPolicyEstimator).
    • Provide two forcaster implementations which do not exist today ( 1. mempool-based and 2. previous-6-blocks-seen-in-mempool) to demonstrate functionality.

    In the present, there is a strong tendency for users of Bitcoin Core to consult external fee estimation services when they want timely (next 1 or 2 blocks) confirmation of transactions, whilst also not overpaying. Examples of these include mempool.space, whatthefee.io, Samourai’s nextblock.is (now down), johoe, blockchair etc., with more popping up every month.

    We also analysed/estimated Bitcoin Core users not using in-built estimation in a post here.

    In our opinion having users feel the need to use external fee estimation services that they could equally have served to them by their own node, feels sub-optimal.

    In addition to this, when users do use the current Bitcoin Core fee estimator, there are often times when they end up overpaying, see delving bitcoin post Mempool based fee estimation and various issues over the years e.g. #30009 . This is avoidable.

    Work from a student of @renepickhardt link demonstrated something we also measured independently – that bitcoin core’s current estimates are often overpaying significantly following fee spikes. This effect can be directly mitigated by using a mempool-based estimation.

    Perhaps it is a good idea to use it as a secondary source, but probably it should only ever adjust fee estimations upward, not down.

    In this changeset we take the approach of using the lowest result from all “confident” Forcasters. The rationale is that we expect users wanting fast confirmation to have RBF enabled, allowing them to bump fees if we still undershoot.

    Comments from @harding link explained that it may be possible for miners to artificially increase a strictly-mempool-based fee-rate. By taking the lower (confident) result from n Forcasters, we attempt to protect against this attack (and others like it), at the potential cost of having to RBF.

    We do plan to add additional sanity checks to the mempool-based Forcaster as described in #27995, but these are not yet implemented. In any case, even without these additional checks we have been seeing much-improved short time-scale estimations from Bitcoin Core.

  7. [policy, fees]: add fee estimator module
    Co-authored-by: willcl-ark <will@256k1.dev>
    57f4f5355a
  8. [policy, fees]: add `CBlockPolicyEstimator` to `FeeEstimator`
    - Refactor `CBlockPolicyEstimator` to be a member of `FeeEstimator` module
      but not as a forcaster. the `FeeEstimator` will own a pointer to `CBlockPolicyEstimator`
      it retains all it's features and all RPC behaviours, these change does not change any behaviour.
    
    Co-authored-by: willcl-ark <will@256k1.dev>
    b2fa22931b
  9. [policy]: make `CFeeRate` work with `uint64_t` sizes
    Co-authored-by: Pieter Wuille <bitcoin-dev@wuille.net>
    b6241b8169
  10. [refactor, test]: enable `BlockAssembler` to return pkg's fee rate's and vsize's
    - This commit adds a new method GetNextBlockFeeRateAndVsize to miner.cpp that gets
      the fee rate's and vsize's of generated block, the method skips block validity
      test because it's for the purpose of fee estimation.
    
    - The commit also test that block assembler now returns selected package vsize's and fee rates.
    
    Co-authored-by: Pieter Wuille <bitcoin-dev@wuille.net>
    
    Co-authored-by: ismaelsadeeq <ask4ismailsadiq@gmail.com>
    4ca9384d70
  11. [policy, fees]: create a mempool based fee rate forecaster
    - The mempool based fee rate forecaster generate a predicted fee rate estimate
      for a given confirmation target using the mempool unconfirmed transactions.
    
    Co-authored-by: willcl-ark <will@256k1.dev>
    93f9b6ecfe
  12. [test]: add `MemPoolPolicyEstimator` unit test e8f5da0592
  13. [fees]: cache `MemPoolPolicyEstimator` forecasts
    - Provide new estimates only when the time delta from previous
      forecast is older than 30 seconds.
    
    - This caching helps avoid the high cost of frequently generating block templates,
      preventing users from inadvertently calling `estimateFee` repeatedly.
    
    Co-authored-by: willcl-ark <will@256k1.dev>
    4f708b666e
  14. [mini miner]: Linearize should also return packages fees and sizes
    Co-authored-by: willcl-ark <will@256k1.dev>
    7ce165d6bb
  15. [fees]: add function that computes ancestors and descendants of txs
    - GetTxAncestorsAndDescendants takes the vector of transactions removed from the mempool
      after a block is connected. The function assumed that the order the transactions were
      included in the block was maintained; that is, all transaction parents was be added
      into the vector first before descendants.
    
    - GetTxAncestorsAndDescendants computes all the ancestors and descendants of the transactions.
      The transaction is also included as a descendant and ancestor of itself.
    
    Co-authored-by: willcl-ark <will@256k1.dev>
    aeb2f1e665
  16. [fees]: add method that linearize transaction removed from mempool
    Co-authored-by: willcl-ark <will@256k1.dev>
    ae74f11912
  17. [policy, fees]: add last 6 blocks fee estimate forecaster a61fbe4194
  18. [rpc]: create an rpc `estimatefeewithforecasters`
    - Given a confirmation target, we use fee estimator module that call all
    available fee estimator forcasters and return the lowest fee rate that if
    a transaction use will likely confirm in a given confirmation target.
    
    - Currently `estimatefeewithforecasters` only supports confirmation target
      1 and 2, that is it forecast fee rate estimate that will likely make
      a transaction confirm as soon as possible.
    
    Co-authored-by: willcl-ark <will@256k1.dev>
    50b119a611
  19. [doc]: add fee estimator tracing documentation 1a2576bc38
  20. [rpc]: rename `estimatefeewithforecasters` to `estimatefee` a19af1a2c7
  21. ismaelsadeeq force-pushed on May 29, 2024
  22. [test]: calculate correct fee rate in `create_self_transfer`
    This commit updates the fee rate calculation in `create_self_transfer` to account
    for the size increase when target_weight is not 0.
    93146927ac
  23. [test]: test `estimatefee` rpc 6fb2e37138
  24. ismaelsadeeq force-pushed on May 29, 2024
  25. DrahtBot removed the label CI failed on May 29, 2024
  26. DrahtBot added the label Needs rebase on Jun 11, 2024
  27. DrahtBot commented at 12:20 pm on June 11, 2024: contributor

    🐙 This pull request conflicts with the target branch and needs rebase.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-06-29 07:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me