49 struct EncodedDoubleFormatter
51 template<
typename Stream>
void Ser(Stream &s,
double v)
56 template<
typename Stream>
void Unser(Stream& s,
double& v)
123 TxConfirmStats(
const std::vector<double>& defaultBuckets,
const std::map<double, unsigned int>& defaultBucketMap,
124 unsigned int maxPeriods,
double decay,
unsigned int scale);
135 void Record(
int blocksToConfirm,
double val);
138 unsigned int NewTx(
unsigned int nBlockHeight,
double val);
141 void removeTx(
unsigned int entryHeight,
unsigned int nBestSeenHeight,
142 unsigned int bucketIndex,
bool inBlock);
158 double minSuccess,
unsigned int nBlockHeight,
171 void Read(
AutoFile& filein,
int nFileVersion,
size_t numBuckets);
176 const std::map<double, unsigned int>& defaultBucketMap,
177 unsigned int maxPeriods,
double _decay,
unsigned int _scale)
178 : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
180 assert(_scale != 0 &&
"_scale must be non-zero");
183 for (
unsigned int i = 0; i < maxPeriods; i++) {
197 for (
unsigned int i = 0; i <
unconfTxs.size(); i++) {
206 for (
unsigned int j = 0; j <
buckets.size(); j++) {
216 if (blocksToConfirm < 1)
218 int periodsToConfirm = (blocksToConfirm +
scale - 1) /
scale;
219 unsigned int bucketindex =
bucketMap.lower_bound(feerate)->second;
220 for (
size_t i = periodsToConfirm; i <=
confAvg.size(); i++) {
230 for (
unsigned int j = 0; j <
buckets.size(); j++) {
231 for (
unsigned int i = 0; i <
confAvg.size(); i++) {
242 double successBreakPoint,
unsigned int nBlockHeight,
250 const int periodTarget = (confTarget +
scale - 1) /
scale;
251 const int maxbucketindex =
buckets.size() - 1;
258 unsigned int curNearBucket = maxbucketindex;
259 unsigned int bestNearBucket = maxbucketindex;
260 unsigned int curFarBucket = maxbucketindex;
261 unsigned int bestFarBucket = maxbucketindex;
263 bool foundAnswer =
false;
265 bool newBucketRange =
true;
271 for (
int bucket = maxbucketindex; bucket >= 0; --bucket) {
272 if (newBucketRange) {
273 curNearBucket = bucket;
274 newBucketRange =
false;
276 curFarBucket = bucket;
277 nConf +=
confAvg[periodTarget - 1][bucket];
279 failNum +=
failAvg[periodTarget - 1][bucket];
280 for (
unsigned int confct = confTarget; confct <
GetMaxConfirms(); confct++)
281 extraNum +=
unconfTxs[(nBlockHeight - confct) % bins][bucket];
287 if (totalNum >= sufficientTxVal / (1 -
decay)) {
288 double curPct = nConf / (totalNum + failNum + extraNum);
291 if (curPct < successBreakPoint) {
292 if (passing ==
true) {
294 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
295 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
296 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
320 bestNearBucket = curNearBucket;
321 bestFarBucket = curFarBucket;
322 newBucketRange =
true;
334 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
335 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
336 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
339 if (foundAnswer && txSum != 0) {
341 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
350 passBucket.
start = minBucket ?
buckets[minBucket-1] : 0;
355 if (passing && !newBucketRange) {
356 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
357 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
358 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
366 float passed_within_target_perc = 0.0;
367 float failed_within_target_perc = 0.0;
375 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",
376 confTarget, 100.0 * successBreakPoint,
decay,
377 median, passBucket.
start, passBucket.
end,
378 passed_within_target_perc,
381 failed_within_target_perc,
386 result->
pass = passBucket;
387 result->
fail = failBucket;
396 fileout << Using<EncodedDoubleFormatter>(
decay);
398 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
399 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
400 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
401 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
409 size_t maxConfirms, maxPeriods;
412 filein >> Using<EncodedDoubleFormatter>(
decay);
413 if (decay <= 0 || decay >= 1) {
414 throw std::runtime_error(
"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
418 throw std::runtime_error(
"Corrupt estimates file. Scale must be non-zero");
421 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
423 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate average bucket count");
425 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
426 if (
txCtAvg.size() != numBuckets) {
427 throw std::runtime_error(
"Corrupt estimates file. Mismatch in tx count bucket count");
429 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
431 maxConfirms =
scale * maxPeriods;
433 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) {
434 throw std::runtime_error(
"Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
436 for (
unsigned int i = 0; i < maxPeriods; i++) {
437 if (
confAvg[i].size() != numBuckets) {
438 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate conf average bucket count");
442 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
443 if (maxPeriods !=
failAvg.size()) {
444 throw std::runtime_error(
"Corrupt estimates file. Mismatch in confirms tracked for failures");
446 for (
unsigned int i = 0; i < maxPeriods; i++) {
447 if (
failAvg[i].size() != numBuckets) {
448 throw std::runtime_error(
"Corrupt estimates file. Mismatch in one of failure average bucket counts");
457 numBuckets, maxConfirms);
462 unsigned int bucketindex =
bucketMap.lower_bound(val)->second;
463 unsigned int blockIndex = nBlockHeight %
unconfTxs.size();
471 int blocksAgo = nBestSeenHeight - entryHeight;
472 if (nBestSeenHeight == 0)
479 if (blocksAgo >= (
int)
unconfTxs.size()) {
488 unsigned int blockIndex = entryHeight %
unconfTxs.size();
489 if (
unconfTxs[blockIndex][bucketindex] > 0) {
493 blockIndex, bucketindex);
496 if (!inBlock && (
unsigned int)blocksAgo >=
scale) {
498 unsigned int periodsAgo = blocksAgo /
scale;
499 for (
size_t i = 0; i < periodsAgo && i <
failAvg.size(); i++) {
519 std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
520 if (pos != mapMemPoolTxs.end()) {
521 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
522 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
523 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
524 mapMemPoolTxs.erase(hash);
532 : m_estimation_filepath{estimation_filepath}
534 static_assert(MIN_BUCKET_FEERATE > 0,
"Min feerate must be nonzero");
535 size_t bucketIndex = 0;
537 for (
double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
538 buckets.push_back(bucketBoundary);
539 bucketMap[bucketBoundary] = bucketIndex;
543 assert(bucketMap.size() == buckets.size());
545 feeStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
546 shortStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
547 longStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
551 if (est_file.IsNull()) {
556 std::chrono::hours file_age = GetFeeEstimatorFileAge();
558 LogPrintf(
"Fee estimation file %s too old (age=%lld > %lld hours) and will not be used to avoid serving stale estimates.\n",
fs::PathToString(m_estimation_filepath), Ticks<std::chrono::hours>(file_age), Ticks<std::chrono::hours>(
MAX_FILE_AGE));
562 if (!Read(est_file)) {
572 unsigned int txHeight = entry.
GetHeight();
574 if (mapMemPoolTxs.count(hash)) {
580 if (txHeight != nBestSeenHeight) {
590 if (!validFeeEstimate) {
599 mapMemPoolTxs[hash].blockHeight = txHeight;
600 unsigned int bucketIndex = feeStats->NewTx(txHeight, (
double)feeRate.GetFeePerK());
601 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
602 unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (
double)feeRate.GetFeePerK());
603 assert(bucketIndex == bucketIndex2);
604 unsigned int bucketIndex3 = longStats->NewTx(txHeight, (
double)feeRate.GetFeePerK());
605 assert(bucketIndex == bucketIndex3);
619 int blocksToConfirm = nBlockHeight - entry->
GetHeight();
620 if (blocksToConfirm <= 0) {
630 feeStats->Record(blocksToConfirm, (
double)feeRate.GetFeePerK());
631 shortStats->Record(blocksToConfirm, (
double)feeRate.GetFeePerK());
632 longStats->Record(blocksToConfirm, (
double)feeRate.GetFeePerK());
637 std::vector<const CTxMemPoolEntry*>& entries)
640 if (nBlockHeight <= nBestSeenHeight) {
652 nBestSeenHeight = nBlockHeight;
655 feeStats->ClearCurrent(nBlockHeight);
656 shortStats->ClearCurrent(nBlockHeight);
657 longStats->ClearCurrent(nBlockHeight);
660 feeStats->UpdateMovingAverages();
661 shortStats->UpdateMovingAverages();
662 longStats->UpdateMovingAverages();
664 unsigned int countedTxs = 0;
666 for (
const auto& entry : entries) {
671 if (firstRecordedHeight == 0 && countedTxs > 0) {
672 firstRecordedHeight = nBestSeenHeight;
677 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",
678 countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
700 stats = shortStats.get();
705 stats = feeStats.get();
709 stats = longStats.get();
717 if (confTarget <= 0 || (
unsigned int)confTarget > stats->
GetMaxConfirms())
719 if (successThreshold > 1)
722 double median = stats->
EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
735 return shortStats->GetMaxConfirms();
738 return feeStats->GetMaxConfirms();
741 return longStats->GetMaxConfirms();
749 if (firstRecordedHeight == 0)
return 0;
750 assert(nBestSeenHeight >= firstRecordedHeight);
752 return nBestSeenHeight - firstRecordedHeight;
757 if (historicalFirst == 0)
return 0;
758 assert(historicalBest >= historicalFirst);
762 return historicalBest - historicalFirst;
777 double estimate = -1;
778 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
780 if (confTarget <= shortStats->GetMaxConfirms()) {
781 estimate = shortStats->EstimateMedianVal(confTarget,
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
783 else if (confTarget <= feeStats->GetMaxConfirms()) {
784 estimate = feeStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
787 estimate = longStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
789 if (checkShorterHorizon) {
792 if (confTarget > feeStats->GetMaxConfirms()) {
793 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(),
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
794 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
796 if (result) *result = tempResult;
799 if (confTarget > shortStats->GetMaxConfirms()) {
800 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(),
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
801 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
803 if (result) *result = tempResult;
816 double estimate = -1;
818 if (doubleTarget <= shortStats->GetMaxConfirms()) {
821 if (doubleTarget <= feeStats->GetMaxConfirms()) {
823 if (longEstimate > estimate) {
824 estimate = longEstimate;
825 if (result) *result = tempResult;
851 if (confTarget <= 0 || (
unsigned int)confTarget > longStats->GetMaxConfirms()) {
856 if (confTarget == 1) confTarget = 2;
859 if ((
unsigned int)confTarget > maxUsableEstimate) {
860 confTarget = maxUsableEstimate;
864 if (confTarget <= 1)
return CFeeRate(0);
879 feeCalc->
est = tempResult;
884 if (actualEst > median) {
887 feeCalc->
est = tempResult;
892 if (doubleEst > median) {
895 feeCalc->
est = tempResult;
900 if (conservative || median == -1) {
902 if (consEst > median) {
905 feeCalc->
est = tempResult;
924 if (est_file.IsNull() || !
Write(est_file)) {
937 fileout << nBestSeenHeight;
939 fileout << firstRecordedHeight << nBestSeenHeight;
942 fileout << historicalFirst << historicalBest;
944 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
945 feeStats->Write(fileout);
946 shortStats->Write(fileout);
947 longStats->Write(fileout);
949 catch (
const std::exception&) {
950 LogPrintf(
"CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
960 int nVersionRequired, nVersionThatWrote;
961 filein >> nVersionRequired >> nVersionThatWrote;
963 throw std::runtime_error(
strprintf(
"up-version (%d) fee estimate file", nVersionRequired));
968 unsigned int nFileBestSeenHeight;
969 filein >> nFileBestSeenHeight;
971 if (nVersionRequired < 149900) {
972 LogPrintf(
"%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
974 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
975 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
976 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
977 throw std::runtime_error(
"Corrupt estimates file. Historical block range for estimates is invalid");
979 std::vector<double> fileBuckets;
980 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
981 size_t numBuckets = fileBuckets.size();
982 if (numBuckets <= 1 || numBuckets > 1000) {
983 throw std::runtime_error(
"Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
989 fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
990 fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
991 fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
995 buckets = fileBuckets;
997 for (
unsigned int i = 0; i < buckets.size(); i++) {
998 bucketMap[buckets[i]] = i;
1002 feeStats = std::move(fileFeeStats);
1003 shortStats = std::move(fileShortStats);
1004 longStats = std::move(fileLongStats);
1006 nBestSeenHeight = nFileBestSeenHeight;
1007 historicalFirst = nFileHistoricalFirst;
1008 historicalBest = nFileHistoricalBest;
1011 catch (
const std::exception& e) {
1012 LogPrintf(
"CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
1020 const auto startclear{SteadyClock::now()};
1022 size_t num_entries = mapMemPoolTxs.size();
1024 while (!mapMemPoolTxs.empty()) {
1025 auto mi = mapMemPoolTxs.begin();
1028 const auto endclear{SteadyClock::now()};
1029 LogPrint(
BCLog::ESTIMATEFEE,
"Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
1035 auto now = std::filesystem::file_time_type::clock::now();
1036 return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
1040 double max_filter_fee_rate,
1041 double fee_filter_spacing)
1043 std::set<double> fee_set;
1047 for (
double bucket_boundary = min_fee_limit;
1048 bucket_boundary <= max_filter_fee_rate;
1049 bucket_boundary *= fee_filter_spacing) {
1051 fee_set.insert(bucket_boundary);
1066 std::set<double>::iterator it =
m_fee_set.lower_bound(currentMinFee);
1072 return static_cast<CAmount>(*it);
static constexpr double MED_DECAY
Decay of .9952 is a half-life of 144 blocks or about 1 day.
std::vector< std::vector< double > > failAvg
bool _removeTx(const uint256 &hash, bool inBlock) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
A non-thread-safe helper for the removeTx function.
CFeeRate estimateFee(int confTarget) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
DEPRECATED.
void processBlock(unsigned int nBlockHeight, std::vector< const CTxMemPoolEntry *> &entries) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process all the transactions that have been included in a block.
bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry *entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Process a transaction confirmed in a block.
#define LogPrint(category,...)
FILE * fopen(const fs::path &p, const char *mode)
int32_t GetTxSize() const
static constexpr double HALF_SUCCESS_PCT
Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks.
static constexpr unsigned int MED_BLOCK_PERIODS
Track confirm delays up to 48 blocks for medium horizon.
TxConfirmStats(const std::vector< double > &defaultBuckets, const std::map< double, unsigned int > &defaultBucketMap, unsigned int maxPeriods, double decay, unsigned int scale)
Create new TxConfirmStats.
double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
static constexpr std::chrono::hours MAX_FILE_AGE
fee_estimates.dat that are more than 60 hours (2.5 days) old will not be read, as fee estimates are b...
unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of recorded fee estimate data represented in saved data file.
static constexpr double MAX_FILTER_FEERATE
We will instantiate an instance of this class to track transactions that were included in a block...
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
static constexpr double DOUBLE_SUCCESS_PCT
Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks.
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Calculation of highest target that reasonable estimate can be provided for.
void Record(int blocksToConfirm, double val)
Record a new transaction data point in the current block stats.
Mutex m_insecure_rand_mutex
Non-refcounted RAII wrapper for FILE*.
uint64_t EncodeDouble(double f) noexcept
void resizeInMemoryCounters(size_t newbuckets)
bool removeTx(uint256 hash, bool inBlock) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Remove a transaction from the mempool tracking stats.
void ClearCurrent(unsigned int nBlockHeight)
Roll the circular buffer for unconfirmed txs.
static constexpr double SUFFICIENT_TXS_SHORT
Require an avg of 0.5 tx when using short decay since there are fewer blocks considered.
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
void FlushFeeEstimates() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Record current fee estimations.
static constexpr double FEE_FILTER_SPACING
FEE_FILTER_SPACING is just used to provide some quantization of fee filter results.
int64_t CAmount
Amount in satoshis (Can be negative)
std::chrono::hours GetFeeEstimatorFileAge()
Calculates the age of the file, since last modified.
static constexpr double SUCCESS_PCT
Require greater than 85% of X feerate transactions to be confirmed within Y blocks.
double EstimateMedianVal(int confTarget, double sufficientTxVal, double minSuccess, unsigned int nBlockHeight, EstimationResult *result=nullptr) const
Calculate a feerate estimate.
const std::map< double, unsigned int > & bucketMap
static constexpr unsigned int SHORT_SCALE
static constexpr double LONG_DECAY
Decay of .99931 is a half-life of 1008 blocks or about 1 week.
std::vector< std::vector< double > > confAvg
static std::string PathToString(const path &path)
Convert path object to a byte string.
bool Write(AutoFile &fileout) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Write estimation data to a file.
unsigned int NewTx(unsigned int nBlockHeight, double val)
Record a new transaction entering the mempool.
unsigned int GetHeight() const
void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketIndex, bool inBlock)
Remove a transaction from mempool tracking stats.
CAmount round(CAmount currentMinFee) EXCLUSIVE_LOCKS_REQUIRED(!m_insecure_rand_mutex)
Quantize a minimum fee for privacy purpose before broadcast.
const uint256 & GetHash() const
const CAmount & GetFee() const
FeeFilterRounder(const CFeeRate &min_incremental_fee, FastRandomContext &rng)
Create new FeeFilterRounder.
double DecodeDouble(uint64_t v) noexcept
const std::vector< double > & buckets
unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of data recorded while fee estimates have been running.
void Flush() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Drop still unconfirmed transactions and record current estimations, if the fee estimation file is pre...
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Estimate feerate needed to get be included in a block within confTarget blocks.
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
std::string ToString() const
void Read(AutoFile &filein, int nFileVersion, size_t numBuckets)
Read saved state of estimation data from a file and replace all internal data structures and variable...
void processTransaction(const CTxMemPoolEntry &entry, bool validFeeEstimate) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process a transaction accepted to the mempool.
void Write(AutoFile &fileout) const
Write state of estimation data to a file.
CBlockPolicyEstimator(const fs::path &estimation_filepath, const bool read_stale_estimates)
Create new BlockPolicyEstimator and initialize stats tracking classes with default values...
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
static constexpr unsigned int LONG_SCALE
std::vector< std::vector< int > > unconfTxs
static constexpr unsigned int MED_SCALE
static const unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren't valid.
std::vector< int > oldUnconfTxs
bool Read(AutoFile &filein) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Read estimation data from a file.
const CTransaction & GetTx() const
unsigned int GetMaxConfirms() const
Return the max number of confirms we're tracking.
static constexpr unsigned int LONG_BLOCK_PERIODS
Track confirm delays up to 1008 blocks for long horizon.
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
#define AssertLockNotHeld(cs)
static constexpr unsigned int SHORT_BLOCK_PERIODS
Track confirm delays up to 12 blocks for short horizon.
static constexpr double INF_FEERATE
static constexpr double SUFFICIENT_FEETXS
Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance.
std::vector< double > m_feerate_avg
static constexpr double SHORT_DECAY
Decay of .962 is a half-life of 18 blocks or about 3 hours.
static std::set< double > MakeFeeSet(const CFeeRate &min_incremental_fee, double max_filter_fee_rate, double fee_filter_spacing)
std::vector< double > txCtAvg
void UpdateMovingAverages()
Update our estimates by decaying our historical moving average and updating with the data gathered fr...
CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result=nullptr) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Return a specific fee estimate calculation with a given success threshold and time horizon...
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
const fs::path m_estimation_filepath
void FlushUnconfirmed() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool...
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Calculation of highest target that estimates are tracked for.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
const std::set< double > m_fee_set