23 #include <util/time.h> 53 struct EncodedDoubleFormatter
55 template<
typename Stream>
void Ser(Stream &
s,
double v)
60 template<
typename Stream>
void Unser(Stream&
s,
double& v)
127 TxConfirmStats(
const std::vector<double>& defaultBuckets,
const std::map<double, unsigned int>& defaultBucketMap,
128 unsigned int maxPeriods,
double decay,
unsigned int scale);
139 void Record(
int blocksToConfirm,
double val);
142 unsigned int NewTx(
unsigned int nBlockHeight,
double val);
145 void removeTx(
unsigned int entryHeight,
unsigned int nBestSeenHeight,
146 unsigned int bucketIndex,
bool inBlock);
162 double minSuccess,
unsigned int nBlockHeight,
180 const std::map<double, unsigned int>& defaultBucketMap,
181 unsigned int maxPeriods,
double _decay,
unsigned int _scale)
182 : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
184 assert(_scale != 0 &&
"_scale must be non-zero");
187 for (
unsigned int i = 0; i < maxPeriods; i++) {
201 for (
unsigned int i = 0; i <
unconfTxs.size(); i++) {
210 for (
unsigned int j = 0; j <
buckets.size(); j++) {
220 if (blocksToConfirm < 1)
222 int periodsToConfirm = (blocksToConfirm +
scale - 1) /
scale;
223 unsigned int bucketindex =
bucketMap.lower_bound(feerate)->second;
224 for (
size_t i = periodsToConfirm; i <=
confAvg.size(); i++) {
234 for (
unsigned int j = 0; j <
buckets.size(); j++) {
235 for (
unsigned int i = 0; i <
confAvg.size(); i++) {
246 double successBreakPoint,
unsigned int nBlockHeight,
254 const int periodTarget = (confTarget +
scale - 1) /
scale;
255 const int maxbucketindex =
buckets.size() - 1;
262 unsigned int curNearBucket = maxbucketindex;
263 unsigned int bestNearBucket = maxbucketindex;
264 unsigned int curFarBucket = maxbucketindex;
265 unsigned int bestFarBucket = maxbucketindex;
270 double partialNum = 0;
272 bool foundAnswer =
false;
274 bool newBucketRange =
true;
280 for (
int bucket = maxbucketindex; bucket >= 0; --bucket) {
281 if (newBucketRange) {
282 curNearBucket = bucket;
283 newBucketRange =
false;
285 curFarBucket = bucket;
286 nConf +=
confAvg[periodTarget - 1][bucket];
289 failNum +=
failAvg[periodTarget - 1][bucket];
290 for (
unsigned int confct = confTarget; confct <
GetMaxConfirms(); confct++)
291 extraNum +=
unconfTxs[(nBlockHeight - confct) % bins][bucket];
298 if (partialNum < sufficientTxVal / (1 -
decay)) {
305 double curPct = nConf / (totalNum + failNum + extraNum);
308 if (curPct < successBreakPoint) {
309 if (passing ==
true) {
311 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
312 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
313 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
337 bestNearBucket = curNearBucket;
338 bestFarBucket = curFarBucket;
339 newBucketRange =
true;
351 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
352 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
353 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
356 if (foundAnswer && txSum != 0) {
358 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
367 passBucket.
start = minBucket ?
buckets[minBucket-1] : 0;
372 if (passing && !newBucketRange) {
373 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
374 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
375 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
383 float passed_within_target_perc = 0.0;
384 float failed_within_target_perc = 0.0;
392 LogDebug(
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",
393 confTarget, 100.0 * successBreakPoint,
decay,
394 median, passBucket.
start, passBucket.
end,
395 passed_within_target_perc,
398 failed_within_target_perc,
403 result->pass = passBucket;
404 result->fail = failBucket;
413 fileout << Using<EncodedDoubleFormatter>(
decay);
415 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
416 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
417 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
418 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
426 uint64_t maxConfirms, maxPeriods;
429 filein >> Using<EncodedDoubleFormatter>(
decay);
430 if (decay <= 0 || decay >= 1) {
431 throw std::runtime_error(
"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
435 throw std::runtime_error(
"Corrupt estimates file. Scale must be non-zero");
438 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
440 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate average bucket count");
442 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
443 if (
txCtAvg.size() != numBuckets) {
444 throw std::runtime_error(
"Corrupt estimates file. Mismatch in tx count bucket count");
446 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
448 maxConfirms =
scale * maxPeriods;
450 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) {
451 throw std::runtime_error(
"Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
453 for (
unsigned int i = 0; i < maxPeriods; i++) {
454 if (
confAvg[i].size() != numBuckets) {
455 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate conf average bucket count");
459 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
460 if (maxPeriods !=
failAvg.size()) {
461 throw std::runtime_error(
"Corrupt estimates file. Mismatch in confirms tracked for failures");
463 for (
unsigned int i = 0; i < maxPeriods; i++) {
464 if (
failAvg[i].size() != numBuckets) {
465 throw std::runtime_error(
"Corrupt estimates file. Mismatch in one of failure average bucket counts");
474 numBuckets, maxConfirms);
479 unsigned int bucketindex =
bucketMap.lower_bound(val)->second;
480 unsigned int blockIndex = nBlockHeight %
unconfTxs.size();
488 int blocksAgo = nBestSeenHeight - entryHeight;
489 if (nBestSeenHeight == 0)
496 if (blocksAgo >= (
int)
unconfTxs.size()) {
505 unsigned int blockIndex = entryHeight %
unconfTxs.size();
506 if (
unconfTxs[blockIndex][bucketindex] > 0) {
510 blockIndex, bucketindex);
513 if (!inBlock && (
unsigned int)blocksAgo >=
scale) {
515 unsigned int periodsAgo = blocksAgo /
scale;
516 for (
size_t i = 0; i < periodsAgo && i <
failAvg.size(); i++) {
531 std::map<Txid, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
532 if (pos != mapMemPoolTxs.end()) {
533 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
534 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
535 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
536 mapMemPoolTxs.erase(hash);
544 : m_estimation_filepath{estimation_filepath}
546 static_assert(MIN_BUCKET_FEERATE > 0,
"Min feerate must be nonzero");
547 size_t bucketIndex = 0;
549 for (
double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
550 buckets.push_back(bucketBoundary);
551 bucketMap[bucketBoundary] = bucketIndex;
555 assert(bucketMap.size() == buckets.size());
557 feeStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
558 shortStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
559 longStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
563 if (est_file.IsNull()) {
564 LogInfo(
"%s is not found. Continue anyway.", fs::PathToString(m_estimation_filepath));
568 std::chrono::hours file_age = GetFeeEstimatorFileAge();
570 LogWarning(
"Fee estimation file %s too old (age=%lld > %lld hours) and will not be used to avoid serving stale estimates.", fs::PathToString(m_estimation_filepath), Ticks<std::chrono::hours>(file_age), Ticks<std::chrono::hours>(
MAX_FILE_AGE));
574 if (!Read(est_file)) {
575 LogWarning(
"Failed to read fee estimates from %s. Continue anyway.", fs::PathToString(m_estimation_filepath));
600 const auto& hash = tx.
info.
m_tx->GetHash();
601 if (mapMemPoolTxs.contains(hash)) {
607 if (txHeight != nBestSeenHeight) {
623 if (!validForFeeEstimation) {
632 mapMemPoolTxs[hash].blockHeight = txHeight;
633 unsigned int bucketIndex = feeStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
634 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
635 unsigned int bucketIndex2 = shortStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
636 assert(bucketIndex == bucketIndex2);
637 unsigned int bucketIndex3 = longStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
638 assert(bucketIndex == bucketIndex3);
653 if (blocksToConfirm <= 0) {
663 feeStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
664 shortStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
665 longStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
670 unsigned int nBlockHeight)
673 if (nBlockHeight <= nBestSeenHeight) {
685 nBestSeenHeight = nBlockHeight;
688 feeStats->ClearCurrent(nBlockHeight);
689 shortStats->ClearCurrent(nBlockHeight);
690 longStats->ClearCurrent(nBlockHeight);
693 feeStats->UpdateMovingAverages();
694 shortStats->UpdateMovingAverages();
695 longStats->UpdateMovingAverages();
697 unsigned int countedTxs = 0;
699 for (
const auto& tx : txs_removed_for_block) {
704 if (firstRecordedHeight == 0 && countedTxs > 0) {
705 firstRecordedHeight = nBestSeenHeight;
710 LogDebug(
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",
711 countedTxs, txs_removed_for_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
733 stats = shortStats.get();
738 stats = feeStats.get();
742 stats = longStats.get();
750 if (confTarget <= 0 || (
unsigned int)confTarget > stats->
GetMaxConfirms())
752 if (successThreshold > 1)
755 double median = stats->
EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight,
result);
768 return shortStats->GetMaxConfirms();
771 return feeStats->GetMaxConfirms();
774 return longStats->GetMaxConfirms();
782 if (firstRecordedHeight == 0)
return 0;
783 assert(nBestSeenHeight >= firstRecordedHeight);
785 return nBestSeenHeight - firstRecordedHeight;
790 if (historicalFirst == 0)
return 0;
791 assert(historicalBest >= historicalFirst);
795 return historicalBest - historicalFirst;
810 double estimate = -1;
811 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
813 if (confTarget <= shortStats->GetMaxConfirms()) {
816 else if (confTarget <= feeStats->GetMaxConfirms()) {
817 estimate = feeStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight,
result);
820 estimate = longStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight,
result);
822 if (checkShorterHorizon) {
825 if (confTarget > feeStats->GetMaxConfirms()) {
826 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(),
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
827 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
832 if (confTarget > shortStats->GetMaxConfirms()) {
833 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(),
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
834 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
849 double estimate = -1;
851 if (doubleTarget <= shortStats->GetMaxConfirms()) {
854 if (doubleTarget <= feeStats->GetMaxConfirms()) {
856 if (longEstimate > estimate) {
857 estimate = longEstimate;
885 if (confTarget <= 0 || (
unsigned int)confTarget > longStats->GetMaxConfirms()) {
890 if (confTarget == 1) confTarget = 2;
893 if ((
unsigned int)confTarget > maxUsableEstimate) {
894 confTarget = maxUsableEstimate;
898 if (confTarget <= 1)
return CFeeRate(0);
921 feeCalc->
est = tempResult;
926 if (actualEst > median) {
929 feeCalc->
est = tempResult;
934 if (doubleEst > median) {
937 feeCalc->
est = tempResult;
942 if (conservative || median == -1) {
944 if (consEst > median) {
947 feeCalc->
est = tempResult;
966 if (est_file.IsNull() || !
Write(est_file)) {
968 (void)est_file.fclose();
971 if (est_file.fclose() != 0) {
983 fileout << nBestSeenHeight;
985 fileout << firstRecordedHeight << nBestSeenHeight;
988 fileout << historicalFirst << historicalBest;
990 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
991 feeStats->Write(fileout);
992 shortStats->Write(fileout);
993 longStats->Write(fileout);
995 catch (
const std::exception&) {
996 LogWarning(
"Unable to write policy estimator data (non-fatal)");
1006 int nVersionRequired;
1007 filein >> nVersionRequired;
1009 throw std::runtime_error{
strprintf(
"File version (%d) too high to be read.", nVersionRequired)};
1014 unsigned int nFileBestSeenHeight;
1015 filein >> nFileBestSeenHeight;
1018 LogWarning(
"Incompatible old fee estimation data (non-fatal). Version: %d", nVersionRequired);
1020 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
1021 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
1022 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
1023 throw std::runtime_error(
"Corrupt estimates file. Historical block range for estimates is invalid");
1025 std::vector<double> fileBuckets;
1026 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
1027 size_t numBuckets = fileBuckets.
size();
1028 if (numBuckets <= 1 || numBuckets > 1000) {
1029 throw std::runtime_error(
"Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
1035 fileFeeStats->Read(filein, numBuckets);
1036 fileShortStats->Read(filein, numBuckets);
1037 fileLongStats->Read(filein, numBuckets);
1041 buckets = fileBuckets;
1043 for (
unsigned int i = 0; i < buckets.size(); i++) {
1044 bucketMap[buckets[i]] = i;
1048 feeStats = std::move(fileFeeStats);
1049 shortStats = std::move(fileShortStats);
1050 longStats = std::move(fileLongStats);
1052 nBestSeenHeight = nFileBestSeenHeight;
1053 historicalFirst = nFileHistoricalFirst;
1054 historicalBest = nFileHistoricalBest;
1057 catch (
const std::exception& e) {
1058 LogWarning(
"Unable to read policy estimator data (non-fatal): %s", e.what());
1066 const auto startclear{SteadyClock::now()};
1068 size_t num_entries = mapMemPoolTxs.size();
1070 while (!mapMemPoolTxs.empty()) {
1071 auto mi = mapMemPoolTxs.begin();
1074 const auto endclear{SteadyClock::now()};
1075 LogDebug(
BCLog::ESTIMATEFEE,
"Recorded %u unconfirmed txs from mempool in %.3fs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
1081 auto now{fs::file_time_type::clock::now()};
1082 return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
1086 double max_filter_fee_rate,
1087 double fee_filter_spacing)
1089 std::set<double> fee_set;
1093 for (
double bucket_boundary = min_fee_limit;
1094 bucket_boundary <= max_filter_fee_rate;
1095 bucket_boundary *= fee_filter_spacing) {
1097 fee_set.insert(bucket_boundary);
1112 std::set<double>::iterator it =
m_fee_set.lower_bound(currentMinFee);
1118 return static_cast<CAmount>(*it);
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr double MED_DECAY
Decay of .9952 is a half-life of 144 blocks or about 1 day.
CBlockPolicyEstimator(const fs::path &estimation_filepath, bool read_stale_estimates)
Create new BlockPolicyEstimator and initialize stats tracking classes with default values...
std::vector< std::vector< double > > failAvg
void TransactionAddedToMempool(const NewMempoolTransactionInfo &tx, uint64_t) override EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Overridden from CValidationInterface.
CFeeRate estimateFee(int confTarget) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
DEPRECATED.
FILE * fopen(const fs::path &p, const char *mode)
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.
constexpr int CURRENT_FEES_FILE_VERSION
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.
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal...
const bool m_submitted_in_package
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...
void processTransaction(const NewMempoolTransactionInfo &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process a transaction accepted to the mempool.
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)
void ClearCurrent(unsigned int nBlockHeight)
Roll the circular buffer for unconfirmed txs.
const int64_t m_virtual_transaction_size
The virtual transaction size.
static constexpr double SUFFICIENT_TXS_SHORT
Require an avg of 0.5 tx when using short decay since there are fewer blocks considered.
void FlushFeeEstimates() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Record current fee estimations.
std::string SysErrorString(int err)
Return system error string from errno value.
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
void processBlock(const std::vector< RemovedMempoolTransactionInfo > &txs_removed_for_block, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process all the transactions that have been included in a block.
static constexpr double LONG_DECAY
Decay of .99931 is a half-life of 1008 blocks or about 1 week.
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
std::vector< std::vector< double > > confAvg
const bool m_chainstate_is_current
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.
void Read(AutoFile &filein, size_t numBuckets)
Read saved state of estimation data from a file and replace all internal data structures and variable...
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.
FeeFilterRounder(const CFeeRate &min_incremental_fee, FastRandomContext &rng)
Create new FeeFilterRounder.
int64_t size()
Return the size of the file.
bool _removeTx(const Txid &hash, bool inBlock) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
A non-thread-safe helper for the removeTx function.
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...
virtual 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.
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...
void Write(AutoFile &fileout) const
Write state of estimation data to a file.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
static constexpr unsigned int LONG_SCALE
std::vector< std::vector< int > > unconfTxs
const bool m_has_no_mempool_parents
#define LogDebug(category,...)
static constexpr unsigned int MED_SCALE
static constexpr double INF_FEERATE
static const unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren't valid.
const bool m_mempool_limit_bypassed
std::vector< int > oldUnconfTxs
bool Read(AutoFile &filein) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Read estimation data from a file.
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.
static std::string PathToString(const path &path)
Convert path object to a byte string.
const CTransactionRef m_tx
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac...
#define AssertLockNotHeld(cs)
static constexpr unsigned int SHORT_BLOCK_PERIODS
Track confirm delays up to 12 blocks for short horizon.
static constexpr double SUFFICIENT_FEETXS
Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance.
virtual ~CBlockPolicyEstimator()
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.
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:...
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...
virtual unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Calculation of highest target that estimates are tracked for.
const unsigned int txHeight
void MempoolTransactionsRemovedForBlock(const std::vector< RemovedMempoolTransactionInfo > &txs_removed_for_block, unsigned int nBlockHeight) override EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
static std::set< double > MakeFeeSet(const CFeeRate &min_incremental_fee, double max_filter_fee_rate, double fee_filter_spacing)
void TransactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason, uint64_t) override EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Notifies listeners of a transaction leaving mempool.
bool processBlockTx(unsigned int nBlockHeight, const RemovedMempoolTransactionInfo &tx) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Process a transaction confirmed in a block.
bool removeTx(Txid hash) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Remove a transaction from the mempool tracking stats for non BLOCK removal reasons.
const std::set< double > m_fee_set