@@ -55,7 +55,7 @@ class TxConfirmStats
5555
5656 // Sum the total feerate of all tx's in each bucket
5757 // Track the historical moving average of this total over blocks
58- std::vector<double > avg ;
58+ std::vector<double > m_feerate_avg ;
5959
6060 // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
6161 // Combine the total value with the tx counts to calculate the avg feerate per bucket
@@ -114,12 +114,10 @@ class TxConfirmStats
114114 * @param confTarget target number of confirmations
115115 * @param sufficientTxVal required average number of transactions per block in a bucket range
116116 * @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
119117 * @param nBlockHeight the current block height
120118 */
121119 double EstimateMedianVal (int confTarget, double sufficientTxVal,
122- double minSuccess, bool requireGreater, unsigned int nBlockHeight,
120+ double minSuccess, unsigned int nBlockHeight,
123121 EstimationResult *result = nullptr ) const ;
124122
125123 /* * Return the max number of confirms we're tracking */
@@ -139,22 +137,18 @@ class TxConfirmStats
139137TxConfirmStats::TxConfirmStats (const std::vector<double >& defaultBuckets,
140138 const std::map<double , unsigned int >& defaultBucketMap,
141139 unsigned int maxPeriods, double _decay, unsigned int _scale)
142- : buckets(defaultBuckets), bucketMap(defaultBucketMap)
140+ : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
143141{
144- decay = _decay;
145142 assert (_scale != 0 && " _scale must be non-zero" );
146- scale = _scale;
147143 confAvg.resize (maxPeriods);
148- for (unsigned int i = 0 ; i < maxPeriods; i++) {
149- confAvg[i].resize (buckets.size ());
150- }
151144 failAvg.resize (maxPeriods);
152145 for (unsigned int i = 0 ; i < maxPeriods; i++) {
146+ confAvg[i].resize (buckets.size ());
153147 failAvg[i].resize (buckets.size ());
154148 }
155149
156150 txCtAvg.resize (buckets.size ());
157- avg .resize (buckets.size ());
151+ m_feerate_avg .resize (buckets.size ());
158152
159153 resizeInMemoryCounters (buckets.size ());
160154}
@@ -172,68 +166,61 @@ void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {
172166void TxConfirmStats::ClearCurrent (unsigned int nBlockHeight)
173167{
174168 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];
176170 unconfTxs[nBlockHeight%unconfTxs.size ()][j] = 0 ;
177171 }
178172}
179173
180174
181- void TxConfirmStats::Record (int blocksToConfirm, double val )
175+ void TxConfirmStats::Record (int blocksToConfirm, double feerate )
182176{
183177 // blocksToConfirm is 1-based
184178 if (blocksToConfirm < 1 )
185179 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 ;
188182 for (size_t i = periodsToConfirm; i <= confAvg.size (); i++) {
189183 confAvg[i - 1 ][bucketindex]++;
190184 }
191185 txCtAvg[bucketindex]++;
192- avg [bucketindex] += val ;
186+ m_feerate_avg [bucketindex] += feerate ;
193187}
194188
195189void TxConfirmStats::UpdateMovingAverages ()
196190{
191+ assert (confAvg.size () == failAvg.size ());
197192 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;
204199 }
205200}
206201
207202// returns -1 on error conditions
208203double 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
211206{
212207 // Counters for a bucket (or range of buckets)
213208 double nConf = 0 ; // Number of tx's confirmed within the confTarget
214209 double totalNum = 0 ; // Total number of tx's that were ever confirmed
215210 int extraNum = 0 ; // Number of tx's still in mempool for confTarget or longer
216211 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 ;
227214
228215 // We'll combine buckets until we have enough samples.
229216 // The near and far variables will define the range we've combined
230217 // The best variables are the last range we saw which still had a high
231218 // enough confirmation rate to count as success.
232219 // 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 ;
237224
238225 bool foundAnswer = false ;
239226 unsigned int bins = unconfTxs.size ();
@@ -242,8 +229,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
242229 EstimatorBucket passBucket;
243230 EstimatorBucket failBucket;
244231
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) {
247234 if (newBucketRange) {
248235 curNearBucket = bucket;
249236 newBucketRange = false ;
@@ -253,7 +240,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
253240 totalNum += txCtAvg[bucket];
254241 failNum += failAvg[periodTarget - 1 ][bucket];
255242 for (unsigned int confct = confTarget; confct < GetMaxConfirms (); confct++)
256- extraNum += unconfTxs[(nBlockHeight - confct)% bins][bucket];
243+ extraNum += unconfTxs[(nBlockHeight - confct) % bins][bucket];
257244 extraNum += oldUnconfTxs[bucket];
258245 // If we have enough transaction data points in this range of buckets,
259246 // we can test for success
@@ -263,7 +250,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
263250 double curPct = nConf / (totalNum + failNum + extraNum);
264251
265252 // 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) {
267254 if (passing == true ) {
268255 // First time we hit a failure record the failed bucket
269256 unsigned int failMinBucket = std::min (curNearBucket, curFarBucket);
@@ -317,7 +304,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
317304 if (txCtAvg[j] < txSum)
318305 txSum -= txCtAvg[j];
319306 else { // we're in the right bucket
320- median = avg [j] / txCtAvg[j];
307+ median = m_feerate_avg [j] / txCtAvg[j];
321308 break ;
322309 }
323310 }
@@ -338,13 +325,22 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
338325 failBucket.leftMempool = failNum;
339326 }
340327
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,
343339 median, passBucket.start , passBucket.end ,
344- 100 * passBucket. withinTarget / (passBucket. totalConfirmed + passBucket. inMempool + passBucket. leftMempool ) ,
340+ passed_within_target_perc ,
345341 passBucket.withinTarget , passBucket.totalConfirmed , passBucket.inMempool , passBucket.leftMempool ,
346342 failBucket.start , failBucket.end ,
347- 100 * failBucket. withinTarget / (failBucket. totalConfirmed + failBucket. inMempool + failBucket. leftMempool ) ,
343+ failed_within_target_perc ,
348344 failBucket.withinTarget , failBucket.totalConfirmed , failBucket.inMempool , failBucket.leftMempool );
349345
350346
@@ -361,7 +357,7 @@ void TxConfirmStats::Write(CAutoFile& fileout) const
361357{
362358 fileout << decay;
363359 fileout << scale;
364- fileout << avg ;
360+ fileout << m_feerate_avg ;
365361 fileout << txCtAvg;
366362 fileout << confAvg;
367363 fileout << failAvg;
@@ -384,8 +380,8 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
384380 throw std::runtime_error (" Corrupt estimates file. Scale must be non-zero" );
385381 }
386382
387- filein >> avg ;
388- if (avg .size () != numBuckets) {
383+ filein >> m_feerate_avg ;
384+ if (m_feerate_avg .size () != numBuckets) {
389385 throw std::runtime_error (" Corrupt estimates file. Mismatch in feerate average bucket count" );
390386 }
391387 filein >> txCtAvg;
@@ -664,7 +660,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
664660 if (successThreshold > 1 )
665661 return CFeeRate (0 );
666662
667- double median = stats->EstimateMedianVal (confTarget, sufficientTxs, successThreshold, true , nBestSeenHeight, result);
663+ double median = stats->EstimateMedianVal (confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
668664
669665 if (median < 0 )
670666 return CFeeRate (0 );
@@ -725,26 +721,26 @@ double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, doubl
725721 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms ()) {
726722 // Find estimate from shortest time horizon possible
727723 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);
729725 }
730726 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);
732728 }
733729 else { // long horizon
734- estimate = longStats->EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, successThreshold, true , nBestSeenHeight, result);
730+ estimate = longStats->EstimateMedianVal (confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
735731 }
736732 if (checkShorterHorizon) {
737733 EstimationResult tempResult;
738734 // If a lower confTarget from a more recent horizon returns a lower answer use it.
739735 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);
741737 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
742738 estimate = medMax;
743739 if (result) *result = tempResult;
744740 }
745741 }
746742 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);
748744 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
749745 estimate = shortMax;
750746 if (result) *result = tempResult;
@@ -763,10 +759,10 @@ double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget,
763759 double estimate = -1 ;
764760 EstimationResult tempResult;
765761 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);
767763 }
768764 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);
770766 if (longEstimate > estimate) {
771767 estimate = longEstimate;
772768 if (result) *result = tempResult;
0 commit comments