33#include <system_error>
58 return "Half Target 60% Threshold";
60 return "Target 85% Threshold";
62 return "Double Target 95% Threshold";
64 return "Conservative Double Target longer horizon";
71struct EncodedDoubleFormatter
73 template<
typename Stream>
void Ser(
Stream &
s,
double v)
78 template<
typename Stream>
void Unser(
Stream&
s,
double& v)
145 TxConfirmStats(
const std::vector<double>& defaultBuckets,
const std::map<double, unsigned int>& defaultBucketMap,
146 unsigned int maxPeriods,
double decay,
unsigned int scale);
157 void Record(
int blocksToConfirm,
double val);
160 unsigned int NewTx(
unsigned int nBlockHeight,
double val);
163 void removeTx(
unsigned int entryHeight,
unsigned int nBestSeenHeight,
164 unsigned int bucketIndex,
bool inBlock);
180 double minSuccess,
unsigned int nBlockHeight,
198 const std::map<double, unsigned int>& defaultBucketMap,
199 unsigned int maxPeriods,
double _decay,
unsigned int _scale)
200 : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
202 assert(_scale != 0 &&
"_scale must be non-zero");
205 for (
unsigned int i = 0; i < maxPeriods; i++) {
219 for (
unsigned int i = 0; i <
unconfTxs.size(); i++) {
228 for (
unsigned int j = 0; j <
buckets.size(); j++) {
238 if (blocksToConfirm < 1)
240 int periodsToConfirm = (blocksToConfirm +
scale - 1) /
scale;
241 unsigned int bucketindex =
bucketMap.lower_bound(feerate)->second;
242 for (
size_t i = periodsToConfirm; i <=
confAvg.size(); i++) {
252 for (
unsigned int j = 0; j <
buckets.size(); j++) {
253 for (
unsigned int i = 0; i <
confAvg.size(); i++) {
264 double successBreakPoint,
unsigned int nBlockHeight,
272 const int periodTarget = (confTarget +
scale - 1) /
scale;
273 const int maxbucketindex =
buckets.size() - 1;
280 unsigned int curNearBucket = maxbucketindex;
281 unsigned int bestNearBucket = maxbucketindex;
282 unsigned int curFarBucket = maxbucketindex;
283 unsigned int bestFarBucket = maxbucketindex;
288 double partialNum = 0;
290 bool foundAnswer =
false;
292 bool newBucketRange =
true;
298 for (
int bucket = maxbucketindex; bucket >= 0; --bucket) {
299 if (newBucketRange) {
300 curNearBucket = bucket;
301 newBucketRange =
false;
303 curFarBucket = bucket;
304 nConf +=
confAvg[periodTarget - 1][bucket];
307 failNum +=
failAvg[periodTarget - 1][bucket];
308 for (
unsigned int confct = confTarget; confct <
GetMaxConfirms(); confct++)
309 extraNum +=
unconfTxs[(nBlockHeight - confct) % bins][bucket];
316 if (partialNum < sufficientTxVal / (1 -
decay)) {
323 double curPct = nConf / (totalNum + failNum + extraNum);
326 if (curPct < successBreakPoint) {
327 if (passing ==
true) {
329 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
330 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
331 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
355 bestNearBucket = curNearBucket;
356 bestFarBucket = curFarBucket;
357 newBucketRange =
true;
369 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
370 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
371 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
374 if (foundAnswer && txSum != 0) {
376 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
385 passBucket.
start = minBucket ?
buckets[minBucket-1] : 0;
390 if (passing && !newBucketRange) {
391 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
392 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
393 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
401 float passed_within_target_perc = 0.0;
402 float failed_within_target_perc = 0.0;
410 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",
411 confTarget, 100.0 * successBreakPoint,
decay,
412 median, passBucket.
start, passBucket.
end,
413 passed_within_target_perc,
416 failed_within_target_perc,
421 result->
pass = passBucket;
422 result->
fail = failBucket;
431 fileout << Using<EncodedDoubleFormatter>(
decay);
433 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
434 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
435 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
436 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
444 uint64_t maxConfirms, maxPeriods;
447 filein >> Using<EncodedDoubleFormatter>(
decay);
448 if (decay <= 0 || decay >= 1) {
449 throw std::runtime_error(
"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
453 throw std::runtime_error(
"Corrupt estimates file. Scale must be non-zero");
456 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
458 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate average bucket count");
460 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
461 if (
txCtAvg.size() != numBuckets) {
462 throw std::runtime_error(
"Corrupt estimates file. Mismatch in tx count bucket count");
464 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
466 maxConfirms =
scale * maxPeriods;
468 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) {
469 throw std::runtime_error(
"Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
471 for (
unsigned int i = 0; i < maxPeriods; i++) {
472 if (
confAvg[i].size() != numBuckets) {
473 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate conf average bucket count");
477 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
478 if (maxPeriods !=
failAvg.size()) {
479 throw std::runtime_error(
"Corrupt estimates file. Mismatch in confirms tracked for failures");
481 for (
unsigned int i = 0; i < maxPeriods; i++) {
482 if (
failAvg[i].size() != numBuckets) {
483 throw std::runtime_error(
"Corrupt estimates file. Mismatch in one of failure average bucket counts");
492 numBuckets, maxConfirms);
497 unsigned int bucketindex =
bucketMap.lower_bound(val)->second;
498 unsigned int blockIndex = nBlockHeight %
unconfTxs.size();
506 int blocksAgo = nBestSeenHeight - entryHeight;
507 if (nBestSeenHeight == 0)
514 if (blocksAgo >= (
int)
unconfTxs.size()) {
523 unsigned int blockIndex = entryHeight %
unconfTxs.size();
524 if (
unconfTxs[blockIndex][bucketindex] > 0) {
528 blockIndex, bucketindex);
531 if (!inBlock && (
unsigned int)blocksAgo >=
scale) {
533 unsigned int periodsAgo = blocksAgo /
scale;
534 for (
size_t i = 0; i < periodsAgo && i <
failAvg.size(); i++) {
549 std::map<Txid, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
550 if (pos != mapMemPoolTxs.end()) {
551 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
552 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
553 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
554 mapMemPoolTxs.erase(hash);
562 : m_estimation_filepath{estimation_filepath}
565 size_t bucketIndex = 0;
568 buckets.push_back(bucketBoundary);
569 bucketMap[bucketBoundary] = bucketIndex;
573 assert(bucketMap.size() == buckets.size());
581 if (est_file.IsNull()) {
592 if (!
Read(est_file)) {
603 const auto& hash = tx.
info.
m_tx->GetHash();
604 if (mapMemPoolTxs.contains(hash)) {
610 if (txHeight != nBestSeenHeight) {
626 if (!validForFeeEstimation) {
635 mapMemPoolTxs[hash].blockHeight = txHeight;
636 unsigned int bucketIndex = feeStats->NewTx(txHeight,
static_cast<double>(feeRate.
GetFeePerK()));
637 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
638 unsigned int bucketIndex2 = shortStats->NewTx(txHeight,
static_cast<double>(feeRate.
GetFeePerK()));
639 assert(bucketIndex == bucketIndex2);
640 unsigned int bucketIndex3 = longStats->NewTx(txHeight,
static_cast<double>(feeRate.
GetFeePerK()));
641 assert(bucketIndex == bucketIndex3);
656 if (blocksToConfirm <= 0) {
666 feeStats->Record(blocksToConfirm,
static_cast<double>(feeRate.
GetFeePerK()));
667 shortStats->Record(blocksToConfirm,
static_cast<double>(feeRate.
GetFeePerK()));
668 longStats->Record(blocksToConfirm,
static_cast<double>(feeRate.
GetFeePerK()));
673 unsigned int nBlockHeight)
676 if (nBlockHeight <= nBestSeenHeight) {
688 nBestSeenHeight = nBlockHeight;
691 feeStats->ClearCurrent(nBlockHeight);
692 shortStats->ClearCurrent(nBlockHeight);
693 longStats->ClearCurrent(nBlockHeight);
696 feeStats->UpdateMovingAverages();
697 shortStats->UpdateMovingAverages();
698 longStats->UpdateMovingAverages();
700 unsigned int countedTxs = 0;
702 for (
const auto& tx : txs_removed_for_block) {
707 if (firstRecordedHeight == 0 && countedTxs > 0) {
708 firstRecordedHeight = nBestSeenHeight;
713 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",
714 countedTxs, txs_removed_for_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
736 stats = shortStats.get();
741 stats = feeStats.get();
745 stats = longStats.get();
753 if (confTarget <= 0 || (
unsigned int)confTarget > stats->
GetMaxConfirms())
755 if (successThreshold > 1)
758 double median = stats->
EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
771 return shortStats->GetMaxConfirms();
774 return feeStats->GetMaxConfirms();
777 return longStats->GetMaxConfirms();
785 if (firstRecordedHeight == 0)
return 0;
786 assert(nBestSeenHeight >= firstRecordedHeight);
788 return nBestSeenHeight - firstRecordedHeight;
793 if (historicalFirst == 0)
return 0;
794 assert(historicalBest >= historicalFirst);
798 return historicalBest - historicalFirst;
813 double estimate = -1;
814 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
816 if (confTarget <= shortStats->GetMaxConfirms()) {
817 estimate = shortStats->EstimateMedianVal(confTarget,
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
819 else if (confTarget <= feeStats->GetMaxConfirms()) {
820 estimate = feeStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
823 estimate = longStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
825 if (checkShorterHorizon) {
828 if (confTarget > feeStats->GetMaxConfirms()) {
829 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(),
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
830 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
832 if (result) *result = tempResult;
835 if (confTarget > shortStats->GetMaxConfirms()) {
836 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(),
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
837 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
839 if (result) *result = tempResult;
852 double estimate = -1;
854 if (doubleTarget <= shortStats->GetMaxConfirms()) {
857 if (doubleTarget <= feeStats->GetMaxConfirms()) {
859 if (longEstimate > estimate) {
860 estimate = longEstimate;
861 if (result) *result = tempResult;
879 if (!feeCalc) feeCalc = &temp_fee_calc;
889 if (confTarget <= 0 || (
unsigned int)confTarget > longStats->GetMaxConfirms()) {
894 if (confTarget == 1) confTarget = 2;
897 if ((
unsigned int)confTarget > maxUsableEstimate) {
898 confTarget = maxUsableEstimate;
902 if (confTarget <= 1)
return CFeeRate(0);
924 feeCalc->
est = tempResult;
928 if (actualEst > median) {
930 feeCalc->
est = tempResult;
934 if (doubleEst > median) {
936 feeCalc->
est = tempResult;
940 if (conservative || median == -1) {
942 if (consEst > median) {
944 feeCalc->
est = tempResult;
951 LogDebug(
BCLog::ESTIMATEFEE,
"estimateSmartFee Selected feerate: %g Tgt: %d (requested %d) Reason: \"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)",
986 std::error_code error;
995 if (est_file.IsNull() || !
Write(est_file)) {
997 (void)est_file.fclose();
1000 if (est_file.fclose() != 0) {
1012 fileout << nBestSeenHeight;
1014 fileout << firstRecordedHeight << nBestSeenHeight;
1017 fileout << historicalFirst << historicalBest;
1019 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
1020 feeStats->Write(fileout);
1021 shortStats->Write(fileout);
1022 longStats->Write(fileout);
1024 catch (
const std::exception&) {
1025 LogWarning(
"Unable to write policy estimator data (non-fatal)");
1035 int nVersionRequired;
1036 filein >> nVersionRequired;
1038 throw std::runtime_error{
strprintf(
"File version (%d) too high to be read.", nVersionRequired)};
1041 throw std::runtime_error{
strprintf(
"File version (%d) incompatible: Too old to be read", nVersionRequired)};
1046 unsigned int nFileBestSeenHeight;
1047 filein >> nFileBestSeenHeight;
1050 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
1051 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
1052 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
1053 throw std::runtime_error(
"Corrupt estimates file. Historical block range for estimates is invalid");
1055 std::vector<double> fileBuckets;
1056 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
1057 size_t numBuckets = fileBuckets.
size();
1058 if (numBuckets <= 1 || numBuckets > 1000) {
1059 throw std::runtime_error(
"Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
1065 fileFeeStats->Read(filein, numBuckets);
1066 fileShortStats->Read(filein, numBuckets);
1067 fileLongStats->Read(filein, numBuckets);
1071 buckets = fileBuckets;
1073 for (
unsigned int i = 0; i < buckets.size(); i++) {
1074 bucketMap[buckets[i]] = i;
1078 feeStats = std::move(fileFeeStats);
1079 shortStats = std::move(fileShortStats);
1080 longStats = std::move(fileLongStats);
1082 nBestSeenHeight = nFileBestSeenHeight;
1083 historicalFirst = nFileHistoricalFirst;
1084 historicalBest = nFileHistoricalBest;
1086 catch (
const std::exception& e) {
1087 LogWarning(
"Unable to read policy estimator data (non-fatal): %s", e.what());
1095 const auto startclear{SteadyClock::now()};
1099 while (!mapMemPoolTxs.empty()) {
1100 auto mi = mapMemPoolTxs.begin();
1103 const auto endclear{SteadyClock::now()};
1110 auto now{fs::file_time_type::clock::now()};
1111 return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
1115 double max_filter_fee_rate,
1116 double fee_filter_spacing)
1118 std::set<double> fee_set;
1122 for (
double bucket_boundary = min_fee_limit;
1123 bucket_boundary <= max_filter_fee_rate;
1124 bucket_boundary *= fee_filter_spacing) {
1126 fee_set.insert(bucket_boundary);
1133 : m_fee_set{
MakeFeeSet(minIncrementalFee, MAX_FILTER_FEERATE, FEE_FILTER_SPACING)},
1141 std::set<double>::iterator it =
m_fee_set.lower_bound(currentMinFee);
1147 return static_cast<CAmount>(*it);
int64_t CAmount
Amount in satoshis (Can be negative)
constexpr std::chrono::hours MAX_FILE_AGE
Block policy estimate files that are more than 60 hours (2.5 days) old will not be read,...
BlockPolicyEstimateReason
Non-refcounted RAII wrapper for FILE*.
int64_t size()
Return the size of the file.
void processTransaction(const NewMempoolTransactionInfo &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process a transaction accepted to the mempool.
static constexpr unsigned int LONG_SCALE
static constexpr double SUCCESS_PCT
Require greater than 85% of X feerate transactions to be confirmed within Y blocks.
static constexpr double MIN_BUCKET_FEERATE
Minimum and Maximum values for tracking feerates The MIN_BUCKET_FEERATE should just be set to the low...
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
static constexpr double FEE_SPACING
Spacing of FeeRate buckets We have to lump transactions into buckets based on feerate,...
void Flush() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Drop still unconfirmed transactions and record current estimations, if the fee estimation file is pre...
static constexpr double SUFFICIENT_FEETXS
Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance.
bool removeTx(Txid hash) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Remove a transaction from the mempool tracking stats for non BLOCK removal reasons.
static constexpr double MAX_BUCKET_FEERATE
CBlockPolicyEstimator(const fs::path &estimation_filepath, bool read_stale_estimates)
Create new BlockPolicyEstimator and initialize stats tracking classes with default values.
void FlushFeeEstimates() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Record current fee estimations.
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.
static constexpr unsigned int LONG_BLOCK_PERIODS
Track confirm delays up to 1008 blocks for long horizon.
bool Write(AutoFile &fileout) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Write estimation data to a file.
static constexpr double SHORT_DECAY
Decay of .962 is a half-life of 18 blocks or about 3 hours.
std::chrono::hours GetFeeEstimatorFileAge()
Calculates the age of the file, since last modified.
virtual unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Calculation of highest target that estimates are tracked for.
static constexpr double LONG_DECAY
Decay of .99931 is a half-life of 1008 blocks or about 1 week.
double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
static constexpr double HALF_SUCCESS_PCT
Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks.
static constexpr double MED_DECAY
Decay of .9952 is a half-life of 144 blocks or about 1 day.
CFeeRate estimateFee(int confTarget) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
DEPRECATED.
bool _removeTx(const Txid &hash, bool inBlock) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
A non-thread-safe helper for the removeTx function.
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Calculation of highest target that reasonable estimate can be provided for.
util::Expected< FeeRateEstimation, FeeRateEstimationError > EstimateFeeRate(int target, bool conservative) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Estimate the feerate needed to confirm within target blocks; wraps estimateSmartFee into a FeeRateEst...
static constexpr unsigned int SHORT_SCALE
unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of data recorded while fee estimates have been running.
bool Read(AutoFile &filein) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Read estimation data from a file.
static constexpr unsigned int SHORT_BLOCK_PERIODS
Track confirm delays up to 12 blocks for short horizon.
static constexpr double DOUBLE_SUCCESS_PCT
Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks.
unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of recorded fee estimate data represented in saved data file.
void FlushUnconfirmed() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool.
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,...
unsigned int MaximumTarget() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Return the highest confirmation target for which an estimate can be provided.
static constexpr unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren't valid.
static constexpr double SUFFICIENT_TXS_SHORT
Require an avg of 0.5 tx when using short decay since there are fewer blocks considered.
bool processBlockTx(unsigned int nBlockHeight, const RemovedMempoolTransactionInfo &tx) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Process a transaction confirmed in a block.
static constexpr unsigned int MED_SCALE
static constexpr unsigned int MED_BLOCK_PERIODS
Track confirm delays up to 48 blocks for medium horizon.
const fs::path m_estimation_filepath
virtual ~CBlockPolicyEstimator()
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.
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
const std::set< double > m_fee_set
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.
Mutex m_insecure_rand_mutex
We will instantiate an instance of this class to track transactions that were included in a block.
void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketIndex, bool inBlock)
Remove a transaction from mempool tracking stats.
std::vector< std::vector< double > > failAvg
TxConfirmStats(const std::vector< double > &defaultBuckets, const std::map< double, unsigned int > &defaultBucketMap, unsigned int maxPeriods, double decay, unsigned int scale)
Create new TxConfirmStats.
unsigned int GetMaxConfirms() const
Return the max number of confirms we're tracking.
void ClearCurrent(unsigned int nBlockHeight)
Roll the circular buffer for unconfirmed txs.
void Record(int blocksToConfirm, double val)
Record a new transaction data point in the current block stats.
void resizeInMemoryCounters(size_t newbuckets)
std::vector< double > txCtAvg
std::vector< int > oldUnconfTxs
void UpdateMovingAverages()
Update our estimates by decaying our historical moving average and updating with the data gathered fr...
const std::map< double, unsigned int > & bucketMap
const std::vector< double > & buckets
void Read(AutoFile &filein, size_t numBuckets)
Read saved state of estimation data from a file and replace all internal data structures and variable...
std::vector< std::vector< double > > confAvg
void Write(AutoFile &fileout) const
Write state of estimation data to a file.
std::vector< std::vector< int > > unconfTxs
unsigned int NewTx(unsigned int nBlockHeight, double val)
Record a new transaction entering the mempool.
std::vector< double > m_feerate_avg
double EstimateMedianVal(int confTarget, double sufficientTxVal, double minSuccess, unsigned int nBlockHeight, EstimationResult *result=nullptr) const
Calculate a feerate estimate.
The util::Expected class provides a standard way for low-level functions to return either error value...
static std::string PathToString(const path &path)
Convert path object to a byte string.
#define LogDebug(category,...)
FILE * fopen(const fs::path &p, const char *mode)
static constexpr double INF_FEERATE
static std::set< double > MakeFeeSet(const CFeeRate &min_incremental_fee, double max_filter_fee_rate, double fee_filter_spacing)
std::string StringForBlockPolicyEstimateReason(BlockPolicyEstimateReason reason)
constexpr int CURRENT_FEES_FILE_VERSION
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
uint64_t EncodeDouble(double f) noexcept
double DecodeDouble(uint64_t v) noexcept
BlockPolicyEstimateReason reason
A successful fee rate estimate returned by a fee rate estimator.
const bool m_submitted_in_package
const bool m_has_no_mempool_parents
const bool m_chainstate_is_current
const bool m_mempool_limit_bypassed
const unsigned int txHeight
const CTransactionRef m_tx
const int64_t m_virtual_transaction_size
The virtual transaction size.
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
std::string SysErrorString(int err)
Return system error string from errno value.
util::Unexpected< FeeRateEstimationError > EstimationError(FeeRateEstimatorType estimator, int returned_target, std::string error)
Build a fee rate estimation error result: a zero-value estimation identifying the estimator and targe...