@@ -477,7 +477,7 @@ bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
477477}
478478
479479CBlockPolicyEstimator::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) {
0 commit comments