Skip to content

Commit 5f1f0c6

Browse files
committed
Historical block span
Store in fee estimate file the block span for which we were tracking estimates, so we know what targets we can successfully evaluate with the data in the file. When restarting use either this historical block span to set valid range of targets until our current span of tracking estimates is just as long.
1 parent aa19b8e commit 5f1f0c6

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

src/policy/fees.cpp

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
477477
}
478478

479479
CBlockPolicyEstimator::CBlockPolicyEstimator()
480-
: nBestSeenHeight(0), firstRecordedHeight(0), trackedTxs(0), untrackedTxs(0)
480+
: nBestSeenHeight(0), firstRecordedHeight(0), historicalFirst(0), historicalBest(0), trackedTxs(0), untrackedTxs(0)
481481
{
482482
static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
483483
minTrackedFee = CFeeRate(MIN_BUCKET_FEERATE);
@@ -609,8 +609,9 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
609609
}
610610

611611

612-
LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy after updating estimates for %u of %u txs in block, since last block %u of %u tracked, new mempool map size %u\n",
613-
countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size());
612+
LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n",
613+
countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
614+
MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");
614615

615616
trackedTxs = 0;
616617
untrackedTxs = 0;
@@ -663,6 +664,29 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
663664
return CFeeRate(median);
664665
}
665666

667+
unsigned int CBlockPolicyEstimator::BlockSpan() const
668+
{
669+
if (firstRecordedHeight == 0) return 0;
670+
assert(nBestSeenHeight >= firstRecordedHeight);
671+
672+
return nBestSeenHeight - firstRecordedHeight;
673+
}
674+
675+
unsigned int CBlockPolicyEstimator::HistoricalBlockSpan() const
676+
{
677+
if (historicalFirst == 0) return 0;
678+
assert(historicalBest >= historicalFirst);
679+
680+
if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;
681+
682+
return historicalBest - historicalFirst;
683+
}
684+
685+
unsigned int CBlockPolicyEstimator::MaxUsableEstimate() const
686+
{
687+
// Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate
688+
return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);
689+
}
666690

667691
/** Return a fee estimate at the required successThreshold from the shortest
668692
* time horizon which tracks confirmations up to the desired target. If
@@ -731,6 +755,14 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
731755
if (confTarget == 1)
732756
confTarget = 2;
733757

758+
unsigned int maxUsableEstimate = MaxUsableEstimate();
759+
if (maxUsableEstimate <= 1)
760+
return CFeeRate(0);
761+
762+
if ((unsigned int)confTarget > maxUsableEstimate) {
763+
confTarget = maxUsableEstimate;
764+
}
765+
734766
assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
735767

736768
/** true is passed to estimateCombined fee for target/2 and target so
@@ -784,8 +816,12 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
784816
fileout << 149900; // version required to read: 0.14.99 or later
785817
fileout << CLIENT_VERSION; // version that wrote the file
786818
fileout << nBestSeenHeight;
787-
unsigned int future1 = 0, future2 = 0;
788-
fileout << future1 << future2;
819+
if (BlockSpan() > HistoricalBlockSpan()/2) {
820+
fileout << firstRecordedHeight << nBestSeenHeight;
821+
}
822+
else {
823+
fileout << historicalFirst << historicalBest;
824+
}
789825
fileout << buckets;
790826
feeStats->Write(fileout);
791827
shortStats->Write(fileout);
@@ -803,7 +839,7 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
803839
try {
804840
LOCK(cs_feeEstimator);
805841
int nVersionRequired, nVersionThatWrote;
806-
unsigned int nFileBestSeenHeight;
842+
unsigned int nFileBestSeenHeight, nFileHistoricalFirst, nFileHistoricalBest;
807843
filein >> nVersionRequired >> nVersionThatWrote;
808844
if (nVersionRequired > CLIENT_VERSION)
809845
return error("CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file", nVersionRequired);
@@ -838,9 +874,10 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
838874
}
839875
}
840876
else { // nVersionThatWrote >= 149900
841-
unsigned int future1, future2;
842-
filein >> future1 >> future2;
843-
877+
filein >> nFileHistoricalFirst >> nFileHistoricalBest;
878+
if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
879+
throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
880+
}
844881
std::vector<double> fileBuckets;
845882
filein >> fileBuckets;
846883
size_t numBuckets = fileBuckets.size();
@@ -871,6 +908,8 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
871908
longStats = fileLongStats.release();
872909

873910
nBestSeenHeight = nFileBestSeenHeight;
911+
historicalFirst = nFileHistoricalFirst;
912+
historicalBest = nFileHistoricalBest;
874913
}
875914
}
876915
catch (const std::exception& e) {

src/policy/fees.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ class CBlockPolicyEstimator
9898
static constexpr unsigned int MED_BLOCK_CONFIRMS = 48;
9999
/** Track confirm delays up to 1008 blocks for longer decay */
100100
static constexpr unsigned int LONG_BLOCK_CONFIRMS = 1008;
101+
/** Historical estimates that are older than this aren't valid */
102+
static const unsigned int OLDEST_ESTIMATE_HISTORY = 6 * 1008;
101103

102104
/** Decay of .962 is a half-life of 18 blocks or about 3 hours */
103105
static constexpr double SHORT_DECAY = .962;
@@ -205,6 +207,9 @@ class CBlockPolicyEstimator
205207

206208
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon) const;
207209
double estimateConservativeFee(unsigned int doubleTarget) const;
210+
unsigned int BlockSpan() const;
211+
unsigned int HistoricalBlockSpan() const;
212+
unsigned int MaxUsableEstimate() const;
208213
};
209214

210215
class FeeFilterRounder

0 commit comments

Comments
 (0)