32struct EncodedDoubleFormatter
34 template<
typename Stream>
void Ser(Stream &s,
double v)
39 template<
typename Stream>
void Unser(Stream& s,
double& v)
106 TxConfirmStats(
const std::vector<double>& defaultBuckets,
const std::map<double, unsigned int>& defaultBucketMap,
107 unsigned int maxPeriods,
double decay,
unsigned int scale);
118 void Record(
int blocksToConfirm,
double val);
121 unsigned int NewTx(
unsigned int nBlockHeight,
double val);
124 void removeTx(
unsigned int entryHeight,
unsigned int nBestSeenHeight,
125 unsigned int bucketIndex,
bool inBlock);
141 double minSuccess,
unsigned int nBlockHeight,
154 void Read(
CAutoFile& filein,
int nFileVersion,
size_t numBuckets);
159 const std::map<double, unsigned int>& defaultBucketMap,
160 unsigned int maxPeriods,
double _decay,
unsigned int _scale)
161 : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
163 assert(_scale != 0 &&
"_scale must be non-zero");
166 for (
unsigned int i = 0; i < maxPeriods; i++) {
180 for (
unsigned int i = 0; i <
unconfTxs.size(); i++) {
189 for (
unsigned int j = 0; j <
buckets.size(); j++) {
199 if (blocksToConfirm < 1)
201 int periodsToConfirm = (blocksToConfirm +
scale - 1) /
scale;
202 unsigned int bucketindex =
bucketMap.lower_bound(feerate)->second;
203 for (
size_t i = periodsToConfirm; i <=
confAvg.size(); i++) {
213 for (
unsigned int j = 0; j <
buckets.size(); j++) {
214 for (
unsigned int i = 0; i <
confAvg.size(); i++) {
225 double successBreakPoint,
unsigned int nBlockHeight,
233 const int periodTarget = (confTarget +
scale - 1) /
scale;
234 const int maxbucketindex =
buckets.size() - 1;
241 unsigned int curNearBucket = maxbucketindex;
242 unsigned int bestNearBucket = maxbucketindex;
243 unsigned int curFarBucket = maxbucketindex;
244 unsigned int bestFarBucket = maxbucketindex;
246 bool foundAnswer =
false;
248 bool newBucketRange =
true;
254 for (
int bucket = maxbucketindex; bucket >= 0; --bucket) {
255 if (newBucketRange) {
256 curNearBucket = bucket;
257 newBucketRange =
false;
259 curFarBucket = bucket;
260 nConf +=
confAvg[periodTarget - 1][bucket];
262 failNum +=
failAvg[periodTarget - 1][bucket];
263 for (
unsigned int confct = confTarget; confct <
GetMaxConfirms(); confct++)
264 extraNum +=
unconfTxs[(nBlockHeight - confct) % bins][bucket];
270 if (totalNum >= sufficientTxVal / (1 -
decay)) {
271 double curPct = nConf / (totalNum + failNum + extraNum);
274 if (curPct < successBreakPoint) {
275 if (passing ==
true) {
277 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
278 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
279 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
303 bestNearBucket = curNearBucket;
304 bestFarBucket = curFarBucket;
305 newBucketRange =
true;
317 unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
318 unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
319 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
322 if (foundAnswer && txSum != 0) {
324 for (
unsigned int j = minBucket; j <= maxBucket; j++) {
333 passBucket.
start = minBucket ?
buckets[minBucket-1] : 0;
338 if (passing && !newBucketRange) {
339 unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
340 unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
341 failBucket.
start = failMinBucket ?
buckets[failMinBucket - 1] : 0;
349 float passed_within_target_perc = 0.0;
350 float failed_within_target_perc = 0.0;
358 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",
359 confTarget, 100.0 * successBreakPoint,
decay,
360 median, passBucket.
start, passBucket.
end,
361 passed_within_target_perc,
364 failed_within_target_perc,
369 result->
pass = passBucket;
370 result->
fail = failBucket;
379 fileout << Using<EncodedDoubleFormatter>(
decay);
381 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
382 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
383 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
384 fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
392 size_t maxConfirms, maxPeriods;
395 filein >> Using<EncodedDoubleFormatter>(
decay);
396 if (decay <= 0 || decay >= 1) {
397 throw std::runtime_error(
"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
401 throw std::runtime_error(
"Corrupt estimates file. Scale must be non-zero");
404 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
m_feerate_avg);
406 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate average bucket count");
408 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(
txCtAvg);
409 if (
txCtAvg.size() != numBuckets) {
410 throw std::runtime_error(
"Corrupt estimates file. Mismatch in tx count bucket count");
412 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
confAvg);
414 maxConfirms =
scale * maxPeriods;
416 if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) {
417 throw std::runtime_error(
"Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
419 for (
unsigned int i = 0; i < maxPeriods; i++) {
420 if (
confAvg[i].size() != numBuckets) {
421 throw std::runtime_error(
"Corrupt estimates file. Mismatch in feerate conf average bucket count");
425 filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(
failAvg);
426 if (maxPeriods !=
failAvg.size()) {
427 throw std::runtime_error(
"Corrupt estimates file. Mismatch in confirms tracked for failures");
429 for (
unsigned int i = 0; i < maxPeriods; i++) {
430 if (
failAvg[i].size() != numBuckets) {
431 throw std::runtime_error(
"Corrupt estimates file. Mismatch in one of failure average bucket counts");
440 numBuckets, maxConfirms);
445 unsigned int bucketindex =
bucketMap.lower_bound(val)->second;
446 unsigned int blockIndex = nBlockHeight %
unconfTxs.size();
454 int blocksAgo = nBestSeenHeight - entryHeight;
455 if (nBestSeenHeight == 0)
462 if (blocksAgo >= (
int)
unconfTxs.size()) {
471 unsigned int blockIndex = entryHeight %
unconfTxs.size();
472 if (
unconfTxs[blockIndex][bucketindex] > 0) {
476 blockIndex, bucketindex);
479 if (!inBlock && (
unsigned int)blocksAgo >=
scale) {
481 unsigned int periodsAgo = blocksAgo /
scale;
482 for (
size_t i = 0; i < periodsAgo && i <
failAvg.size(); i++) {
496 std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
497 if (pos != mapMemPoolTxs.end()) {
498 feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
499 shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
500 longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
501 mapMemPoolTxs.erase(hash);
509 : nBestSeenHeight(0), firstRecordedHeight(0), historicalFirst(0), historicalBest(0), trackedTxs(0), untrackedTxs(0)
512 size_t bucketIndex = 0;
515 buckets.push_back(bucketBoundary);
516 bucketMap[bucketBoundary] = bucketIndex;
520 assert(bucketMap.size() == buckets.size());
541 unsigned int txHeight = entry.
GetHeight();
543 if (mapMemPoolTxs.count(hash)) {
549 if (txHeight != nBestSeenHeight) {
559 if (!validFeeEstimate) {
568 mapMemPoolTxs[hash].blockHeight = txHeight;
569 unsigned int bucketIndex = feeStats->NewTx(txHeight, (
double)feeRate.
GetFeePerK());
570 mapMemPoolTxs[hash].bucketIndex = bucketIndex;
571 unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (
double)feeRate.
GetFeePerK());
572 assert(bucketIndex == bucketIndex2);
573 unsigned int bucketIndex3 = longStats->NewTx(txHeight, (
double)feeRate.
GetFeePerK());
574 assert(bucketIndex == bucketIndex3);
587 int blocksToConfirm = nBlockHeight - entry->
GetHeight();
588 if (blocksToConfirm <= 0) {
598 feeStats->Record(blocksToConfirm, (
double)feeRate.
GetFeePerK());
599 shortStats->Record(blocksToConfirm, (
double)feeRate.
GetFeePerK());
600 longStats->Record(blocksToConfirm, (
double)feeRate.
GetFeePerK());
605 std::vector<const CTxMemPoolEntry*>& entries)
608 if (nBlockHeight <= nBestSeenHeight) {
620 nBestSeenHeight = nBlockHeight;
623 feeStats->ClearCurrent(nBlockHeight);
624 shortStats->ClearCurrent(nBlockHeight);
625 longStats->ClearCurrent(nBlockHeight);
628 feeStats->UpdateMovingAverages();
629 shortStats->UpdateMovingAverages();
630 longStats->UpdateMovingAverages();
632 unsigned int countedTxs = 0;
634 for (
const auto& entry : entries) {
639 if (firstRecordedHeight == 0 && countedTxs > 0) {
640 firstRecordedHeight = nBestSeenHeight;
645 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",
646 countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
668 stats = shortStats.get();
673 stats = feeStats.get();
677 stats = longStats.get();
685 if (confTarget <= 0 || (
unsigned int)confTarget > stats->
GetMaxConfirms())
687 if (successThreshold > 1)
690 double median = stats->
EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
703 return shortStats->GetMaxConfirms();
706 return feeStats->GetMaxConfirms();
709 return longStats->GetMaxConfirms();
717 if (firstRecordedHeight == 0)
return 0;
718 assert(nBestSeenHeight >= firstRecordedHeight);
720 return nBestSeenHeight - firstRecordedHeight;
725 if (historicalFirst == 0)
return 0;
726 assert(historicalBest >= historicalFirst);
730 return historicalBest - historicalFirst;
745 double estimate = -1;
746 if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
748 if (confTarget <= shortStats->GetMaxConfirms()) {
749 estimate = shortStats->EstimateMedianVal(confTarget,
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
751 else if (confTarget <= feeStats->GetMaxConfirms()) {
752 estimate = feeStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
755 estimate = longStats->EstimateMedianVal(confTarget,
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
757 if (checkShorterHorizon) {
760 if (confTarget > feeStats->GetMaxConfirms()) {
761 double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(),
SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
762 if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
764 if (result) *result = tempResult;
767 if (confTarget > shortStats->GetMaxConfirms()) {
768 double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(),
SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
769 if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
771 if (result) *result = tempResult;
784 double estimate = -1;
786 if (doubleTarget <= shortStats->GetMaxConfirms()) {
789 if (doubleTarget <= feeStats->GetMaxConfirms()) {
791 if (longEstimate > estimate) {
792 estimate = longEstimate;
793 if (result) *result = tempResult;
819 if (confTarget <= 0 || (
unsigned int)confTarget > longStats->GetMaxConfirms()) {
824 if (confTarget == 1) confTarget = 2;
827 if ((
unsigned int)confTarget > maxUsableEstimate) {
828 confTarget = maxUsableEstimate;
832 if (confTarget <= 1)
return CFeeRate(0);
847 feeCalc->
est = tempResult;
852 if (actualEst > median) {
855 feeCalc->
est = tempResult;
860 if (doubleEst > median) {
863 feeCalc->
est = tempResult;
868 if (conservative || median == -1) {
870 if (consEst > median) {
873 feeCalc->
est = tempResult;
900 fileout << nBestSeenHeight;
902 fileout << firstRecordedHeight << nBestSeenHeight;
905 fileout << historicalFirst << historicalBest;
907 fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
908 feeStats->Write(fileout);
909 shortStats->Write(fileout);
910 longStats->Write(fileout);
912 catch (
const std::exception&) {
913 LogPrintf(
"CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
923 int nVersionRequired, nVersionThatWrote;
924 filein >> nVersionRequired >> nVersionThatWrote;
926 throw std::runtime_error(
strprintf(
"up-version (%d) fee estimate file", nVersionRequired));
931 unsigned int nFileBestSeenHeight;
932 filein >> nFileBestSeenHeight;
934 if (nVersionRequired < 149900) {
935 LogPrintf(
"%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
937 unsigned int nFileHistoricalFirst, nFileHistoricalBest;
938 filein >> nFileHistoricalFirst >> nFileHistoricalBest;
939 if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
940 throw std::runtime_error(
"Corrupt estimates file. Historical block range for estimates is invalid");
942 std::vector<double> fileBuckets;
943 filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
944 size_t numBuckets = fileBuckets.size();
945 if (numBuckets <= 1 || numBuckets > 1000) {
946 throw std::runtime_error(
"Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
952 fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
953 fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
954 fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
958 buckets = fileBuckets;
960 for (
unsigned int i = 0; i < buckets.size(); i++) {
961 bucketMap[buckets[i]] = i;
965 feeStats = std::move(fileFeeStats);
966 shortStats = std::move(fileShortStats);
967 longStats = std::move(fileLongStats);
969 nBestSeenHeight = nFileBestSeenHeight;
970 historicalFirst = nFileHistoricalFirst;
971 historicalBest = nFileHistoricalBest;
974 catch (
const std::exception& e) {
975 LogPrintf(
"CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
984 size_t num_entries = mapMemPoolTxs.size();
986 while (!mapMemPoolTxs.empty()) {
987 auto mi = mapMemPoolTxs.begin();
991 LogPrint(
BCLog::ESTIMATEFEE,
"Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
999 feeset.insert(bucketBoundary);
1005 std::set<double>::iterator it =
feeset.lower_bound(currentMinFee);
1009 return static_cast<CAmount>(*it);
int64_t CAmount
Amount in satoshis (Can be negative)
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Non-refcounted RAII wrapper for FILE*.
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
RecursiveMutex m_cs_fee_estimator
static constexpr unsigned int LONG_SCALE
bool Read(CAutoFile &filein)
Read estimation data from a file.
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,...
static const unsigned int OLDEST_ESTIMATE_HISTORY
Historical estimates that are older than this aren't valid.
CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result=nullptr) const
Return a specific fee estimate calculation with a given success threshold and time horizon,...
static constexpr double SUFFICIENT_FEETXS
Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance.
static constexpr double MAX_BUCKET_FEERATE
static constexpr unsigned int LONG_BLOCK_PERIODS
Track confirm delays up to 1008 blocks for long horizon.
static constexpr double SHORT_DECAY
Decay of .962 is a half-life of 18 blocks or about 3 hours.
bool Write(CAutoFile &fileout) const
Write estimation data to a file.
CBlockPolicyEstimator()
Create new BlockPolicyEstimator and initialize stats tracking classes with default values.
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.
bool removeTx(uint256 hash, bool inBlock)
Remove a transaction from the mempool tracking stats.
void FlushUnconfirmed()
Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool.
void Flush()
Drop still unconfirmed transactions and record current estimations, if the fee estimation file is pre...
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Calculation of highest target that reasonable estimate can be provided for.
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.
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.
bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry *entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator)
Process a transaction confirmed in a block.
static constexpr double SUFFICIENT_TXS_SHORT
Require an avg of 0.5 tx when using short decay since there are fewer blocks considered.
static constexpr unsigned int MED_SCALE
static constexpr unsigned int MED_BLOCK_PERIODS
Track confirm delays up to 48 blocks for medium horizon.
void processTransaction(const CTxMemPoolEntry &entry, bool validFeeEstimate)
Process a transaction accepted to the mempool.
void processBlock(unsigned int nBlockHeight, std::vector< const CTxMemPoolEntry * > &entries)
Process all the transactions that have been included in a block.
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
Estimate feerate needed to get be included in a block within confTarget blocks.
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const
Calculation of highest target that estimates are tracked for.
CFeeRate estimateFee(int confTarget) const
DEPRECATED.
Fee rate in satoshis per kilobyte: CAmount / kB.
CAmount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
const uint256 & GetHash() const
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
unsigned int GetHeight() const
const CTransaction & GetTx() const
const CAmount & GetFee() const
uint32_t rand32() noexcept
Generate a random 32-bit integer.
FastRandomContext insecure_rand
static constexpr double MAX_FILTER_FEERATE
CAmount round(CAmount currentMinFee)
Quantize a minimum fee for privacy purpose before broadcast.
FeeFilterRounder(const CFeeRate &minIncrementalFee)
Create new FeeFilterRounder.
std::set< double > feeset
static constexpr double FEE_FILTER_SPACING
FEE_FILTER_SPACING is just used to provide some quantization of fee filter results.
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 Write(CAutoFile &fileout) const
Write state of estimation data to a file.
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
std::vector< std::vector< double > > confAvg
std::vector< std::vector< int > > unconfTxs
void Read(CAutoFile &filein, int nFileVersion, size_t numBuckets)
Read saved state of estimation data from a file and replace all internal data structures and variable...
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.
std::string ToString() const
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
#define LogPrint(category,...)
static std::string PathToString(const path &path)
Convert path object to byte string.
FILE * fopen(const fs::path &p, const char *mode)
static constexpr double INF_FEERATE
static const char * FEE_ESTIMATES_FILENAME
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
uint64_t EncodeDouble(double f) noexcept
double DecodeDouble(uint64_t v) noexcept
int64_t GetTimeMicros()
Returns the system time (not mockable)