Bitcoin Core  0.19.99
P2P Digital Currency
fees.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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.h>
7 
8 #include <clientversion.h>
9 #include <streams.h>
10 #include <txmempool.h>
11 #include <util/system.h>
12 
13 static constexpr double INF_FEERATE = 1e99;
14 
16  static const std::map<FeeEstimateHorizon, std::string> horizon_strings = {
20  };
21  auto horizon_string = horizon_strings.find(horizon);
22 
23  if (horizon_string == horizon_strings.end()) return "unknown";
24 
25  return horizon_string->second;
26 }
27 
37 {
38 private:
39  //Define the buckets we will group transactions into
40  const std::vector<double>& buckets; // The upper-bound of the range for the bucket (inclusive)
41  const std::map<double, unsigned int>& bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
42 
43  // For each bucket X:
44  // Count the total # of txs in each bucket
45  // Track the historical moving average of this total over blocks
46  std::vector<double> txCtAvg;
47 
48  // Count the total # of txs confirmed within Y blocks in each bucket
49  // Track the historical moving average of these totals over blocks
50  std::vector<std::vector<double>> confAvg; // confAvg[Y][X]
51 
52  // Track moving avg of txs which have been evicted from the mempool
53  // after failing to be confirmed within Y blocks
54  std::vector<std::vector<double>> failAvg; // failAvg[Y][X]
55 
56  // Sum the total feerate of all tx's in each bucket
57  // Track the historical moving average of this total over blocks
58  std::vector<double> avg;
59 
60  // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
61  // Combine the total value with the tx counts to calculate the avg feerate per bucket
62 
63  double decay;
64 
65  // Resolution (# of blocks) with which confirmations are tracked
66  unsigned int scale;
67 
68  // Mempool counts of outstanding transactions
69  // For each bucket X, track the number of transactions in the mempool
70  // that are unconfirmed for each possible confirmation value Y
71  std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
72  // transactions still unconfirmed after GetMaxConfirms for each bucket
73  std::vector<int> oldUnconfTxs;
74 
75  void resizeInMemoryCounters(size_t newbuckets);
76 
77 public:
85  TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,
86  unsigned int maxPeriods, double decay, unsigned int scale);
87 
89  void ClearCurrent(unsigned int nBlockHeight);
90 
97  void Record(int blocksToConfirm, double val);
98 
100  unsigned int NewTx(unsigned int nBlockHeight, double val);
101 
103  void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
104  unsigned int bucketIndex, bool inBlock);
105 
108  void UpdateMovingAverages();
109 
121  double EstimateMedianVal(int confTarget, double sufficientTxVal,
122  double minSuccess, bool requireGreater, unsigned int nBlockHeight,
123  EstimationResult *result = nullptr) const;
124 
126  unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
127 
129  void Write(CAutoFile& fileout) const;
130 
135  void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets);
136 };
137 
138 
139 TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
140  const std::map<double, unsigned int>& defaultBucketMap,
141  unsigned int maxPeriods, double _decay, unsigned int _scale)
142  : buckets(defaultBuckets), bucketMap(defaultBucketMap)
143 {
144  decay = _decay;
145  assert(_scale != 0 && "_scale must be non-zero");
146  scale = _scale;
147  confAvg.resize(maxPeriods);
148  for (unsigned int i = 0; i < maxPeriods; i++) {
149  confAvg[i].resize(buckets.size());
150  }
151  failAvg.resize(maxPeriods);
152  for (unsigned int i = 0; i < maxPeriods; i++) {
153  failAvg[i].resize(buckets.size());
154  }
155 
156  txCtAvg.resize(buckets.size());
157  avg.resize(buckets.size());
158 
160 }
161 
162 void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {
163  // newbuckets must be passed in because the buckets referred to during Read have not been updated yet.
164  unconfTxs.resize(GetMaxConfirms());
165  for (unsigned int i = 0; i < unconfTxs.size(); i++) {
166  unconfTxs[i].resize(newbuckets);
167  }
168  oldUnconfTxs.resize(newbuckets);
169 }
170 
171 // Roll the unconfirmed txs circular buffer
172 void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)
173 {
174  for (unsigned int j = 0; j < buckets.size(); j++) {
175  oldUnconfTxs[j] += unconfTxs[nBlockHeight%unconfTxs.size()][j];
176  unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;
177  }
178 }
179 
180 
181 void TxConfirmStats::Record(int blocksToConfirm, double val)
182 {
183  // blocksToConfirm is 1-based
184  if (blocksToConfirm < 1)
185  return;
186  int periodsToConfirm = (blocksToConfirm + scale - 1)/scale;
187  unsigned int bucketindex = bucketMap.lower_bound(val)->second;
188  for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {
189  confAvg[i - 1][bucketindex]++;
190  }
191  txCtAvg[bucketindex]++;
192  avg[bucketindex] += val;
193 }
194 
196 {
197  for (unsigned int j = 0; j < buckets.size(); j++) {
198  for (unsigned int i = 0; i < confAvg.size(); i++)
199  confAvg[i][j] = confAvg[i][j] * decay;
200  for (unsigned int i = 0; i < failAvg.size(); i++)
201  failAvg[i][j] = failAvg[i][j] * decay;
202  avg[j] = avg[j] * decay;
203  txCtAvg[j] = txCtAvg[j] * decay;
204  }
205 }
206 
207 // returns -1 on error conditions
208 double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
209  double successBreakPoint, bool requireGreater,
210  unsigned int nBlockHeight, EstimationResult *result) const
211 {
212  // Counters for a bucket (or range of buckets)
213  double nConf = 0; // Number of tx's confirmed within the confTarget
214  double totalNum = 0; // Total number of tx's that were ever confirmed
215  int extraNum = 0; // Number of tx's still in mempool for confTarget or longer
216  double failNum = 0; // Number of tx's that were never confirmed but removed from the mempool after confTarget
217  int periodTarget = (confTarget + scale - 1)/scale;
218 
219  int maxbucketindex = buckets.size() - 1;
220 
221  // requireGreater means we are looking for the lowest feerate such that all higher
222  // values pass, so we start at maxbucketindex (highest feerate) and look at successively
223  // smaller buckets until we reach failure. Otherwise, we are looking for the highest
224  // feerate such that all lower values fail, and we go in the opposite direction.
225  unsigned int startbucket = requireGreater ? maxbucketindex : 0;
226  int step = requireGreater ? -1 : 1;
227 
228  // We'll combine buckets until we have enough samples.
229  // The near and far variables will define the range we've combined
230  // The best variables are the last range we saw which still had a high
231  // enough confirmation rate to count as success.
232  // The cur variables are the current range we're counting.
233  unsigned int curNearBucket = startbucket;
234  unsigned int bestNearBucket = startbucket;
235  unsigned int curFarBucket = startbucket;
236  unsigned int bestFarBucket = startbucket;
237 
238  bool foundAnswer = false;
239  unsigned int bins = unconfTxs.size();
240  bool newBucketRange = true;
241  bool passing = true;
242  EstimatorBucket passBucket;
243  EstimatorBucket failBucket;
244 
245  // Start counting from highest(default) or lowest feerate transactions
246  for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
247  if (newBucketRange) {
248  curNearBucket = bucket;
249  newBucketRange = false;
250  }
251  curFarBucket = bucket;
252  nConf += confAvg[periodTarget - 1][bucket];
253  totalNum += txCtAvg[bucket];
254  failNum += failAvg[periodTarget - 1][bucket];
255  for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)
256  extraNum += unconfTxs[(nBlockHeight - confct)%bins][bucket];
257  extraNum += oldUnconfTxs[bucket];
258  // If we have enough transaction data points in this range of buckets,
259  // we can test for success
260  // (Only count the confirmed data points, so that each confirmation count
261  // will be looking at the same amount of data and same bucket breaks)
262  if (totalNum >= sufficientTxVal / (1 - decay)) {
263  double curPct = nConf / (totalNum + failNum + extraNum);
264 
265  // Check to see if we are no longer getting confirmed at the success rate
266  if ((requireGreater && curPct < successBreakPoint) || (!requireGreater && curPct > successBreakPoint)) {
267  if (passing == true) {
268  // First time we hit a failure record the failed bucket
269  unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
270  unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
271  failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
272  failBucket.end = buckets[failMaxBucket];
273  failBucket.withinTarget = nConf;
274  failBucket.totalConfirmed = totalNum;
275  failBucket.inMempool = extraNum;
276  failBucket.leftMempool = failNum;
277  passing = false;
278  }
279  continue;
280  }
281  // Otherwise update the cumulative stats, and the bucket variables
282  // and reset the counters
283  else {
284  failBucket = EstimatorBucket(); // Reset any failed bucket, currently passing
285  foundAnswer = true;
286  passing = true;
287  passBucket.withinTarget = nConf;
288  nConf = 0;
289  passBucket.totalConfirmed = totalNum;
290  totalNum = 0;
291  passBucket.inMempool = extraNum;
292  passBucket.leftMempool = failNum;
293  failNum = 0;
294  extraNum = 0;
295  bestNearBucket = curNearBucket;
296  bestFarBucket = curFarBucket;
297  newBucketRange = true;
298  }
299  }
300  }
301 
302  double median = -1;
303  double txSum = 0;
304 
305  // Calculate the "average" feerate of the best bucket range that met success conditions
306  // Find the bucket with the median transaction and then report the average feerate from that bucket
307  // This is a compromise between finding the median which we can't since we don't save all tx's
308  // and reporting the average which is less accurate
309  unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
310  unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
311  for (unsigned int j = minBucket; j <= maxBucket; j++) {
312  txSum += txCtAvg[j];
313  }
314  if (foundAnswer && txSum != 0) {
315  txSum = txSum / 2;
316  for (unsigned int j = minBucket; j <= maxBucket; j++) {
317  if (txCtAvg[j] < txSum)
318  txSum -= txCtAvg[j];
319  else { // we're in the right bucket
320  median = avg[j] / txCtAvg[j];
321  break;
322  }
323  }
324 
325  passBucket.start = minBucket ? buckets[minBucket-1] : 0;
326  passBucket.end = buckets[maxBucket];
327  }
328 
329  // If we were passing until we reached last few buckets with insufficient data, then report those as failed
330  if (passing && !newBucketRange) {
331  unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
332  unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
333  failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
334  failBucket.end = buckets[failMaxBucket];
335  failBucket.withinTarget = nConf;
336  failBucket.totalConfirmed = totalNum;
337  failBucket.inMempool = extraNum;
338  failBucket.leftMempool = failNum;
339  }
340 
341  LogPrint(BCLog::ESTIMATEFEE, "FeeEst: %d %s%.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",
342  confTarget, requireGreater ? ">" : "<", 100.0 * successBreakPoint, decay,
343  median, passBucket.start, passBucket.end,
344  100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool),
345  passBucket.withinTarget, passBucket.totalConfirmed, passBucket.inMempool, passBucket.leftMempool,
346  failBucket.start, failBucket.end,
347  100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool),
348  failBucket.withinTarget, failBucket.totalConfirmed, failBucket.inMempool, failBucket.leftMempool);
349 
350 
351  if (result) {
352  result->pass = passBucket;
353  result->fail = failBucket;
354  result->decay = decay;
355  result->scale = scale;
356  }
357  return median;
358 }
359 
360 void TxConfirmStats::Write(CAutoFile& fileout) const
361 {
362  fileout << decay;
363  fileout << scale;
364  fileout << avg;
365  fileout << txCtAvg;
366  fileout << confAvg;
367  fileout << failAvg;
368 }
369 
370 void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets)
371 {
372  // Read data file and do some very basic sanity checking
373  // buckets and bucketMap are not updated yet, so don't access them
374  // If there is a read failure, we'll just discard this entire object anyway
375  size_t maxConfirms, maxPeriods;
376 
377  // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
378  filein >> decay;
379  if (decay <= 0 || decay >= 1) {
380  throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
381  }
382  filein >> scale;
383  if (scale == 0) {
384  throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
385  }
386 
387  filein >> avg;
388  if (avg.size() != numBuckets) {
389  throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
390  }
391  filein >> txCtAvg;
392  if (txCtAvg.size() != numBuckets) {
393  throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
394  }
395  filein >> confAvg;
396  maxPeriods = confAvg.size();
397  maxConfirms = scale * maxPeriods;
398 
399  if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) { // one week
400  throw std::runtime_error("Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
401  }
402  for (unsigned int i = 0; i < maxPeriods; i++) {
403  if (confAvg[i].size() != numBuckets) {
404  throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
405  }
406  }
407 
408  filein >> failAvg;
409  if (maxPeriods != failAvg.size()) {
410  throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
411  }
412  for (unsigned int i = 0; i < maxPeriods; i++) {
413  if (failAvg[i].size() != numBuckets) {
414  throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
415  }
416  }
417 
418  // Resize the current block variables which aren't stored in the data file
419  // to match the number of confirms and buckets
420  resizeInMemoryCounters(numBuckets);
421 
422  LogPrint(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n",
423  numBuckets, maxConfirms);
424 }
425 
426 unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
427 {
428  unsigned int bucketindex = bucketMap.lower_bound(val)->second;
429  unsigned int blockIndex = nBlockHeight % unconfTxs.size();
430  unconfTxs[blockIndex][bucketindex]++;
431  return bucketindex;
432 }
433 
434 void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock)
435 {
436  //nBestSeenHeight is not updated yet for the new block
437  int blocksAgo = nBestSeenHeight - entryHeight;
438  if (nBestSeenHeight == 0) // the BlockPolicyEstimator hasn't seen any blocks yet
439  blocksAgo = 0;
440  if (blocksAgo < 0) {
441  LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, blocks ago is negative for mempool tx\n");
442  return; //This can't happen because we call this with our best seen height, no entries can have higher
443  }
444 
445  if (blocksAgo >= (int)unconfTxs.size()) {
446  if (oldUnconfTxs[bucketindex] > 0) {
447  oldUnconfTxs[bucketindex]--;
448  } else {
449  LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n",
450  bucketindex);
451  }
452  }
453  else {
454  unsigned int blockIndex = entryHeight % unconfTxs.size();
455  if (unconfTxs[blockIndex][bucketindex] > 0) {
456  unconfTxs[blockIndex][bucketindex]--;
457  } else {
458  LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
459  blockIndex, bucketindex);
460  }
461  }
462  if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period
463  assert(scale != 0);
464  unsigned int periodsAgo = blocksAgo / scale;
465  for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {
466  failAvg[i][bucketindex]++;
467  }
468  }
469 }
470 
471 // This function is called from CTxMemPool::removeUnchecked to ensure
472 // txs removed from the mempool for any reason are no longer
473 // tracked. Txs that were part of a block have already been removed in
474 // processBlockTx to ensure they are never double tracked, but it is
475 // of no harm to try to remove them again.
476 bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
477 {
478  LOCK(m_cs_fee_estimator);
479  std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
480  if (pos != mapMemPoolTxs.end()) {
481  feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
482  shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
483  longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
484  mapMemPoolTxs.erase(hash);
485  return true;
486  } else {
487  return false;
488  }
489 }
490 
492  : nBestSeenHeight(0), firstRecordedHeight(0), historicalFirst(0), historicalBest(0), trackedTxs(0), untrackedTxs(0)
493 {
494  static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
495  size_t bucketIndex = 0;
496  for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
497  buckets.push_back(bucketBoundary);
498  bucketMap[bucketBoundary] = bucketIndex;
499  }
500  buckets.push_back(INF_FEERATE);
501  bucketMap[INF_FEERATE] = bucketIndex;
502  assert(bucketMap.size() == buckets.size());
503 
504  feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
505  shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
506  longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
507 }
508 
510 {
511 }
512 
513 void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
514 {
516  unsigned int txHeight = entry.GetHeight();
517  uint256 hash = entry.GetTx().GetHash();
518  if (mapMemPoolTxs.count(hash)) {
519  LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
520  hash.ToString());
521  return;
522  }
523 
524  if (txHeight != nBestSeenHeight) {
525  // Ignore side chains and re-orgs; assuming they are random they don't
526  // affect the estimate. We'll potentially double count transactions in 1-block reorgs.
527  // Ignore txs if BlockPolicyEstimator is not in sync with ::ChainActive().Tip().
528  // It will be synced next time a block is processed.
529  return;
530  }
531 
532  // Only want to be updating estimates when our blockchain is synced,
533  // otherwise we'll miscalculate how many blocks its taking to get included.
534  if (!validFeeEstimate) {
535  untrackedTxs++;
536  return;
537  }
538  trackedTxs++;
539 
540  // Feerates are stored and reported as BTC-per-kb:
541  CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
542 
543  mapMemPoolTxs[hash].blockHeight = txHeight;
544  unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
545  mapMemPoolTxs[hash].bucketIndex = bucketIndex;
546  unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
547  assert(bucketIndex == bucketIndex2);
548  unsigned int bucketIndex3 = longStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
549  assert(bucketIndex == bucketIndex3);
550 }
551 
552 bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
553 {
554  if (!removeTx(entry->GetTx().GetHash(), true)) {
555  // This transaction wasn't being tracked for fee estimation
556  return false;
557  }
558 
559  // How many blocks did it take for miners to include this transaction?
560  // blocksToConfirm is 1-based, so a transaction included in the earliest
561  // possible block has confirmation count of 1
562  int blocksToConfirm = nBlockHeight - entry->GetHeight();
563  if (blocksToConfirm <= 0) {
564  // This can't happen because we don't process transactions from a block with a height
565  // lower than our greatest seen height
566  LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
567  return false;
568  }
569 
570  // Feerates are stored and reported as BTC-per-kb:
571  CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
572 
573  feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
574  shortStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
575  longStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
576  return true;
577 }
578 
579 void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
580  std::vector<const CTxMemPoolEntry*>& entries)
581 {
583  if (nBlockHeight <= nBestSeenHeight) {
584  // Ignore side chains and re-orgs; assuming they are random
585  // they don't affect the estimate.
586  // And if an attacker can re-org the chain at will, then
587  // you've got much bigger problems than "attacker can influence
588  // transaction fees."
589  return;
590  }
591 
592  // Must update nBestSeenHeight in sync with ClearCurrent so that
593  // calls to removeTx (via processBlockTx) correctly calculate age
594  // of unconfirmed txs to remove from tracking.
595  nBestSeenHeight = nBlockHeight;
596 
597  // Update unconfirmed circular buffer
598  feeStats->ClearCurrent(nBlockHeight);
599  shortStats->ClearCurrent(nBlockHeight);
600  longStats->ClearCurrent(nBlockHeight);
601 
602  // Decay all exponential averages
603  feeStats->UpdateMovingAverages();
604  shortStats->UpdateMovingAverages();
605  longStats->UpdateMovingAverages();
606 
607  unsigned int countedTxs = 0;
608  // Update averages with data points from current block
609  for (const auto& entry : entries) {
610  if (processBlockTx(nBlockHeight, entry))
611  countedTxs++;
612  }
613 
614  if (firstRecordedHeight == 0 && countedTxs > 0) {
615  firstRecordedHeight = nBestSeenHeight;
616  LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight);
617  }
618 
619 
620  LogPrint(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",
621  countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
622  MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");
623 
624  trackedTxs = 0;
625  untrackedTxs = 0;
626 }
627 
629 {
630  // It's not possible to get reasonable estimates for confTarget of 1
631  if (confTarget <= 1)
632  return CFeeRate(0);
633 
635 }
636 
637 CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
638 {
639  TxConfirmStats* stats;
640  double sufficientTxs = SUFFICIENT_FEETXS;
641  switch (horizon) {
643  stats = shortStats.get();
644  sufficientTxs = SUFFICIENT_TXS_SHORT;
645  break;
646  }
648  stats = feeStats.get();
649  break;
650  }
652  stats = longStats.get();
653  break;
654  }
655  default: {
656  throw std::out_of_range("CBlockPolicyEstimator::estimateRawFee unknown FeeEstimateHorizon");
657  }
658  }
659 
661  // Return failure if trying to analyze a target we're not tracking
662  if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
663  return CFeeRate(0);
664  if (successThreshold > 1)
665  return CFeeRate(0);
666 
667  double median = stats->EstimateMedianVal(confTarget, sufficientTxs, successThreshold, true, nBestSeenHeight, result);
668 
669  if (median < 0)
670  return CFeeRate(0);
671 
672  return CFeeRate(llround(median));
673 }
674 
676 {
678  switch (horizon) {
680  return shortStats->GetMaxConfirms();
681  }
683  return feeStats->GetMaxConfirms();
684  }
686  return longStats->GetMaxConfirms();
687  }
688  default: {
689  throw std::out_of_range("CBlockPolicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon");
690  }
691  }
692 }
693 
695 {
696  if (firstRecordedHeight == 0) return 0;
697  assert(nBestSeenHeight >= firstRecordedHeight);
698 
699  return nBestSeenHeight - firstRecordedHeight;
700 }
701 
703 {
704  if (historicalFirst == 0) return 0;
705  assert(historicalBest >= historicalFirst);
706 
707  if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;
708 
709  return historicalBest - historicalFirst;
710 }
711 
713 {
714  // Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate
715  return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);
716 }
717 
722 double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const
723 {
724  double estimate = -1;
725  if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
726  // Find estimate from shortest time horizon possible
727  if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon
728  estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight, result);
729  }
730  else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon
731  estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, result);
732  }
733  else { // long horizon
734  estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, result);
735  }
736  if (checkShorterHorizon) {
737  EstimationResult tempResult;
738  // If a lower confTarget from a more recent horizon returns a lower answer use it.
739  if (confTarget > feeStats->GetMaxConfirms()) {
740  double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, &tempResult);
741  if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
742  estimate = medMax;
743  if (result) *result = tempResult;
744  }
745  }
746  if (confTarget > shortStats->GetMaxConfirms()) {
747  double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight, &tempResult);
748  if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
749  estimate = shortMax;
750  if (result) *result = tempResult;
751  }
752  }
753  }
754  }
755  return estimate;
756 }
757 
761 double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const
762 {
763  double estimate = -1;
764  EstimationResult tempResult;
765  if (doubleTarget <= shortStats->GetMaxConfirms()) {
766  estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight, result);
767  }
768  if (doubleTarget <= feeStats->GetMaxConfirms()) {
769  double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight, &tempResult);
770  if (longEstimate > estimate) {
771  estimate = longEstimate;
772  if (result) *result = tempResult;
773  }
774  }
775  return estimate;
776 }
777 
785 CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
786 {
788 
789  if (feeCalc) {
790  feeCalc->desiredTarget = confTarget;
791  feeCalc->returnedTarget = confTarget;
792  }
793 
794  double median = -1;
795  EstimationResult tempResult;
796 
797  // Return failure if trying to analyze a target we're not tracking
798  if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
799  return CFeeRate(0); // error condition
800  }
801 
802  // It's not possible to get reasonable estimates for confTarget of 1
803  if (confTarget == 1) confTarget = 2;
804 
805  unsigned int maxUsableEstimate = MaxUsableEstimate();
806  if ((unsigned int)confTarget > maxUsableEstimate) {
807  confTarget = maxUsableEstimate;
808  }
809  if (feeCalc) feeCalc->returnedTarget = confTarget;
810 
811  if (confTarget <= 1) return CFeeRate(0); // error condition
812 
813  assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
824  double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
825  if (feeCalc) {
826  feeCalc->est = tempResult;
827  feeCalc->reason = FeeReason::HALF_ESTIMATE;
828  }
829  median = halfEst;
830  double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
831  if (actualEst > median) {
832  median = actualEst;
833  if (feeCalc) {
834  feeCalc->est = tempResult;
835  feeCalc->reason = FeeReason::FULL_ESTIMATE;
836  }
837  }
838  double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
839  if (doubleEst > median) {
840  median = doubleEst;
841  if (feeCalc) {
842  feeCalc->est = tempResult;
844  }
845  }
846 
847  if (conservative || median == -1) {
848  double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
849  if (consEst > median) {
850  median = consEst;
851  if (feeCalc) {
852  feeCalc->est = tempResult;
853  feeCalc->reason = FeeReason::CONSERVATIVE;
854  }
855  }
856  }
857 
858  if (median < 0) return CFeeRate(0); // error condition
859 
860  return CFeeRate(llround(median));
861 }
862 
863 
865 {
866  try {
868  fileout << 149900; // version required to read: 0.14.99 or later
869  fileout << CLIENT_VERSION; // version that wrote the file
870  fileout << nBestSeenHeight;
871  if (BlockSpan() > HistoricalBlockSpan()/2) {
872  fileout << firstRecordedHeight << nBestSeenHeight;
873  }
874  else {
875  fileout << historicalFirst << historicalBest;
876  }
877  fileout << buckets;
878  feeStats->Write(fileout);
879  shortStats->Write(fileout);
880  longStats->Write(fileout);
881  }
882  catch (const std::exception&) {
883  LogPrintf("CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
884  return false;
885  }
886  return true;
887 }
888 
890 {
891  try {
893  int nVersionRequired, nVersionThatWrote;
894  filein >> nVersionRequired >> nVersionThatWrote;
895  if (nVersionRequired > CLIENT_VERSION)
896  return error("CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file", nVersionRequired);
897 
898  // Read fee estimates file into temporary variables so existing data
899  // structures aren't corrupted if there is an exception.
900  unsigned int nFileBestSeenHeight;
901  filein >> nFileBestSeenHeight;
902 
903  if (nVersionRequired < 149900) {
904  LogPrintf("%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
905  } else { // New format introduced in 149900
906  unsigned int nFileHistoricalFirst, nFileHistoricalBest;
907  filein >> nFileHistoricalFirst >> nFileHistoricalBest;
908  if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
909  throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
910  }
911  std::vector<double> fileBuckets;
912  filein >> fileBuckets;
913  size_t numBuckets = fileBuckets.size();
914  if (numBuckets <= 1 || numBuckets > 1000)
915  throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
916 
917  std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
918  std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
919  std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
920  fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
921  fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
922  fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
923 
924  // Fee estimates file parsed correctly
925  // Copy buckets from file and refresh our bucketmap
926  buckets = fileBuckets;
927  bucketMap.clear();
928  for (unsigned int i = 0; i < buckets.size(); i++) {
929  bucketMap[buckets[i]] = i;
930  }
931 
932  // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
933  feeStats = std::move(fileFeeStats);
934  shortStats = std::move(fileShortStats);
935  longStats = std::move(fileLongStats);
936 
937  nBestSeenHeight = nFileBestSeenHeight;
938  historicalFirst = nFileHistoricalFirst;
939  historicalBest = nFileHistoricalBest;
940  }
941  }
942  catch (const std::exception& e) {
943  LogPrintf("CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
944  return false;
945  }
946  return true;
947 }
948 
950  int64_t startclear = GetTimeMicros();
952  size_t num_entries = mapMemPoolTxs.size();
953  // Remove every entry in mapMemPoolTxs
954  while (!mapMemPoolTxs.empty()) {
955  auto mi = mapMemPoolTxs.begin();
956  removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
957  }
958  int64_t endclear = GetTimeMicros();
959  LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
960 }
961 
963 {
964  CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
965  feeset.insert(0);
966  for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FILTER_FEERATE; bucketBoundary *= FEE_FILTER_SPACING) {
967  feeset.insert(bucketBoundary);
968  }
969 }
970 
972 {
973  std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
974  if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
975  it--;
976  }
977  return static_cast<CAmount>(*it);
978 }
static constexpr double MED_DECAY
Decay of .998 is a half-life of 144 blocks or about 1 day.
Definition: fees.h:149
EstimatorBucket pass
Definition: fees.h:69
std::vector< std::vector< double > > failAvg
Definition: fees.cpp:54
EstimationResult est
Definition: fees.h:77
bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry *entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Process a transaction confirmed in a block.
Definition: fees.cpp:552
#define LogPrint(category,...)
Definition: logging.h:178
int returnedTarget
Definition: fees.h:80
static constexpr double MAX_BUCKET_FEERATE
Definition: fees.h:173
static constexpr double HALF_SUCCESS_PCT
Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks.
Definition: fees.h:154
size_t GetTxSize() const
Definition: txmempool.cpp:52
static constexpr unsigned int MED_BLOCK_PERIODS
Track confirm delays up to 48 blocks for medium horizon.
Definition: fees.h:138
double start
Definition: fees.h:58
bool removeTx(uint256 hash, bool inBlock)
Remove a transaction from the mempool tracking stats.
Definition: fees.cpp:476
CBlockPolicyEstimator()
Create new BlockPolicyEstimator and initialize stats tracking classes with default values...
Definition: fees.cpp:491
TxConfirmStats(const std::vector< double > &defaultBuckets, const std::map< double, unsigned int > &defaultBucketMap, unsigned int maxPeriods, double decay, unsigned int scale)
Create new TxConfirmStats.
Definition: fees.cpp:139
double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
Definition: fees.cpp:761
bool Write(CAutoFile &fileout) const
Write estimation data to a file.
Definition: fees.cpp:864
void FlushUnconfirmed()
Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool...
Definition: fees.cpp:949
std::vector< double > avg
Definition: fees.cpp:58
unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of recorded fee estimate data represented in saved data file.
Definition: fees.cpp:702
FeeReason reason
Definition: fees.h:78
We will instantiate an instance of this class to track transactions that were included in a block...
Definition: fees.cpp:36
static void LogPrintf(const char *fmt, const Args &... args)
Definition: logging.h:162
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
Definition: fees.cpp:15
static constexpr double DOUBLE_SUCCESS_PCT
Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks.
Definition: fees.h:158
static constexpr double FEE_SPACING
Spacing of FeeRate buckets We have to lump transactions into buckets based on feerate, but we want to be able to give accurate estimates over a large range of potential feerates Therefore it makes sense to exponentially space the buckets.
Definition: fees.h:180
CCriticalSection m_cs_fee_estimator
Definition: fees.h:226
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Calculation of highest target that reasonable estimate can be provided for.
Definition: fees.cpp:712
double decay
Definition: fees.cpp:63
void Record(int blocksToConfirm, double val)
Record a new transaction data point in the current block stats.
Definition: fees.cpp:181
static constexpr double MIN_BUCKET_FEERATE
Minimum and Maximum values for tracking feerates The MIN_BUCKET_FEERATE should just be set to the low...
Definition: fees.h:172
double withinTarget
Definition: fees.h:60
void resizeInMemoryCounters(size_t newbuckets)
Definition: fees.cpp:162
void ClearCurrent(unsigned int nBlockHeight)
Roll the circular buffer for unconfirmed txs.
Definition: fees.cpp:172
int desiredTarget
Definition: fees.h:79
static constexpr double SUFFICIENT_TXS_SHORT
Require an avg of 0.5 tx when using short decay since there are fewer blocks considered.
Definition: fees.h:163
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
Definition: txmempool.h:65
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
static constexpr double SUCCESS_PCT
Require greater than 85% of X feerate transactions to be confirmed within Y blocks.
Definition: fees.h:156
void Read(CAutoFile &filein, int nFileVersion, size_t numBuckets)
Read saved state of estimation data from a file and replace all internal data structures and variable...
Definition: fees.cpp:370
const std::map< double, unsigned int > & bucketMap
Definition: fees.cpp:41
static constexpr unsigned int SHORT_SCALE
Definition: fees.h:136
static constexpr double LONG_DECAY
Decay of .9995 is a half-life of 1008 blocks or about 1 week.
Definition: fees.h:151
std::vector< std::vector< double > > confAvg
Definition: fees.cpp:50
unsigned int NewTx(unsigned int nBlockHeight, double val)
Record a new transaction entering the mempool.
Definition: fees.cpp:426
unsigned int GetHeight() const
Definition: txmempool.h:104
double end
Definition: fees.h:59
EstimatorBucket fail
Definition: fees.h:70
CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result=nullptr) const
Return a specific fee estimate calculation with a given success threshold and time horizon...
Definition: fees.cpp:637
#define LOCK(cs)
Definition: sync.h:180
void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketIndex, bool inBlock)
Remove a transaction from mempool tracking stats.
Definition: fees.cpp:434
const uint256 & GetHash() const
Definition: transaction.h:322
const CAmount & GetFee() const
Definition: txmempool.h:100
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
Estimate feerate needed to get be included in a block within confTarget blocks.
Definition: fees.cpp:785
unsigned int scale
Definition: fees.cpp:66
const std::vector< double > & buckets
Definition: fees.cpp:40
unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of data recorded while fee estimates have been running.
Definition: fees.cpp:694
double inMempool
Definition: fees.h:62
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
Definition: fees.cpp:722
std::string ToString() const
Definition: uint256.cpp:60
FeeFilterRounder(const CFeeRate &minIncrementalFee)
Create new FeeFilterRounder.
Definition: fees.cpp:962
CFeeRate estimateFee(int confTarget) const
DEPRECATED.
Definition: fees.cpp:628
static constexpr unsigned int LONG_SCALE
Definition: fees.h:142
int64_t GetTimeMicros()
Returns the system time (not mockable)
Definition: time.cpp:62
FeeEstimateHorizon
Definition: fees.h:27
std::vector< std::vector< int > > unconfTxs
Definition: fees.cpp:71
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const
Calculation of highest target that estimates are tracked for.
Definition: fees.cpp:675
256-bit opaque blob.
Definition: uint256.h:120
static constexpr unsigned int MED_SCALE
Definition: fees.h:139
static const unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren&#39;t valid.
Definition: fees.h:144
std::vector< int > oldUnconfTxs
Definition: fees.cpp:73
void processBlock(unsigned int nBlockHeight, std::vector< const CTxMemPoolEntry *> &entries)
Process all the transactions that have been included in a block.
Definition: fees.cpp:579
const CTransaction & GetTx() const
Definition: txmempool.h:98
bool Read(CAutoFile &filein)
Read estimation data from a file.
Definition: fees.cpp:889
double leftMempool
Definition: fees.h:63
unsigned int GetMaxConfirms() const
Return the max number of confirms we&#39;re tracking.
Definition: fees.cpp:126
static constexpr unsigned int LONG_BLOCK_PERIODS
Track confirm delays up to 1008 blocks for long horizon.
Definition: fees.h:141
Fee rate in satoshis per kilobyte: CAmount / kB.
Definition: feerate.h:19
static constexpr unsigned int SHORT_BLOCK_PERIODS
Track confirm delays up to 12 blocks for short horizon.
Definition: fees.h:135
static constexpr double INF_FEERATE
Definition: fees.cpp:13
double totalConfirmed
Definition: fees.h:61
static constexpr double SUFFICIENT_FEETXS
Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance.
Definition: fees.h:161
CAmount round(CAmount currentMinFee)
Quantize a minimum fee for privacy purpose before broadcast.
Definition: fees.cpp:971
static constexpr double SHORT_DECAY
Decay of .962 is a half-life of 18 blocks or about 3 hours.
Definition: fees.h:147
double EstimateMedianVal(int confTarget, double sufficientTxVal, double minSuccess, bool requireGreater, unsigned int nBlockHeight, EstimationResult *result=nullptr) const
Calculate a feerate estimate.
Definition: fees.cpp:208
void Write(CAutoFile &fileout) const
Write state of estimation data to a file.
Definition: fees.cpp:360
std::vector< double > txCtAvg
Definition: fees.cpp:46
auto it
Definition: validation.cpp:362
void UpdateMovingAverages()
Update our estimates by decaying our historical moving average and updating with the data gathered fr...
Definition: fees.cpp:195
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
unsigned int scale
Definition: fees.h:72
bool error(const char *fmt, const Args &... args)
Definition: system.h:48
CAmount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Definition: feerate.h:41
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:601
void processTransaction(const CTxMemPoolEntry &entry, bool validFeeEstimate)
Process a transaction accepted to the mempool.
Definition: fees.cpp:513
double decay
Definition: fees.h:71