Bitcoin Core 30.99.0
P2P Digital Currency
block_policy_estimator.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2022 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
7
8#include <common/system.h>
9#include <consensus/amount.h>
11#include <logging.h>
12#include <policy/feerate.h>
14#include <random.h>
15#include <serialize.h>
16#include <streams.h>
17#include <sync.h>
18#include <tinyformat.h>
19#include <uint256.h>
20#include <util/fs.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 <utility>
34
35// The current format written, and the version required to read. Must be
36// increased to at least 289900+1 on the next breaking change.
37constexpr int CURRENT_FEES_FILE_VERSION{149900};
38
39static constexpr double INF_FEERATE = 1e99;
40
42{
43 switch (horizon) {
44 case FeeEstimateHorizon::SHORT_HALFLIFE: return "short";
45 case FeeEstimateHorizon::MED_HALFLIFE: return "medium";
46 case FeeEstimateHorizon::LONG_HALFLIFE: return "long";
47 } // no default case, so the compiler can warn about missing cases
48 assert(false);
49}
50
51namespace {
52
53struct EncodedDoubleFormatter
54{
55 template<typename Stream> void Ser(Stream &s, double v)
56 {
57 s << EncodeDouble(v);
58 }
59
60 template<typename Stream> void Unser(Stream& s, double& v)
61 {
62 uint64_t encoded;
63 s >> encoded;
64 v = DecodeDouble(encoded);
65 }
66};
67
68} // namespace
69
79{
80private:
81 //Define the buckets we will group transactions into
82 const std::vector<double>& buckets; // The upper-bound of the range for the bucket (inclusive)
83 const std::map<double, unsigned int>& bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
84
85 // For each bucket X:
86 // Count the total # of txs in each bucket
87 // Track the historical moving average of this total over blocks
88 std::vector<double> txCtAvg;
89
90 // Count the total # of txs confirmed within Y blocks in each bucket
91 // Track the historical moving average of these totals over blocks
92 std::vector<std::vector<double>> confAvg; // confAvg[Y][X]
93
94 // Track moving avg of txs which have been evicted from the mempool
95 // after failing to be confirmed within Y blocks
96 std::vector<std::vector<double>> failAvg; // failAvg[Y][X]
97
98 // Sum the total feerate of all tx's in each bucket
99 // Track the historical moving average of this total over blocks
100 std::vector<double> m_feerate_avg;
101
102 // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
103 // Combine the total value with the tx counts to calculate the avg feerate per bucket
104
105 double decay;
106
107 // Resolution (# of blocks) with which confirmations are tracked
108 unsigned int scale;
109
110 // Mempool counts of outstanding transactions
111 // For each bucket X, track the number of transactions in the mempool
112 // that are unconfirmed for each possible confirmation value Y
113 std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
114 // transactions still unconfirmed after GetMaxConfirms for each bucket
115 std::vector<int> oldUnconfTxs;
116
117 void resizeInMemoryCounters(size_t newbuckets);
118
119public:
127 TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,
128 unsigned int maxPeriods, double decay, unsigned int scale);
129
131 void ClearCurrent(unsigned int nBlockHeight);
132
139 void Record(int blocksToConfirm, double val);
140
142 unsigned int NewTx(unsigned int nBlockHeight, double val);
143
145 void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
146 unsigned int bucketIndex, bool inBlock);
147
151
161 double EstimateMedianVal(int confTarget, double sufficientTxVal,
162 double minSuccess, unsigned int nBlockHeight,
163 EstimationResult *result = nullptr) const;
164
166 unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
167
169 void Write(AutoFile& fileout) const;
170
175 void Read(AutoFile& filein, size_t numBuckets);
176};
177
178
179TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
180 const std::map<double, unsigned int>& defaultBucketMap,
181 unsigned int maxPeriods, double _decay, unsigned int _scale)
182 : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
183{
184 assert(_scale != 0 && "_scale must be non-zero");
185 confAvg.resize(maxPeriods);
186 failAvg.resize(maxPeriods);
187 for (unsigned int i = 0; i < maxPeriods; i++) {
188 confAvg[i].resize(buckets.size());
189 failAvg[i].resize(buckets.size());
190 }
191
192 txCtAvg.resize(buckets.size());
193 m_feerate_avg.resize(buckets.size());
194
196}
197
199 // newbuckets must be passed in because the buckets referred to during Read have not been updated yet.
200 unconfTxs.resize(GetMaxConfirms());
201 for (unsigned int i = 0; i < unconfTxs.size(); i++) {
202 unconfTxs[i].resize(newbuckets);
203 }
204 oldUnconfTxs.resize(newbuckets);
205}
206
207// Roll the unconfirmed txs circular buffer
208void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)
209{
210 for (unsigned int j = 0; j < buckets.size(); j++) {
211 oldUnconfTxs[j] += unconfTxs[nBlockHeight % unconfTxs.size()][j];
212 unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;
213 }
214}
215
216
217void TxConfirmStats::Record(int blocksToConfirm, double feerate)
218{
219 // blocksToConfirm is 1-based
220 if (blocksToConfirm < 1)
221 return;
222 int periodsToConfirm = (blocksToConfirm + scale - 1) / scale;
223 unsigned int bucketindex = bucketMap.lower_bound(feerate)->second;
224 for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {
225 confAvg[i - 1][bucketindex]++;
226 }
227 txCtAvg[bucketindex]++;
228 m_feerate_avg[bucketindex] += feerate;
229}
230
232{
233 assert(confAvg.size() == failAvg.size());
234 for (unsigned int j = 0; j < buckets.size(); j++) {
235 for (unsigned int i = 0; i < confAvg.size(); i++) {
236 confAvg[i][j] *= decay;
237 failAvg[i][j] *= decay;
238 }
239 m_feerate_avg[j] *= decay;
240 txCtAvg[j] *= decay;
241 }
242}
243
244// returns -1 on error conditions
245double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
246 double successBreakPoint, unsigned int nBlockHeight,
247 EstimationResult *result) const
248{
249 // Counters for a bucket (or range of buckets)
250 double nConf = 0; // Number of tx's confirmed within the confTarget
251 double totalNum = 0; // Total number of tx's that were ever confirmed
252 int extraNum = 0; // Number of tx's still in mempool for confTarget or longer
253 double failNum = 0; // Number of tx's that were never confirmed but removed from the mempool after confTarget
254 const int periodTarget = (confTarget + scale - 1) / scale;
255 const int maxbucketindex = buckets.size() - 1;
256
257 // We'll combine buckets until we have enough samples.
258 // The near and far variables will define the range we've combined
259 // The best variables are the last range we saw which still had a high
260 // enough confirmation rate to count as success.
261 // The cur variables are the current range we're counting.
262 unsigned int curNearBucket = maxbucketindex;
263 unsigned int bestNearBucket = maxbucketindex;
264 unsigned int curFarBucket = maxbucketindex;
265 unsigned int bestFarBucket = maxbucketindex;
266
267 // We'll always group buckets into sets that meet sufficientTxVal --
268 // this ensures that we're using consistent groups between different
269 // confirmation targets.
270 double partialNum = 0;
271
272 bool foundAnswer = false;
273 unsigned int bins = unconfTxs.size();
274 bool newBucketRange = true;
275 bool passing = true;
276 EstimatorBucket passBucket;
277 EstimatorBucket failBucket;
278
279 // Start counting from highest feerate transactions
280 for (int bucket = maxbucketindex; bucket >= 0; --bucket) {
281 if (newBucketRange) {
282 curNearBucket = bucket;
283 newBucketRange = false;
284 }
285 curFarBucket = bucket;
286 nConf += confAvg[periodTarget - 1][bucket];
287 partialNum += txCtAvg[bucket];
288 totalNum += txCtAvg[bucket];
289 failNum += failAvg[periodTarget - 1][bucket];
290 for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)
291 extraNum += unconfTxs[(nBlockHeight - confct) % bins][bucket];
292 extraNum += oldUnconfTxs[bucket];
293 // If we have enough transaction data points in this range of buckets,
294 // we can test for success
295 // (Only count the confirmed data points, so that each confirmation count
296 // will be looking at the same amount of data and same bucket breaks)
297
298 if (partialNum < sufficientTxVal / (1 - decay)) {
299 // the buckets we've added in this round aren't sufficient
300 // so keep adding
301 continue;
302 } else {
303 partialNum = 0; // reset for the next range we'll add
304
305 double curPct = nConf / (totalNum + failNum + extraNum);
306
307 // Check to see if we are no longer getting confirmed at the success rate
308 if (curPct < successBreakPoint) {
309 if (passing == true) {
310 // First time we hit a failure record the failed bucket
311 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
312 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
313 failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
314 failBucket.end = buckets[failMaxBucket];
315 failBucket.withinTarget = nConf;
316 failBucket.totalConfirmed = totalNum;
317 failBucket.inMempool = extraNum;
318 failBucket.leftMempool = failNum;
319 passing = false;
320 }
321 continue;
322 }
323 // Otherwise update the cumulative stats, and the bucket variables
324 // and reset the counters
325 else {
326 failBucket = EstimatorBucket(); // Reset any failed bucket, currently passing
327 foundAnswer = true;
328 passing = true;
329 passBucket.withinTarget = nConf;
330 nConf = 0;
331 passBucket.totalConfirmed = totalNum;
332 totalNum = 0;
333 passBucket.inMempool = extraNum;
334 passBucket.leftMempool = failNum;
335 failNum = 0;
336 extraNum = 0;
337 bestNearBucket = curNearBucket;
338 bestFarBucket = curFarBucket;
339 newBucketRange = true;
340 }
341 }
342 }
343
344 double median = -1;
345 double txSum = 0;
346
347 // Calculate the "average" feerate of the best bucket range that met success conditions
348 // Find the bucket with the median transaction and then report the average feerate from that bucket
349 // This is a compromise between finding the median which we can't since we don't save all tx's
350 // and reporting the average which is less accurate
351 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
352 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
353 for (unsigned int j = minBucket; j <= maxBucket; j++) {
354 txSum += txCtAvg[j];
355 }
356 if (foundAnswer && txSum != 0) {
357 txSum = txSum / 2;
358 for (unsigned int j = minBucket; j <= maxBucket; j++) {
359 if (txCtAvg[j] < txSum)
360 txSum -= txCtAvg[j];
361 else { // we're in the right bucket
362 median = m_feerate_avg[j] / txCtAvg[j];
363 break;
364 }
365 }
366
367 passBucket.start = minBucket ? buckets[minBucket-1] : 0;
368 passBucket.end = buckets[maxBucket];
369 }
370
371 // If we were passing until we reached last few buckets with insufficient data, then report those as failed
372 if (passing && !newBucketRange) {
373 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
374 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
375 failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
376 failBucket.end = buckets[failMaxBucket];
377 failBucket.withinTarget = nConf;
378 failBucket.totalConfirmed = totalNum;
379 failBucket.inMempool = extraNum;
380 failBucket.leftMempool = failNum;
381 }
382
383 float passed_within_target_perc = 0.0;
384 float failed_within_target_perc = 0.0;
385 if ((passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool)) {
386 passed_within_target_perc = 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool);
387 }
388 if ((failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool)) {
389 failed_within_target_perc = 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool);
390 }
391
392 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",
393 confTarget, 100.0 * successBreakPoint, decay,
394 median, passBucket.start, passBucket.end,
395 passed_within_target_perc,
396 passBucket.withinTarget, passBucket.totalConfirmed, passBucket.inMempool, passBucket.leftMempool,
397 failBucket.start, failBucket.end,
398 failed_within_target_perc,
399 failBucket.withinTarget, failBucket.totalConfirmed, failBucket.inMempool, failBucket.leftMempool);
400
401
402 if (result) {
403 result->pass = passBucket;
404 result->fail = failBucket;
405 result->decay = decay;
406 result->scale = scale;
407 }
408 return median;
409}
410
411void TxConfirmStats::Write(AutoFile& fileout) const
412{
413 fileout << Using<EncodedDoubleFormatter>(decay);
414 fileout << scale;
415 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
416 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
417 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
418 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
419}
420
421void TxConfirmStats::Read(AutoFile& filein, size_t numBuckets)
422{
423 // Read data file and do some very basic sanity checking
424 // buckets and bucketMap are not updated yet, so don't access them
425 // If there is a read failure, we'll just discard this entire object anyway
426 size_t maxConfirms, maxPeriods;
427
428 // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
429 filein >> Using<EncodedDoubleFormatter>(decay);
430 if (decay <= 0 || decay >= 1) {
431 throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
432 }
433 filein >> scale;
434 if (scale == 0) {
435 throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
436 }
437
438 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
439 if (m_feerate_avg.size() != numBuckets) {
440 throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
441 }
442 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
443 if (txCtAvg.size() != numBuckets) {
444 throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
445 }
446 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
447 maxPeriods = confAvg.size();
448 maxConfirms = scale * maxPeriods;
449
450 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) { // one week
451 throw std::runtime_error("Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
452 }
453 for (unsigned int i = 0; i < maxPeriods; i++) {
454 if (confAvg[i].size() != numBuckets) {
455 throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
456 }
457 }
458
459 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
460 if (maxPeriods != failAvg.size()) {
461 throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
462 }
463 for (unsigned int i = 0; i < maxPeriods; i++) {
464 if (failAvg[i].size() != numBuckets) {
465 throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
466 }
467 }
468
469 // Resize the current block variables which aren't stored in the data file
470 // to match the number of confirms and buckets
471 resizeInMemoryCounters(numBuckets);
472
473 LogDebug(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n",
474 numBuckets, maxConfirms);
475}
476
477unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
478{
479 unsigned int bucketindex = bucketMap.lower_bound(val)->second;
480 unsigned int blockIndex = nBlockHeight % unconfTxs.size();
481 unconfTxs[blockIndex][bucketindex]++;
482 return bucketindex;
483}
484
485void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock)
486{
487 //nBestSeenHeight is not updated yet for the new block
488 int blocksAgo = nBestSeenHeight - entryHeight;
489 if (nBestSeenHeight == 0) // the BlockPolicyEstimator hasn't seen any blocks yet
490 blocksAgo = 0;
491 if (blocksAgo < 0) {
492 LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, blocks ago is negative for mempool tx\n");
493 return; //This can't happen because we call this with our best seen height, no entries can have higher
494 }
495
496 if (blocksAgo >= (int)unconfTxs.size()) {
497 if (oldUnconfTxs[bucketindex] > 0) {
498 oldUnconfTxs[bucketindex]--;
499 } else {
500 LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n",
501 bucketindex);
502 }
503 }
504 else {
505 unsigned int blockIndex = entryHeight % unconfTxs.size();
506 if (unconfTxs[blockIndex][bucketindex] > 0) {
507 unconfTxs[blockIndex][bucketindex]--;
508 } else {
509 LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
510 blockIndex, bucketindex);
511 }
512 }
513 if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period
514 assert(scale != 0);
515 unsigned int periodsAgo = blocksAgo / scale;
516 for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {
517 failAvg[i][bucketindex]++;
518 }
519 }
520}
521
523{
525 return _removeTx(hash, /*inBlock=*/false);
526}
527
528bool CBlockPolicyEstimator::_removeTx(const Txid& hash, bool inBlock)
529{
531 std::map<Txid, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
532 if (pos != mapMemPoolTxs.end()) {
533 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
534 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
535 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
536 mapMemPoolTxs.erase(hash);
537 return true;
538 } else {
539 return false;
540 }
541}
542
543CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath, const bool read_stale_estimates)
544 : m_estimation_filepath{estimation_filepath}
545{
546 static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
547 size_t bucketIndex = 0;
548
549 for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
550 buckets.push_back(bucketBoundary);
551 bucketMap[bucketBoundary] = bucketIndex;
552 }
553 buckets.push_back(INF_FEERATE);
554 bucketMap[INF_FEERATE] = bucketIndex;
555 assert(bucketMap.size() == buckets.size());
556
557 feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
558 shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
559 longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
560
562
563 if (est_file.IsNull()) {
564 LogInfo("%s is not found. Continue anyway.", fs::PathToString(m_estimation_filepath));
565 return;
566 }
567
568 std::chrono::hours file_age = GetFeeEstimatorFileAge();
569 if (file_age > MAX_FILE_AGE && !read_stale_estimates) {
570 LogPrintf("Fee estimation file %s too old (age=%lld > %lld hours) and will not be used to avoid serving stale estimates.\n", fs::PathToString(m_estimation_filepath), Ticks<std::chrono::hours>(file_age), Ticks<std::chrono::hours>(MAX_FILE_AGE));
571 return;
572 }
573
574 if (!Read(est_file)) {
575 LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
576 }
577}
578
580
582{
584}
585
587{
588 removeTx(tx->GetHash());
589}
590
591void CBlockPolicyEstimator::MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int nBlockHeight)
592{
593 processBlock(txs_removed_for_block, nBlockHeight);
594}
595
597{
599 const unsigned int txHeight = tx.info.txHeight;
600 const auto& hash = tx.info.m_tx->GetHash();
601 if (mapMemPoolTxs.count(hash)) {
602 LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
603 hash.ToString());
604 return;
605 }
606
607 if (txHeight != nBestSeenHeight) {
608 // Ignore side chains and re-orgs; assuming they are random they don't
609 // affect the estimate. We'll potentially double count transactions in 1-block reorgs.
610 // Ignore txs if BlockPolicyEstimator is not in sync with ActiveChain().Tip().
611 // It will be synced next time a block is processed.
612 return;
613 }
614 // This transaction should only count for fee estimation if:
615 // - it's not being re-added during a reorg which bypasses typical mempool fee limits
616 // - the node is not behind
617 // - the transaction is not dependent on any other transactions in the mempool
618 // - it's not part of a package.
619 const bool validForFeeEstimation = !tx.m_mempool_limit_bypassed && !tx.m_submitted_in_package && tx.m_chainstate_is_current && tx.m_has_no_mempool_parents;
620
621 // Only want to be updating estimates when our blockchain is synced,
622 // otherwise we'll miscalculate how many blocks its taking to get included.
623 if (!validForFeeEstimation) {
624 untrackedTxs++;
625 return;
626 }
627 trackedTxs++;
628
629 // Feerates are stored and reported as BTC-per-kb:
630 const CFeeRate feeRate(tx.info.m_fee, tx.info.m_virtual_transaction_size);
631
632 mapMemPoolTxs[hash].blockHeight = txHeight;
633 unsigned int bucketIndex = feeStats->NewTx(txHeight, static_cast<double>(feeRate.GetFeePerK()));
634 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
635 unsigned int bucketIndex2 = shortStats->NewTx(txHeight, static_cast<double>(feeRate.GetFeePerK()));
636 assert(bucketIndex == bucketIndex2);
637 unsigned int bucketIndex3 = longStats->NewTx(txHeight, static_cast<double>(feeRate.GetFeePerK()));
638 assert(bucketIndex == bucketIndex3);
639}
640
642{
644 if (!_removeTx(tx.info.m_tx->GetHash(), true)) {
645 // This transaction wasn't being tracked for fee estimation
646 return false;
647 }
648
649 // How many blocks did it take for miners to include this transaction?
650 // blocksToConfirm is 1-based, so a transaction included in the earliest
651 // possible block has confirmation count of 1
652 int blocksToConfirm = nBlockHeight - tx.info.txHeight;
653 if (blocksToConfirm <= 0) {
654 // This can't happen because we don't process transactions from a block with a height
655 // lower than our greatest seen height
656 LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
657 return false;
658 }
659
660 // Feerates are stored and reported as BTC-per-kb:
662
663 feeStats->Record(blocksToConfirm, static_cast<double>(feeRate.GetFeePerK()));
664 shortStats->Record(blocksToConfirm, static_cast<double>(feeRate.GetFeePerK()));
665 longStats->Record(blocksToConfirm, static_cast<double>(feeRate.GetFeePerK()));
666 return true;
667}
668
669void CBlockPolicyEstimator::processBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block,
670 unsigned int nBlockHeight)
671{
673 if (nBlockHeight <= nBestSeenHeight) {
674 // Ignore side chains and re-orgs; assuming they are random
675 // they don't affect the estimate.
676 // And if an attacker can re-org the chain at will, then
677 // you've got much bigger problems than "attacker can influence
678 // transaction fees."
679 return;
680 }
681
682 // Must update nBestSeenHeight in sync with ClearCurrent so that
683 // calls to removeTx (via processBlockTx) correctly calculate age
684 // of unconfirmed txs to remove from tracking.
685 nBestSeenHeight = nBlockHeight;
686
687 // Update unconfirmed circular buffer
688 feeStats->ClearCurrent(nBlockHeight);
689 shortStats->ClearCurrent(nBlockHeight);
690 longStats->ClearCurrent(nBlockHeight);
691
692 // Decay all exponential averages
693 feeStats->UpdateMovingAverages();
694 shortStats->UpdateMovingAverages();
695 longStats->UpdateMovingAverages();
696
697 unsigned int countedTxs = 0;
698 // Update averages with data points from current block
699 for (const auto& tx : txs_removed_for_block) {
700 if (processBlockTx(nBlockHeight, tx))
701 countedTxs++;
702 }
703
704 if (firstRecordedHeight == 0 && countedTxs > 0) {
705 firstRecordedHeight = nBestSeenHeight;
706 LogDebug(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight);
707 }
708
709
710 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",
711 countedTxs, txs_removed_for_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
712 MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");
713
714 trackedTxs = 0;
715 untrackedTxs = 0;
716}
717
719{
720 // It's not possible to get reasonable estimates for confTarget of 1
721 if (confTarget <= 1)
722 return CFeeRate(0);
723
725}
726
727CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
728{
729 TxConfirmStats* stats = nullptr;
730 double sufficientTxs = SUFFICIENT_FEETXS;
731 switch (horizon) {
733 stats = shortStats.get();
734 sufficientTxs = SUFFICIENT_TXS_SHORT;
735 break;
736 }
738 stats = feeStats.get();
739 break;
740 }
742 stats = longStats.get();
743 break;
744 }
745 } // no default case, so the compiler can warn about missing cases
746 assert(stats);
747
749 // Return failure if trying to analyze a target we're not tracking
750 if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
751 return CFeeRate(0);
752 if (successThreshold > 1)
753 return CFeeRate(0);
754
755 double median = stats->EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
756
757 if (median < 0)
758 return CFeeRate(0);
759
760 return CFeeRate(llround(median));
761}
762
764{
766 switch (horizon) {
768 return shortStats->GetMaxConfirms();
769 }
771 return feeStats->GetMaxConfirms();
772 }
774 return longStats->GetMaxConfirms();
775 }
776 } // no default case, so the compiler can warn about missing cases
777 assert(false);
778}
779
781{
782 if (firstRecordedHeight == 0) return 0;
783 assert(nBestSeenHeight >= firstRecordedHeight);
784
785 return nBestSeenHeight - firstRecordedHeight;
786}
787
789{
790 if (historicalFirst == 0) return 0;
791 assert(historicalBest >= historicalFirst);
792
793 if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;
794
795 return historicalBest - historicalFirst;
796}
797
799{
800 // Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate
801 return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);
802}
803
808double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const
809{
810 double estimate = -1;
811 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
812 // Find estimate from shortest time horizon possible
813 if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon
814 estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
815 }
816 else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon
817 estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
818 }
819 else { // long horizon
820 estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
821 }
822 if (checkShorterHorizon) {
823 EstimationResult tempResult;
824 // If a lower confTarget from a more recent horizon returns a lower answer use it.
825 if (confTarget > feeStats->GetMaxConfirms()) {
826 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
827 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
828 estimate = medMax;
829 if (result) *result = tempResult;
830 }
831 }
832 if (confTarget > shortStats->GetMaxConfirms()) {
833 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
834 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
835 estimate = shortMax;
836 if (result) *result = tempResult;
837 }
838 }
839 }
840 }
841 return estimate;
842}
843
847double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const
848{
849 double estimate = -1;
850 EstimationResult tempResult;
851 if (doubleTarget <= shortStats->GetMaxConfirms()) {
852 estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, result);
853 }
854 if (doubleTarget <= feeStats->GetMaxConfirms()) {
855 double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, &tempResult);
856 if (longEstimate > estimate) {
857 estimate = longEstimate;
858 if (result) *result = tempResult;
859 }
860 }
861 return estimate;
862}
863
871CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
872{
874
875 if (feeCalc) {
876 feeCalc->desiredTarget = confTarget;
877 feeCalc->returnedTarget = confTarget;
878 feeCalc->best_height = nBestSeenHeight;
879 }
880
881 double median = -1;
882 EstimationResult tempResult;
883
884 // Return failure if trying to analyze a target we're not tracking
885 if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
886 return CFeeRate(0); // error condition
887 }
888
889 // It's not possible to get reasonable estimates for confTarget of 1
890 if (confTarget == 1) confTarget = 2;
891
892 unsigned int maxUsableEstimate = MaxUsableEstimate();
893 if ((unsigned int)confTarget > maxUsableEstimate) {
894 confTarget = maxUsableEstimate;
895 }
896 if (feeCalc) feeCalc->returnedTarget = confTarget;
897
898 if (confTarget <= 1) return CFeeRate(0); // error condition
899
900 assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
919 double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
920 if (feeCalc) {
921 feeCalc->est = tempResult;
923 }
924 median = halfEst;
925 double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
926 if (actualEst > median) {
927 median = actualEst;
928 if (feeCalc) {
929 feeCalc->est = tempResult;
931 }
932 }
933 double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
934 if (doubleEst > median) {
935 median = doubleEst;
936 if (feeCalc) {
937 feeCalc->est = tempResult;
939 }
940 }
941
942 if (conservative || median == -1) {
943 double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
944 if (consEst > median) {
945 median = consEst;
946 if (feeCalc) {
947 feeCalc->est = tempResult;
949 }
950 }
951 }
952
953 if (median < 0) return CFeeRate(0); // error condition
954
955 return CFeeRate(llround(median));
956}
957
961}
962
964{
966 if (est_file.IsNull() || !Write(est_file)) {
967 LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
968 (void)est_file.fclose();
969 return;
970 }
971 if (est_file.fclose() != 0) {
972 LogError("Failed to close fee estimates file %s: %s. Continuing anyway.", fs::PathToString(m_estimation_filepath), SysErrorString(errno));
973 return;
974 }
975 LogInfo("Flushed fee estimates to %s.", fs::PathToString(m_estimation_filepath.filename()));
976}
977
979{
980 try {
982 fileout << CURRENT_FEES_FILE_VERSION;
983 fileout << int{0}; // Unused dummy field. Written files may contain any value in [0, 289900]
984 fileout << nBestSeenHeight;
985 if (BlockSpan() > HistoricalBlockSpan()/2) {
986 fileout << firstRecordedHeight << nBestSeenHeight;
987 }
988 else {
989 fileout << historicalFirst << historicalBest;
990 }
991 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
992 feeStats->Write(fileout);
993 shortStats->Write(fileout);
994 longStats->Write(fileout);
995 }
996 catch (const std::exception&) {
997 LogWarning("Unable to write policy estimator data (non-fatal)");
998 return false;
999 }
1000 return true;
1001}
1002
1004{
1005 try {
1007 int nVersionRequired, dummy;
1008 filein >> nVersionRequired >> dummy;
1009 if (nVersionRequired > CURRENT_FEES_FILE_VERSION) {
1010 throw std::runtime_error{strprintf("File version (%d) too high to be read.", nVersionRequired)};
1011 }
1012
1013 // Read fee estimates file into temporary variables so existing data
1014 // structures aren't corrupted if there is an exception.
1015 unsigned int nFileBestSeenHeight;
1016 filein >> nFileBestSeenHeight;
1017
1018 if (nVersionRequired < CURRENT_FEES_FILE_VERSION) {
1019 LogWarning("Incompatible old fee estimation data (non-fatal). Version: %d", nVersionRequired);
1020 } else { // nVersionRequired == CURRENT_FEES_FILE_VERSION
1021 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
1022 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
1023 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
1024 throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
1025 }
1026 std::vector<double> fileBuckets;
1027 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
1028 size_t numBuckets = fileBuckets.size();
1029 if (numBuckets <= 1 || numBuckets > 1000) {
1030 throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
1031 }
1032
1033 std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
1034 std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
1035 std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
1036 fileFeeStats->Read(filein, numBuckets);
1037 fileShortStats->Read(filein, numBuckets);
1038 fileLongStats->Read(filein, numBuckets);
1039
1040 // Fee estimates file parsed correctly
1041 // Copy buckets from file and refresh our bucketmap
1042 buckets = fileBuckets;
1043 bucketMap.clear();
1044 for (unsigned int i = 0; i < buckets.size(); i++) {
1045 bucketMap[buckets[i]] = i;
1046 }
1047
1048 // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
1049 feeStats = std::move(fileFeeStats);
1050 shortStats = std::move(fileShortStats);
1051 longStats = std::move(fileLongStats);
1052
1053 nBestSeenHeight = nFileBestSeenHeight;
1054 historicalFirst = nFileHistoricalFirst;
1055 historicalBest = nFileHistoricalBest;
1056 }
1057 }
1058 catch (const std::exception& e) {
1059 LogWarning("Unable to read policy estimator data (non-fatal): %s", e.what());
1060 return false;
1061 }
1062 return true;
1063}
1064
1066{
1067 const auto startclear{SteadyClock::now()};
1069 size_t num_entries = mapMemPoolTxs.size();
1070 // Remove every entry in mapMemPoolTxs
1071 while (!mapMemPoolTxs.empty()) {
1072 auto mi = mapMemPoolTxs.begin();
1073 _removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
1074 }
1075 const auto endclear{SteadyClock::now()};
1076 LogDebug(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %.3fs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
1077}
1078
1080{
1081 auto file_time{fs::last_write_time(m_estimation_filepath)};
1082 auto now{fs::file_time_type::clock::now()};
1083 return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
1084}
1085
1086static std::set<double> MakeFeeSet(const CFeeRate& min_incremental_fee,
1087 double max_filter_fee_rate,
1088 double fee_filter_spacing)
1089{
1090 std::set<double> fee_set;
1091
1092 const CAmount min_fee_limit{std::max(CAmount(1), min_incremental_fee.GetFeePerK() / 2)};
1093 fee_set.insert(0);
1094 for (double bucket_boundary = min_fee_limit;
1095 bucket_boundary <= max_filter_fee_rate;
1096 bucket_boundary *= fee_filter_spacing) {
1097
1098 fee_set.insert(bucket_boundary);
1099 }
1100
1101 return fee_set;
1102}
1103
1105 : m_fee_set{MakeFeeSet(minIncrementalFee, MAX_FILTER_FEERATE, FEE_FILTER_SPACING)},
1106 insecure_rand{rng}
1107{
1108}
1109
1111{
1113 std::set<double>::iterator it = m_fee_set.lower_bound(currentMinFee);
1114 if (it == m_fee_set.end() ||
1115 (it != m_fee_set.begin() &&
1116 WITH_LOCK(m_insecure_rand_mutex, return insecure_rand.rand32()) % 3 != 0)) {
1117 --it;
1118 }
1119 return static_cast<CAmount>(*it);
1120}
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
static constexpr double INF_FEERATE
static std::set< double > MakeFeeSet(const CFeeRate &min_incremental_fee, double max_filter_fee_rate, double fee_filter_spacing)
constexpr int CURRENT_FEES_FILE_VERSION
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
static constexpr std::chrono::hours MAX_FILE_AGE
fee_estimates.dat that are more than 60 hours (2.5 days) old will not be read, as fee estimates are b...
FeeEstimateHorizon
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:371
void processTransaction(const NewMempoolTransactionInfo &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process a transaction accepted to the mempool.
static constexpr unsigned int LONG_SCALE
static constexpr double SUCCESS_PCT
Require greater than 85% of X feerate transactions to be confirmed within Y blocks.
static constexpr double MIN_BUCKET_FEERATE
Minimum and Maximum values for tracking feerates The MIN_BUCKET_FEERATE should just be set to the low...
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
static constexpr double FEE_SPACING
Spacing of FeeRate buckets We have to lump transactions into buckets based on feerate,...
static const unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren't valid.
void Flush() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Drop still unconfirmed transactions and record current estimations, if the fee estimation file is pre...
static constexpr double SUFFICIENT_FEETXS
Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance.
bool removeTx(Txid hash) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Remove a transaction from the mempool tracking stats for non BLOCK removal reasons.
static constexpr double MAX_BUCKET_FEERATE
void FlushFeeEstimates() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Record current fee estimations.
virtual CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Estimate feerate needed to get be included in a block within confTarget blocks.
static constexpr unsigned int LONG_BLOCK_PERIODS
Track confirm delays up to 1008 blocks for long horizon.
bool Write(AutoFile &fileout) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Write estimation data to a file.
static constexpr double SHORT_DECAY
Decay of .962 is a half-life of 18 blocks or about 3 hours.
std::chrono::hours GetFeeEstimatorFileAge()
Calculates the age of the file, since last modified.
virtual unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Calculation of highest target that estimates are tracked for.
static constexpr double LONG_DECAY
Decay of .99931 is a half-life of 1008 blocks or about 1 week.
double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
void TransactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason, uint64_t) override EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Notifies listeners of a transaction leaving mempool.
static constexpr double HALF_SUCCESS_PCT
Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks.
static constexpr double MED_DECAY
Decay of .9952 is a half-life of 144 blocks or about 1 day.
CFeeRate estimateFee(int confTarget) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
DEPRECATED.
CBlockPolicyEstimator(const fs::path &estimation_filepath, const bool read_stale_estimates)
Create new BlockPolicyEstimator and initialize stats tracking classes with default values.
bool _removeTx(const Txid &hash, bool inBlock) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
A non-thread-safe helper for the removeTx function.
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Calculation of highest target that reasonable estimate can be provided for.
static constexpr unsigned int SHORT_SCALE
unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of data recorded while fee estimates have been running.
void MempoolTransactionsRemovedForBlock(const std::vector< RemovedMempoolTransactionInfo > &txs_removed_for_block, unsigned int nBlockHeight) override EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
bool Read(AutoFile &filein) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Read estimation data from a file.
static constexpr unsigned int SHORT_BLOCK_PERIODS
Track confirm delays up to 12 blocks for short horizon.
static constexpr double DOUBLE_SUCCESS_PCT
Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks.
unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of recorded fee estimate data represented in saved data file.
void FlushUnconfirmed() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool.
CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result=nullptr) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Return a specific fee estimate calculation with a given success threshold and time horizon,...
static constexpr double SUFFICIENT_TXS_SHORT
Require an avg of 0.5 tx when using short decay since there are fewer blocks considered.
bool processBlockTx(unsigned int nBlockHeight, const RemovedMempoolTransactionInfo &tx) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Process a transaction confirmed in a block.
static constexpr unsigned int MED_SCALE
static constexpr unsigned int MED_BLOCK_PERIODS
Track confirm delays up to 48 blocks for medium horizon.
const fs::path m_estimation_filepath
virtual ~CBlockPolicyEstimator()
void TransactionAddedToMempool(const NewMempoolTransactionInfo &tx, uint64_t) override EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Overridden from CValidationInterface.
void processBlock(const std::vector< RemovedMempoolTransactionInfo > &txs_removed_for_block, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process all the transactions that have been included in a block.
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
Definition: feerate.h:35
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
Definition: feerate.h:63
Fast randomness source.
Definition: random.h:386
const std::set< double > m_fee_set
CAmount round(CAmount currentMinFee) EXCLUSIVE_LOCKS_REQUIRED(!m_insecure_rand_mutex)
Quantize a minimum fee for privacy purpose before broadcast.
FeeFilterRounder(const CFeeRate &min_incremental_fee, FastRandomContext &rng)
Create new FeeFilterRounder.
We will instantiate an instance of this class to track transactions that were included in a block.
void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketIndex, bool inBlock)
Remove a transaction from mempool tracking stats.
std::vector< std::vector< double > > failAvg
TxConfirmStats(const std::vector< double > &defaultBuckets, const std::map< double, unsigned int > &defaultBucketMap, unsigned int maxPeriods, double decay, unsigned int scale)
Create new TxConfirmStats.
unsigned int GetMaxConfirms() const
Return the max number of confirms we're tracking.
void ClearCurrent(unsigned int nBlockHeight)
Roll the circular buffer for unconfirmed txs.
void Record(int blocksToConfirm, double val)
Record a new transaction data point in the current block stats.
void resizeInMemoryCounters(size_t newbuckets)
std::vector< double > txCtAvg
std::vector< int > oldUnconfTxs
void UpdateMovingAverages()
Update our estimates by decaying our historical moving average and updating with the data gathered fr...
const std::map< double, unsigned int > & bucketMap
const std::vector< double > & buckets
void Read(AutoFile &filein, size_t numBuckets)
Read saved state of estimation data from a file and replace all internal data structures and variable...
std::vector< std::vector< double > > confAvg
void Write(AutoFile &fileout) const
Write state of estimation data to a file.
std::vector< std::vector< int > > unconfTxs
unsigned int NewTx(unsigned int nBlockHeight, double val)
Record a new transaction entering the mempool.
std::vector< double > m_feerate_avg
double EstimateMedianVal(int confTarget, double sufficientTxVal, double minSuccess, unsigned int nBlockHeight, EstimationResult *result=nullptr) const
Calculate a feerate estimate.
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:157
#define LogWarning(...)
Definition: logging.h:357
#define LogInfo(...)
Definition: logging.h:356
#define LogError(...)
Definition: logging.h:358
#define LogDebug(category,...)
Definition: logging.h:381
#define LogPrintf(...)
Definition: logging.h:361
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal.
@ ESTIMATEFEE
Definition: logging.h:74
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
uint64_t EncodeDouble(double f) noexcept
Definition: serfloat.cpp:37
double DecodeDouble(uint64_t v) noexcept
Definition: serfloat.cpp:10
unsigned int best_height
EstimationResult est
const bool m_has_no_mempool_parents
const bool m_chainstate_is_current
const bool m_mempool_limit_bypassed
const CAmount m_fee
const unsigned int txHeight
const CTransactionRef m_tx
const int64_t m_virtual_transaction_size
The virtual transaction size.
#define AssertLockNotHeld(cs)
Definition: sync.h:142
#define LOCK(cs)
Definition: sync.h:259
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:290
std::string SysErrorString(int err)
Return system error string from errno value.
Definition: syserror.cpp:19
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
AssertLockHeld(pool.cs)
assert(!tx.IsCoinBase())