14
14
#include " util.h"
15
15
16
16
void TxConfirmStats::Initialize (std::vector<double >& defaultBuckets,
17
- unsigned int maxConfirms, double _decay, std::string _dataTypeString )
17
+ unsigned int maxConfirms, double _decay)
18
18
{
19
19
decay = _decay;
20
- dataTypeString = _dataTypeString;
21
20
for (unsigned int i = 0 ; i < defaultBuckets.size (); i++) {
22
21
buckets.push_back (defaultBuckets[i]);
23
22
bucketMap[defaultBuckets[i]] = i;
@@ -87,10 +86,10 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
87
86
88
87
int maxbucketindex = buckets.size () - 1 ;
89
88
90
- // requireGreater means we are looking for the lowest fee/priority such that all higher
91
- // values pass, so we start at maxbucketindex (highest fee ) and look at successively
89
+ // requireGreater means we are looking for the lowest feerate such that all higher
90
+ // values pass, so we start at maxbucketindex (highest feerate ) and look at successively
92
91
// smaller buckets until we reach failure. Otherwise, we are looking for the highest
93
- // fee/priority such that all lower values fail, and we go in the opposite direction.
92
+ // feerate such that all lower values fail, and we go in the opposite direction.
94
93
unsigned int startbucket = requireGreater ? maxbucketindex : 0 ;
95
94
int step = requireGreater ? -1 : 1 ;
96
95
@@ -107,7 +106,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
107
106
bool foundAnswer = false ;
108
107
unsigned int bins = unconfTxs.size ();
109
108
110
- // Start counting from highest(default) or lowest fee/pri transactions
109
+ // Start counting from highest(default) or lowest feerate transactions
111
110
for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
112
111
curFarBucket = bucket;
113
112
nConf += confAvg[confTarget - 1 ][bucket];
@@ -145,8 +144,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
145
144
double median = -1 ;
146
145
double txSum = 0 ;
147
146
148
- // Calculate the "average" fee of the best bucket range that met success conditions
149
- // Find the bucket with the median transaction and then report the average fee from that bucket
147
+ // Calculate the "average" feerate of the best bucket range that met success conditions
148
+ // Find the bucket with the median transaction and then report the average feerate from that bucket
150
149
// This is a compromise between finding the median which we can't since we don't save all tx's
151
150
// and reporting the average which is less accurate
152
151
unsigned int minBucket = bestNearBucket < bestFarBucket ? bestNearBucket : bestFarBucket;
@@ -166,8 +165,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
166
165
}
167
166
}
168
167
169
- LogPrint (" estimatefee" , " %3d: For conf success %s %4.2f need %s %s: %12.5g from buckets %8g - %8g Cur Bucket stats %6.2f%% %8.1f/(%.1f+%d mempool)\n " ,
170
- confTarget, requireGreater ? " >" : " <" , successBreakPoint, dataTypeString,
168
+ LogPrint (" estimatefee" , " %3d: For conf success %s %4.2f need feerate %s: %12.5g from buckets %8g - %8g Cur Bucket stats %6.2f%% %8.1f/(%.1f+%d mempool)\n " ,
169
+ confTarget, requireGreater ? " >" : " <" , successBreakPoint,
171
170
requireGreater ? " >" : " <" , median, buckets[minBucket], buckets[maxBucket],
172
171
100 * nConf / (totalNum + extraNum), nConf, totalNum, extraNum);
173
172
@@ -200,10 +199,10 @@ void TxConfirmStats::Read(CAutoFile& filein)
200
199
filein >> fileBuckets;
201
200
numBuckets = fileBuckets.size ();
202
201
if (numBuckets <= 1 || numBuckets > 1000 )
203
- throw std::runtime_error (" Corrupt estimates file. Must have between 2 and 1000 fee/pri buckets" );
202
+ throw std::runtime_error (" Corrupt estimates file. Must have between 2 and 1000 feerate buckets" );
204
203
filein >> fileAvg;
205
204
if (fileAvg.size () != numBuckets)
206
- throw std::runtime_error (" Corrupt estimates file. Mismatch in fee/pri average bucket count" );
205
+ throw std::runtime_error (" Corrupt estimates file. Mismatch in feerate average bucket count" );
207
206
filein >> fileTxCtAvg;
208
207
if (fileTxCtAvg.size () != numBuckets)
209
208
throw std::runtime_error (" Corrupt estimates file. Mismatch in tx count bucket count" );
@@ -213,9 +212,9 @@ void TxConfirmStats::Read(CAutoFile& filein)
213
212
throw std::runtime_error (" Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms" );
214
213
for (unsigned int i = 0 ; i < maxConfirms; i++) {
215
214
if (fileConfAvg[i].size () != numBuckets)
216
- throw std::runtime_error (" Corrupt estimates file. Mismatch in fee/pri conf average bucket count" );
215
+ throw std::runtime_error (" Corrupt estimates file. Mismatch in feerate conf average bucket count" );
217
216
}
218
- // Now that we've processed the entire fee estimate data file and not
217
+ // Now that we've processed the entire feerate estimate data file and not
219
218
// thrown any errors, we can copy it to our data structures
220
219
decay = fileDecay;
221
220
buckets = fileBuckets;
@@ -242,16 +241,15 @@ void TxConfirmStats::Read(CAutoFile& filein)
242
241
for (unsigned int i = 0 ; i < buckets.size (); i++)
243
242
bucketMap[buckets[i]] = i;
244
243
245
- LogPrint (" estimatefee" , " Reading estimates: %u %s buckets counting confirms up to %u blocks\n " ,
246
- numBuckets, dataTypeString, maxConfirms);
244
+ LogPrint (" estimatefee" , " Reading estimates: %u buckets counting confirms up to %u blocks\n " ,
245
+ numBuckets, maxConfirms);
247
246
}
248
247
249
248
unsigned int TxConfirmStats::NewTx (unsigned int nBlockHeight, double val)
250
249
{
251
250
unsigned int bucketindex = bucketMap.lower_bound (val)->second ;
252
251
unsigned int blockIndex = nBlockHeight % unconfTxs.size ();
253
252
unconfTxs[blockIndex][bucketindex]++;
254
- LogPrint (" estimatefee" , " adding to %s" , dataTypeString);
255
253
return bucketindex;
256
254
}
257
255
@@ -291,12 +289,10 @@ void CBlockPolicyEstimator::removeTx(uint256 hash)
291
289
hash.ToString ().c_str ());
292
290
return ;
293
291
}
294
- TxConfirmStats *stats = pos->second .stats ;
295
292
unsigned int entryHeight = pos->second .blockHeight ;
296
293
unsigned int bucketIndex = pos->second .bucketIndex ;
297
294
298
- if (stats != NULL )
299
- stats->removeTx (entryHeight, nBestSeenHeight, bucketIndex);
295
+ feeStats.removeTx (entryHeight, nBestSeenHeight, bucketIndex);
300
296
mapMemPoolTxs.erase (hash);
301
297
}
302
298
@@ -309,45 +305,14 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
309
305
vfeelist.push_back (bucketBoundary);
310
306
}
311
307
vfeelist.push_back (INF_FEERATE);
312
- feeStats.Initialize (vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, " FeeRate" );
313
-
314
- minTrackedPriority = AllowFreeThreshold () < MIN_PRIORITY ? MIN_PRIORITY : AllowFreeThreshold ();
315
- std::vector<double > vprilist;
316
- for (double bucketBoundary = minTrackedPriority; bucketBoundary <= MAX_PRIORITY; bucketBoundary *= PRI_SPACING) {
317
- vprilist.push_back (bucketBoundary);
318
- }
319
- vprilist.push_back (INF_PRIORITY);
320
- priStats.Initialize (vprilist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, " Priority" );
321
-
322
- feeUnlikely = CFeeRate (0 );
323
- feeLikely = CFeeRate (INF_FEERATE);
324
- priUnlikely = 0 ;
325
- priLikely = INF_PRIORITY;
326
- }
327
-
328
- bool CBlockPolicyEstimator::isFeeDataPoint (const CFeeRate &fee, double pri)
329
- {
330
- if ((pri < minTrackedPriority && fee >= minTrackedFee) ||
331
- (pri < priUnlikely && fee > feeLikely)) {
332
- return true ;
333
- }
334
- return false ;
335
- }
336
-
337
- bool CBlockPolicyEstimator::isPriDataPoint (const CFeeRate &fee, double pri)
338
- {
339
- if ((fee < minTrackedFee && pri >= minTrackedPriority) ||
340
- (fee < feeUnlikely && pri > priLikely)) {
341
- return true ;
342
- }
343
- return false ;
308
+ feeStats.Initialize (vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
344
309
}
345
310
346
311
void CBlockPolicyEstimator::processTransaction (const CTxMemPoolEntry& entry, bool fCurrentEstimate )
347
312
{
348
313
unsigned int txHeight = entry.GetHeight ();
349
314
uint256 hash = entry.GetTx ().GetHash ();
350
- if (mapMemPoolTxs[hash]. stats != NULL ) {
315
+ if (mapMemPoolTxs. count (hash) ) {
351
316
LogPrint (" estimatefee" , " Blockpolicy error mempool tx %s already being tracked\n " ,
352
317
hash.ToString ().c_str ());
353
318
return ;
@@ -371,30 +336,11 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
371
336
return ;
372
337
}
373
338
374
- // Fees are stored and reported as BTC-per-kb:
339
+ // Feerates are stored and reported as BTC-per-kb:
375
340
CFeeRate feeRate (entry.GetFee (), entry.GetTxSize ());
376
341
377
- // Want the priority of the tx at confirmation. However we don't know
378
- // what that will be and its too hard to continue updating it
379
- // so use starting priority as a proxy
380
- double curPri = entry.GetPriority (txHeight);
381
342
mapMemPoolTxs[hash].blockHeight = txHeight;
382
-
383
- LogPrint (" estimatefee" , " Blockpolicy mempool tx %s " , hash.ToString ().substr (0 ,10 ));
384
- // Record this as a priority estimate
385
- if (entry.GetFee () == 0 || isPriDataPoint (feeRate, curPri)) {
386
- mapMemPoolTxs[hash].stats = &priStats;
387
- mapMemPoolTxs[hash].bucketIndex = priStats.NewTx (txHeight, curPri);
388
- }
389
- // Record this as a fee estimate
390
- else if (isFeeDataPoint (feeRate, curPri)) {
391
- mapMemPoolTxs[hash].stats = &feeStats;
392
- mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx (txHeight, (double )feeRate.GetFeePerK ());
393
- }
394
- else {
395
- LogPrint (" estimatefee" , " not adding" );
396
- }
397
- LogPrint (" estimatefee" , " \n " );
343
+ mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx (txHeight, (double )feeRate.GetFeePerK ());
398
344
}
399
345
400
346
void CBlockPolicyEstimator::processBlockTx (unsigned int nBlockHeight, const CTxMemPoolEntry& entry)
@@ -417,21 +363,10 @@ void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
417
363
return ;
418
364
}
419
365
420
- // Fees are stored and reported as BTC-per-kb:
366
+ // Feerates are stored and reported as BTC-per-kb:
421
367
CFeeRate feeRate (entry.GetFee (), entry.GetTxSize ());
422
368
423
- // Want the priority of the tx at confirmation. The priority when it
424
- // entered the mempool could easily be very small and change quickly
425
- double curPri = entry.GetPriority (nBlockHeight);
426
-
427
- // Record this as a priority estimate
428
- if (entry.GetFee () == 0 || isPriDataPoint (feeRate, curPri)) {
429
- priStats.Record (blocksToConfirm, curPri);
430
- }
431
- // Record this as a fee estimate
432
- else if (isFeeDataPoint (feeRate, curPri)) {
433
- feeStats.Record (blocksToConfirm, (double )feeRate.GetFeePerK ());
434
- }
369
+ feeStats.Record (blocksToConfirm, (double )feeRate.GetFeePerK ());
435
370
}
436
371
437
372
void CBlockPolicyEstimator::processBlock (unsigned int nBlockHeight,
@@ -452,41 +387,15 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
452
387
if (!fCurrentEstimate )
453
388
return ;
454
389
455
- // Update the dynamic cutoffs
456
- // a fee/priority is "likely" the reason your tx was included in a block if >85% of such tx's
457
- // were confirmed in 2 blocks and is "unlikely" if <50% were confirmed in 10 blocks
458
- LogPrint (" estimatefee" , " Blockpolicy recalculating dynamic cutoffs:\n " );
459
- priLikely = priStats.EstimateMedianVal (2 , SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true , nBlockHeight);
460
- if (priLikely == -1 )
461
- priLikely = INF_PRIORITY;
462
-
463
- double feeLikelyEst = feeStats.EstimateMedianVal (2 , SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true , nBlockHeight);
464
- if (feeLikelyEst == -1 )
465
- feeLikely = CFeeRate (INF_FEERATE);
466
- else
467
- feeLikely = CFeeRate (feeLikelyEst);
468
-
469
- priUnlikely = priStats.EstimateMedianVal (10 , SUFFICIENT_PRITXS, UNLIKELY_PCT, false , nBlockHeight);
470
- if (priUnlikely == -1 )
471
- priUnlikely = 0 ;
472
-
473
- double feeUnlikelyEst = feeStats.EstimateMedianVal (10 , SUFFICIENT_FEETXS, UNLIKELY_PCT, false , nBlockHeight);
474
- if (feeUnlikelyEst == -1 )
475
- feeUnlikely = CFeeRate (0 );
476
- else
477
- feeUnlikely = CFeeRate (feeUnlikelyEst);
478
-
479
- // Clear the current block states
390
+ // Clear the current block state
480
391
feeStats.ClearCurrent (nBlockHeight);
481
- priStats.ClearCurrent (nBlockHeight);
482
392
483
393
// Repopulate the current block states
484
394
for (unsigned int i = 0 ; i < entries.size (); i++)
485
395
processBlockTx (nBlockHeight, entries[i]);
486
396
487
- // Update all exponential averages with the current block states
397
+ // Update all exponential averages with the current block state
488
398
feeStats.UpdateMovingAverages ();
489
- priStats.UpdateMovingAverages ();
490
399
491
400
LogPrint (" estimatefee" , " Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n " ,
492
401
entries.size (), mapMemPoolTxs.size ());
@@ -522,7 +431,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
522
431
if (answerFoundAtTarget)
523
432
*answerFoundAtTarget = confTarget - 1 ;
524
433
525
- // If mempool is limiting txs , return at least the min fee from the mempool
434
+ // If mempool is limiting txs , return at least the min feerate from the mempool
526
435
CAmount minPoolFee = pool.GetMinFee (GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 ).GetFeePerK ();
527
436
if (minPoolFee > 0 && minPoolFee > median)
528
437
return CFeeRate (minPoolFee);
@@ -535,51 +444,38 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
535
444
536
445
double CBlockPolicyEstimator::estimatePriority (int confTarget)
537
446
{
538
- // Return failure if trying to analyze a target we're not tracking
539
- if (confTarget <= 0 || (unsigned int )confTarget > priStats.GetMaxConfirms ())
540
- return -1 ;
541
-
542
- return priStats.EstimateMedianVal (confTarget, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true , nBestSeenHeight);
447
+ return -1 ;
543
448
}
544
449
545
450
double CBlockPolicyEstimator::estimateSmartPriority (int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
546
451
{
547
452
if (answerFoundAtTarget)
548
453
*answerFoundAtTarget = confTarget;
549
- // Return failure if trying to analyze a target we're not tracking
550
- if (confTarget <= 0 || (unsigned int )confTarget > priStats.GetMaxConfirms ())
551
- return -1 ;
552
454
553
455
// If mempool is limiting txs, no priority txs are allowed
554
456
CAmount minPoolFee = pool.GetMinFee (GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 ).GetFeePerK ();
555
457
if (minPoolFee > 0 )
556
458
return INF_PRIORITY;
557
459
558
- double median = -1 ;
559
- while (median < 0 && (unsigned int )confTarget <= priStats.GetMaxConfirms ()) {
560
- median = priStats.EstimateMedianVal (confTarget++, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true , nBestSeenHeight);
561
- }
562
-
563
- if (answerFoundAtTarget)
564
- *answerFoundAtTarget = confTarget - 1 ;
565
-
566
- return median;
460
+ return -1 ;
567
461
}
568
462
569
463
void CBlockPolicyEstimator::Write (CAutoFile& fileout)
570
464
{
571
465
fileout << nBestSeenHeight;
572
466
feeStats.Write (fileout);
573
- priStats.Write (fileout);
574
467
}
575
468
576
- void CBlockPolicyEstimator::Read (CAutoFile& filein)
469
+ void CBlockPolicyEstimator::Read (CAutoFile& filein, int nFileVersion )
577
470
{
578
471
int nFileBestSeenHeight;
579
472
filein >> nFileBestSeenHeight;
580
473
feeStats.Read (filein);
581
- priStats.Read (filein);
582
474
nBestSeenHeight = nFileBestSeenHeight;
475
+ if (nFileVersion < 139900 ) {
476
+ TxConfirmStats priStats;
477
+ priStats.Read (filein);
478
+ }
583
479
}
584
480
585
481
FeeFilterRounder::FeeFilterRounder (const CFeeRate& minIncrementalFee)
0 commit comments