@@ -107,7 +107,8 @@ class TxConfirmStats
107
107
* @param nBlockHeight the current block height
108
108
*/
109
109
double EstimateMedianVal (int confTarget, double sufficientTxVal,
110
- double minSuccess, bool requireGreater, unsigned int nBlockHeight) const ;
110
+ double minSuccess, bool requireGreater, unsigned int nBlockHeight,
111
+ EstimationResult *result = nullptr ) const ;
111
112
112
113
/* * Return the max number of confirms we're tracking */
113
114
unsigned int GetMaxConfirms () const { return confAvg.size (); }
@@ -186,7 +187,7 @@ void TxConfirmStats::UpdateMovingAverages()
186
187
// returns -1 on error conditions
187
188
double TxConfirmStats::EstimateMedianVal (int confTarget, double sufficientTxVal,
188
189
double successBreakPoint, bool requireGreater,
189
- unsigned int nBlockHeight) const
190
+ unsigned int nBlockHeight, EstimationResult *result ) const
190
191
{
191
192
// Counters for a bucket (or range of buckets)
192
193
double nConf = 0 ; // Number of tx's confirmed within the confTarget
@@ -215,6 +216,9 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
215
216
bool foundAnswer = false ;
216
217
unsigned int bins = unconfTxs.size ();
217
218
bool newBucketRange = true ;
219
+ bool passing = true ;
220
+ EstimatorBucket passBucket;
221
+ EstimatorBucket failBucket;
218
222
219
223
// Start counting from highest(default) or lowest feerate transactions
220
224
for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
@@ -237,14 +241,30 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
237
241
238
242
// Check to see if we are no longer getting confirmed at the success rate
239
243
if ((requireGreater && curPct < successBreakPoint) || (!requireGreater && curPct > successBreakPoint)) {
244
+ if (passing == true ) {
245
+ // First time we hit a failure record the failed bucket
246
+ unsigned int failMinBucket = std::min (curNearBucket, curFarBucket);
247
+ unsigned int failMaxBucket = std::max (curNearBucket, curFarBucket);
248
+ failBucket.start = failMinBucket ? buckets[failMinBucket - 1 ] : 0 ;
249
+ failBucket.end = buckets[failMaxBucket];
250
+ failBucket.withinTarget = nConf;
251
+ failBucket.totalConfirmed = totalNum;
252
+ failBucket.inMempool = extraNum;
253
+ passing = false ;
254
+ }
240
255
continue ;
241
256
}
242
257
// Otherwise update the cumulative stats, and the bucket variables
243
258
// and reset the counters
244
259
else {
260
+ failBucket = EstimatorBucket (); // Reset any failed bucket, currently passing
245
261
foundAnswer = true ;
262
+ passing = true ;
263
+ passBucket.withinTarget = nConf;
246
264
nConf = 0 ;
265
+ passBucket.totalConfirmed = totalNum;
247
266
totalNum = 0 ;
267
+ passBucket.inMempool = extraNum;
248
268
extraNum = 0 ;
249
269
bestNearBucket = curNearBucket;
250
270
bestFarBucket = curFarBucket;
@@ -260,8 +280,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
260
280
// Find the bucket with the median transaction and then report the average feerate from that bucket
261
281
// This is a compromise between finding the median which we can't since we don't save all tx's
262
282
// and reporting the average which is less accurate
263
- unsigned int minBucket = bestNearBucket < bestFarBucket ? bestNearBucket : bestFarBucket ;
264
- unsigned int maxBucket = bestNearBucket > bestFarBucket ? bestNearBucket : bestFarBucket ;
283
+ unsigned int minBucket = std::min ( bestNearBucket, bestFarBucket) ;
284
+ unsigned int maxBucket = std::max ( bestNearBucket, bestFarBucket) ;
265
285
for (unsigned int j = minBucket; j <= maxBucket; j++) {
266
286
txSum += txCtAvg[j];
267
287
}
@@ -275,13 +295,37 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
275
295
break ;
276
296
}
277
297
}
298
+
299
+ passBucket.start = minBucket ? buckets[minBucket-1 ] : 0 ;
300
+ passBucket.end = buckets[maxBucket];
301
+ }
302
+
303
+ // If we were passing until we reached last few buckets with insufficient data, then report those as failed
304
+ if (passing && !newBucketRange) {
305
+ unsigned int failMinBucket = std::min (curNearBucket, curFarBucket);
306
+ unsigned int failMaxBucket = std::max (curNearBucket, curFarBucket);
307
+ failBucket.start = failMinBucket ? buckets[failMinBucket - 1 ] : 0 ;
308
+ failBucket.end = buckets[failMaxBucket];
309
+ failBucket.withinTarget = nConf;
310
+ failBucket.totalConfirmed = totalNum;
311
+ failBucket.inMempool = extraNum;
278
312
}
279
313
280
- LogPrint (BCLog::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 " ,
281
- confTarget, requireGreater ? " >" : " <" , successBreakPoint,
282
- requireGreater ? " >" : " <" , median, buckets[minBucket], buckets[maxBucket],
283
- 100 * nConf / (totalNum + extraNum), nConf, totalNum, extraNum);
314
+ LogPrint (BCLog::ESTIMATEFEE, " FeeEst: %d %s%.0f%% decay %.5f: need feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f+%d mem) Fail: (%g - %g) %.2f%% %.1f/(%.1f+%d mem)\n " ,
315
+ confTarget, requireGreater ? " >" : " <" , 100.0 * successBreakPoint, decay,
316
+ median, passBucket.start , passBucket.end ,
317
+ 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool ),
318
+ passBucket.withinTarget , passBucket.totalConfirmed , passBucket.inMempool ,
319
+ failBucket.start , failBucket.end ,
320
+ 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool ),
321
+ failBucket.withinTarget , failBucket.totalConfirmed , failBucket.inMempool );
284
322
323
+
324
+ if (result) {
325
+ result->pass = passBucket;
326
+ result->fail = failBucket;
327
+ result->decay = decay;
328
+ }
285
329
return median;
286
330
}
287
331
@@ -537,13 +581,44 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
537
581
538
582
CFeeRate CBlockPolicyEstimator::estimateFee (int confTarget) const
539
583
{
584
+ // It's not possible to get reasonable estimates for confTarget of 1
585
+ if (confTarget <= 1 )
586
+ return CFeeRate (0 );
587
+
588
+ return estimateRawFee (confTarget, DOUBLE_SUCCESS_PCT, FeeEstimateHorizon::MED_HALFLIFE);
589
+ }
590
+
591
+ CFeeRate CBlockPolicyEstimator::estimateRawFee (int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
592
+ {
593
+ TxConfirmStats* stats;
594
+ double sufficientTxs = SUFFICIENT_FEETXS;
595
+ switch (horizon) {
596
+ case FeeEstimateHorizon::SHORT_HALFLIFE: {
597
+ stats = shortStats;
598
+ sufficientTxs = SUFFICIENT_TXS_SHORT;
599
+ break ;
600
+ }
601
+ case FeeEstimateHorizon::MED_HALFLIFE: {
602
+ stats = feeStats;
603
+ break ;
604
+ }
605
+ case FeeEstimateHorizon::LONG_HALFLIFE: {
606
+ stats = longStats;
607
+ break ;
608
+ }
609
+ default : {
610
+ return CFeeRate (0 );
611
+ }
612
+ }
613
+
540
614
LOCK (cs_feeEstimator);
541
615
// Return failure if trying to analyze a target we're not tracking
542
- // It's not possible to get reasonable estimates for confTarget of 1
543
- if (confTarget <= 1 || (unsigned int )confTarget > feeStats->GetMaxConfirms ())
616
+ if (confTarget <= 0 || (unsigned int )confTarget > stats->GetMaxConfirms ())
617
+ return CFeeRate (0 );
618
+ if (successThreshold > 1 )
544
619
return CFeeRate (0 );
545
620
546
- double median = feeStats ->EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT , true , nBestSeenHeight);
621
+ double median = stats ->EstimateMedianVal (confTarget, sufficientTxs, successThreshold , true , nBestSeenHeight, result );
547
622
548
623
if (median < 0 )
549
624
return CFeeRate (0 );
0 commit comments