mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-12 13:42:10 +02:00
Merge bitcoin/bitcoin#35830: fees: Return false for incompatible fee estimates
b9d573e4a9fees: Return false for incompatible fee estimates (Hao Xu) Pull request description: policy_estimator_io deliberately reuses a CBlockPolicyEstimator because constructing one for every fuzz input severely reduces throughput. However, Read() returns true for an incompatible old fee estimates file without replacing the estimator state. The target then calls Write() with state loaded by a previous input, making coverage depend on corpus order. Return false for incompatible files so the target skips Write() when no state was loaded. This keeps the estimator reuse optimization instead of resetting the expensive object before every fuzz input. For the in-tree production caller, incompatible files remain non-fatal and the estimator still starts from its default state. Read() now reports failure, so startup emits one additional non-fatal warning. Node startup and estimator state are unchanged, as is RPC behavior. ACKs for top commit: maflcko: review ACKb9d573e4a9📩 sedited: ACKb9d573e4a9Tree-SHA512: d6ec5986122716ad2c6fb5305626aec71b4b416242791547a12f86fb210d768c87fcb9615fd50259908656766bbe085d55ae90e1d72eaee24d438eecfd9c6dd4
This commit is contained in:
@@ -1008,51 +1008,51 @@ bool CBlockPolicyEstimator::Read(AutoFile& filein)
|
||||
if (nVersionRequired > CURRENT_FEES_FILE_VERSION) {
|
||||
throw std::runtime_error{strprintf("File version (%d) too high to be read.", nVersionRequired)};
|
||||
}
|
||||
if (nVersionRequired < CURRENT_FEES_FILE_VERSION) {
|
||||
throw std::runtime_error{strprintf("File version (%d) incompatible: Too old to be read", nVersionRequired)};
|
||||
}
|
||||
|
||||
// Read fee estimates file into temporary variables so existing data
|
||||
// structures aren't corrupted if there is an exception.
|
||||
unsigned int nFileBestSeenHeight;
|
||||
filein >> nFileBestSeenHeight;
|
||||
|
||||
if (nVersionRequired < CURRENT_FEES_FILE_VERSION) {
|
||||
LogWarning("Incompatible old fee estimation data (non-fatal). Version: %d", nVersionRequired);
|
||||
} else { // nVersionRequired == CURRENT_FEES_FILE_VERSION
|
||||
unsigned int nFileHistoricalFirst, nFileHistoricalBest;
|
||||
filein >> nFileHistoricalFirst >> nFileHistoricalBest;
|
||||
if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
|
||||
throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
|
||||
}
|
||||
std::vector<double> fileBuckets;
|
||||
filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
|
||||
size_t numBuckets = fileBuckets.size();
|
||||
if (numBuckets <= 1 || numBuckets > 1000) {
|
||||
throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
|
||||
}
|
||||
|
||||
std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
|
||||
std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
|
||||
std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
|
||||
fileFeeStats->Read(filein, numBuckets);
|
||||
fileShortStats->Read(filein, numBuckets);
|
||||
fileLongStats->Read(filein, numBuckets);
|
||||
|
||||
// Fee estimates file parsed correctly
|
||||
// Copy buckets from file and refresh our bucketmap
|
||||
buckets = fileBuckets;
|
||||
bucketMap.clear();
|
||||
for (unsigned int i = 0; i < buckets.size(); i++) {
|
||||
bucketMap[buckets[i]] = i;
|
||||
}
|
||||
|
||||
// Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
|
||||
feeStats = std::move(fileFeeStats);
|
||||
shortStats = std::move(fileShortStats);
|
||||
longStats = std::move(fileLongStats);
|
||||
|
||||
nBestSeenHeight = nFileBestSeenHeight;
|
||||
historicalFirst = nFileHistoricalFirst;
|
||||
historicalBest = nFileHistoricalBest;
|
||||
// nVersionRequired == CURRENT_FEES_FILE_VERSION
|
||||
unsigned int nFileHistoricalFirst, nFileHistoricalBest;
|
||||
filein >> nFileHistoricalFirst >> nFileHistoricalBest;
|
||||
if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
|
||||
throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
|
||||
}
|
||||
std::vector<double> fileBuckets;
|
||||
filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
|
||||
size_t numBuckets = fileBuckets.size();
|
||||
if (numBuckets <= 1 || numBuckets > 1000) {
|
||||
throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
|
||||
}
|
||||
|
||||
std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
|
||||
std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
|
||||
std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
|
||||
fileFeeStats->Read(filein, numBuckets);
|
||||
fileShortStats->Read(filein, numBuckets);
|
||||
fileLongStats->Read(filein, numBuckets);
|
||||
|
||||
// Fee estimates file parsed correctly
|
||||
// Copy buckets from file and refresh our bucketmap
|
||||
buckets = fileBuckets;
|
||||
bucketMap.clear();
|
||||
for (unsigned int i = 0; i < buckets.size(); i++) {
|
||||
bucketMap[buckets[i]] = i;
|
||||
}
|
||||
|
||||
// Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
|
||||
feeStats = std::move(fileFeeStats);
|
||||
shortStats = std::move(fileShortStats);
|
||||
longStats = std::move(fileLongStats);
|
||||
|
||||
nBestSeenHeight = nFileBestSeenHeight;
|
||||
historicalFirst = nFileHistoricalFirst;
|
||||
historicalBest = nFileHistoricalBest;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LogWarning("Unable to read policy estimator data (non-fatal): %s", e.what());
|
||||
|
||||
Reference in New Issue
Block a user