1414#include " util.h"
1515
1616void TxConfirmStats::Initialize (std::vector<double >& defaultBuckets,
17- unsigned int maxConfirms, double _decay, std::string _dataTypeString )
17+ unsigned int maxConfirms, double _decay)
1818{
1919 decay = _decay;
20- dataTypeString = _dataTypeString;
2120 for (unsigned int i = 0 ; i < defaultBuckets.size (); i++) {
2221 buckets.push_back (defaultBuckets[i]);
2322 bucketMap[defaultBuckets[i]] = i;
@@ -87,10 +86,10 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
8786
8887 int maxbucketindex = buckets.size () - 1 ;
8988
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
9291 // 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.
9493 unsigned int startbucket = requireGreater ? maxbucketindex : 0 ;
9594 int step = requireGreater ? -1 : 1 ;
9695
@@ -107,7 +106,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
107106 bool foundAnswer = false ;
108107 unsigned int bins = unconfTxs.size ();
109108
110- // Start counting from highest(default) or lowest fee/pri transactions
109+ // Start counting from highest(default) or lowest feerate transactions
111110 for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
112111 curFarBucket = bucket;
113112 nConf += confAvg[confTarget - 1 ][bucket];
@@ -145,8 +144,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
145144 double median = -1 ;
146145 double txSum = 0 ;
147146
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
150149 // This is a compromise between finding the median which we can't since we don't save all tx's
151150 // and reporting the average which is less accurate
152151 unsigned int minBucket = bestNearBucket < bestFarBucket ? bestNearBucket : bestFarBucket;
@@ -166,8 +165,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
166165 }
167166 }
168167
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,
171170 requireGreater ? " >" : " <" , median, buckets[minBucket], buckets[maxBucket],
172171 100 * nConf / (totalNum + extraNum), nConf, totalNum, extraNum);
173172
@@ -200,10 +199,10 @@ void TxConfirmStats::Read(CAutoFile& filein)
200199 filein >> fileBuckets;
201200 numBuckets = fileBuckets.size ();
202201 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" );
204203 filein >> fileAvg;
205204 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" );
207206 filein >> fileTxCtAvg;
208207 if (fileTxCtAvg.size () != numBuckets)
209208 throw std::runtime_error (" Corrupt estimates file. Mismatch in tx count bucket count" );
@@ -213,9 +212,9 @@ void TxConfirmStats::Read(CAutoFile& filein)
213212 throw std::runtime_error (" Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms" );
214213 for (unsigned int i = 0 ; i < maxConfirms; i++) {
215214 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" );
217216 }
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
219218 // thrown any errors, we can copy it to our data structures
220219 decay = fileDecay;
221220 buckets = fileBuckets;
@@ -242,16 +241,15 @@ void TxConfirmStats::Read(CAutoFile& filein)
242241 for (unsigned int i = 0 ; i < buckets.size (); i++)
243242 bucketMap[buckets[i]] = i;
244243
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);
247246}
248247
249248unsigned int TxConfirmStats::NewTx (unsigned int nBlockHeight, double val)
250249{
251250 unsigned int bucketindex = bucketMap.lower_bound (val)->second ;
252251 unsigned int blockIndex = nBlockHeight % unconfTxs.size ();
253252 unconfTxs[blockIndex][bucketindex]++;
254- LogPrint (" estimatefee" , " adding to %s" , dataTypeString);
255253 return bucketindex;
256254}
257255
@@ -291,12 +289,10 @@ void CBlockPolicyEstimator::removeTx(uint256 hash)
291289 hash.ToString ().c_str ());
292290 return ;
293291 }
294- TxConfirmStats *stats = pos->second .stats ;
295292 unsigned int entryHeight = pos->second .blockHeight ;
296293 unsigned int bucketIndex = pos->second .bucketIndex ;
297294
298- if (stats != NULL )
299- stats->removeTx (entryHeight, nBestSeenHeight, bucketIndex);
295+ feeStats.removeTx (entryHeight, nBestSeenHeight, bucketIndex);
300296 mapMemPoolTxs.erase (hash);
301297}
302298
@@ -309,45 +305,14 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
309305 vfeelist.push_back (bucketBoundary);
310306 }
311307 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);
344309}
345310
346311void CBlockPolicyEstimator::processTransaction (const CTxMemPoolEntry& entry, bool fCurrentEstimate )
347312{
348313 unsigned int txHeight = entry.GetHeight ();
349314 uint256 hash = entry.GetTx ().GetHash ();
350- if (mapMemPoolTxs[hash]. stats != NULL ) {
315+ if (mapMemPoolTxs. count (hash) ) {
351316 LogPrint (" estimatefee" , " Blockpolicy error mempool tx %s already being tracked\n " ,
352317 hash.ToString ().c_str ());
353318 return ;
@@ -371,30 +336,11 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
371336 return ;
372337 }
373338
374- // Fees are stored and reported as BTC-per-kb:
339+ // Feerates are stored and reported as BTC-per-kb:
375340 CFeeRate feeRate (entry.GetFee (), entry.GetTxSize ());
376341
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);
381342 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 ());
398344}
399345
400346void CBlockPolicyEstimator::processBlockTx (unsigned int nBlockHeight, const CTxMemPoolEntry& entry)
@@ -417,21 +363,10 @@ void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
417363 return ;
418364 }
419365
420- // Fees are stored and reported as BTC-per-kb:
366+ // Feerates are stored and reported as BTC-per-kb:
421367 CFeeRate feeRate (entry.GetFee (), entry.GetTxSize ());
422368
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 ());
435370}
436371
437372void CBlockPolicyEstimator::processBlock (unsigned int nBlockHeight,
@@ -452,41 +387,15 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
452387 if (!fCurrentEstimate )
453388 return ;
454389
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
480391 feeStats.ClearCurrent (nBlockHeight);
481- priStats.ClearCurrent (nBlockHeight);
482392
483393 // Repopulate the current block states
484394 for (unsigned int i = 0 ; i < entries.size (); i++)
485395 processBlockTx (nBlockHeight, entries[i]);
486396
487- // Update all exponential averages with the current block states
397+ // Update all exponential averages with the current block state
488398 feeStats.UpdateMovingAverages ();
489- priStats.UpdateMovingAverages ();
490399
491400 LogPrint (" estimatefee" , " Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n " ,
492401 entries.size (), mapMemPoolTxs.size ());
@@ -522,7 +431,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
522431 if (answerFoundAtTarget)
523432 *answerFoundAtTarget = confTarget - 1 ;
524433
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
526435 CAmount minPoolFee = pool.GetMinFee (GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 ).GetFeePerK ();
527436 if (minPoolFee > 0 && minPoolFee > median)
528437 return CFeeRate (minPoolFee);
@@ -535,51 +444,38 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
535444
536445double CBlockPolicyEstimator::estimatePriority (int confTarget)
537446{
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 ;
543448}
544449
545450double CBlockPolicyEstimator::estimateSmartPriority (int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
546451{
547452 if (answerFoundAtTarget)
548453 *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 ;
552454
553455 // If mempool is limiting txs, no priority txs are allowed
554456 CAmount minPoolFee = pool.GetMinFee (GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 ).GetFeePerK ();
555457 if (minPoolFee > 0 )
556458 return INF_PRIORITY;
557459
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 ;
567461}
568462
569463void CBlockPolicyEstimator::Write (CAutoFile& fileout)
570464{
571465 fileout << nBestSeenHeight;
572466 feeStats.Write (fileout);
573- priStats.Write (fileout);
574467}
575468
576- void CBlockPolicyEstimator::Read (CAutoFile& filein)
469+ void CBlockPolicyEstimator::Read (CAutoFile& filein, int nFileVersion )
577470{
578471 int nFileBestSeenHeight;
579472 filein >> nFileBestSeenHeight;
580473 feeStats.Read (filein);
581- priStats.Read (filein);
582474 nBestSeenHeight = nFileBestSeenHeight;
475+ if (nFileVersion < 139900 ) {
476+ TxConfirmStats priStats;
477+ priStats.Read (filein);
478+ }
583479}
584480
585481FeeFilterRounder::FeeFilterRounder (const CFeeRate& minIncrementalFee)
0 commit comments