Convert uses of double-serialization to {En,De}codeDouble

pull/826/head
Pieter Wuille 4 years ago
parent afd964d70b
commit fff1cae43a

@ -10,6 +10,7 @@
#include <logging.h> #include <logging.h>
#include <streams.h> #include <streams.h>
#include <txmempool.h> #include <txmempool.h>
#include <util/serfloat.h>
#include <util/system.h> #include <util/system.h>
static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat"; static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
@ -26,6 +27,25 @@ std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
assert(false); assert(false);
} }
namespace {
struct EncodedDoubleFormatter
{
template<typename Stream> void Ser(Stream &s, double v)
{
s << EncodeDouble(v);
}
template<typename Stream> 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 * 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 * 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 void TxConfirmStats::Write(CAutoFile& fileout) const
{ {
fileout << decay; fileout << Using<EncodedDoubleFormatter>(decay);
fileout << scale; fileout << scale;
fileout << m_feerate_avg; fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
fileout << txCtAvg; fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
fileout << confAvg; fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
fileout << failAvg; fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
} }
void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets) 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; size_t maxConfirms, maxPeriods;
// The current version will store the decay with each individual TxConfirmStats and also keep a scale factor // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
filein >> decay; filein >> Using<EncodedDoubleFormatter>(decay);
if (decay <= 0 || decay >= 1) { if (decay <= 0 || decay >= 1) {
throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)"); 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"); throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
} }
filein >> m_feerate_avg; filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
if (m_feerate_avg.size() != numBuckets) { if (m_feerate_avg.size() != numBuckets) {
throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count"); throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
} }
filein >> txCtAvg; filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
if (txCtAvg.size() != numBuckets) { if (txCtAvg.size() != numBuckets) {
throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count"); throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
} }
filein >> confAvg; filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
maxPeriods = confAvg.size(); maxPeriods = confAvg.size();
maxConfirms = scale * maxPeriods; maxConfirms = scale * maxPeriods;
@ -402,7 +422,7 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
} }
} }
filein >> failAvg; filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
if (maxPeriods != failAvg.size()) { if (maxPeriods != failAvg.size()) {
throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures"); throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
} }
@ -884,7 +904,7 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
else { else {
fileout << historicalFirst << historicalBest; fileout << historicalFirst << historicalBest;
} }
fileout << buckets; fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
feeStats->Write(fileout); feeStats->Write(fileout);
shortStats->Write(fileout); shortStats->Write(fileout);
longStats->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"); throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
} }
std::vector<double> fileBuckets; std::vector<double> fileBuckets;
filein >> fileBuckets; filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
size_t numBuckets = fileBuckets.size(); size_t numBuckets = fileBuckets.size();
if (numBuckets <= 1 || numBuckets > 1000) { if (numBuckets <= 1 || numBuckets > 1000) {
throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets"); throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");

@ -7,10 +7,13 @@
#include <streams.h> #include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h> #include <test/fuzz/fuzz.h>
#include <util/serfloat.h>
#include <version.h> #include <version.h>
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <cmath>
#include <limits>
FUZZ_TARGET(float) FUZZ_TARGET(float)
{ {
@ -19,12 +22,17 @@ FUZZ_TARGET(float)
{ {
const double d = fuzzed_data_provider.ConsumeFloatingPoint<double>(); const double d = fuzzed_data_provider.ConsumeFloatingPoint<double>();
(void)memusage::DynamicUsage(d); (void)memusage::DynamicUsage(d);
assert(ser_uint64_to_double(ser_double_to_uint64(d)) == d);
CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); uint64_t encoded = EncodeDouble(d);
stream << d; if constexpr (std::numeric_limits<double>::is_iec559) {
double d_deserialized; if (!std::isnan(d)) {
stream >> d_deserialized; uint64_t encoded_in_memory;
assert(d == d_deserialized); 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);
} }
} }

Loading…
Cancel
Save