Coverage Report

Created: 2026-09-02 14:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/policy/fees/block_policy_estimator.cpp
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present The Bitcoin Core developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
#include <policy/fees/block_policy_estimator.h>
7
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>
24
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>
35
36
// The current format written, and the version required to read. Must be
37
// increased to at least 309900+1 on the next breaking change.
38
constexpr int CURRENT_FEES_FILE_VERSION{309900};
39
40
static constexpr double INF_FEERATE = 1e99;
41
42
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
43
319
{
44
319
    switch (horizon) {
45
63
    case FeeEstimateHorizon::SHORT_HALFLIFE: return "short";
46
128
    case FeeEstimateHorizon::MED_HALFLIFE: return "medium";
47
128
    case FeeEstimateHorizon::LONG_HALFLIFE: return "long";
48
319
    } // no default case, so the compiler can warn about missing cases
49
319
    assert(false);
50
0
}
51
52
std::string StringForBlockPolicyEstimateReason(BlockPolicyEstimateReason reason)
53
3.25k
{
54
3.25k
    switch (reason) {
55
0
    case BlockPolicyEstimateReason::NONE:
56
0
        return "None";
57
3.13k
    case BlockPolicyEstimateReason::HALF_ESTIMATE:
58
3.13k
        return "Half Target 60% Threshold";
59
51
    case BlockPolicyEstimateReason::FULL_ESTIMATE:
60
51
        return "Target 85% Threshold";
61
0
    case BlockPolicyEstimateReason::DOUBLE_ESTIMATE:
62
0
        return "Double Target 95% Threshold";
63
71
    case BlockPolicyEstimateReason::CONSERVATIVE:
64
71
        return "Conservative Double Target longer horizon";
65
3.25k
    } // no default case, so the compiler can warn about missing cases
66
3.25k
    assert(false);
67
0
}
68
69
namespace {
70
71
struct EncodedDoubleFormatter
72
{
73
    template<typename Stream> void Ser(Stream &s, double v)
74
41.2M
    {
75
41.2M
        s << EncodeDouble(v);
76
41.2M
    }
77
78
    template<typename Stream> void Unser(Stream& s, double& v)
79
21.0M
    {
80
21.0M
        uint64_t encoded;
81
21.0M
        s >> encoded;
82
21.0M
        v = DecodeDouble(encoded);
83
21.0M
    }
84
};
85
86
} // namespace
87
88
/**
89
 * We will instantiate an instance of this class to track transactions that were
90
 * included in a block. We will lump transactions into a bucket according to their
91
 * approximate feerate and then track how long it took for those txs to be included in a block
92
 *
93
 * The tracking of unconfirmed (mempool) transactions is completely independent of the
94
 * historical tracking of transactions that have been confirmed in a block.
95
 */
96
class TxConfirmStats
97
{
98
private:
99
    //Define the buckets we will group transactions into
100
    const std::vector<double>& buckets;              // The upper-bound of the range for the bucket (inclusive)
101
    const std::map<double, unsigned int>& bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
102
103
    // For each bucket X:
104
    // Count the total # of txs in each bucket
105
    // Track the historical moving average of this total over blocks
106
    std::vector<double> txCtAvg;
107
108
    // Count the total # of txs confirmed within Y blocks in each bucket
109
    // Track the historical moving average of these totals over blocks
110
    std::vector<std::vector<double>> confAvg; // confAvg[Y][X]
111
112
    // Track moving avg of txs which have been evicted from the mempool
113
    // after failing to be confirmed within Y blocks
114
    std::vector<std::vector<double>> failAvg; // failAvg[Y][X]
115
116
    // Sum the total feerate of all tx's in each bucket
117
    // Track the historical moving average of this total over blocks
118
    std::vector<double> m_feerate_avg;
119
120
    // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
121
    // Combine the total value with the tx counts to calculate the avg feerate per bucket
122
123
    double decay;
124
125
    // Resolution (# of blocks) with which confirmations are tracked
126
    unsigned int scale;
127
128
    // Mempool counts of outstanding transactions
129
    // For each bucket X, track the number of transactions in the mempool
130
    // that are unconfirmed for each possible confirmation value Y
131
    std::vector<std::vector<int> > unconfTxs;  //unconfTxs[Y][X]
132
    // transactions still unconfirmed after GetMaxConfirms for each bucket
133
    std::vector<int> oldUnconfTxs;
134
135
    void resizeInMemoryCounters(size_t newbuckets);
136
137
public:
138
    /**
139
     * Create new TxConfirmStats. This is called by BlockPolicyEstimator's
140
     * constructor with default values.
141
     * @param defaultBuckets contains the upper limits for the bucket boundaries
142
     * @param maxPeriods max number of periods to track
143
     * @param decay how much to decay the historical moving average per block
144
     */
145
    TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,
146
                   unsigned int maxPeriods, double decay, unsigned int scale);
147
148
    /** Roll the circular buffer for unconfirmed txs*/
149
    void ClearCurrent(unsigned int nBlockHeight);
150
151
    /**
152
     * Record a new transaction data point in the current block stats
153
     * @param blocksToConfirm the number of blocks it took this transaction to confirm
154
     * @param val the feerate of the transaction
155
     * @warning blocksToConfirm is 1-based and has to be >= 1
156
     */
157
    void Record(int blocksToConfirm, double val);
158
159
    /** Record a new transaction entering the mempool*/
160
    unsigned int NewTx(unsigned int nBlockHeight, double val);
161
162
    /** Remove a transaction from mempool tracking stats*/
163
    void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
164
                  unsigned int bucketIndex, bool inBlock);
165
166
    /** Update our estimates by decaying our historical moving average and updating
167
        with the data gathered from the current block */
168
    void UpdateMovingAverages();
169
170
    /**
171
     * Calculate a feerate estimate.  Find the lowest value bucket (or range of buckets
172
     * to make sure we have enough data points) whose transactions still have sufficient likelihood
173
     * of being confirmed within the target number of confirmations
174
     * @param confTarget target number of confirmations
175
     * @param sufficientTxVal required average number of transactions per block in a bucket range
176
     * @param minSuccess the success probability we require
177
     * @param nBlockHeight the current block height
178
     */
179
    double EstimateMedianVal(int confTarget, double sufficientTxVal,
180
                             double minSuccess, unsigned int nBlockHeight,
181
                             EstimationResult *result = nullptr) const;
182
183
    /** Return the max number of confirms we're tracking */
184
760M
    unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
185
186
    /** Write state of estimation data to a file*/
187
    void Write(AutoFile& fileout) const;
188
189
    /**
190
     * Read saved state of estimation data from a file and replace all internal data structures and
191
     * variables with this state.
192
     */
193
    void Read(AutoFile& filein, size_t numBuckets);
194
};
195
196
197
TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
198
                                const std::map<double, unsigned int>& defaultBucketMap,
199
                               unsigned int maxPeriods, double _decay, unsigned int _scale)
200
4.82k
    : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
201
4.82k
{
202
4.82k
    assert(_scale != 0 && "_scale must be non-zero");
203
4.82k
    confAvg.resize(maxPeriods);
204
4.82k
    failAvg.resize(maxPeriods);
205
130k
    for (unsigned int i = 0; i < maxPeriods; i++) {
206
125k
        confAvg[i].resize(buckets.size());
207
125k
        failAvg[i].resize(buckets.size());
208
125k
    }
209
210
4.82k
    txCtAvg.resize(buckets.size());
211
4.82k
    m_feerate_avg.resize(buckets.size());
212
213
4.82k
    resizeInMemoryCounters(buckets.size());
214
4.82k
}
215
216
6.45k
void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {
217
    // newbuckets must be passed in because the buckets referred to during Read have not been updated yet.
218
6.45k
    unconfTxs.resize(GetMaxConfirms());
219
2.30M
    for (unsigned int i = 0; i < unconfTxs.size(); i++) {
220
2.29M
        unconfTxs[i].resize(newbuckets);
221
2.29M
    }
222
6.45k
    oldUnconfTxs.resize(newbuckets);
223
6.45k
}
224
225
// Roll the unconfirmed txs circular buffer
226
void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)
227
212k
{
228
50.6M
    for (unsigned int j = 0; j < buckets.size(); j++) {
229
50.3M
        oldUnconfTxs[j] += unconfTxs[nBlockHeight % unconfTxs.size()][j];
230
50.3M
        unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;
231
50.3M
    }
232
212k
}
233
234
235
void TxConfirmStats::Record(int blocksToConfirm, double feerate)
236
133k
{
237
    // blocksToConfirm is 1-based
238
133k
    if (blocksToConfirm < 1)
239
0
        return;
240
133k
    int periodsToConfirm = (blocksToConfirm + scale - 1) / scale;
241
133k
    unsigned int bucketindex = bucketMap.lower_bound(feerate)->second;
242
3.46M
    for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {
243
3.33M
        confAvg[i - 1][bucketindex]++;
244
3.33M
    }
245
133k
    txCtAvg[bucketindex]++;
246
133k
    m_feerate_avg[bucketindex] += feerate;
247
133k
}
248
249
void TxConfirmStats::UpdateMovingAverages()
250
212k
{
251
212k
    assert(confAvg.size() == failAvg.size());
252
50.6M
    for (unsigned int j = 0; j < buckets.size(); j++) {
253
1.36G
        for (unsigned int i = 0; i < confAvg.size(); i++) {
254
1.31G
            confAvg[i][j] *= decay;
255
1.31G
            failAvg[i][j] *= decay;
256
1.31G
        }
257
50.3M
        m_feerate_avg[j] *= decay;
258
50.3M
        txCtAvg[j] *= decay;
259
50.3M
    }
260
212k
}
261
262
// returns -1 on error conditions
263
double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
264
                                         double successBreakPoint, unsigned int nBlockHeight,
265
                                         EstimationResult *result) const
266
22.6k
{
267
    // Counters for a bucket (or range of buckets)
268
22.6k
    double nConf = 0; // Number of tx's confirmed within the confTarget
269
22.6k
    double totalNum = 0; // Total number of tx's that were ever confirmed
270
22.6k
    int extraNum = 0;  // Number of tx's still in mempool for confTarget or longer
271
22.6k
    double failNum = 0; // Number of tx's that were never confirmed but removed from the mempool after confTarget
272
22.6k
    const int periodTarget = (confTarget + scale - 1) / scale;
273
22.6k
    const int maxbucketindex = buckets.size() - 1;
274
275
    // We'll combine buckets until we have enough samples.
276
    // The near and far variables will define the range we've combined
277
    // The best variables are the last range we saw which still had a high
278
    // enough confirmation rate to count as success.
279
    // The cur variables are the current range we're counting.
280
22.6k
    unsigned int curNearBucket = maxbucketindex;
281
22.6k
    unsigned int bestNearBucket = maxbucketindex;
282
22.6k
    unsigned int curFarBucket = maxbucketindex;
283
22.6k
    unsigned int bestFarBucket = maxbucketindex;
284
285
    // We'll always group buckets into sets that meet sufficientTxVal --
286
    // this ensures that we're using consistent groups between different
287
    // confirmation targets.
288
22.6k
    double partialNum = 0;
289
290
22.6k
    bool foundAnswer = false;
291
22.6k
    unsigned int bins = unconfTxs.size();
292
22.6k
    bool newBucketRange = true;
293
22.6k
    bool passing = true;
294
22.6k
    EstimatorBucket passBucket;
295
22.6k
    EstimatorBucket failBucket;
296
297
    // Start counting from highest feerate transactions
298
5.38M
    for (int bucket = maxbucketindex; bucket >= 0; --bucket) {
299
5.36M
        if (newBucketRange) {
300
62.3k
            curNearBucket = bucket;
301
62.3k
            newBucketRange = false;
302
62.3k
        }
303
5.36M
        curFarBucket = bucket;
304
5.36M
        nConf += confAvg[periodTarget - 1][bucket];
305
5.36M
        partialNum += txCtAvg[bucket];
306
5.36M
        totalNum += txCtAvg[bucket];
307
5.36M
        failNum += failAvg[periodTarget - 1][bucket];
308
760M
        for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)
309
755M
            extraNum += unconfTxs[(nBlockHeight - confct) % bins][bucket];
310
5.36M
        extraNum += oldUnconfTxs[bucket];
311
        // If we have enough transaction data points in this range of buckets,
312
        // we can test for success
313
        // (Only count the confirmed data points, so that each confirmation count
314
        // will be looking at the same amount of data and same bucket breaks)
315
316
5.36M
        if (partialNum < sufficientTxVal / (1 - decay)) {
317
            // the buckets we've added in this round aren't sufficient
318
            // so keep adding
319
5.31M
            continue;
320
5.31M
        } else {
321
49.8k
            partialNum = 0; // reset for the next range we'll add
322
323
49.8k
            double curPct = nConf / (totalNum + failNum + extraNum);
324
325
            // Check to see if we are no longer getting confirmed at the success rate
326
49.8k
            if (curPct < successBreakPoint) {
327
10.0k
                if (passing == true) {
328
                    // First time we hit a failure record the failed bucket
329
981
                    unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
330
981
                    unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
331
981
                    failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
332
981
                    failBucket.end = buckets[failMaxBucket];
333
981
                    failBucket.withinTarget = nConf;
334
981
                    failBucket.totalConfirmed = totalNum;
335
981
                    failBucket.inMempool = extraNum;
336
981
                    failBucket.leftMempool = failNum;
337
981
                    passing = false;
338
981
                }
339
10.0k
                continue;
340
10.0k
            }
341
            // Otherwise update the cumulative stats, and the bucket variables
342
            // and reset the counters
343
39.7k
            else {
344
39.7k
                failBucket = EstimatorBucket(); // Reset any failed bucket, currently passing
345
39.7k
                foundAnswer = true;
346
39.7k
                passing = true;
347
39.7k
                passBucket.withinTarget = nConf;
348
39.7k
                nConf = 0;
349
39.7k
                passBucket.totalConfirmed = totalNum;
350
39.7k
                totalNum = 0;
351
39.7k
                passBucket.inMempool = extraNum;
352
39.7k
                passBucket.leftMempool = failNum;
353
39.7k
                failNum = 0;
354
39.7k
                extraNum = 0;
355
39.7k
                bestNearBucket = curNearBucket;
356
39.7k
                bestFarBucket = curFarBucket;
357
39.7k
                newBucketRange = true;
358
39.7k
            }
359
49.8k
        }
360
5.36M
    }
361
362
22.6k
    double median = -1;
363
22.6k
    double txSum = 0;
364
365
    // Calculate the "average" feerate of the best bucket range that met success conditions
366
    // Find the bucket with the median transaction and then report the average feerate from that bucket
367
    // This is a compromise between finding the median which we can't since we don't save all tx's
368
    // and reporting the average which is less accurate
369
22.6k
    unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
370
22.6k
    unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
371
1.53M
    for (unsigned int j = minBucket; j <= maxBucket; j++) {
372
1.50M
        txSum += txCtAvg[j];
373
1.50M
    }
374
22.6k
    if (foundAnswer && txSum != 0) {
375
12.8k
        txSum = txSum / 2;
376
227k
        for (unsigned int j = minBucket; j <= maxBucket; j++) {
377
227k
            if (txCtAvg[j] < txSum)
378
214k
                txSum -= txCtAvg[j];
379
12.8k
            else { // we're in the right bucket
380
12.8k
                median = m_feerate_avg[j] / txCtAvg[j];
381
12.8k
                break;
382
12.8k
            }
383
227k
        }
384
385
12.8k
        passBucket.start = minBucket ? buckets[minBucket-1] : 0;
386
12.8k
        passBucket.end = buckets[maxBucket];
387
12.8k
    }
388
389
    // If we were passing until we reached last few buckets with insufficient data, then report those as failed
390
22.6k
    if (passing && !newBucketRange) {
391
21.8k
        unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
392
21.8k
        unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
393
21.8k
        failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
394
21.8k
        failBucket.end = buckets[failMaxBucket];
395
21.8k
        failBucket.withinTarget = nConf;
396
21.8k
        failBucket.totalConfirmed = totalNum;
397
21.8k
        failBucket.inMempool = extraNum;
398
21.8k
        failBucket.leftMempool = failNum;
399
21.8k
    }
400
401
22.6k
    float passed_within_target_perc = 0.0;
402
22.6k
    float failed_within_target_perc = 0.0;
403
22.6k
    if ((passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool)) {
404
12.8k
        passed_within_target_perc = 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool);
405
12.8k
    }
406
22.6k
    if ((failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool)) {
407
14.3k
        failed_within_target_perc = 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool);
408
14.3k
    }
409
410
22.6k
    LogDebug(BCLog::ESTIMATEFEE, "FeeEst: %d > %.0f%% decay %.5f: feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
411
22.6k
             confTarget, 100.0 * successBreakPoint, decay,
412
22.6k
             median, passBucket.start, passBucket.end,
413
22.6k
             passed_within_target_perc,
414
22.6k
             passBucket.withinTarget, passBucket.totalConfirmed, passBucket.inMempool, passBucket.leftMempool,
415
22.6k
             failBucket.start, failBucket.end,
416
22.6k
             failed_within_target_perc,
417
22.6k
             failBucket.withinTarget, failBucket.totalConfirmed, failBucket.inMempool, failBucket.leftMempool);
418
419
420
22.6k
    if (result) {
421
22.5k
        result->pass = passBucket;
422
22.5k
        result->fail = failBucket;
423
22.5k
        result->decay = decay;
424
22.5k
        result->scale = scale;
425
22.5k
    }
426
22.6k
    return median;
427
22.6k
}
428
429
void TxConfirmStats::Write(AutoFile& fileout) const
430
3.20k
{
431
3.20k
    fileout << Using<EncodedDoubleFormatter>(decay);
432
3.20k
    fileout << scale;
433
3.20k
    fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
434
3.20k
    fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
435
3.20k
    fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
436
3.20k
    fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
437
3.20k
}
438
439
void TxConfirmStats::Read(AutoFile& filein, size_t numBuckets)
440
1.63k
{
441
    // Read data file and do some very basic sanity checking
442
    // buckets and bucketMap are not updated yet, so don't access them
443
    // If there is a read failure, we'll just discard this entire object anyway
444
1.63k
    uint64_t maxConfirms, maxPeriods;
445
446
    // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
447
1.63k
    filein >> Using<EncodedDoubleFormatter>(decay);
448
1.63k
    if (decay <= 0 || decay >= 1) {
449
0
        throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
450
0
    }
451
1.63k
    filein >> scale;
452
1.63k
    if (scale == 0) {
453
0
        throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
454
0
    }
455
456
1.63k
    filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
457
1.63k
    if (m_feerate_avg.size() != numBuckets) {
458
0
        throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
459
0
    }
460
1.63k
    filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
461
1.63k
    if (txCtAvg.size() != numBuckets) {
462
0
        throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
463
0
    }
464
1.63k
    filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
465
1.63k
    maxPeriods = confAvg.size();
466
1.63k
    maxConfirms = scale * maxPeriods;
467
468
1.63k
    if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) { // one week
469
0
        throw std::runtime_error("Corrupt estimates file.  Must maintain estimates for between 1 and 1008 (one week) confirms");
470
0
    }
471
44.0k
    for (unsigned int i = 0; i < maxPeriods; i++) {
472
42.4k
        if (confAvg[i].size() != numBuckets) {
473
0
            throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
474
0
        }
475
42.4k
    }
476
477
1.63k
    filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
478
1.63k
    if (maxPeriods != failAvg.size()) {
479
0
        throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
480
0
    }
481
44.0k
    for (unsigned int i = 0; i < maxPeriods; i++) {
482
42.4k
        if (failAvg[i].size() != numBuckets) {
483
0
            throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
484
0
        }
485
42.4k
    }
486
487
    // Resize the current block variables which aren't stored in the data file
488
    // to match the number of confirms and buckets
489
1.63k
    resizeInMemoryCounters(numBuckets);
490
491
1.63k
    LogDebug(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n",
492
1.63k
             numBuckets, maxConfirms);
493
1.63k
}
494
495
unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
496
141k
{
497
141k
    unsigned int bucketindex = bucketMap.lower_bound(val)->second;
498
141k
    unsigned int blockIndex = nBlockHeight % unconfTxs.size();
499
141k
    unconfTxs[blockIndex][bucketindex]++;
500
141k
    return bucketindex;
501
141k
}
502
503
void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock)
504
141k
{
505
    //nBestSeenHeight is not updated yet for the new block
506
141k
    int blocksAgo = nBestSeenHeight - entryHeight;
507
141k
    if (nBestSeenHeight == 0)  // the BlockPolicyEstimator hasn't seen any blocks yet
508
0
        blocksAgo = 0;
509
141k
    if (blocksAgo < 0) {
510
0
        LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, blocks ago is negative for mempool tx\n");
511
0
        return;  //This can't happen because we call this with our best seen height, no entries can have higher
512
0
    }
513
514
141k
    if (blocksAgo >= (int)unconfTxs.size()) {
515
4.39k
        if (oldUnconfTxs[bucketindex] > 0) {
516
4.39k
            oldUnconfTxs[bucketindex]--;
517
4.39k
        } else {
518
0
            LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n",
519
0
                     bucketindex);
520
0
        }
521
4.39k
    }
522
137k
    else {
523
137k
        unsigned int blockIndex = entryHeight % unconfTxs.size();
524
137k
        if (unconfTxs[blockIndex][bucketindex] > 0) {
525
137k
            unconfTxs[blockIndex][bucketindex]--;
526
137k
        } else {
527
0
            LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
528
0
                     blockIndex, bucketindex);
529
0
        }
530
137k
    }
531
141k
    if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period
532
929
        assert(scale != 0);
533
929
        unsigned int periodsAgo = blocksAgo / scale;
534
2.46k
        for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {
535
1.53k
            failAvg[i][bucketindex]++;
536
1.53k
        }
537
929
    }
538
141k
}
539
540
bool CBlockPolicyEstimator::removeTx(Txid hash)
541
2.14k
{
542
2.14k
    LOCK(m_cs_fee_estimator);
543
2.14k
    return _removeTx(hash, /*inBlock=*/false);
544
2.14k
}
545
546
bool CBlockPolicyEstimator::_removeTx(const Txid& hash, bool inBlock)
547
50.6k
{
548
50.6k
    AssertLockHeld(m_cs_fee_estimator);
549
50.6k
    std::map<Txid, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
550
50.6k
    if (pos != mapMemPoolTxs.end()) {
551
47.1k
        feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
552
47.1k
        shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
553
47.1k
        longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
554
47.1k
        mapMemPoolTxs.erase(hash);
555
47.1k
        return true;
556
47.1k
    } else {
557
3.48k
        return false;
558
3.48k
    }
559
50.6k
}
560
561
CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath, const bool read_stale_estimates)
562
1.06k
    : m_estimation_filepath{estimation_filepath}
563
1.06k
{
564
1.06k
    static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
565
1.06k
    size_t bucketIndex = 0;
566
567
252k
    for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
568
251k
        buckets.push_back(bucketBoundary);
569
251k
        bucketMap[bucketBoundary] = bucketIndex;
570
251k
    }
571
1.06k
    buckets.push_back(INF_FEERATE);
572
1.06k
    bucketMap[INF_FEERATE] = bucketIndex;
573
1.06k
    assert(bucketMap.size() == buckets.size());
574
575
1.06k
    feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
576
1.06k
    shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
577
1.06k
    longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
578
579
1.06k
    AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "rb")};
580
581
1.06k
    if (est_file.IsNull()) {
582
519
        LogInfo("%s is not found. Continue anyway.", fs::PathToString(m_estimation_filepath));
583
519
        return;
584
519
    }
585
586
546
    std::chrono::hours file_age = GetFeeEstimatorFileAge();
587
546
    if (file_age > MAX_FILE_AGE && !read_stale_estimates) {
588
1
        LogWarning("Fee estimation file %s too old (age=%lld > %lld hours) and will not be used to avoid serving stale estimates.", fs::PathToString(m_estimation_filepath), Ticks<std::chrono::hours>(file_age), Ticks<std::chrono::hours>(MAX_FILE_AGE));
589
1
        return;
590
1
    }
591
592
545
    if (!Read(est_file)) {
593
1
        LogWarning("Failed to read fee estimates from %s. Continue anyway.", fs::PathToString(m_estimation_filepath));
594
1
    }
595
545
}
596
597
1.06k
CBlockPolicyEstimator::~CBlockPolicyEstimator() = default;
598
599
void CBlockPolicyEstimator::processTransaction(const NewMempoolTransactionInfo& tx)
600
51.4k
{
601
51.4k
    LOCK(m_cs_fee_estimator);
602
51.4k
    const unsigned int txHeight = tx.info.txHeight;
603
51.4k
    const auto& hash = tx.info.m_tx->GetHash();
604
51.4k
    if (mapMemPoolTxs.contains(hash)) {
605
0
        LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
606
0
                 hash.ToString());
607
0
        return;
608
0
    }
609
610
51.4k
    if (txHeight != nBestSeenHeight) {
611
        // Ignore side chains and re-orgs; assuming they are random they don't
612
        // affect the estimate.  We'll potentially double count transactions in 1-block reorgs.
613
        // Ignore txs if BlockPolicyEstimator is not in sync with ActiveChain().Tip().
614
        // It will be synced next time a block is processed.
615
528
        return;
616
528
    }
617
    // This transaction should only count for fee estimation if:
618
    // - it's not being re-added during a reorg which bypasses typical mempool fee limits
619
    // - the node is not behind
620
    // - the transaction is not dependent on any other transactions in the mempool
621
    // - it's not part of a package.
622
50.8k
    const bool validForFeeEstimation = !tx.m_mempool_limit_bypassed && !tx.m_submitted_in_package && tx.m_chainstate_is_current && tx.m_has_no_mempool_parents;
623
624
    // Only want to be updating estimates when our blockchain is synced,
625
    // otherwise we'll miscalculate how many blocks its taking to get included.
626
50.8k
    if (!validForFeeEstimation) {
627
3.71k
        untrackedTxs++;
628
3.71k
        return;
629
3.71k
    }
630
47.1k
    trackedTxs++;
631
632
    // Feerates are stored and reported as BTC-per-kb:
633
47.1k
    const CFeeRate feeRate(tx.info.m_fee, tx.info.m_virtual_transaction_size);
634
635
47.1k
    mapMemPoolTxs[hash].blockHeight = txHeight;
636
47.1k
    unsigned int bucketIndex = feeStats->NewTx(txHeight, static_cast<double>(feeRate.GetFeePerK()));
637
47.1k
    mapMemPoolTxs[hash].bucketIndex = bucketIndex;
638
47.1k
    unsigned int bucketIndex2 = shortStats->NewTx(txHeight, static_cast<double>(feeRate.GetFeePerK()));
639
47.1k
    assert(bucketIndex == bucketIndex2);
640
47.1k
    unsigned int bucketIndex3 = longStats->NewTx(txHeight, static_cast<double>(feeRate.GetFeePerK()));
641
47.1k
    assert(bucketIndex == bucketIndex3);
642
47.1k
}
643
644
bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const RemovedMempoolTransactionInfo& tx)
645
47.3k
{
646
47.3k
    AssertLockHeld(m_cs_fee_estimator);
647
47.3k
    if (!_removeTx(tx.info.m_tx->GetHash(), true)) {
648
        // This transaction wasn't being tracked for fee estimation
649
2.69k
        return false;
650
2.69k
    }
651
652
    // How many blocks did it take for miners to include this transaction?
653
    // blocksToConfirm is 1-based, so a transaction included in the earliest
654
    // possible block has confirmation count of 1
655
44.6k
    int blocksToConfirm = nBlockHeight - tx.info.txHeight;
656
44.6k
    if (blocksToConfirm <= 0) {
657
        // This can't happen because we don't process transactions from a block with a height
658
        // lower than our greatest seen height
659
0
        LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
660
0
        return false;
661
0
    }
662
663
    // Feerates are stored and reported as BTC-per-kb:
664
44.6k
    CFeeRate feeRate(tx.info.m_fee, tx.info.m_virtual_transaction_size);
665
666
44.6k
    feeStats->Record(blocksToConfirm, static_cast<double>(feeRate.GetFeePerK()));
667
44.6k
    shortStats->Record(blocksToConfirm, static_cast<double>(feeRate.GetFeePerK()));
668
44.6k
    longStats->Record(blocksToConfirm, static_cast<double>(feeRate.GetFeePerK()));
669
44.6k
    return true;
670
44.6k
}
671
672
void CBlockPolicyEstimator::processBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block,
673
                                         unsigned int nBlockHeight)
674
79.6k
{
675
79.6k
    LOCK(m_cs_fee_estimator);
676
79.6k
    if (nBlockHeight <= nBestSeenHeight) {
677
        // Ignore side chains and re-orgs; assuming they are random
678
        // they don't affect the estimate.
679
        // And if an attacker can re-org the chain at will, then
680
        // you've got much bigger problems than "attacker can influence
681
        // transaction fees."
682
8.81k
        return;
683
8.81k
    }
684
685
    // Must update nBestSeenHeight in sync with ClearCurrent so that
686
    // calls to removeTx (via processBlockTx) correctly calculate age
687
    // of unconfirmed txs to remove from tracking.
688
70.8k
    nBestSeenHeight = nBlockHeight;
689
690
    // Update unconfirmed circular buffer
691
70.8k
    feeStats->ClearCurrent(nBlockHeight);
692
70.8k
    shortStats->ClearCurrent(nBlockHeight);
693
70.8k
    longStats->ClearCurrent(nBlockHeight);
694
695
    // Decay all exponential averages
696
70.8k
    feeStats->UpdateMovingAverages();
697
70.8k
    shortStats->UpdateMovingAverages();
698
70.8k
    longStats->UpdateMovingAverages();
699
700
70.8k
    unsigned int countedTxs = 0;
701
    // Update averages with data points from current block
702
70.8k
    for (const auto& tx : txs_removed_for_block) {
703
47.3k
        if (processBlockTx(nBlockHeight, tx))
704
44.6k
            countedTxs++;
705
47.3k
    }
706
707
70.8k
    if (firstRecordedHeight == 0 && countedTxs > 0) {
708
259
        firstRecordedHeight = nBestSeenHeight;
709
259
        LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight);
710
259
    }
711
712
713
70.8k
    LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n",
714
70.8k
             countedTxs, txs_removed_for_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
715
70.8k
             MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");
716
717
70.8k
    trackedTxs = 0;
718
70.8k
    untrackedTxs = 0;
719
70.8k
}
720
721
CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
722
94
{
723
    // It's not possible to get reasonable estimates for confTarget of 1
724
94
    if (confTarget <= 1)
725
6
        return CFeeRate(0);
726
727
88
    return estimateRawFee(confTarget, DOUBLE_SUCCESS_PCT, FeeEstimateHorizon::MED_HALFLIFE);
728
94
}
729
730
CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
731
407
{
732
407
    TxConfirmStats* stats = nullptr;
733
407
    double sufficientTxs = SUFFICIENT_FEETXS;
734
407
    switch (horizon) {
735
63
    case FeeEstimateHorizon::SHORT_HALFLIFE: {
736
63
        stats = shortStats.get();
737
63
        sufficientTxs = SUFFICIENT_TXS_SHORT;
738
63
        break;
739
0
    }
740
216
    case FeeEstimateHorizon::MED_HALFLIFE: {
741
216
        stats = feeStats.get();
742
216
        break;
743
0
    }
744
128
    case FeeEstimateHorizon::LONG_HALFLIFE: {
745
128
        stats = longStats.get();
746
128
        break;
747
0
    }
748
407
    } // no default case, so the compiler can warn about missing cases
749
407
    assert(stats);
750
751
407
    LOCK(m_cs_fee_estimator);
752
    // Return failure if trying to analyze a target we're not tracking
753
407
    if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
754
0
        return CFeeRate(0);
755
407
    if (successThreshold > 1)
756
0
        return CFeeRate(0);
757
758
407
    double median = stats->EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
759
760
407
    if (median < 0)
761
25
        return CFeeRate(0);
762
763
382
    return CFeeRate(llround(median));
764
407
}
765
766
unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
767
4.45k
{
768
4.45k
    LOCK(m_cs_fee_estimator);
769
4.45k
    switch (horizon) {
770
128
    case FeeEstimateHorizon::SHORT_HALFLIFE: {
771
128
        return shortStats->GetMaxConfirms();
772
0
    }
773
128
    case FeeEstimateHorizon::MED_HALFLIFE: {
774
128
        return feeStats->GetMaxConfirms();
775
0
    }
776
4.19k
    case FeeEstimateHorizon::LONG_HALFLIFE: {
777
4.19k
        return longStats->GetMaxConfirms();
778
0
    }
779
4.45k
    } // no default case, so the compiler can warn about missing cases
780
4.45k
    assert(false);
781
0
}
782
783
unsigned int CBlockPolicyEstimator::BlockSpan() const
784
149k
{
785
149k
    if (firstRecordedHeight == 0) return 0;
786
149k
    assert(nBestSeenHeight >= firstRecordedHeight);
787
788
36.0k
    return nBestSeenHeight - firstRecordedHeight;
789
36.0k
}
790
791
unsigned int CBlockPolicyEstimator::HistoricalBlockSpan() const
792
149k
{
793
149k
    if (historicalFirst == 0) return 0;
794
149k
    assert(historicalBest >= historicalFirst);
795
796
4.28k
    if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;
797
798
4.28k
    return historicalBest - historicalFirst;
799
4.28k
}
800
801
unsigned int CBlockPolicyEstimator::MaxUsableEstimate() const
802
77.6k
{
803
    // Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate
804
77.6k
    return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);
805
77.6k
}
806
807
/** Return a fee estimate at the required successThreshold from the shortest
808
 * time horizon which tracks confirmations up to the desired target.  If
809
 * checkShorterHorizon is requested, also allow short time horizon estimates
810
 * for a lower target to reduce the given answer */
811
double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const
812
14.6k
{
813
14.6k
    double estimate = -1;
814
14.6k
    if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
815
        // Find estimate from shortest time horizon possible
816
14.6k
        if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon
817
11.3k
            estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
818
11.3k
        }
819
3.25k
        else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon
820
1.61k
            estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
821
1.61k
        }
822
1.64k
        else { // long horizon
823
1.64k
            estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
824
1.64k
        }
825
14.6k
        if (checkShorterHorizon) {
826
14.6k
            EstimationResult tempResult;
827
            // If a lower confTarget from a more recent horizon returns a lower answer use it.
828
14.6k
            if (confTarget > feeStats->GetMaxConfirms()) {
829
1.64k
                double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
830
1.64k
                if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
831
1.08k
                    estimate = medMax;
832
1.08k
                    if (result) *result = tempResult;
833
1.08k
                }
834
1.64k
            }
835
14.6k
            if (confTarget > shortStats->GetMaxConfirms()) {
836
3.25k
                double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
837
3.25k
                if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
838
241
                    estimate = shortMax;
839
241
                    if (result) *result = tempResult;
840
241
                }
841
3.25k
            }
842
14.6k
        }
843
14.6k
    }
844
14.6k
    return estimate;
845
14.6k
}
846
847
/** Ensure that for a conservative estimate, the DOUBLE_SUCCESS_PCT is also met
848
 * at 2 * target for any longer time horizons.
849
 */
850
double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const
851
1.69k
{
852
1.69k
    double estimate = -1;
853
1.69k
    EstimationResult tempResult;
854
1.69k
    if (doubleTarget <= shortStats->GetMaxConfirms()) {
855
1.29k
        estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, result);
856
1.29k
    }
857
1.69k
    if (doubleTarget <= feeStats->GetMaxConfirms()) {
858
1.41k
        double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, &tempResult);
859
1.41k
        if (longEstimate > estimate) {
860
1
            estimate = longEstimate;
861
1
            if (result) *result = tempResult;
862
1
        }
863
1.41k
    }
864
1.69k
    return estimate;
865
1.69k
}
866
867
/** estimateSmartFee returns the max of the feerates calculated with a 60%
868
 * threshold required at target / 2, an 85% threshold required at target and a
869
 * 95% threshold required at 2 * target.  Each calculation is performed at the
870
 * shortest time horizon which tracks the required target.  Conservative
871
 * estimates, however, required the 95% threshold at 2 * target be met for any
872
 * longer time horizons also.
873
 */
874
CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
875
6.78k
{
876
6.78k
    LOCK(m_cs_fee_estimator);
877
878
6.78k
    FeeCalculation temp_fee_calc;
879
6.78k
    if (!feeCalc) feeCalc = &temp_fee_calc;
880
881
6.78k
    feeCalc->desiredTarget = confTarget;
882
6.78k
    feeCalc->returnedTarget = confTarget;
883
6.78k
    feeCalc->best_height = nBestSeenHeight;
884
885
6.78k
    double median = -1;
886
6.78k
    EstimationResult tempResult;
887
888
    // Return failure if trying to analyze a target we're not tracking
889
6.78k
    if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
890
0
        return CFeeRate(0);  // error condition
891
0
    }
892
893
    // It's not possible to get reasonable estimates for confTarget of 1
894
6.78k
    if (confTarget == 1) confTarget = 2;
895
896
6.78k
    unsigned int maxUsableEstimate = MaxUsableEstimate();
897
6.78k
    if ((unsigned int)confTarget > maxUsableEstimate) {
898
5.76k
        confTarget = maxUsableEstimate;
899
5.76k
    }
900
6.78k
    feeCalc->returnedTarget = confTarget;
901
902
6.78k
    if (confTarget <= 1) return CFeeRate(0); // error condition
903
904
6.78k
    assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
905
    /** true is passed to estimateCombined fee for target/2 and target so
906
     * that we check the max confirms for shorter time horizons as well.
907
     * This is necessary to preserve monotonically increasing estimates.
908
     * For non-conservative estimates we do the same thing for 2*target, but
909
     * for conservative estimates we want to skip these shorter horizons
910
     * checks for 2*target because we are taking the max over all time
911
     * horizons so we already have monotonically increasing estimates and
912
     * the purpose of conservative estimates is not to let short term
913
     * fluctuations lower our estimates by too much.
914
     *
915
     * Note: In certain rare edge cases, monotonically increasing estimates may
916
     * not be guaranteed. Specifically, given two targets N and M, where M > N,
917
     * if a sub-estimate for target N fails to return a valid fee rate, while
918
     * target M has valid fee rate for that sub-estimate, target M may result
919
     * in a higher fee rate estimate than target N.
920
     *
921
     * See: https://github.com/bitcoin/bitcoin/issues/11800#issuecomment-349697807
922
     */
923
4.87k
    double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
924
4.87k
    feeCalc->est = tempResult;
925
4.87k
    feeCalc->reason = BlockPolicyEstimateReason::HALF_ESTIMATE;
926
4.87k
    median = halfEst;
927
4.87k
    double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
928
4.87k
    if (actualEst > median) {
929
51
        median = actualEst;
930
51
        feeCalc->est = tempResult;
931
51
        feeCalc->reason = BlockPolicyEstimateReason::FULL_ESTIMATE;
932
51
    }
933
4.87k
    double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
934
4.87k
    if (doubleEst > median) {
935
0
        median = doubleEst;
936
0
        feeCalc->est = tempResult;
937
0
        feeCalc->reason = BlockPolicyEstimateReason::DOUBLE_ESTIMATE;
938
0
    }
939
940
4.87k
    if (conservative || median == -1) {
941
1.69k
        double consEst =  estimateConservativeFee(2 * confTarget, &tempResult);
942
1.69k
        if (consEst > median) {
943
71
            median = consEst;
944
71
            feeCalc->est = tempResult;
945
71
            feeCalc->reason = BlockPolicyEstimateReason::CONSERVATIVE;
946
71
        }
947
1.69k
    }
948
949
4.87k
    if (median < 0) return CFeeRate(0); // error condition
950
951
3.25k
    LogDebug(BCLog::ESTIMATEFEE, "estimateSmartFee Selected feerate: %g Tgt: %d (requested %d) Reason: \"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)",
952
3.25k
             median, feeCalc->returnedTarget, feeCalc->desiredTarget, StringForBlockPolicyEstimateReason(feeCalc->reason), feeCalc->est.decay,
953
3.25k
             feeCalc->est.pass.start, feeCalc->est.pass.end,
954
3.25k
             (feeCalc->est.pass.totalConfirmed + feeCalc->est.pass.inMempool + feeCalc->est.pass.leftMempool) > 0.0 ? 100 * feeCalc->est.pass.withinTarget / (feeCalc->est.pass.totalConfirmed + feeCalc->est.pass.inMempool + feeCalc->est.pass.leftMempool) : 0.0,
955
3.25k
             feeCalc->est.pass.withinTarget, feeCalc->est.pass.totalConfirmed, feeCalc->est.pass.inMempool, feeCalc->est.pass.leftMempool,
956
3.25k
             feeCalc->est.fail.start, feeCalc->est.fail.end,
957
3.25k
             (feeCalc->est.fail.totalConfirmed + feeCalc->est.fail.inMempool + feeCalc->est.fail.leftMempool) > 0.0 ? 100 * feeCalc->est.fail.withinTarget / (feeCalc->est.fail.totalConfirmed + feeCalc->est.fail.inMempool + feeCalc->est.fail.leftMempool) : 0.0,
958
3.25k
             feeCalc->est.fail.withinTarget, feeCalc->est.fail.totalConfirmed, feeCalc->est.fail.inMempool, feeCalc->est.fail.leftMempool);
959
960
3.25k
    return CFeeRate(llround(median));
961
4.87k
}
962
963
util::Expected<FeeRateEstimation, FeeRateEstimationError> CBlockPolicyEstimator::EstimateFeeRate(int target, bool conservative) const
964
6.78k
{
965
6.78k
    FeeCalculation fee_calc;
966
6.78k
    CFeeRate feerate{estimateSmartFee(target, &fee_calc, conservative)};
967
6.78k
    if (feerate == CFeeRate(0)) {
968
3.53k
        return EstimationError(FeeRateEstimatorType::BLOCK_POLICY, fee_calc.returnedTarget, "Insufficient data or no feerate found");
969
3.53k
    }
970
3.25k
    return FeeRateEstimation{FeeRateEstimatorType::BLOCK_POLICY, feerate.GetFeePerVSize(), fee_calc.returnedTarget};
971
6.78k
}
972
973
unsigned int CBlockPolicyEstimator::MaximumTarget() const
974
4.07k
{
975
4.07k
    return HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
976
4.07k
}
977
978
1.06k
void CBlockPolicyEstimator::Flush() {
979
1.06k
    FlushUnconfirmed();
980
1.06k
    FlushFeeEstimates();
981
1.06k
}
982
983
void CBlockPolicyEstimator::FlushFeeEstimates()
984
1.06k
{
985
1.06k
    if (!m_estimation_filepath.parent_path().empty()) {
986
1.06k
        std::error_code error;
987
1.06k
        fs::create_directories(m_estimation_filepath.parent_path(), error);
988
1.06k
        if (error) {
989
0
            LogWarning("Failed to create fee estimates directory %s: %s. Continue anyway.", fs::PathToString(m_estimation_filepath.parent_path()), error.message());
990
0
            return;
991
0
        }
992
1.06k
    }
993
994
1.06k
    AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "wb")};
995
1.06k
    if (est_file.IsNull() || !Write(est_file)) {
996
0
        LogWarning("Failed to write fee estimates to %s. Continue anyway.", fs::PathToString(m_estimation_filepath));
997
0
        (void)est_file.fclose();
998
0
        return;
999
0
    }
1000
1.06k
    if (est_file.fclose() != 0) {
1001
0
        LogWarning("Failed to close fee estimates file %s: %s. Continuing anyway.", fs::PathToString(m_estimation_filepath), SysErrorString(errno));
1002
0
        return;
1003
0
    }
1004
1.06k
    LogDebug(BCLog::ESTIMATEFEE, "Flushed fee estimates to %s.", fs::PathToString(m_estimation_filepath));
1005
1.06k
}
1006
1007
bool CBlockPolicyEstimator::Write(AutoFile& fileout) const
1008
1.06k
{
1009
1.06k
    try {
1010
1.06k
        LOCK(m_cs_fee_estimator);
1011
1.06k
        fileout << CURRENT_FEES_FILE_VERSION;
1012
1.06k
        fileout << nBestSeenHeight;
1013
1.06k
        if (BlockSpan() > HistoricalBlockSpan()/2) {
1014
175
            fileout << firstRecordedHeight << nBestSeenHeight;
1015
175
        }
1016
893
        else {
1017
893
            fileout << historicalFirst << historicalBest;
1018
893
        }
1019
1.06k
        fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
1020
1.06k
        feeStats->Write(fileout);
1021
1.06k
        shortStats->Write(fileout);
1022
1.06k
        longStats->Write(fileout);
1023
1.06k
    }
1024
1.06k
    catch (const std::exception&) {
1025
0
        LogWarning("Unable to write policy estimator data (non-fatal)");
1026
0
        return false;
1027
0
    }
1028
1.06k
    return true;
1029
1.06k
}
1030
1031
bool CBlockPolicyEstimator::Read(AutoFile& filein)
1032
545
{
1033
545
    try {
1034
545
        LOCK(m_cs_fee_estimator);
1035
545
        int nVersionRequired;
1036
545
        filein >> nVersionRequired;
1037
545
        if (nVersionRequired > CURRENT_FEES_FILE_VERSION) {
1038
0
            throw std::runtime_error{strprintf("File version (%d) too high to be read.", nVersionRequired)};
1039
0
        }
1040
545
        if (nVersionRequired < CURRENT_FEES_FILE_VERSION) {
1041
1
            throw std::runtime_error{strprintf("File version (%d) incompatible: Too old to be read", nVersionRequired)};
1042
1
        }
1043
1044
        // Read fee estimates file into temporary variables so existing data
1045
        // structures aren't corrupted if there is an exception.
1046
544
        unsigned int nFileBestSeenHeight;
1047
544
        filein >> nFileBestSeenHeight;
1048
1049
        // nVersionRequired == CURRENT_FEES_FILE_VERSION
1050
544
        unsigned int nFileHistoricalFirst, nFileHistoricalBest;
1051
544
        filein >> nFileHistoricalFirst >> nFileHistoricalBest;
1052
544
        if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
1053
0
            throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
1054
0
        }
1055
544
        std::vector<double> fileBuckets;
1056
544
        filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
1057
544
        size_t numBuckets = fileBuckets.size();
1058
544
        if (numBuckets <= 1 || numBuckets > 1000) {
1059
0
            throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
1060
0
        }
1061
1062
544
        std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
1063
544
        std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
1064
544
        std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
1065
544
        fileFeeStats->Read(filein, numBuckets);
1066
544
        fileShortStats->Read(filein, numBuckets);
1067
544
        fileLongStats->Read(filein, numBuckets);
1068
1069
        // Fee estimates file parsed correctly
1070
        // Copy buckets from file and refresh our bucketmap
1071
544
        buckets = fileBuckets;
1072
544
        bucketMap.clear();
1073
129k
        for (unsigned int i = 0; i < buckets.size(); i++) {
1074
128k
            bucketMap[buckets[i]] = i;
1075
128k
        }
1076
1077
        // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
1078
544
        feeStats = std::move(fileFeeStats);
1079
544
        shortStats = std::move(fileShortStats);
1080
544
        longStats = std::move(fileLongStats);
1081
1082
544
        nBestSeenHeight = nFileBestSeenHeight;
1083
544
        historicalFirst = nFileHistoricalFirst;
1084
544
        historicalBest = nFileHistoricalBest;
1085
544
    }
1086
545
    catch (const std::exception& e) {
1087
1
        LogWarning("Unable to read policy estimator data (non-fatal): %s", e.what());
1088
1
        return false;
1089
1
    }
1090
544
    return true;
1091
545
}
1092
1093
void CBlockPolicyEstimator::FlushUnconfirmed()
1094
1.06k
{
1095
1.06k
    const auto startclear{SteadyClock::now()};
1096
1.06k
    LOCK(m_cs_fee_estimator);
1097
1.06k
    size_t num_entries = mapMemPoolTxs.size();
1098
    // Remove every entry in mapMemPoolTxs
1099
2.20k
    while (!mapMemPoolTxs.empty()) {
1100
1.14k
        auto mi = mapMemPoolTxs.begin();
1101
1.14k
        _removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
1102
1.14k
    }
1103
1.06k
    const auto endclear{SteadyClock::now()};
1104
1.06k
    LogDebug(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %.3fs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
1105
1.06k
}
1106
1107
std::chrono::hours CBlockPolicyEstimator::GetFeeEstimatorFileAge()
1108
546
{
1109
546
    auto file_time{fs::last_write_time(m_estimation_filepath)};
1110
546
    auto now{fs::file_time_type::clock::now()};
1111
546
    return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
1112
546
}
1113
1114
static std::set<double> MakeFeeSet(const CFeeRate& min_incremental_fee,
1115
                                   double max_filter_fee_rate,
1116
                                   double fee_filter_spacing)
1117
1.24k
{
1118
1.24k
    std::set<double> fee_set;
1119
1120
1.24k
    const CAmount min_fee_limit{std::max(CAmount(1), min_incremental_fee.GetFeePerK() / 2)};
1121
1.24k
    fee_set.insert(0);
1122
1.24k
    for (double bucket_boundary = min_fee_limit;
1123
161k
         bucket_boundary <= max_filter_fee_rate;
1124
160k
         bucket_boundary *= fee_filter_spacing) {
1125
1126
160k
        fee_set.insert(bucket_boundary);
1127
160k
    }
1128
1129
1.24k
    return fee_set;
1130
1.24k
}
1131
1132
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee, FastRandomContext& rng)
1133
1.24k
    : m_fee_set{MakeFeeSet(minIncrementalFee, MAX_FILTER_FEERATE, FEE_FILTER_SPACING)},
1134
1.24k
      insecure_rand{rng}
1135
1.24k
{
1136
1.24k
}
1137
1138
CAmount FeeFilterRounder::round(CAmount currentMinFee)
1139
3.42k
{
1140
3.42k
    AssertLockNotHeld(m_insecure_rand_mutex);
1141
3.42k
    std::set<double>::iterator it = m_fee_set.lower_bound(currentMinFee);
1142
3.42k
    if (it == m_fee_set.end() ||
1143
3.42k
        (it != m_fee_set.begin() &&
1144
2.61k
         WITH_LOCK(m_insecure_rand_mutex, return insecure_rand.rand32()) % 3 != 0)) {
1145
876
        --it;
1146
876
    }
1147
3.42k
    return static_cast<CAmount>(*it);
1148
3.42k
}