From fff1cae43af959a601cf2558cb3c77f3c2b1aa80 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 18 May 2021 12:36:53 -0700 Subject: [PATCH] Convert uses of double-serialization to {En,De}codeDouble --- src/policy/fees.cpp | 44 ++++++++++++++++++++++++++++++----------- src/test/fuzz/float.cpp | 20 +++++++++++++------ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 52c33621669..2ae5798ebec 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat"; @@ -26,6 +27,25 @@ std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) assert(false); } +namespace { + +struct EncodedDoubleFormatter +{ + template void Ser(Stream &s, double v) + { + s << EncodeDouble(v); + } + + template void Unser(Stream& s, double& v) + { + uint64_t encoded; + s >> encoded; + v = DecodeDouble(encoded); + } +}; + +} // namespace + /** * We will instantiate an instance of this class to track transactions that were * included in a block. We will lump transactions into a bucket according to their @@ -356,12 +376,12 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal, void TxConfirmStats::Write(CAutoFile& fileout) const { - fileout << decay; + fileout << Using(decay); fileout << scale; - fileout << m_feerate_avg; - fileout << txCtAvg; - fileout << confAvg; - fileout << failAvg; + fileout << Using>(m_feerate_avg); + fileout << Using>(txCtAvg); + fileout << Using>>(confAvg); + fileout << Using>>(failAvg); } void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets) @@ -372,7 +392,7 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets size_t maxConfirms, maxPeriods; // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor - filein >> decay; + filein >> Using(decay); if (decay <= 0 || decay >= 1) { throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)"); } @@ -381,15 +401,15 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets throw std::runtime_error("Corrupt estimates file. Scale must be non-zero"); } - filein >> m_feerate_avg; + filein >> Using>(m_feerate_avg); if (m_feerate_avg.size() != numBuckets) { throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count"); } - filein >> txCtAvg; + filein >> Using>(txCtAvg); if (txCtAvg.size() != numBuckets) { throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count"); } - filein >> confAvg; + filein >> Using>>(confAvg); maxPeriods = confAvg.size(); maxConfirms = scale * maxPeriods; @@ -402,7 +422,7 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets } } - filein >> failAvg; + filein >> Using>>(failAvg); if (maxPeriods != failAvg.size()) { throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures"); } @@ -884,7 +904,7 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const else { fileout << historicalFirst << historicalBest; } - fileout << buckets; + fileout << Using>(buckets); feeStats->Write(fileout); shortStats->Write(fileout); longStats->Write(fileout); @@ -920,7 +940,7 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein) throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid"); } std::vector fileBuckets; - filein >> fileBuckets; + filein >> Using>(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"); diff --git a/src/test/fuzz/float.cpp b/src/test/fuzz/float.cpp index f806c82d14b..e95d593b227 100644 --- a/src/test/fuzz/float.cpp +++ b/src/test/fuzz/float.cpp @@ -7,10 +7,13 @@ #include #include #include +#include #include #include #include +#include +#include FUZZ_TARGET(float) { @@ -19,12 +22,17 @@ FUZZ_TARGET(float) { const double d = fuzzed_data_provider.ConsumeFloatingPoint(); (void)memusage::DynamicUsage(d); - assert(ser_uint64_to_double(ser_double_to_uint64(d)) == d); - CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); - stream << d; - double d_deserialized; - stream >> d_deserialized; - assert(d == d_deserialized); + uint64_t encoded = EncodeDouble(d); + if constexpr (std::numeric_limits::is_iec559) { + if (!std::isnan(d)) { + uint64_t encoded_in_memory; + std::copy((const unsigned char*)&d, (const unsigned char*)(&d + 1), (unsigned char*)&encoded_in_memory); + assert(encoded_in_memory == encoded); + } + } + double d_deserialized = DecodeDouble(encoded); + assert(std::isnan(d) == std::isnan(d_deserialized)); + assert(std::isnan(d) || d == d_deserialized); } }