Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <policy/fees/block_policy_estimator.h>8#include <common/system.h>9#include <consensus/amount.h>10#include <kernel/mempool_entry.h>11#include <policy/feerate.h>12#include <primitives/transaction.h>13#include <random.h>14#include <serialize.h>15#include <streams.h>16#include <sync.h>17#include <tinyformat.h>18#include <uint256.h>19#include <util/fs.h>20#include <util/log.h>21#include <util/serfloat.h>22#include <util/syserror.h>23#include <util/time.h>25#include <algorithm>26#include <cassert>27#include <chrono>28#include <cmath>29#include <cstddef>30#include <cstdint>31#include <exception>32#include <stdexcept>33#include <system_error>34#include <utility>36// The current format written, and the version required to read. Must be37// increased to at least 309900+1 on the next breaking change.38constexpr int CURRENT_FEES_FILE_VERSION{309900};40static constexpr double INF_FEERATE = 1e99;42std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)43{44switch (horizon) {45case FeeEstimateHorizon::SHORT_HALFLIFE: return "short";46case FeeEstimateHorizon::MED_HALFLIFE: return "medium";47case FeeEstimateHorizon::LONG_HALFLIFE: return "long";48} // no default case, so the compiler can warn about missing cases49assert(false);50}52std::string StringForBlockPolicyEstimateReason(BlockPolicyEstimateReason reason)53{54switch (reason) {55case BlockPolicyEstimateReason::NONE:56return "None";57case BlockPolicyEstimateReason::HALF_ESTIMATE:58return "Half Target 60% Threshold";59case BlockPolicyEstimateReason::FULL_ESTIMATE:60return "Target 85% Threshold";61case BlockPolicyEstimateReason::DOUBLE_ESTIMATE:62return "Double Target 95% Threshold";63case BlockPolicyEstimateReason::CONSERVATIVE:64return "Conservative Double Target longer horizon";65} // no default case, so the compiler can warn about missing cases66assert(false);67}69namespace {71struct EncodedDoubleFormatter72{73template<typename Stream> void Ser(Stream &s, double v)74{75s << EncodeDouble(v);76}78template<typename Stream> void Unser(Stream& s, double& v)79{80uint64_t encoded;81s >> encoded;82v = DecodeDouble(encoded);83}84};86} // namespace88/**89* We will instantiate an instance of this class to track transactions that were90* included in a block. We will lump transactions into a bucket according to their91* approximate feerate and then track how long it took for those txs to be included in a block92*93* The tracking of unconfirmed (mempool) transactions is completely independent of the94* historical tracking of transactions that have been confirmed in a block.95*/96class TxConfirmStats97{98private:99//Define the buckets we will group transactions into100const std::vector<double>& buckets; // The upper-bound of the range for the bucket (inclusive)101const std::map<double, unsigned int>& bucketMap; // Map of bucket upper-bound to index into all vectors by bucket103// For each bucket X:104// Count the total # of txs in each bucket105// Track the historical moving average of this total over blocks106std::vector<double> txCtAvg;108// Count the total # of txs confirmed within Y blocks in each bucket109// Track the historical moving average of these totals over blocks110std::vector<std::vector<double>> confAvg; // confAvg[Y][X]112// Track moving avg of txs which have been evicted from the mempool113// after failing to be confirmed within Y blocks114std::vector<std::vector<double>> failAvg; // failAvg[Y][X]116// Sum the total feerate of all tx's in each bucket117// Track the historical moving average of this total over blocks118std::vector<double> m_feerate_avg;120// Combine the conf counts with tx counts to calculate the confirmation % for each Y,X121// Combine the total value with the tx counts to calculate the avg feerate per bucket123double decay;125// Resolution (# of blocks) with which confirmations are tracked126unsigned int scale;128// Mempool counts of outstanding transactions129// For each bucket X, track the number of transactions in the mempool130// that are unconfirmed for each possible confirmation value Y131std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]132// transactions still unconfirmed after GetMaxConfirms for each bucket133std::vector<int> oldUnconfTxs;135void resizeInMemoryCounters(size_t newbuckets);137public:138/**139* Create new TxConfirmStats. This is called by BlockPolicyEstimator's140* constructor with default values.141* @param defaultBuckets contains the upper limits for the bucket boundaries142* @param maxPeriods max number of periods to track143* @param decay how much to decay the historical moving average per block144*/145TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,146unsigned int maxPeriods, double decay, unsigned int scale);148/** Roll the circular buffer for unconfirmed txs*/149void ClearCurrent(unsigned int nBlockHeight);151/**152* Record a new transaction data point in the current block stats153* @param blocksToConfirm the number of blocks it took this transaction to confirm154* @param val the feerate of the transaction155* @warning blocksToConfirm is 1-based and has to be >= 1156*/157void Record(int blocksToConfirm, double val);159/** Record a new transaction entering the mempool*/160unsigned int NewTx(unsigned int nBlockHeight, double val);162/** Remove a transaction from mempool tracking stats*/163void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,164unsigned int bucketIndex, bool inBlock);166/** Update our estimates by decaying our historical moving average and updating167with the data gathered from the current block */168void UpdateMovingAverages();170/**171* Calculate a feerate estimate. Find the lowest value bucket (or range of buckets172* to make sure we have enough data points) whose transactions still have sufficient likelihood173* of being confirmed within the target number of confirmations174* @param confTarget target number of confirmations175* @param sufficientTxVal required average number of transactions per block in a bucket range176* @param minSuccess the success probability we require177* @param nBlockHeight the current block height178*/179double EstimateMedianVal(int confTarget, double sufficientTxVal,180double minSuccess, unsigned int nBlockHeight,181EstimationResult *result = nullptr) const;183/** Return the max number of confirms we're tracking */184unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }186/** Write state of estimation data to a file*/187void Write(AutoFile& fileout) const;189/**190* Read saved state of estimation data from a file and replace all internal data structures and191* variables with this state.192*/193void Read(AutoFile& filein, size_t numBuckets);194};197TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,198const std::map<double, unsigned int>& defaultBucketMap,199unsigned int maxPeriods, double _decay, unsigned int _scale)200: buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)201{202assert(_scale != 0 && "_scale must be non-zero");203confAvg.resize(maxPeriods);204failAvg.resize(maxPeriods);205for (unsigned int i = 0; i < maxPeriods; i++) {206confAvg[i].resize(buckets.size());207failAvg[i].resize(buckets.size());208}210txCtAvg.resize(buckets.size());211m_feerate_avg.resize(buckets.size());213resizeInMemoryCounters(buckets.size());214}216void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {217// newbuckets must be passed in because the buckets referred to during Read have not been updated yet.218unconfTxs.resize(GetMaxConfirms());219for (unsigned int i = 0; i < unconfTxs.size(); i++) {220unconfTxs[i].resize(newbuckets);221}222oldUnconfTxs.resize(newbuckets);223}225// Roll the unconfirmed txs circular buffer226void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)227{228for (unsigned int j = 0; j < buckets.size(); j++) {229oldUnconfTxs[j] += unconfTxs[nBlockHeight % unconfTxs.size()][j];230unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;231}232}235void TxConfirmStats::Record(int blocksToConfirm, double feerate)236{237// blocksToConfirm is 1-based238if (blocksToConfirm < 1)239return;240int periodsToConfirm = (blocksToConfirm + scale - 1) / scale;241unsigned int bucketindex = bucketMap.lower_bound(feerate)->second;242for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {243confAvg[i - 1][bucketindex]++;244}245txCtAvg[bucketindex]++;246m_feerate_avg[bucketindex] += feerate;247}249void TxConfirmStats::UpdateMovingAverages()250{
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.