52 struct EncodedDoubleFormatter
54 template<
typename Stream>
void Ser(Stream &
s,
double v)
59 template<
typename Stream>
void Unser(Stream&
s,
double& v)
126 TxConfirmStats(
const std::vector<double>& defaultBuckets,
const std::map<double, unsigned int>& defaultBucketMap,
127 unsigned int maxPeriods,
double decay,
unsigned int scale);
138 void Record(
int blocksToConfirm,
double val);
141 unsigned int NewTx(
unsigned int nBlockHeight,
double val);
144 void removeTx(
unsigned int entryHeight,
unsigned int nBestSeenHeight,
145 unsigned int bucketIndex,
bool inBlock);
161 double minSuccess,
unsigned int nBlockHeight,
179 const std::map<double, unsigned int>& defaultBucketMap,
180 unsigned int maxPeriods,
double _decay,
unsigned int _scale)
181 : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
183 assert(_scale != 0 &&
"_scale must be non-zero");
186 for (
unsigned int i = 0; i < maxPeriods; i++) {
200 for (
unsigned int i = 0; i <
unconfTxs.size(); i++) {
209 for (
unsigned int j = 0; j <
buckets.size(); j++) {
219 if (blocksToConfirm < 1)
221 int periodsToConfirm = (blocksToConfirm +
scale - 1) /
scale;
222 unsigned int bucketindex =
bucketMap.lower_bound(feerate)->second;
223 for (
size_t i = periodsToConfirm; i <=
confAvg.size(); i++) {
233 for (
unsigned int j = 0; j <
buckets.size(); j++) {
234 for (
unsigned int i = 0; i <
confAvg.size(); i++) {
245 double successBreakPoint,
unsigned int nBlockHeight,
253 const int periodTarget = (confTarget +
scale - 1) /
scale;
254 const int maxbucketindex =
buckets.size() - 1;
261 unsigned int curNearBucket = maxbucketindex;
262 unsigned int bestNearBucket = maxbucketindex;
263 unsigned int curFarBucket = maxbucketindex;
264 unsigned int bestFarBucket = maxbucketindex;
269 double partialNum = 0;
271 bool foundAnswer =
false;
273 bool newBucketRange =
true;
279 for (
int bucket = maxbucketindex; bucket >= 0; --bucket) {
280 if (newBucketRange) {
281 curNearBucket = bucket;
282 newBucketRange =
false;
284 curFarBucket = bucket;
285 nConf +=
confAvg[periodTarget - 1][bucket];
288 failNum +=
failAvg[periodTarget - 1][bucket];
289 for (
unsigned int confct = confTarget; confct <
GetMaxConfirms(); confct++)
290 extraNum +=
unconfTxs[(nBlockHeight - confct) % bins][bucket];
297 if (partialNum < sufficientTxVal / (1 -
decay)) {
304 double curPct = nConf / (totalNum + failNum + extraNum);
307 if (curPct < successBreakPoint) {
308 if (passing ==
true) {
310 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
311 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
312 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
336 bestNearBucket = curNearBucket;
337 bestFarBucket = curFarBucket;
338 newBucketRange =
true;
350 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
351 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
352 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
355 if (foundAnswer && txSum != 0) {
357 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
366 passBucket.
start = minBucket ?
buckets[minBucket-1] : 0;
371 if (passing && !newBucketRange) {
372 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
373 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
374 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
382 float passed_within_target_perc = 0.0;
383 float failed_within_target_perc = 0.0;
391 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",
392 confTarget, 100.0 * successBreakPoint,
decay,
393 median, passBucket.
start, passBucket.
end,
394 passed_within_target_perc,
397 failed_within_target_perc,
402 result->pass = passBucket;
403 result->fail = failBucket;
412 fileout << Using<EncodedDoubleFormatter>(
decay);
414 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
415 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
416 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
417 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
425 size_t maxConfirms, maxPeriods;
428 filein >> Using<EncodedDoubleFormatter>(
decay);
429 if (decay <= 0 || decay >= 1) {
430 throw std::runtime_error(
"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
434 throw std::runtime_error(
"Corrupt estimates file. Scale must be non-zero");
437 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
439 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate average bucket count");
441 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
442 if (
txCtAvg.size() != numBuckets) {
443 throw std::runtime_error(
"Corrupt estimates file. Mismatch in tx count bucket count");
445 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
447 maxConfirms =
scale * maxPeriods;
449 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) {
450 throw std::runtime_error(
"Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
452 for (
unsigned int i = 0; i < maxPeriods; i++) {
453 if (
confAvg[i].size() != numBuckets) {
454 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate conf average bucket count");
458 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
459 if (maxPeriods !=
failAvg.size()) {
460 throw std::runtime_error(
"Corrupt estimates file. Mismatch in confirms tracked for failures");
462 for (
unsigned int i = 0; i < maxPeriods; i++) {
463 if (
failAvg[i].size() != numBuckets) {
464 throw std::runtime_error(
"Corrupt estimates file. Mismatch in one of failure average bucket counts");
473 numBuckets, maxConfirms);
478 unsigned int bucketindex =
bucketMap.lower_bound(val)->second;
479 unsigned int blockIndex = nBlockHeight %
unconfTxs.size();
487 int blocksAgo = nBestSeenHeight - entryHeight;
488 if (nBestSeenHeight == 0)
495 if (blocksAgo >= (
int)
unconfTxs.size()) {
504 unsigned int blockIndex = entryHeight %
unconfTxs.size();
505 if (
unconfTxs[blockIndex][bucketindex] > 0) {
509 blockIndex, bucketindex);
512 if (!inBlock && (
unsigned int)blocksAgo >=
scale) {
514 unsigned int periodsAgo = blocksAgo /
scale;
515 for (
size_t i = 0; i < periodsAgo && i <
failAvg.size(); i++) {
530 std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
531 if (pos != mapMemPoolTxs.end()) {
532 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
533 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
534 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
535 mapMemPoolTxs.erase(hash);
543 : m_estimation_filepath{estimation_filepath}
545 static_assert(MIN_BUCKET_FEERATE > 0,
"Min feerate must be nonzero");
546 size_t bucketIndex = 0;
548 for (
double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
549 buckets.push_back(bucketBoundary);
550 bucketMap[bucketBoundary] = bucketIndex;
554 assert(bucketMap.size() == buckets.size());
556 feeStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
557 shortStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
558 longStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
562 if (est_file.IsNull()) {
567 std::chrono::hours file_age = GetFeeEstimatorFileAge();
569 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));
573 if (!Read(est_file)) {
599 const auto& hash = tx.
info.
m_tx->GetHash();
600 if (mapMemPoolTxs.count(hash)) {
606 if (txHeight != nBestSeenHeight) {
622 if (!validForFeeEstimation) {
631 mapMemPoolTxs[hash].blockHeight = txHeight;
632 unsigned int bucketIndex = feeStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
633 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
634 unsigned int bucketIndex2 = shortStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
635 assert(bucketIndex == bucketIndex2);
636 unsigned int bucketIndex3 = longStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
637 assert(bucketIndex == bucketIndex3);
652 if (blocksToConfirm <= 0) {
662 feeStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
663 shortStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
664 longStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
669 unsigned int nBlockHeight)
672 if (nBlockHeight <= nBestSeenHeight) {
684 nBestSeenHeight = nBlockHeight;
687 feeStats->ClearCurrent(nBlockHeight);
688 shortStats->ClearCurrent(nBlockHeight);
689 longStats->ClearCurrent(nBlockHeight);
692 feeStats->UpdateMovingAverages();
693 shortStats->UpdateMovingAverages();
694 longStats->UpdateMovingAverages();
696 unsigned int countedTxs = 0;
698 for (
const auto& tx : txs_removed_for_block) {
703 if (firstRecordedHeight == 0 && countedTxs > 0) {
704 firstRecordedHeight = nBestSeenHeight;
709 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",
710 countedTxs, txs_removed_for_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
732 stats = shortStats.get();
737 stats = feeStats.get();
741 stats = longStats.get();
749 if (confTarget <= 0 || (
unsigned int)confTarget > stats->
GetMaxConfirms())
751 if (successThreshold > 1)
754 double median = stats->
EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight,
result);
767 return shortStats->GetMaxConfirms();
770 return feeStats->GetMaxConfirms();
773 return longStats->GetMaxConfirms();
781 if (firstRecordedHeight == 0)
return 0;
782 assert(nBestSeenHeight >= firstRecordedHeight);
784 return nBestSeenHeight - firstRecordedHeight;
789 if (historicalFirst == 0)
return 0;
790 assert(historicalBest >= historicalFirst);
794 return historicalBest - historicalFirst;
809 double estimate = -1;
810 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
812 if (confTarget <= shortStats->GetMaxConfirms()) {
815 else if (confTarget <= feeStats->GetMaxConfirms()) {
816 estimate = feeStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight,
result);
819 estimate = longStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight,
result);
821 if (checkShorterHorizon) {
824 if (confTarget > feeStats->GetMaxConfirms()) {
825 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(),
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
826 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
831 if (confTarget > shortStats->GetMaxConfirms()) {
832 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(),
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
833 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
848 double estimate = -1;
850 if (doubleTarget <= shortStats->GetMaxConfirms()) {
853 if (doubleTarget <= feeStats->GetMaxConfirms()) {
855 if (longEstimate > estimate) {
856 estimate = longEstimate;
883 if (confTarget <= 0 || (
unsigned int)confTarget > longStats->GetMaxConfirms()) {
888 if (confTarget == 1) confTarget = 2;
891 if ((
unsigned int)confTarget > maxUsableEstimate) {
892 confTarget = maxUsableEstimate;
896 if (confTarget <= 1)
return CFeeRate(0);
911 feeCalc->
est = tempResult;
916 if (actualEst > median) {
919 feeCalc->
est = tempResult;
924 if (doubleEst > median) {
927 feeCalc->
est = tempResult;
932 if (conservative || median == -1) {
934 if (consEst > median) {
937 feeCalc->
est = tempResult;
956 if (est_file.IsNull() || !
Write(est_file)) {
969 fileout << nBestSeenHeight;
971 fileout << firstRecordedHeight << nBestSeenHeight;
974 fileout << historicalFirst << historicalBest;
976 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
977 feeStats->Write(fileout);
978 shortStats->Write(fileout);
979 longStats->Write(fileout);
981 catch (
const std::exception&) {
982 LogWarning(
"Unable to write policy estimator data (non-fatal)");
992 int nVersionRequired, dummy;
993 filein >> nVersionRequired >> dummy;
995 throw std::runtime_error{
strprintf(
"File version (%d) too high to be read.", nVersionRequired)};
1000 unsigned int nFileBestSeenHeight;
1001 filein >> nFileBestSeenHeight;
1004 LogWarning(
"Incompatible old fee estimation data (non-fatal). Version: %d", nVersionRequired);
1006 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
1007 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
1008 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
1009 throw std::runtime_error(
"Corrupt estimates file. Historical block range for estimates is invalid");
1011 std::vector<double> fileBuckets;
1012 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
1013 size_t numBuckets = fileBuckets.size();
1014 if (numBuckets <= 1 || numBuckets > 1000) {
1015 throw std::runtime_error(
"Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
1021 fileFeeStats->Read(filein, numBuckets);
1022 fileShortStats->Read(filein, numBuckets);
1023 fileLongStats->Read(filein, numBuckets);
1027 buckets = fileBuckets;
1029 for (
unsigned int i = 0; i < buckets.size(); i++) {
1030 bucketMap[buckets[i]] = i;
1034 feeStats = std::move(fileFeeStats);
1035 shortStats = std::move(fileShortStats);
1036 longStats = std::move(fileLongStats);
1038 nBestSeenHeight = nFileBestSeenHeight;
1039 historicalFirst = nFileHistoricalFirst;
1040 historicalBest = nFileHistoricalBest;
1043 catch (
const std::exception& e) {
1044 LogWarning(
"Unable to read policy estimator data (non-fatal): %s", e.what());
1052 const auto startclear{SteadyClock::now()};
1054 size_t num_entries = mapMemPoolTxs.size();
1056 while (!mapMemPoolTxs.empty()) {
1057 auto mi = mapMemPoolTxs.begin();
1060 const auto endclear{SteadyClock::now()};
1061 LogDebug(
BCLog::ESTIMATEFEE,
"Recorded %u unconfirmed txs from mempool in %.3fs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
1067 auto now{fs::file_time_type::clock::now()};
1068 return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
1072 double max_filter_fee_rate,
1073 double fee_filter_spacing)
1075 std::set<double> fee_set;
1079 for (
double bucket_boundary = min_fee_limit;
1080 bucket_boundary <= max_filter_fee_rate;
1081 bucket_boundary *= fee_filter_spacing) {
1083 fee_set.insert(bucket_boundary);
1098 std::set<double>::iterator it =
m_fee_set.lower_bound(currentMinFee);
1104 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.
constexpr int CURRENT_FEES_FILE_VERSION
std::vector< std::vector< double > > failAvg
void TransactionAddedToMempool(const NewMempoolTransactionInfo &tx, uint64_t) override EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Overridden from CValidationInterface.
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.
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.
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
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...
void processTransaction(const NewMempoolTransactionInfo &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process a transaction accepted to the mempool.
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*.
bool removeTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Remove a transaction from the mempool tracking stats for non BLOCK removal reasons.
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.
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::vector< std::vector< double > > confAvg
const bool m_chainstate_is_current
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.
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.
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.
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
const bool m_has_no_mempool_parents
static constexpr unsigned int MED_SCALE
static const unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren't valid.
const bool m_mempool_limit_bypassed
#define LogDebug(category,...)
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.
const CTransactionRef m_tx
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.
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.
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:...
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.
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.
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.
const std::set< double > m_fee_set