aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter@wuille.net>2021-05-18 12:36:53 -0700
committerPieter Wuille <pieter@wuille.net>2021-05-24 16:15:05 -0700
commitfff1cae43af959a601cf2558cb3c77f3c2b1aa80 (patch)
treef84c771447fb072e76515d65179f4cd0dd5c31b1
parentafd964d70b6f7583ecf89c380f80db07f5b66a60 (diff)
downloadbitcoin-fff1cae43af959a601cf2558cb3c77f3c2b1aa80.tar.xz
Convert uses of double-serialization to {En,De}codeDouble
-rw-r--r--src/policy/fees.cpp44
-rw-r--r--src/test/fuzz/float.cpp20
2 files changed, 46 insertions, 18 deletions
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 52c3362166..2ae5798ebe 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -10,6 +10,7 @@
#include <logging.h>
#include <streams.h>
#include <txmempool.h>
+#include <util/serfloat.h>
#include <util/system.h>
static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
@@ -26,6 +27,25 @@ std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
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
* 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<EncodedDoubleFormatter>(decay);
fileout << scale;
- fileout << m_feerate_avg;
- fileout << txCtAvg;
- fileout << confAvg;
- fileout << failAvg;
+ fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
+ fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
+ fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
+ fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(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<EncodedDoubleFormatter>(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<VectorFormatter<EncodedDoubleFormatter>>(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<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
if (txCtAvg.size() != numBuckets) {
throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
}
- filein >> confAvg;
+ filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(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<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(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<VectorFormatter<EncodedDoubleFormatter>>(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<double> fileBuckets;
- filein >> 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");
diff --git a/src/test/fuzz/float.cpp b/src/test/fuzz/float.cpp
index f806c82d14..e95d593b22 100644
--- a/src/test/fuzz/float.cpp
+++ b/src/test/fuzz/float.cpp
@@ -7,10 +7,13 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <util/serfloat.h>
#include <version.h>
#include <cassert>
#include <cstdint>
+#include <cmath>
+#include <limits>
FUZZ_TARGET(float)
{
@@ -19,12 +22,17 @@ FUZZ_TARGET(float)
{
const double d = fuzzed_data_provider.ConsumeFloatingPoint<double>();
(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<double>::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);
}
}