Skip to content

Commit b2322e0

Browse files
morcoslaanwj
authored andcommitted
Remove priority estimation
1 parent ed64bce commit b2322e0

File tree

5 files changed

+101
-251
lines changed

5 files changed

+101
-251
lines changed

src/policy/fees.cpp

Lines changed: 32 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414
#include "util.h"
1515

1616
void 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

249248
unsigned 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

346311
void 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

400346
void 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

437372
void 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

536445
double 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

545450
double 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

569463
void 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

585481
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)

0 commit comments

Comments
 (0)