@@ -55,7 +55,7 @@ class TxConfirmStats
55
55
56
56
// Sum the total feerate of all tx's in each bucket
57
57
// Track the historical moving average of this total over blocks
58
- std::vector<double > avg ;
58
+ std::vector<double > m_feerate_avg ;
59
59
60
60
// Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
61
61
// Combine the total value with the tx counts to calculate the avg feerate per bucket
@@ -114,12 +114,10 @@ class TxConfirmStats
114
114
* @param confTarget target number of confirmations
115
115
* @param sufficientTxVal required average number of transactions per block in a bucket range
116
116
* @param minSuccess the success probability we require
117
- * @param requireGreater return the lowest feerate such that all higher values pass minSuccess OR
118
- * return the highest feerate such that all lower values fail minSuccess
119
117
* @param nBlockHeight the current block height
120
118
*/
121
119
double EstimateMedianVal (int confTarget, double sufficientTxVal,
122
- double minSuccess, bool requireGreater, unsigned int nBlockHeight,
120
+ double minSuccess, unsigned int nBlockHeight,
123
121
EstimationResult *result = nullptr ) const ;
124
122
125
123
/* * Return the max number of confirms we're tracking */
@@ -139,22 +137,18 @@ class TxConfirmStats
139
137
TxConfirmStats::TxConfirmStats (const std::vector<double >& defaultBuckets,
140
138
const std::map<double , unsigned int >& defaultBucketMap,
141
139
unsigned int maxPeriods, double _decay, unsigned int _scale)
142
- : buckets(defaultBuckets), bucketMap(defaultBucketMap)
140
+ : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
143
141
{
144
- decay = _decay;
145
142
assert (_scale != 0 && " _scale must be non-zero" );
146
- scale = _scale;
147
143
confAvg.resize (maxPeriods);
148
- for (unsigned int i = 0 ; i < maxPeriods; i++) {
149
- confAvg[i].resize (buckets.size ());
150
- }
151
144
failAvg.resize (maxPeriods);
152
145
for (unsigned int i = 0 ; i < maxPeriods; i++) {
146
+ confAvg[i].resize (buckets.size ());
153
147
failAvg[i].resize (buckets.size ());
154
148
}
155
149
156
150
txCtAvg.resize (buckets.size ());
157
- avg .resize (buckets.size ());
151
+ m_feerate_avg .resize (buckets.size ());
158
152
159
153
resizeInMemoryCounters (buckets.size ());
160
154
}
@@ -172,68 +166,61 @@ void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {
172
166
void TxConfirmStats::ClearCurrent (unsigned int nBlockHeight)
173
167
{
174
168
for (unsigned int j = 0 ; j < buckets.size (); j++) {
175
- oldUnconfTxs[j] += unconfTxs[nBlockHeight% unconfTxs.size ()][j];
169
+ oldUnconfTxs[j] += unconfTxs[nBlockHeight % unconfTxs.size ()][j];
176
170
unconfTxs[nBlockHeight%unconfTxs.size ()][j] = 0 ;
177
171
}
178
172
}
179
173
180
174
181
- void TxConfirmStats::Record (int blocksToConfirm, double val )
175
+ void TxConfirmStats::Record (int blocksToConfirm, double feerate )
182
176
{
183
177
// blocksToConfirm is 1-based
184
178
if (blocksToConfirm < 1 )
185
179
return ;
186
- int periodsToConfirm = (blocksToConfirm + scale - 1 )/ scale;
187
- unsigned int bucketindex = bucketMap.lower_bound (val )->second ;
180
+ int periodsToConfirm = (blocksToConfirm + scale - 1 ) / scale;
181
+ unsigned int bucketindex = bucketMap.lower_bound (feerate )->second ;
188
182
for (size_t i = periodsToConfirm; i <= confAvg.size (); i++) {
189
183
confAvg[i - 1 ][bucketindex]++;
190
184
}
191
185
txCtAvg[bucketindex]++;
192
- avg [bucketindex] += val ;
186
+ m_feerate_avg [bucketindex] += feerate ;
193
187
}
194
188
195
189
void TxConfirmStats::UpdateMovingAverages ()
196
190
{
191
+ assert (confAvg.size () == failAvg.size ());
197
192
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;
193
+ for (unsigned int i = 0 ; i < confAvg.size (); i++) {
194
+ confAvg[i][j] *= decay;
195
+ failAvg[i][j] *= decay;
196
+ }
197
+ m_feerate_avg [j] *= decay;
198
+ txCtAvg[j] *= decay;
204
199
}
205
200
}
206
201
207
202
// returns -1 on error conditions
208
203
double TxConfirmStats::EstimateMedianVal (int confTarget, double sufficientTxVal,
209
- double successBreakPoint, bool requireGreater ,
210
- unsigned int nBlockHeight, EstimationResult *result) const
204
+ double successBreakPoint, unsigned int nBlockHeight ,
205
+ EstimationResult *result) const
211
206
{
212
207
// Counters for a bucket (or range of buckets)
213
208
double nConf = 0 ; // Number of tx's confirmed within the confTarget
214
209
double totalNum = 0 ; // Total number of tx's that were ever confirmed
215
210
int extraNum = 0 ; // Number of tx's still in mempool for confTarget or longer
216
211
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 ;
212
+ const int periodTarget = (confTarget + scale - 1 ) / scale;
213
+ const int maxbucketindex = buckets.size () - 1 ;
227
214
228
215
// We'll combine buckets until we have enough samples.
229
216
// The near and far variables will define the range we've combined
230
217
// The best variables are the last range we saw which still had a high
231
218
// enough confirmation rate to count as success.
232
219
// 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 ;
220
+ unsigned int curNearBucket = maxbucketindex ;
221
+ unsigned int bestNearBucket = maxbucketindex ;
222
+ unsigned int curFarBucket = maxbucketindex ;
223
+ unsigned int bestFarBucket = maxbucketindex ;
237
224
238
225
bool foundAnswer = false ;
239
226
unsigned int bins = unconfTxs.size ();
@@ -242,8 +229,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
242
229
EstimatorBucket passBucket;
243
230
EstimatorBucket failBucket;
244
231
245
- // Start counting from highest(default) or lowest feerate transactions
246
- for (int bucket = startbucket ; bucket >= 0 && bucket <= maxbucketindex; bucket += step ) {
232
+ // Start counting from highest feerate transactions
233
+ for (int bucket = maxbucketindex ; bucket >= 0 ; -- bucket) {
247
234
if (newBucketRange) {
248
235
curNearBucket = bucket;
249
236
newBucketRange = false ;
@@ -253,7 +240,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
253
240
totalNum += txCtAvg[bucket];
254
241
failNum += failAvg[periodTarget - 1 ][bucket];
255
242
for (unsigned int confct = confTarget; confct < GetMaxConfirms (); confct++)
256
- extraNum += unconfTxs[(nBlockHeight - confct)% bins][bucket];
243
+ extraNum += unconfTxs[(nBlockHeight - confct) % bins][bucket];
257
244
extraNum += oldUnconfTxs[bucket];
258
245
// If we have enough transaction data points in this range of buckets,
259
246
// we can test for success
@@ -263,7 +250,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
263
250
double curPct = nConf / (totalNum + failNum + extraNum);
264
251
265
252
// Check to see if we are no longer getting confirmed at the success rate
266
- if ((requireGreater && curPct < successBreakPoint) || (!requireGreater && curPct > successBreakPoint) ) {
253
+ if (curPct < successBreakPoint) {
267
254
if (passing == true ) {
268
255
// First time we hit a failure record the failed bucket
269
256
unsigned int failMinBucket = std::min (curNearBucket, curFarBucket);
@@ -317,7 +304,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
317
304
if (txCtAvg[j] < txSum)
318
305
txSum -= txCtAvg[j];
319
306
else { // we're in the right bucket
320
- median = avg [j] / txCtAvg[j];
307
+ median = m_feerate_avg [j] / txCtAvg[j];
321
308
break ;
322
309
}
323
310
}
@@ -338,13 +325,22 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
338
325
failBucket.leftMempool = failNum;
339
326
}
340
327
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,
328
+ float passed_within_target_perc = 0.0 ;
329
+ float failed_within_target_perc = 0.0 ;
330
+ if ((passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool )) {
331
+ passed_within_target_perc = 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool );
332
+ }
333
+ if ((failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool )) {
334
+ failed_within_target_perc = 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool );
335
+ }
336
+
337
+ LogPrint (BCLog::ESTIMATEFEE, " FeeEst: %d > %.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 " ,
338
+ confTarget, 100.0 * successBreakPoint, decay,
343
339
median, passBucket.start , passBucket.end ,
344
- 100 * passBucket. withinTarget / (passBucket. totalConfirmed + passBucket. inMempool + passBucket. leftMempool ) ,
340
+ passed_within_target_perc ,
345
341
passBucket.withinTarget , passBucket.totalConfirmed , passBucket.inMempool , passBucket.leftMempool ,
346
342
failBucket.start , failBucket.end ,
347
- 100 * failBucket. withinTarget / (failBucket. totalConfirmed + failBucket. inMempool + failBucket. leftMempool ) ,
343
+ failed_within_target_perc ,
348
344
failBucket.withinTarget , failBucket.totalConfirmed , failBucket.inMempool , failBucket.leftMempool );
349
345
350
346
@@ -361,7 +357,7 @@ void TxConfirmStats::Write(CAutoFile& fileout) const
361
357
{
362
358
fileout << decay;
363
359
fileout << scale;
364
- fileout << avg ;
360
+ fileout << m_feerate_avg ;
365
361
fileout << txCtAvg;
366
362
fileout << confAvg;
367
363
fileout << failAvg;
@@ -384,8 +380,8 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
384
380
throw std::runtime_error (" Corrupt estimates file. Scale must be non-zero" );
385
381
}
386
382
387
- filein >> avg ;
388
- if (avg .size () != numBuckets) {
383
+ filein >> m_feerate_avg ;
384
+ if (m_feerate_avg .size () != numBuckets) {
389
385
throw std::runtime_error (" Corrupt estimates file. Mismatch in feerate average bucket count" );
390
386
}
391
387
filein >> txCtAvg;
@@ -664,7 +660,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
664
660
if (successThreshold > 1 )
665
661
return CFeeRate (0 );
666
662
667
- double median = stats->EstimateMedianVal (confTarget, sufficientTxs, successThreshold, true , nBestSeenHeight, result);
663
+ double median = stats->EstimateMedianVal (confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
668
664
669
665
if (median < 0 )
670
666
return CFeeRate (0 );
@@ -725,26 +721,26 @@ double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, doubl
725
721
if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms ()) {
726
722
// Find estimate from shortest time horizon possible
727
723
if (confTarget <= shortStats->GetMaxConfirms ()) { // short horizon
728
- estimate = shortStats->EstimateMedianVal (confTarget, SUFFICIENT_TXS_SHORT, successThreshold, true , nBestSeenHeight, result);
724
+ estimate = shortStats->EstimateMedianVal (confTarget, SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
729
725
}
730
726
else if (confTarget <= feeStats->GetMaxConfirms ()) { // medium horizon
731
- estimate = feeStats->EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, successThreshold, true , nBestSeenHeight, result);
727
+ estimate = feeStats->EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
732
728
}
733
729
else { // long horizon
734
- estimate = longStats->EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, successThreshold, true , nBestSeenHeight, result);
730
+ estimate = longStats->EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
735
731
}
736
732
if (checkShorterHorizon) {
737
733
EstimationResult tempResult;
738
734
// If a lower confTarget from a more recent horizon returns a lower answer use it.
739
735
if (confTarget > feeStats->GetMaxConfirms ()) {
740
- double medMax = feeStats->EstimateMedianVal (feeStats->GetMaxConfirms (), SUFFICIENT_FEETXS, successThreshold, true , nBestSeenHeight, &tempResult);
736
+ double medMax = feeStats->EstimateMedianVal (feeStats->GetMaxConfirms (), SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
741
737
if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
742
738
estimate = medMax;
743
739
if (result) *result = tempResult;
744
740
}
745
741
}
746
742
if (confTarget > shortStats->GetMaxConfirms ()) {
747
- double shortMax = shortStats->EstimateMedianVal (shortStats->GetMaxConfirms (), SUFFICIENT_TXS_SHORT, successThreshold, true , nBestSeenHeight, &tempResult);
743
+ double shortMax = shortStats->EstimateMedianVal (shortStats->GetMaxConfirms (), SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
748
744
if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
749
745
estimate = shortMax;
750
746
if (result) *result = tempResult;
@@ -763,10 +759,10 @@ double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget,
763
759
double estimate = -1 ;
764
760
EstimationResult tempResult;
765
761
if (doubleTarget <= shortStats->GetMaxConfirms ()) {
766
- estimate = feeStats->EstimateMedianVal (doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true , nBestSeenHeight, result);
762
+ estimate = feeStats->EstimateMedianVal (doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, result);
767
763
}
768
764
if (doubleTarget <= feeStats->GetMaxConfirms ()) {
769
- double longEstimate = longStats->EstimateMedianVal (doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true , nBestSeenHeight, &tempResult);
765
+ double longEstimate = longStats->EstimateMedianVal (doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, &tempResult);
770
766
if (longEstimate > estimate) {
771
767
estimate = longEstimate;
772
768
if (result) *result = tempResult;
0 commit comments