@@ -40,7 +40,9 @@ class TxConfirmStats
40
40
// Track the historical moving average of theses totals over blocks
41
41
std::vector<std::vector<double >> confAvg; // confAvg[Y][X]
42
42
43
- std::vector<std::vector<double >> failAvg; // future use
43
+ // Track moving avg of txs which have been evicted from the mempool
44
+ // after failing to be confirmed within Y blocks
45
+ std::vector<std::vector<double >> failAvg; // failAvg[Y][X]
44
46
45
47
// Sum the total feerate of all tx's in each bucket
46
48
// Track the historical moving average of this total over blocks
@@ -89,7 +91,7 @@ class TxConfirmStats
89
91
90
92
/* * Remove a transaction from mempool tracking stats*/
91
93
void removeTx (unsigned int entryHeight, unsigned int nBestSeenHeight,
92
- unsigned int bucketIndex);
94
+ unsigned int bucketIndex, bool inBlock );
93
95
94
96
/* * Update our estimates by decaying our historical moving average and updating
95
97
with the data gathered from the current block */
@@ -135,6 +137,10 @@ TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
135
137
for (unsigned int i = 0 ; i < maxConfirms; i++) {
136
138
confAvg[i].resize (buckets.size ());
137
139
}
140
+ failAvg.resize (maxConfirms);
141
+ for (unsigned int i = 0 ; i < maxConfirms; i++) {
142
+ failAvg[i].resize (buckets.size ());
143
+ }
138
144
139
145
txCtAvg.resize (buckets.size ());
140
146
avg.resize (buckets.size ());
@@ -179,6 +185,8 @@ void TxConfirmStats::UpdateMovingAverages()
179
185
for (unsigned int j = 0 ; j < buckets.size (); j++) {
180
186
for (unsigned int i = 0 ; i < confAvg.size (); i++)
181
187
confAvg[i][j] = confAvg[i][j] * decay;
188
+ for (unsigned int i = 0 ; i < failAvg.size (); i++)
189
+ failAvg[i][j] = failAvg[i][j] * decay;
182
190
avg[j] = avg[j] * decay;
183
191
txCtAvg[j] = txCtAvg[j] * decay;
184
192
}
@@ -193,6 +201,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
193
201
double nConf = 0 ; // Number of tx's confirmed within the confTarget
194
202
double totalNum = 0 ; // Total number of tx's that were ever confirmed
195
203
int extraNum = 0 ; // Number of tx's still in mempool for confTarget or longer
204
+ double failNum = 0 ; // Number of tx's that were never confirmed but removed from the mempool after confTarget
196
205
197
206
int maxbucketindex = buckets.size () - 1 ;
198
207
@@ -229,6 +238,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
229
238
curFarBucket = bucket;
230
239
nConf += confAvg[confTarget - 1 ][bucket];
231
240
totalNum += txCtAvg[bucket];
241
+ failNum += failAvg[confTarget - 1 ][bucket];
232
242
for (unsigned int confct = confTarget; confct < GetMaxConfirms (); confct++)
233
243
extraNum += unconfTxs[(nBlockHeight - confct)%bins][bucket];
234
244
extraNum += oldUnconfTxs[bucket];
@@ -237,7 +247,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
237
247
// (Only count the confirmed data points, so that each confirmation count
238
248
// will be looking at the same amount of data and same bucket breaks)
239
249
if (totalNum >= sufficientTxVal / (1 - decay)) {
240
- double curPct = nConf / (totalNum + extraNum);
250
+ double curPct = nConf / (totalNum + failNum + extraNum);
241
251
242
252
// Check to see if we are no longer getting confirmed at the success rate
243
253
if ((requireGreater && curPct < successBreakPoint) || (!requireGreater && curPct > successBreakPoint)) {
@@ -250,6 +260,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
250
260
failBucket.withinTarget = nConf;
251
261
failBucket.totalConfirmed = totalNum;
252
262
failBucket.inMempool = extraNum;
263
+ failBucket.leftMempool = failNum;
253
264
passing = false ;
254
265
}
255
266
continue ;
@@ -265,6 +276,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
265
276
passBucket.totalConfirmed = totalNum;
266
277
totalNum = 0 ;
267
278
passBucket.inMempool = extraNum;
279
+ passBucket.leftMempool = failNum;
280
+ failNum = 0 ;
268
281
extraNum = 0 ;
269
282
bestNearBucket = curNearBucket;
270
283
bestFarBucket = curFarBucket;
@@ -309,16 +322,17 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
309
322
failBucket.withinTarget = nConf;
310
323
failBucket.totalConfirmed = totalNum;
311
324
failBucket.inMempool = extraNum;
325
+ failBucket.leftMempool = failNum;
312
326
}
313
327
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 " ,
328
+ LogPrint (BCLog::ESTIMATEFEE, " FeeEst: %d %s%.0f%% decay %.5f: need feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f+%d mem+%.1f out ) Fail: (%g - %g) %.2f%% %.1f/(%.1f+%d mem+%.1f out )\n " ,
315
329
confTarget, requireGreater ? " >" : " <" , 100.0 * successBreakPoint, decay,
316
330
median, passBucket.start , passBucket.end ,
317
- 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool ),
318
- passBucket.withinTarget , passBucket.totalConfirmed , passBucket.inMempool ,
331
+ 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket. leftMempool ),
332
+ passBucket.withinTarget , passBucket.totalConfirmed , passBucket.inMempool , passBucket. leftMempool ,
319
333
failBucket.start , failBucket.end ,
320
- 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool ),
321
- failBucket.withinTarget , failBucket.totalConfirmed , failBucket.inMempool );
334
+ 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket. leftMempool ),
335
+ failBucket.withinTarget , failBucket.totalConfirmed , failBucket.inMempool , failBucket. leftMempool );
322
336
323
337
324
338
if (result) {
@@ -376,6 +390,19 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
376
390
377
391
if (nFileVersion >= 149900 ) {
378
392
filein >> failAvg;
393
+ if (maxConfirms != failAvg.size ()) {
394
+ throw std::runtime_error (" Corrupt estimates file. Mismatch in confirms tracked for failures" );
395
+ }
396
+ for (unsigned int i = 0 ; i < maxConfirms; i++) {
397
+ if (failAvg[i].size () != numBuckets) {
398
+ throw std::runtime_error (" Corrupt estimates file. Mismatch in one of failure average bucket counts" );
399
+ }
400
+ }
401
+ } else {
402
+ failAvg.resize (confAvg.size ());
403
+ for (unsigned int i = 0 ; i < failAvg.size (); i++) {
404
+ failAvg[i].resize (numBuckets);
405
+ }
379
406
}
380
407
381
408
// Resize the current block variables which aren't stored in the data file
@@ -394,7 +421,7 @@ unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
394
421
return bucketindex;
395
422
}
396
423
397
- void TxConfirmStats::removeTx (unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex)
424
+ void TxConfirmStats::removeTx (unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock )
398
425
{
399
426
// nBestSeenHeight is not updated yet for the new block
400
427
int blocksAgo = nBestSeenHeight - entryHeight;
@@ -422,21 +449,26 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
422
449
blockIndex, bucketindex);
423
450
}
424
451
}
452
+ if (!inBlock && blocksAgo >= 1 ) {
453
+ for (size_t i = 0 ; i < blocksAgo && i < failAvg.size (); i++) {
454
+ failAvg[i][bucketindex]++;
455
+ }
456
+ }
425
457
}
426
458
427
459
// This function is called from CTxMemPool::removeUnchecked to ensure
428
460
// txs removed from the mempool for any reason are no longer
429
461
// tracked. Txs that were part of a block have already been removed in
430
462
// processBlockTx to ensure they are never double tracked, but it is
431
463
// of no harm to try to remove them again.
432
- bool CBlockPolicyEstimator::removeTx (uint256 hash)
464
+ bool CBlockPolicyEstimator::removeTx (uint256 hash, bool inBlock )
433
465
{
434
466
LOCK (cs_feeEstimator);
435
467
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find (hash);
436
468
if (pos != mapMemPoolTxs.end ()) {
437
- feeStats->removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex );
438
- shortStats->removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex );
439
- longStats->removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex );
469
+ feeStats->removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex , inBlock );
470
+ shortStats->removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex , inBlock );
471
+ longStats->removeTx (pos->second .blockHeight , nBestSeenHeight, pos->second .bucketIndex , inBlock );
440
472
mapMemPoolTxs.erase (hash);
441
473
return true ;
442
474
} else {
@@ -511,7 +543,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
511
543
512
544
bool CBlockPolicyEstimator::processBlockTx (unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
513
545
{
514
- if (!removeTx (entry->GetTx ().GetHash ())) {
546
+ if (!removeTx (entry->GetTx ().GetHash (), true )) {
515
547
// This transaction wasn't being tracked for fee estimation
516
548
return false ;
517
549
}
@@ -766,6 +798,18 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
766
798
return true ;
767
799
}
768
800
801
+ void CBlockPolicyEstimator::FlushUnconfirmed (CTxMemPool& pool) {
802
+ int64_t startclear = GetTimeMicros ();
803
+ std::vector<uint256> txids;
804
+ pool.queryHashes (txids);
805
+ LOCK (cs_feeEstimator);
806
+ for (auto & txid : txids) {
807
+ removeTx (txid, false );
808
+ }
809
+ int64_t endclear = GetTimeMicros ();
810
+ LogPrint (BCLog::ESTIMATEFEE, " Recorded %u unconfirmed txs from mempool in %ld micros\n " ,txids.size (), endclear - startclear);
811
+ }
812
+
769
813
FeeFilterRounder::FeeFilterRounder (const CFeeRate& minIncrementalFee)
770
814
{
771
815
CAmount minFeeLimit = std::max (CAmount (1 ), minIncrementalFee.GetFeePerK () / 2 );
0 commit comments