Skip to content

Commit

Permalink
tx fees, policy: do not read estimates of old fee_estimates.dat
Browse files Browse the repository at this point in the history
Old fee estimates could cause transactions to become stuck in the
mempool. This commit prevents the node from using stale estimates
from an old file.
  • Loading branch information
ismaelsadeeq committed Jun 14, 2023
1 parent 5b886f2 commit 3eb241a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
25 changes: 23 additions & 2 deletions src/policy/fees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <algorithm>
#include <cassert>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
Expand Down Expand Up @@ -545,9 +546,22 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath
shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));

// If the fee estimation file is present, read recorded estimations
AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "rb")};
if (est_file.IsNull() || !Read(est_file)) {

// Whenever the fee estimation file is not present return early
if (est_file.IsNull()) {
LogPrintf("%s is not found. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
return;
}

std::chrono::hours file_age = GetFeeEstimatorFileAge();
// fee estimate file must not be too old to avoid wrong fee estimates.
if (file_age > MAX_FILE_AGE) {
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));
return;
}

if (!Read(est_file)) {
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
}
}
Expand Down Expand Up @@ -1017,6 +1031,13 @@ void CBlockPolicyEstimator::FlushUnconfirmed()
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
}

std::chrono::hours CBlockPolicyEstimator::GetFeeEstimatorFileAge()
{
auto file_time = std::filesystem::last_write_time(m_estimation_filepath);
auto now = std::filesystem::file_time_type::clock::now();
return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
}

static std::set<double> MakeFeeSet(const CFeeRate& min_incremental_fee,
double max_filter_fee_rate,
double fee_filter_spacing)
Expand Down
8 changes: 8 additions & 0 deletions src/policy/fees.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
// How often to flush fee estimates to fee_estimates.dat.
static constexpr std::chrono::hours FEE_FLUSH_INTERVAL{1};

/** fee_estimates.dat that are more than 60 hours (2.5 days) will not be read,
* as the estimates in the file are stale.
*/
static constexpr std::chrono::hours MAX_FILE_AGE{60};

class AutoFile;
class CTxMemPoolEntry;
class TxConfirmStats;
Expand Down Expand Up @@ -248,6 +253,9 @@ class CBlockPolicyEstimator
void FlushFeeEstimates()
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);

/** Calculates the age of the file, since last modified */
std::chrono::hours GetFeeEstimatorFileAge();

private:
mutable Mutex m_cs_fee_estimator;

Expand Down

0 comments on commit 3eb241a

Please sign in to comment.