mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-10-10 19:43:13 +02:00
tx fees, policy: do not read estimates of old fee_estimates.dat
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.
Github-Pull: #27622
Rebased-From: 3eb241a141
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -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));
|
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));
|
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")};
|
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));
|
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1016,6 +1030,13 @@ void CBlockPolicyEstimator::FlushUnconfirmed() {
|
|||||||
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
|
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
|
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
|
||||||
{
|
{
|
||||||
CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
|
CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
|
||||||
|
@@ -25,6 +25,11 @@
|
|||||||
// How often to flush fee estimates to fee_estimates.dat.
|
// How often to flush fee estimates to fee_estimates.dat.
|
||||||
static constexpr std::chrono::hours FEE_FLUSH_INTERVAL{1};
|
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 AutoFile;
|
||||||
class CTxMemPoolEntry;
|
class CTxMemPoolEntry;
|
||||||
class TxConfirmStats;
|
class TxConfirmStats;
|
||||||
@@ -248,6 +253,9 @@ public:
|
|||||||
void FlushFeeEstimates()
|
void FlushFeeEstimates()
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
||||||
|
|
||||||
|
/** Calculates the age of the file, since last modified */
|
||||||
|
std::chrono::hours GetFeeEstimatorFileAge();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable Mutex m_cs_fee_estimator;
|
mutable Mutex m_cs_fee_estimator;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user