mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
fees: cache MemPoolPolicyEstimator
forecasts
- Provide new forecast 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. Co-authored-by: willcl-ark <will@256k1.dev>
This commit is contained in:
parent
d8c2f8c2f0
commit
7bf7b212a5
2 changed files with 64 additions and 0 deletions
|
@ -28,6 +28,13 @@ ForecastResult MemPoolForecaster::ForecastFeeRate(int target, bool conservative)
|
|||
return result;
|
||||
}
|
||||
|
||||
const auto cached_estimate = cache.get_cached_forecast();
|
||||
const auto known_chain_tip_hash = cache.get_chain_tip_hash();
|
||||
if (cached_estimate && *activeTip->phashBlock == known_chain_tip_hash) {
|
||||
result.feerate = conservative ? cached_estimate->p50 : cached_estimate->p75;
|
||||
return result;
|
||||
}
|
||||
|
||||
node::BlockAssembler::Options options;
|
||||
options.test_block_validity = false;
|
||||
node::BlockAssembler assembler(*m_chainstate, m_mempool, options);
|
||||
|
@ -50,6 +57,7 @@ ForecastResult MemPoolForecaster::ForecastFeeRate(int target, bool conservative)
|
|||
CFeeRate(percentiles.p75.fee, percentiles.p75.size).GetFeePerK(), CURRENCY_ATOM,
|
||||
CFeeRate(percentiles.p95.fee, percentiles.p95.size).GetFeePerK(), CURRENCY_ATOM);
|
||||
|
||||
cache.update(percentiles, *activeTip->phashBlock);
|
||||
result.feerate = conservative ? percentiles.p50 : percentiles.p75;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,15 @@
|
|||
#define BITCOIN_POLICY_FEES_MEMPOOL_FORECASTER_H
|
||||
|
||||
|
||||
#include <logging.h>
|
||||
#include <policy/fees/forecaster.h>
|
||||
#include <policy/fees/forecaster_util.h>
|
||||
#include <sync.h>
|
||||
#include <uint256.h>
|
||||
#include <util/time.h>
|
||||
|
||||
|
||||
#include <chrono>
|
||||
|
||||
class Chainstate;
|
||||
class CTxMemPool;
|
||||
|
@ -14,6 +22,53 @@ class CTxMemPool;
|
|||
// Fee rate forecasts above this confirmation target are not reliable,
|
||||
// as mempool conditions are likely to change.
|
||||
constexpr int MEMPOOL_FORECAST_MAX_TARGET{2};
|
||||
constexpr std::chrono::seconds CACHE_LIFE{30};
|
||||
|
||||
/**
|
||||
* CachedMempoolForecast holds a cache of recent fee rate forecast.
|
||||
* We only provide fresh fee rate if the last saved cache ages more than CACHE_LIFE.
|
||||
*/
|
||||
struct CachedMempoolForecast {
|
||||
private:
|
||||
mutable Mutex cache_mutex;
|
||||
uint256 chain_tip_hash GUARDED_BY(cache_mutex);
|
||||
Percentiles fee_rate GUARDED_BY(cache_mutex);
|
||||
NodeClock::time_point last_updated GUARDED_BY(cache_mutex){NodeClock::now() - CACHE_LIFE - std::chrono::seconds(1)};
|
||||
|
||||
public:
|
||||
CachedMempoolForecast() = default;
|
||||
CachedMempoolForecast(const CachedMempoolForecast&) = delete;
|
||||
CachedMempoolForecast& operator=(const CachedMempoolForecast&) = delete;
|
||||
|
||||
bool isStale() const EXCLUSIVE_LOCKS_REQUIRED(cache_mutex)
|
||||
{
|
||||
AssertLockHeld(cache_mutex);
|
||||
return (last_updated + CACHE_LIFE) < NodeClock::now();
|
||||
}
|
||||
|
||||
std::optional<Percentiles> get_cached_forecast() const EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex)
|
||||
{
|
||||
LOCK(cache_mutex);
|
||||
if (isStale()) return std::nullopt;
|
||||
LogDebug(BCLog::ESTIMATEFEE, "%s: cache is not stale, using cached value\n", forecastTypeToString(ForecastType::MEMPOOL_FORECAST));
|
||||
return fee_rate;
|
||||
}
|
||||
|
||||
uint256 get_chain_tip_hash() const EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex)
|
||||
{
|
||||
LOCK(cache_mutex);
|
||||
return chain_tip_hash;
|
||||
}
|
||||
|
||||
void update(const Percentiles& new_fee_rate, uint256 current_tip_hash) EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex)
|
||||
{
|
||||
LOCK(cache_mutex);
|
||||
fee_rate = new_fee_rate;
|
||||
last_updated = NodeClock::now();
|
||||
chain_tip_hash = current_tip_hash;
|
||||
LogDebug(BCLog::ESTIMATEFEE, "%s: updated cache\n", forecastTypeToString(ForecastType::MEMPOOL_FORECAST));
|
||||
}
|
||||
};
|
||||
|
||||
/** \class MemPoolForecaster
|
||||
* @brief Forecasts the fee rate required for a transaction to be included in the next block.
|
||||
|
@ -40,5 +95,6 @@ public:
|
|||
private:
|
||||
const CTxMemPool* m_mempool;
|
||||
Chainstate* m_chainstate;
|
||||
mutable CachedMempoolForecast cache;
|
||||
};
|
||||
#endif // BITCOIN_POLICY_FEES_MEMPOOL_FORECASTER_H
|
||||
|
|
Loading…
Add table
Reference in a new issue