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;
266 double partialNum = 0;
268 bool foundAnswer =
false;
270 bool newBucketRange =
true;
276 for (
int bucket = maxbucketindex; bucket >= 0; --bucket) {
277 if (newBucketRange) {
278 curNearBucket = bucket;
279 newBucketRange =
false;
281 curFarBucket = bucket;
282 nConf +=
confAvg[periodTarget - 1][bucket];
285 failNum +=
failAvg[periodTarget - 1][bucket];
286 for (
unsigned int confct = confTarget; confct <
GetMaxConfirms(); confct++)
287 extraNum +=
unconfTxs[(nBlockHeight - confct) % bins][bucket];
294 if (partialNum < sufficientTxVal / (1 -
decay)) {
301 double curPct = nConf / (totalNum + failNum + extraNum);
304 if (curPct < successBreakPoint) {
305 if (passing ==
true) {
307 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
308 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
309 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
333 bestNearBucket = curNearBucket;
334 bestFarBucket = curFarBucket;
335 newBucketRange =
true;
347 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
348 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
349 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
352 if (foundAnswer && txSum != 0) {
354 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
363 passBucket.
start = minBucket ?
buckets[minBucket-1] : 0;
368 if (passing && !newBucketRange) {
369 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
370 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
371 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
379 float passed_within_target_perc = 0.0;
380 float failed_within_target_perc = 0.0;
388 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",
389 confTarget, 100.0 * successBreakPoint,
decay,
390 median, passBucket.
start, passBucket.
end,
391 passed_within_target_perc,
394 failed_within_target_perc,
399 result->
pass = passBucket;
400 result->
fail = failBucket;
409 fileout << Using<EncodedDoubleFormatter>(
decay);
411 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
412 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
413 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
414 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
422 size_t maxConfirms, maxPeriods;
425 filein >> Using<EncodedDoubleFormatter>(
decay);
426 if (decay <= 0 || decay >= 1) {
427 throw std::runtime_error(
"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
431 throw std::runtime_error(
"Corrupt estimates file. Scale must be non-zero");
434 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
436 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate average bucket count");
438 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
439 if (
txCtAvg.size() != numBuckets) {
440 throw std::runtime_error(
"Corrupt estimates file. Mismatch in tx count bucket count");
442 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
444 maxConfirms =
scale * maxPeriods;
446 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) {
447 throw std::runtime_error(
"Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
449 for (
unsigned int i = 0; i < maxPeriods; i++) {
450 if (
confAvg[i].size() != numBuckets) {
451 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate conf average bucket count");
455 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
456 if (maxPeriods !=
failAvg.size()) {
457 throw std::runtime_error(
"Corrupt estimates file. Mismatch in confirms tracked for failures");
459 for (
unsigned int i = 0; i < maxPeriods; i++) {
460 if (
failAvg[i].size() != numBuckets) {
461 throw std::runtime_error(
"Corrupt estimates file. Mismatch in one of failure average bucket counts");
470 numBuckets, maxConfirms);
475 unsigned int bucketindex =
bucketMap.lower_bound(val)->second;
476 unsigned int blockIndex = nBlockHeight %
unconfTxs.size();
484 int blocksAgo = nBestSeenHeight - entryHeight;
485 if (nBestSeenHeight == 0)
492 if (blocksAgo >= (
int)
unconfTxs.size()) {
501 unsigned int blockIndex = entryHeight %
unconfTxs.size();
502 if (
unconfTxs[blockIndex][bucketindex] > 0) {
506 blockIndex, bucketindex);
509 if (!inBlock && (
unsigned int)blocksAgo >=
scale) {
511 unsigned int periodsAgo = blocksAgo /
scale;
512 for (
size_t i = 0; i < periodsAgo && i <
failAvg.size(); i++) {
527 std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
528 if (pos != mapMemPoolTxs.end()) {
529 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
530 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
531 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
532 mapMemPoolTxs.erase(hash);
540 : m_estimation_filepath{estimation_filepath}
542 static_assert(MIN_BUCKET_FEERATE > 0,
"Min feerate must be nonzero");
543 size_t bucketIndex = 0;
545 for (
double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
546 buckets.push_back(bucketBoundary);
547 bucketMap[bucketBoundary] = bucketIndex;
551 assert(bucketMap.size() == buckets.size());
553 feeStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
554 shortStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
555 longStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
559 if (est_file.IsNull()) {
564 std::chrono::hours file_age = GetFeeEstimatorFileAge();
566 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));
570 if (!Read(est_file)) {
596 const auto& hash = tx.
info.
m_tx->GetHash();
597 if (mapMemPoolTxs.count(hash)) {
603 if (txHeight != nBestSeenHeight) {
619 if (!validForFeeEstimation) {
628 mapMemPoolTxs[hash].blockHeight = txHeight;
629 unsigned int bucketIndex = feeStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
630 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
631 unsigned int bucketIndex2 = shortStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
632 assert(bucketIndex == bucketIndex2);
633 unsigned int bucketIndex3 = longStats->NewTx(txHeight, static_cast<double>(feeRate.
GetFeePerK()));
634 assert(bucketIndex == bucketIndex3);
649 if (blocksToConfirm <= 0) {
659 feeStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
660 shortStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
661 longStats->Record(blocksToConfirm, static_cast<double>(feeRate.
GetFeePerK()));
666 unsigned int nBlockHeight)
669 if (nBlockHeight <= nBestSeenHeight) {
681 nBestSeenHeight = nBlockHeight;
684 feeStats->ClearCurrent(nBlockHeight);
685 shortStats->ClearCurrent(nBlockHeight);
686 longStats->ClearCurrent(nBlockHeight);
689 feeStats->UpdateMovingAverages();
690 shortStats->UpdateMovingAverages();
691 longStats->UpdateMovingAverages();
693 unsigned int countedTxs = 0;
695 for (
const auto& tx : txs_removed_for_block) {
700 if (firstRecordedHeight == 0 && countedTxs > 0) {
701 firstRecordedHeight = nBestSeenHeight;
706 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",
707 countedTxs, txs_removed_for_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
729 stats = shortStats.get();
734 stats = feeStats.get();
738 stats = longStats.get();
746 if (confTarget <= 0 || (
unsigned int)confTarget > stats->
GetMaxConfirms())
748 if (successThreshold > 1)
751 double median = stats->
EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
764 return shortStats->GetMaxConfirms();
767 return feeStats->GetMaxConfirms();
770 return longStats->GetMaxConfirms();
778 if (firstRecordedHeight == 0)
return 0;
779 assert(nBestSeenHeight >= firstRecordedHeight);
781 return nBestSeenHeight - firstRecordedHeight;
786 if (historicalFirst == 0)
return 0;
787 assert(historicalBest >= historicalFirst);
791 return historicalBest - historicalFirst;
806 double estimate = -1;
807 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
809 if (confTarget <= shortStats->GetMaxConfirms()) {
810 estimate = shortStats->EstimateMedianVal(confTarget,
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
812 else if (confTarget <= feeStats->GetMaxConfirms()) {
813 estimate = feeStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
816 estimate = longStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
818 if (checkShorterHorizon) {
821 if (confTarget > feeStats->GetMaxConfirms()) {
822 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(),
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
823 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
825 if (result) *result = tempResult;
828 if (confTarget > shortStats->GetMaxConfirms()) {
829 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(),
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
830 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
832 if (result) *result = tempResult;
845 double estimate = -1;
847 if (doubleTarget <= shortStats->GetMaxConfirms()) {
850 if (doubleTarget <= feeStats->GetMaxConfirms()) {
852 if (longEstimate > estimate) {
853 estimate = longEstimate;
854 if (result) *result = tempResult;
880 if (confTarget <= 0 || (
unsigned int)confTarget > longStats->GetMaxConfirms()) {
885 if (confTarget == 1) confTarget = 2;
888 if ((
unsigned int)confTarget > maxUsableEstimate) {
889 confTarget = maxUsableEstimate;
893 if (confTarget <= 1)
return CFeeRate(0);
908 feeCalc->
est = tempResult;
913 if (actualEst > median) {
916 feeCalc->
est = tempResult;
921 if (doubleEst > median) {
924 feeCalc->
est = tempResult;
929 if (conservative || median == -1) {
931 if (consEst > median) {
934 feeCalc->
est = tempResult;
953 if (est_file.IsNull() || !
Write(est_file)) {
966 fileout << nBestSeenHeight;
968 fileout << firstRecordedHeight << nBestSeenHeight;
971 fileout << historicalFirst << historicalBest;
973 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
974 feeStats->Write(fileout);
975 shortStats->Write(fileout);
976 longStats->Write(fileout);
978 catch (
const std::exception&) {
979 LogPrintf(
"CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
989 int nVersionRequired, nVersionThatWrote;
990 filein >> nVersionRequired >> nVersionThatWrote;
992 throw std::runtime_error(
strprintf(
"up-version (%d) fee estimate file", nVersionRequired));
997 unsigned int nFileBestSeenHeight;
998 filein >> nFileBestSeenHeight;
1000 if (nVersionRequired < 149900) {
1001 LogPrintf(
"%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
1003 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
1004 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
1005 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
1006 throw std::runtime_error(
"Corrupt estimates file. Historical block range for estimates is invalid");
1008 std::vector<double> fileBuckets;
1009 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
1010 size_t numBuckets = fileBuckets.size();
1011 if (numBuckets <= 1 || numBuckets > 1000) {
1012 throw std::runtime_error(
"Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
1018 fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
1019 fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
1020 fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
1024 buckets = fileBuckets;
1026 for (
unsigned int i = 0; i < buckets.size(); i++) {
1027 bucketMap[buckets[i]] = i;
1031 feeStats = std::move(fileFeeStats);
1032 shortStats = std::move(fileShortStats);
1033 longStats = std::move(fileLongStats);
1035 nBestSeenHeight = nFileBestSeenHeight;
1036 historicalFirst = nFileHistoricalFirst;
1037 historicalBest = nFileHistoricalBest;
1040 catch (
const std::exception& e) {
1041 LogPrintf(
"CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
1049 const auto startclear{SteadyClock::now()};
1051 size_t num_entries = mapMemPoolTxs.size();
1053 while (!mapMemPoolTxs.empty()) {
1054 auto mi = mapMemPoolTxs.begin();
1057 const auto endclear{SteadyClock::now()};
1058 LogPrint(
BCLog::ESTIMATEFEE,
"Recorded %u unconfirmed txs from mempool in %.3fs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
1064 auto now{fs::file_time_type::clock::now()};
1065 return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
1069 double max_filter_fee_rate,
1070 double fee_filter_spacing)
1072 std::set<double> fee_set;
1076 for (
double bucket_boundary = min_fee_limit;
1077 bucket_boundary <= max_filter_fee_rate;
1078 bucket_boundary *= fee_filter_spacing) {
1080 fee_set.insert(bucket_boundary);
1095 std::set<double>::iterator it =
m_fee_set.lower_bound(currentMinFee);
1101 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.
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.
#define LogPrint(category,...)
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 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 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 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
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:...
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.
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