Skip to content

Instantly share code, notes, and snippets.

@ismaelsadeeq
Last active April 13, 2025 14:10
Show Gist options
  • Save ismaelsadeeq/bcfa6b1216eef10076665551d9885722 to your computer and use it in GitHub Desktop.
Save ismaelsadeeq/bcfa6b1216eef10076665551d9885722 to your computer and use it in GitHub Desktop.
Bitcoin Core Fee Estimator Design

Bitcoin Core ASAP (1,2) Fee Estimation Design

1. Introduction

This document introduces a modular and extensible fee estimation system for Bitcoin Core. The design is centered around a fee rate forecasting manager that integrates multiple fee rate forecasting strategies and performs mempool health checks to determine the most appropriate strategy for providing fee rate forecast. This approach facilitates the additions of new strategies while ensuring smooth integration with existing systems.

2. Design Overview

The system is organized into two primary components:

  • ForecasterManager: Manages multiple fee rate forecasters, coordinates between them, and interfaces with RPCs and wallets.
  • Forecaster: Defines the interface for all fee rate forecasters, ensuring consistency and extensibility.

3. ForecasterManager

The ForecasterManager is responsible for aggregating fee rate forecasts from various forecasters and selecting the best at the moment. It maintains shared pointers to each registered forecaster and subscribes to validation interface notifications for performing mempool health checks and updating other forecasters.

classDiagram
    class ForecasterManager {
        +map<ForecastType, std::shared_ptr<Forecaster>> forecasters
        +CBlockPolicyEstimator* GetBlockPolicyEstimator()
        +void RegisterForecaster(std::shared_ptr<Forecaster>)
        +ForecastResult ForecastFeeRateFromForecasters(int target, bool conservative)
    }
    class Forecaster {
        +ForecastType m_forecastType
        +virtual ForecastResult ForecastFeeRate(int target, bool conservative)*
    }
    class CValidationInterface {
        +void MempoolTransactionsRemovedForBlock(...)
        +void BlockConnected(...)
        
    }

    ForecasterManager --> Forecaster
    ForecasterManager --> CValidationInterface
Loading

Responsibilities

  • Registration: Allows new forecasters to be registered.
  • Coordination: Aggregates fee rate from different forecasters and selects the best fee rate.
  • Validation Interface Integration: Listens to network events (block connections, mempool changes) to adjust the state of the mempool as blocks are connected and update block policy estimator.

4. Forecaster

The Forecaster abstract class specifies the interface that all forecasting strategies must implement. This ensures that any new strategy integrates seamlessly into the system.

classDiagram
    class Forecaster {
        +ForecastType m_forecastType*
        +virtual ForecastResult ForecastFeeRate(int target, bool conservative)*
    }
Loading

Definitions

  • ForecastType: An enum to identify the type of forecaster.
  • ForecastFeeRate(int target, bool conservative): A pure virtual method that must be implemented by each derived class to provide fee rate forecast.

5. Forecaster Implementations

5.1. Mempool-Based Forecaster (MemPoolForecaster)

MemPoolForecaster derives from Forecaster and forecast fee rates by constructing block templates from the node’s mempool. It provides:

  • Conservative fee rate: Based on the 50th percentile mining score.
  • Economical: Based on the 75th percentile mining score.

It owns pointers to the mempool and chainstate for generating blocks templates.

classDiagram
    class Forecaster {
        +ForecastType m_forecastType
        +virtual ForecastResult ForecastFeeRate(int target, bool conservative)*
    }
    class MemPoolForecaster {
        +CTxMemPool* m_mempool
        +Chainstate* m_chainstate
        +ForecastResult ForecastFeeRate(int target, bool conservative) override
    }

    Forecaster <|-- MemPoolForecaster
Loading

5.2. Block Policy Estimator Forecaster

This forecaster integrates the existing CBlockPolicyEstimator by subclassing Forecaster. Its implementation of ForecastFeeRate acts as a wrapper around the estimatesmartfee function.

classDiagram
    class Forecaster {
        +ForecastType m_forecastType
        +virtual ForecastResult ForecastFeeRate(int target, bool conservative)*
    }
    class BlockPolicyEstimator {
        +ForecastResult ForecastFeeRate(int target, bool conservative) override
    }

    Forecaster <|-- BlockPolicyEstimator
Loading

6. Fee Estimation Flow

The flow below outlines how the system processes fee estimation requests:

graph TD;
    A[User requests fee estimate] --> B[ForecasterManager receives request]
    B --> C{Sanity checks}
    C -->|Fail| D[Return error message]
    C -->|Pass| E[Determine which forecaster to call]
    E --> F[Call Forecaster and BlockPolicyEstimator ForecastFeeRate]
    F --> G[Return lowest estimate]

Loading

This flow is for ASAP fee rates estimate i.e 1–2 block targets.

For confirmation target > 2 CBlockPolicyEstimator will be used.

Services using this new feature are strongly recommended to make there transactions RBF-opt in to allow for fee bumping.

7. Next Steps

  • Integrate the ForecasterManager with wallet functionality to enable dynamic fee estimation during transaction creation.
  • Continue refining estimation algorithms based on empirical network data and testing e.g when MEV come to pass; mempool will not be reliable for fee rate forecast.

8. FAQ

8.1. Can miners manipulate fee estimates by broadcasting and replacing high-fee transactions?

The design mitigates this risk by ensuring that the mempool-based estimator does not spike fees instantly. If mempool estimates exceed those from the CBlockPolicyEstimator, the system returns the lower estimate to prevent manipulation.

8.2. What happens if CBlockPolicyEstimator provides a lower estimate during congestion?

In periods of congestion, if the mempool-based estimate increases while CBlockPolicyEstimator remains low, transactions may take longer to confirm. However, RBF-enabled transactions can be fee-bumped to accommodate network conditions. As congestion eases, estimates adjust dynamically.

8.3. How does MemPoolForecaster avoid excessive block template generation?

MemPoolForecaster caches recent fee estimates and regenerates block templates only if the last estimate is older than 30 seconds. Considering that transaction propagation across the network typically takes about 15 seconds, this interval is sufficient to reduce overhead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment