7
7
#include " policy/policy.h"
8
8
9
9
#include " amount.h"
10
+ #include " clientversion.h"
10
11
#include " primitives/transaction.h"
11
12
#include " random.h"
12
13
#include " streams.h"
13
14
#include " txmempool.h"
14
15
#include " util.h"
15
16
16
- void TxConfirmStats::Initialize (std::vector<double >& defaultBuckets,
17
- unsigned int maxConfirms, double _decay)
17
+ /* *
18
+ * We will instantiate an instance of this class to track transactions that were
19
+ * included in a block. We will lump transactions into a bucket according to their
20
+ * approximate feerate and then track how long it took for those txs to be included in a block
21
+ *
22
+ * The tracking of unconfirmed (mempool) transactions is completely independent of the
23
+ * historical tracking of transactions that have been confirmed in a block.
24
+ */
25
+ class TxConfirmStats
26
+ {
27
+ private:
28
+ // Define the buckets we will group transactions into
29
+ std::vector<double > buckets; // The upper-bound of the range for the bucket (inclusive)
30
+ std::map<double , unsigned int > bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
31
+
32
+ // For each bucket X:
33
+ // Count the total # of txs in each bucket
34
+ // Track the historical moving average of this total over blocks
35
+ std::vector<double > txCtAvg;
36
+ // and calculate the total for the current block to update the moving average
37
+ std::vector<int > curBlockTxCt;
38
+
39
+ // Count the total # of txs confirmed within Y blocks in each bucket
40
+ // Track the historical moving average of theses totals over blocks
41
+ std::vector<std::vector<double > > confAvg; // confAvg[Y][X]
42
+ // and calculate the totals for the current block to update the moving averages
43
+ std::vector<std::vector<int > > curBlockConf; // curBlockConf[Y][X]
44
+
45
+ // Sum the total feerate of all tx's in each bucket
46
+ // Track the historical moving average of this total over blocks
47
+ std::vector<double > avg;
48
+ // and calculate the total for the current block to update the moving average
49
+ std::vector<double > curBlockVal;
50
+
51
+ // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
52
+ // Combine the total value with the tx counts to calculate the avg feerate per bucket
53
+
54
+ double decay;
55
+
56
+ // Mempool counts of outstanding transactions
57
+ // For each bucket X, track the number of transactions in the mempool
58
+ // that are unconfirmed for each possible confirmation value Y
59
+ std::vector<std::vector<int > > unconfTxs; // unconfTxs[Y][X]
60
+ // transactions still unconfirmed after MAX_CONFIRMS for each bucket
61
+ std::vector<int > oldUnconfTxs;
62
+
63
+ public:
64
+ /* *
65
+ * Create new TxConfirmStats. This is called by BlockPolicyEstimator's
66
+ * constructor with default values.
67
+ * @param defaultBuckets contains the upper limits for the bucket boundaries
68
+ * @param maxConfirms max number of confirms to track
69
+ * @param decay how much to decay the historical moving average per block
70
+ */
71
+ TxConfirmStats (const std::vector<double >& defaultBuckets, unsigned int maxConfirms, double decay);
72
+
73
+ /* * Clear the state of the curBlock variables to start counting for the new block */
74
+ void ClearCurrent (unsigned int nBlockHeight);
75
+
76
+ /* *
77
+ * Record a new transaction data point in the current block stats
78
+ * @param blocksToConfirm the number of blocks it took this transaction to confirm
79
+ * @param val the feerate of the transaction
80
+ * @warning blocksToConfirm is 1-based and has to be >= 1
81
+ */
82
+ void Record (int blocksToConfirm, double val);
83
+
84
+ /* * Record a new transaction entering the mempool*/
85
+ unsigned int NewTx (unsigned int nBlockHeight, double val);
86
+
87
+ /* * Remove a transaction from mempool tracking stats*/
88
+ void removeTx (unsigned int entryHeight, unsigned int nBestSeenHeight,
89
+ unsigned int bucketIndex);
90
+
91
+ /* * Update our estimates by decaying our historical moving average and updating
92
+ with the data gathered from the current block */
93
+ void UpdateMovingAverages ();
94
+
95
+ /* *
96
+ * Calculate a feerate estimate. Find the lowest value bucket (or range of buckets
97
+ * to make sure we have enough data points) whose transactions still have sufficient likelihood
98
+ * of being confirmed within the target number of confirmations
99
+ * @param confTarget target number of confirmations
100
+ * @param sufficientTxVal required average number of transactions per block in a bucket range
101
+ * @param minSuccess the success probability we require
102
+ * @param requireGreater return the lowest feerate such that all higher values pass minSuccess OR
103
+ * return the highest feerate such that all lower values fail minSuccess
104
+ * @param nBlockHeight the current block height
105
+ */
106
+ double EstimateMedianVal (int confTarget, double sufficientTxVal,
107
+ double minSuccess, bool requireGreater, unsigned int nBlockHeight) const ;
108
+
109
+ /* * Return the max number of confirms we're tracking */
110
+ unsigned int GetMaxConfirms () const { return confAvg.size (); }
111
+
112
+ /* * Write state of estimation data to a file*/
113
+ void Write (CAutoFile& fileout) const ;
114
+
115
+ /* *
116
+ * Read saved state of estimation data from a file and replace all internal data structures and
117
+ * variables with this state.
118
+ */
119
+ void Read (CAutoFile& filein);
120
+ };
121
+
122
+
123
+ TxConfirmStats::TxConfirmStats (const std::vector<double >& defaultBuckets,
124
+ unsigned int maxConfirms, double _decay)
18
125
{
19
126
decay = _decay;
20
127
for (unsigned int i = 0 ; i < defaultBuckets.size (); i++) {
@@ -77,7 +184,7 @@ void TxConfirmStats::UpdateMovingAverages()
77
184
// returns -1 on error conditions
78
185
double TxConfirmStats::EstimateMedianVal (int confTarget, double sufficientTxVal,
79
186
double successBreakPoint, bool requireGreater,
80
- unsigned int nBlockHeight)
187
+ unsigned int nBlockHeight) const
81
188
{
82
189
// Counters for a bucket (or range of buckets)
83
190
double nConf = 0 ; // Number of tx's confirmed within the confTarget
@@ -173,7 +280,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
173
280
return median;
174
281
}
175
282
176
- void TxConfirmStats::Write (CAutoFile& fileout)
283
+ void TxConfirmStats::Write (CAutoFile& fileout) const
177
284
{
178
285
fileout << decay;
179
286
fileout << buckets;
@@ -290,9 +397,10 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
290
397
// of no harm to try to remove them again.
291
398
bool CBlockPolicyEstimator::removeTx (uint256 hash)
292
399
{
400
+ LOCK (cs_feeEstimator);
293
401
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find (hash);
294
402
if (pos != mapMemPoolTxs.end ()) {
295
- feeStats. removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex );
403
+ feeStats-> removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex );
296
404
mapMemPoolTxs.erase (hash);
297
405
return true ;
298
406
} else {
@@ -310,11 +418,17 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
310
418
vfeelist.push_back (bucketBoundary);
311
419
}
312
420
vfeelist.push_back (INF_FEERATE);
313
- feeStats.Initialize (vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
421
+ feeStats = new TxConfirmStats (vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
422
+ }
423
+
424
+ CBlockPolicyEstimator::~CBlockPolicyEstimator ()
425
+ {
426
+ delete feeStats;
314
427
}
315
428
316
429
void CBlockPolicyEstimator::processTransaction (const CTxMemPoolEntry& entry, bool validFeeEstimate)
317
430
{
431
+ LOCK (cs_feeEstimator);
318
432
unsigned int txHeight = entry.GetHeight ();
319
433
uint256 hash = entry.GetTx ().GetHash ();
320
434
if (mapMemPoolTxs.count (hash)) {
@@ -343,7 +457,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
343
457
CFeeRate feeRate (entry.GetFee (), entry.GetTxSize ());
344
458
345
459
mapMemPoolTxs[hash].blockHeight = txHeight;
346
- mapMemPoolTxs[hash].bucketIndex = feeStats. NewTx (txHeight, (double )feeRate.GetFeePerK ());
460
+ mapMemPoolTxs[hash].bucketIndex = feeStats-> NewTx (txHeight, (double )feeRate.GetFeePerK ());
347
461
}
348
462
349
463
bool CBlockPolicyEstimator::processBlockTx (unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
@@ -367,13 +481,14 @@ bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
367
481
// Feerates are stored and reported as BTC-per-kb:
368
482
CFeeRate feeRate (entry->GetFee (), entry->GetTxSize ());
369
483
370
- feeStats. Record (blocksToConfirm, (double )feeRate.GetFeePerK ());
484
+ feeStats-> Record (blocksToConfirm, (double )feeRate.GetFeePerK ());
371
485
return true ;
372
486
}
373
487
374
488
void CBlockPolicyEstimator::processBlock (unsigned int nBlockHeight,
375
489
std::vector<const CTxMemPoolEntry*>& entries)
376
490
{
491
+ LOCK (cs_feeEstimator);
377
492
if (nBlockHeight <= nBestSeenHeight) {
378
493
// Ignore side chains and re-orgs; assuming they are random
379
494
// they don't affect the estimate.
@@ -389,7 +504,7 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
389
504
nBestSeenHeight = nBlockHeight;
390
505
391
506
// Clear the current block state and update unconfirmed circular buffer
392
- feeStats. ClearCurrent (nBlockHeight);
507
+ feeStats-> ClearCurrent (nBlockHeight);
393
508
394
509
unsigned int countedTxs = 0 ;
395
510
// Repopulate the current block states
@@ -399,7 +514,7 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
399
514
}
400
515
401
516
// Update all exponential averages with the current block state
402
- feeStats. UpdateMovingAverages ();
517
+ feeStats-> UpdateMovingAverages ();
403
518
404
519
LogPrint (BCLog::ESTIMATEFEE, " Blockpolicy after updating estimates for %u of %u txs in block, since last block %u of %u tracked, new mempool map size %u\n " ,
405
520
countedTxs, entries.size (), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size ());
@@ -408,37 +523,44 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
408
523
untrackedTxs = 0 ;
409
524
}
410
525
411
- CFeeRate CBlockPolicyEstimator::estimateFee (int confTarget)
526
+ CFeeRate CBlockPolicyEstimator::estimateFee (int confTarget) const
412
527
{
528
+ LOCK (cs_feeEstimator);
413
529
// Return failure if trying to analyze a target we're not tracking
414
530
// It's not possible to get reasonable estimates for confTarget of 1
415
- if (confTarget <= 1 || (unsigned int )confTarget > feeStats. GetMaxConfirms ())
531
+ if (confTarget <= 1 || (unsigned int )confTarget > feeStats-> GetMaxConfirms ())
416
532
return CFeeRate (0 );
417
533
418
- double median = feeStats. EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true , nBestSeenHeight);
534
+ double median = feeStats-> EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true , nBestSeenHeight);
419
535
420
536
if (median < 0 )
421
537
return CFeeRate (0 );
422
538
423
539
return CFeeRate (median);
424
540
}
425
541
426
- CFeeRate CBlockPolicyEstimator::estimateSmartFee (int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
542
+ CFeeRate CBlockPolicyEstimator::estimateSmartFee (int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) const
427
543
{
428
544
if (answerFoundAtTarget)
429
545
*answerFoundAtTarget = confTarget;
430
- // Return failure if trying to analyze a target we're not tracking
431
- if (confTarget <= 0 || (unsigned int )confTarget > feeStats.GetMaxConfirms ())
432
- return CFeeRate (0 );
433
-
434
- // It's not possible to get reasonable estimates for confTarget of 1
435
- if (confTarget == 1 )
436
- confTarget = 2 ;
437
546
438
547
double median = -1 ;
439
- while (median < 0 && (unsigned int )confTarget <= feeStats.GetMaxConfirms ()) {
440
- median = feeStats.EstimateMedianVal (confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true , nBestSeenHeight);
441
- }
548
+
549
+ {
550
+ LOCK (cs_feeEstimator);
551
+
552
+ // Return failure if trying to analyze a target we're not tracking
553
+ if (confTarget <= 0 || (unsigned int )confTarget > feeStats->GetMaxConfirms ())
554
+ return CFeeRate (0 );
555
+
556
+ // It's not possible to get reasonable estimates for confTarget of 1
557
+ if (confTarget == 1 )
558
+ confTarget = 2 ;
559
+
560
+ while (median < 0 && (unsigned int )confTarget <= feeStats->GetMaxConfirms ()) {
561
+ median = feeStats->EstimateMedianVal (confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true , nBestSeenHeight);
562
+ }
563
+ } // Must unlock cs_feeEstimator before taking mempool locks
442
564
443
565
if (answerFoundAtTarget)
444
566
*answerFoundAtTarget = confTarget - 1 ;
@@ -454,19 +576,40 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
454
576
return CFeeRate (median);
455
577
}
456
578
457
- void CBlockPolicyEstimator::Write (CAutoFile& fileout)
579
+ bool CBlockPolicyEstimator::Write (CAutoFile& fileout) const
458
580
{
459
- fileout << nBestSeenHeight;
460
- feeStats.Write (fileout);
581
+ try {
582
+ LOCK (cs_feeEstimator);
583
+ fileout << 139900 ; // version required to read: 0.13.99 or later
584
+ fileout << CLIENT_VERSION; // version that wrote the file
585
+ fileout << nBestSeenHeight;
586
+ feeStats->Write (fileout);
587
+ }
588
+ catch (const std::exception&) {
589
+ LogPrintf (" CBlockPolicyEstimator::Write(): unable to read policy estimator data (non-fatal)\n " );
590
+ return false ;
591
+ }
592
+ return true ;
461
593
}
462
594
463
- void CBlockPolicyEstimator::Read (CAutoFile& filein, int nFileVersion )
595
+ bool CBlockPolicyEstimator::Read (CAutoFile& filein)
464
596
{
465
- int nFileBestSeenHeight;
466
- filein >> nFileBestSeenHeight;
467
- feeStats.Read (filein);
468
- nBestSeenHeight = nFileBestSeenHeight;
469
- // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.
597
+ try {
598
+ LOCK (cs_feeEstimator);
599
+ int nVersionRequired, nVersionThatWrote, nFileBestSeenHeight;
600
+ filein >> nVersionRequired >> nVersionThatWrote;
601
+ if (nVersionRequired > CLIENT_VERSION)
602
+ return error (" CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file" , nVersionRequired);
603
+ filein >> nFileBestSeenHeight;
604
+ feeStats->Read (filein);
605
+ nBestSeenHeight = nFileBestSeenHeight;
606
+ // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.
607
+ }
608
+ catch (const std::exception&) {
609
+ LogPrintf (" CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal)\n " );
610
+ return false ;
611
+ }
612
+ return true ;
470
613
}
471
614
472
615
FeeFilterRounder::FeeFilterRounder (const CFeeRate& minIncrementalFee)
0 commit comments