48 struct EncodedDoubleFormatter
50 template<
typename Stream>
void Ser(Stream &s,
double v)
55 template<
typename Stream>
void Unser(Stream& s,
double& v)
122 TxConfirmStats(
const std::vector<double>& defaultBuckets,
const std::map<double, unsigned int>& defaultBucketMap,
123 unsigned int maxPeriods,
double decay,
unsigned int scale);
134 void Record(
int blocksToConfirm,
double val);
137 unsigned int NewTx(
unsigned int nBlockHeight,
double val);
140 void removeTx(
unsigned int entryHeight,
unsigned int nBestSeenHeight,
141 unsigned int bucketIndex,
bool inBlock);
157 double minSuccess,
unsigned int nBlockHeight,
170 void Read(
AutoFile& filein,
int nFileVersion,
size_t numBuckets);
175 const std::map<double, unsigned int>& defaultBucketMap,
176 unsigned int maxPeriods,
double _decay,
unsigned int _scale)
177 : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
179 assert(_scale != 0 &&
"_scale must be non-zero");
182 for (
unsigned int i = 0; i < maxPeriods; i++) {
196 for (
unsigned int i = 0; i <
unconfTxs.size(); i++) {
205 for (
unsigned int j = 0; j <
buckets.size(); j++) {
215 if (blocksToConfirm < 1)
217 int periodsToConfirm = (blocksToConfirm +
scale - 1) /
scale;
218 unsigned int bucketindex =
bucketMap.lower_bound(feerate)->second;
219 for (
size_t i = periodsToConfirm; i <=
confAvg.size(); i++) {
229 for (
unsigned int j = 0; j <
buckets.size(); j++) {
230 for (
unsigned int i = 0; i <
confAvg.size(); i++) {
241 double successBreakPoint,
unsigned int nBlockHeight,
249 const int periodTarget = (confTarget +
scale - 1) /
scale;
250 const int maxbucketindex =
buckets.size() - 1;
257 unsigned int curNearBucket = maxbucketindex;
258 unsigned int bestNearBucket = maxbucketindex;
259 unsigned int curFarBucket = maxbucketindex;
260 unsigned int bestFarBucket = maxbucketindex;
262 bool foundAnswer =
false;
264 bool newBucketRange =
true;
270 for (
int bucket = maxbucketindex; bucket >= 0; --bucket) {
271 if (newBucketRange) {
272 curNearBucket = bucket;
273 newBucketRange =
false;
275 curFarBucket = bucket;
276 nConf +=
confAvg[periodTarget - 1][bucket];
278 failNum +=
failAvg[periodTarget - 1][bucket];
279 for (
unsigned int confct = confTarget; confct <
GetMaxConfirms(); confct++)
280 extraNum +=
unconfTxs[(nBlockHeight - confct) % bins][bucket];
286 if (totalNum >= sufficientTxVal / (1 -
decay)) {
287 double curPct = nConf / (totalNum + failNum + extraNum);
290 if (curPct < successBreakPoint) {
291 if (passing ==
true) {
293 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
294 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
295 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
319 bestNearBucket = curNearBucket;
320 bestFarBucket = curFarBucket;
321 newBucketRange =
true;
333 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
334 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
335 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
338 if (foundAnswer && txSum != 0) {
340 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
349 passBucket.
start = minBucket ?
buckets[minBucket-1] : 0;
354 if (passing && !newBucketRange) {
355 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
356 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
357 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
365 float passed_within_target_perc = 0.0;
366 float failed_within_target_perc = 0.0;
374 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",
375 confTarget, 100.0 * successBreakPoint,
decay,
376 median, passBucket.
start, passBucket.
end,
377 passed_within_target_perc,
380 failed_within_target_perc,
385 result->
pass = passBucket;
386 result->
fail = failBucket;
395 fileout << Using<EncodedDoubleFormatter>(
decay);
397 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
398 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
399 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
400 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
408 size_t maxConfirms, maxPeriods;
411 filein >> Using<EncodedDoubleFormatter>(
decay);
412 if (decay <= 0 || decay >= 1) {
413 throw std::runtime_error(
"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
417 throw std::runtime_error(
"Corrupt estimates file. Scale must be non-zero");
420 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
422 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate average bucket count");
424 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
425 if (
txCtAvg.size() != numBuckets) {
426 throw std::runtime_error(
"Corrupt estimates file. Mismatch in tx count bucket count");
428 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
430 maxConfirms =
scale * maxPeriods;
432 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) {
433 throw std::runtime_error(
"Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
435 for (
unsigned int i = 0; i < maxPeriods; i++) {
436 if (
confAvg[i].size() != numBuckets) {
437 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate conf average bucket count");
441 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
442 if (maxPeriods !=
failAvg.size()) {
443 throw std::runtime_error(
"Corrupt estimates file. Mismatch in confirms tracked for failures");
445 for (
unsigned int i = 0; i < maxPeriods; i++) {
446 if (
failAvg[i].size() != numBuckets) {
447 throw std::runtime_error(
"Corrupt estimates file. Mismatch in one of failure average bucket counts");
456 numBuckets, maxConfirms);
461 unsigned int bucketindex =
bucketMap.lower_bound(val)->second;
462 unsigned int blockIndex = nBlockHeight %
unconfTxs.size();
470 int blocksAgo = nBestSeenHeight - entryHeight;
471 if (nBestSeenHeight == 0)
478 if (blocksAgo >= (
int)
unconfTxs.size()) {
487 unsigned int blockIndex = entryHeight %
unconfTxs.size();
488 if (
unconfTxs[blockIndex][bucketindex] > 0) {
492 blockIndex, bucketindex);
495 if (!inBlock && (
unsigned int)blocksAgo >=
scale) {
497 unsigned int periodsAgo = blocksAgo /
scale;
498 for (
size_t i = 0; i < periodsAgo && i <
failAvg.size(); i++) {
518 std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
519 if (pos != mapMemPoolTxs.end()) {
520 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
521 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
522 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
523 mapMemPoolTxs.erase(hash);
531 : m_estimation_filepath{estimation_filepath}, nBestSeenHeight{0}, firstRecordedHeight{0}, historicalFirst{0}, historicalBest{0}, trackedTxs{0}, untrackedTxs{0}
533 static_assert(MIN_BUCKET_FEERATE > 0,
"Min feerate must be nonzero");
534 size_t bucketIndex = 0;
536 for (
double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
537 buckets.push_back(bucketBoundary);
538 bucketMap[bucketBoundary] = bucketIndex;
542 assert(bucketMap.size() == buckets.size());
544 feeStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
545 shortStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
546 longStats = std::unique_ptr<TxConfirmStats>(
new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
550 if (est_file.IsNull() || !Read(est_file)) {
560 unsigned int txHeight = entry.
GetHeight();
562 if (mapMemPoolTxs.count(hash)) {
568 if (txHeight != nBestSeenHeight) {
578 if (!validFeeEstimate) {
587 mapMemPoolTxs[hash].blockHeight = txHeight;
588 unsigned int bucketIndex = feeStats->NewTx(txHeight, (
double)feeRate.GetFeePerK());
589 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
590 unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (
double)feeRate.GetFeePerK());
591 assert(bucketIndex == bucketIndex2);
592 unsigned int bucketIndex3 = longStats->NewTx(txHeight, (
double)feeRate.GetFeePerK());
593 assert(bucketIndex == bucketIndex3);
607 int blocksToConfirm = nBlockHeight - entry->
GetHeight();
608 if (blocksToConfirm <= 0) {
618 feeStats->Record(blocksToConfirm, (
double)feeRate.GetFeePerK());
619 shortStats->Record(blocksToConfirm, (
double)feeRate.GetFeePerK());
620 longStats->Record(blocksToConfirm, (
double)feeRate.GetFeePerK());
625 std::vector<const CTxMemPoolEntry*>& entries)
628 if (nBlockHeight <= nBestSeenHeight) {
640 nBestSeenHeight = nBlockHeight;
643 feeStats->ClearCurrent(nBlockHeight);
644 shortStats->ClearCurrent(nBlockHeight);
645 longStats->ClearCurrent(nBlockHeight);
648 feeStats->UpdateMovingAverages();
649 shortStats->UpdateMovingAverages();
650 longStats->UpdateMovingAverages();
652 unsigned int countedTxs = 0;
654 for (
const auto& entry : entries) {
659 if (firstRecordedHeight == 0 && countedTxs > 0) {
660 firstRecordedHeight = nBestSeenHeight;
665 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",
666 countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
688 stats = shortStats.get();
693 stats = feeStats.get();
697 stats = longStats.get();
705 if (confTarget <= 0 || (
unsigned int)confTarget > stats->
GetMaxConfirms())
707 if (successThreshold > 1)
710 double median = stats->
EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
723 return shortStats->GetMaxConfirms();
726 return feeStats->GetMaxConfirms();
729 return longStats->GetMaxConfirms();
737 if (firstRecordedHeight == 0)
return 0;
738 assert(nBestSeenHeight >= firstRecordedHeight);
740 return nBestSeenHeight - firstRecordedHeight;
745 if (historicalFirst == 0)
return 0;
746 assert(historicalBest >= historicalFirst);
750 return historicalBest - historicalFirst;
765 double estimate = -1;
766 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
768 if (confTarget <= shortStats->GetMaxConfirms()) {
769 estimate = shortStats->EstimateMedianVal(confTarget,
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
771 else if (confTarget <= feeStats->GetMaxConfirms()) {
772 estimate = feeStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
775 estimate = longStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
777 if (checkShorterHorizon) {
780 if (confTarget > feeStats->GetMaxConfirms()) {
781 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(),
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
782 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
784 if (result) *result = tempResult;
787 if (confTarget > shortStats->GetMaxConfirms()) {
788 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(),
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
789 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
791 if (result) *result = tempResult;
804 double estimate = -1;
806 if (doubleTarget <= shortStats->GetMaxConfirms()) {
809 if (doubleTarget <= feeStats->GetMaxConfirms()) {
811 if (longEstimate > estimate) {
812 estimate = longEstimate;
813 if (result) *result = tempResult;
839 if (confTarget <= 0 || (
unsigned int)confTarget > longStats->GetMaxConfirms()) {
844 if (confTarget == 1) confTarget = 2;
847 if ((
unsigned int)confTarget > maxUsableEstimate) {
848 confTarget = maxUsableEstimate;
852 if (confTarget <= 1)
return CFeeRate(0);
867 feeCalc->
est = tempResult;
872 if (actualEst > median) {
875 feeCalc->
est = tempResult;
880 if (doubleEst > median) {
883 feeCalc->
est = tempResult;
888 if (conservative || median == -1) {
890 if (consEst > median) {
893 feeCalc->
est = tempResult;
908 if (est_file.IsNull() || !
Write(est_file)) {
919 fileout << nBestSeenHeight;
921 fileout << firstRecordedHeight << nBestSeenHeight;
924 fileout << historicalFirst << historicalBest;
926 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
927 feeStats->Write(fileout);
928 shortStats->Write(fileout);
929 longStats->Write(fileout);
931 catch (
const std::exception&) {
932 LogPrintf(
"CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
942 int nVersionRequired, nVersionThatWrote;
943 filein >> nVersionRequired >> nVersionThatWrote;
945 throw std::runtime_error(
strprintf(
"up-version (%d) fee estimate file", nVersionRequired));
950 unsigned int nFileBestSeenHeight;
951 filein >> nFileBestSeenHeight;
953 if (nVersionRequired < 149900) {
954 LogPrintf(
"%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
956 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
957 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
958 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
959 throw std::runtime_error(
"Corrupt estimates file. Historical block range for estimates is invalid");
961 std::vector<double> fileBuckets;
962 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
963 size_t numBuckets = fileBuckets.size();
964 if (numBuckets <= 1 || numBuckets > 1000) {
965 throw std::runtime_error(
"Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
971 fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
972 fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
973 fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
977 buckets = fileBuckets;
979 for (
unsigned int i = 0; i < buckets.size(); i++) {
980 bucketMap[buckets[i]] = i;
984 feeStats = std::move(fileFeeStats);
985 shortStats = std::move(fileShortStats);
986 longStats = std::move(fileLongStats);
988 nBestSeenHeight = nFileBestSeenHeight;
989 historicalFirst = nFileHistoricalFirst;
990 historicalBest = nFileHistoricalBest;
993 catch (
const std::exception& e) {
994 LogPrintf(
"CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
1003 size_t num_entries = mapMemPoolTxs.size();
1005 while (!mapMemPoolTxs.empty()) {
1006 auto mi = mapMemPoolTxs.begin();
1010 LogPrint(
BCLog::ESTIMATEFEE,
"Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
1018 feeset.insert(bucketBoundary);
1024 std::set<double>::iterator it =
feeset.lower_bound(currentMinFee);
1028 return static_cast<CAmount>(*it);
static constexpr double MED_DECAY
Decay of .9952 is a half-life of 144 blocks or about 1 day.
std::vector< std::vector< double > > failAvg
bool _removeTx(const uint256 &hash, bool inBlock) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
A non-thread-safe helper for the removeTx function.
CFeeRate estimateFee(int confTarget) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
DEPRECATED.
void processBlock(unsigned int nBlockHeight, std::vector< const CTxMemPoolEntry *> &entries) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process all the transactions that have been included in a block.
bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry *entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Process a transaction confirmed in a block.
#define LogPrint(category,...)
FILE * fopen(const fs::path &p, const char *mode)
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.
unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of recorded fee estimate data represented in saved data file.
static constexpr double MAX_FILTER_FEERATE
We will instantiate an instance of this class to track transactions that were included in a block...
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
static constexpr double DOUBLE_SUCCESS_PCT
Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks.
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Calculation of highest target that reasonable estimate can be provided for.
void Record(int blocksToConfirm, double val)
Record a new transaction data point in the current block stats.
Non-refcounted RAII wrapper for FILE*.
uint64_t EncodeDouble(double f) noexcept
void resizeInMemoryCounters(size_t newbuckets)
bool removeTx(uint256 hash, bool inBlock) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Remove a transaction from the mempool tracking stats.
void ClearCurrent(unsigned int nBlockHeight)
Roll the circular buffer for unconfirmed txs.
static constexpr double SUFFICIENT_TXS_SHORT
Require an avg of 0.5 tx when using short decay since there are fewer blocks considered.
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
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)
static constexpr double SUCCESS_PCT
Require greater than 85% of X feerate transactions to be confirmed within Y blocks.
double EstimateMedianVal(int confTarget, double sufficientTxVal, double minSuccess, unsigned int nBlockHeight, EstimationResult *result=nullptr) const
Calculate a feerate estimate.
const std::map< double, unsigned int > & bucketMap
static constexpr unsigned int SHORT_SCALE
static constexpr double LONG_DECAY
Decay of .99931 is a half-life of 1008 blocks or about 1 week.
std::vector< std::vector< double > > confAvg
static std::string PathToString(const path &path)
Convert path object to a byte string.
bool Write(AutoFile &fileout) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Write estimation data to a file.
unsigned int NewTx(unsigned int nBlockHeight, double val)
Record a new transaction entering the mempool.
unsigned int GetHeight() const
void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketIndex, bool inBlock)
Remove a transaction from mempool tracking stats.
const uint256 & GetHash() const
const CAmount & GetFee() const
double DecodeDouble(uint64_t v) noexcept
const std::vector< double > & buckets
unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Number of blocks of data recorded while fee estimates have been running.
void Flush() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Drop still unconfirmed transactions and record current estimations, if the fee estimation file is pre...
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Estimate feerate needed to get be included in a block within confTarget blocks.
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Helper for estimateSmartFee.
std::string ToString() const
void Read(AutoFile &filein, int nFileVersion, size_t numBuckets)
Read saved state of estimation data from a file and replace all internal data structures and variable...
FeeFilterRounder(const CFeeRate &minIncrementalFee)
Create new FeeFilterRounder.
void processTransaction(const CTxMemPoolEntry &entry, bool validFeeEstimate) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Process a transaction accepted to the mempool.
void Write(AutoFile &fileout) const
Write state of estimation data to a file.
FastRandomContext insecure_rand
CBlockPolicyEstimator(const fs::path &estimation_filepath)
Create new BlockPolicyEstimator and initialize stats tracking classes with default values...
static constexpr unsigned int LONG_SCALE
uint32_t rand32() noexcept
Generate a random 32-bit integer.
int64_t GetTimeMicros()
Returns the system time (not mockable)
std::vector< std::vector< int > > unconfTxs
static constexpr unsigned int MED_SCALE
static const unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren't valid.
std::vector< int > oldUnconfTxs
bool Read(AutoFile &filein) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Read estimation data from a file.
const CTransaction & GetTx() const
unsigned int GetMaxConfirms() const
Return the max number of confirms we're tracking.
static constexpr unsigned int LONG_BLOCK_PERIODS
Track confirm delays up to 1008 blocks for long horizon.
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
static constexpr unsigned int SHORT_BLOCK_PERIODS
Track confirm delays up to 12 blocks for short horizon.
static constexpr double INF_FEERATE
static constexpr double SUFFICIENT_FEETXS
Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance.
std::vector< double > m_feerate_avg
CAmount round(CAmount currentMinFee)
Quantize a minimum fee for privacy purpose before broadcast.
static constexpr double SHORT_DECAY
Decay of .962 is a half-life of 18 blocks or about 3 hours.
std::set< double > feeset
std::vector< double > txCtAvg
void UpdateMovingAverages()
Update our estimates by decaying our historical moving average and updating with the data gathered fr...
CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result=nullptr) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Return a specific fee estimate calculation with a given success threshold and time horizon...
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
const fs::path m_estimation_filepath
void FlushUnconfirmed() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool...
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Calculation of highest target that estimates are tracked for.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.