From 2c35a93b3cc19dc71d5664f9f61c24a04f419e35 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 1 Dec 2021 14:40:25 -0500 Subject: Generalize/simplify VectorReader into SpanReader --- src/blockfilter.cpp | 8 +++--- src/signet.cpp | 2 +- src/streams.h | 35 +++++++++++++------------- src/test/fuzz/golomb_rice.cpp | 8 +++--- src/test/fuzz/script_assets_test_minimizer.cpp | 4 +-- src/test/script_tests.cpp | 6 ++--- src/test/streams_tests.cpp | 6 ++--- src/wallet/test/wallet_tests.cpp | 2 +- 8 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index 41fa0b6fa0..31a1e62d6b 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -81,7 +81,7 @@ GCSFilter::GCSFilter(const Params& params) GCSFilter::GCSFilter(const Params& params, std::vector encoded_filter) : m_params(params), m_encoded(std::move(encoded_filter)) { - VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0); + SpanReader stream{GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0}; uint64_t N = ReadCompactSize(stream); m_N = static_cast(N); @@ -92,7 +92,7 @@ GCSFilter::GCSFilter(const Params& params, std::vector encoded_fi // Verify that the encoded filter contains exactly N elements. If it has too much or too little // data, a std::ios_base::failure exception will be raised. - BitStreamReader bitreader(stream); + BitStreamReader bitreader{stream}; for (uint64_t i = 0; i < m_N; ++i) { GolombRiceDecode(bitreader, m_params.m_P); } @@ -133,13 +133,13 @@ GCSFilter::GCSFilter(const Params& params, const ElementSet& elements) bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const { - VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0); + SpanReader stream{GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0}; // Seek forward by size of N uint64_t N = ReadCompactSize(stream); assert(N == m_N); - BitStreamReader bitreader(stream); + BitStreamReader bitreader{stream}; uint64_t value = 0; size_t hashes_index = 0; diff --git a/src/signet.cpp b/src/signet.cpp index aafd1999ee..d74a6ef05a 100644 --- a/src/signet.cpp +++ b/src/signet.cpp @@ -98,7 +98,7 @@ std::optional SignetTxs::Create(const CBlock& block, const CScript& c // no signet solution -- allow this to support OP_TRUE as trivial block challenge } else { try { - VectorReader v(SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0); + SpanReader v{SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0}; v >> tx_spending.vin[0].scriptSig; v >> tx_spending.vin[0].scriptWitness.stack; if (!v.empty()) return std::nullopt; // extraneous data encountered diff --git a/src/streams.h b/src/streams.h index 9e8f379cd2..dbb942f306 100644 --- a/src/streams.h +++ b/src/streams.h @@ -128,15 +128,14 @@ private: size_t nPos; }; -/** Minimal stream for reading from an existing vector by reference +/** Minimal stream for reading from an existing byte array by Span. */ -class VectorReader +class SpanReader { private: const int m_type; const int m_version; - const std::vector& m_data; - size_t m_pos = 0; + Span m_data; public: @@ -146,12 +145,13 @@ public: * @param[in] data Referenced byte vector to overwrite/append * @param[in] pos Starting position. Vector index where reads should start. */ - VectorReader(int type, int version, const std::vector& data, size_t pos) - : m_type(type), m_version(version), m_data(data), m_pos(pos) + SpanReader(int type, int version, Span data, size_t pos) + : m_type(type), m_version(version), m_data(data) { - if (m_pos > m_data.size()) { - throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())"); + if (pos > m_data.size()) { + throw std::ios_base::failure("SpanReader(...): end of data (pos > m_data.size())"); } + data = data.subspan(pos); } /** @@ -159,15 +159,15 @@ public: * @param[in] args A list of items to deserialize starting at pos. */ template - VectorReader(int type, int version, const std::vector& data, size_t pos, + SpanReader(int type, int version, Span data, size_t pos, Args&&... args) - : VectorReader(type, version, data, pos) + : SpanReader(type, version, data, pos) { ::UnserializeMany(*this, std::forward(args)...); } template - VectorReader& operator>>(T&& obj) + SpanReader& operator>>(T&& obj) { // Unserialize from this stream ::Unserialize(*this, obj); @@ -177,8 +177,8 @@ public: int GetVersion() const { return m_version; } int GetType() const { return m_type; } - size_t size() const { return m_data.size() - m_pos; } - bool empty() const { return m_data.size() == m_pos; } + size_t size() const { return m_data.size(); } + bool empty() const { return m_data.empty(); } void read(char* dst, size_t n) { @@ -187,12 +187,11 @@ public: } // Read from the beginning of the buffer - size_t pos_next = m_pos + n; - if (pos_next > m_data.size()) { - throw std::ios_base::failure("VectorReader::read(): end of data"); + if (n > m_data.size()) { + throw std::ios_base::failure("SpanReader::read(): end of data"); } - memcpy(dst, m_data.data() + m_pos, n); - m_pos = pos_next; + memcpy(dst, m_data.data(), n); + m_data = m_data.subspan(n); } }; diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp index c99bf940c7..7b4634c67b 100644 --- a/src/test/fuzz/golomb_rice.cpp +++ b/src/test/fuzz/golomb_rice.cpp @@ -82,8 +82,8 @@ FUZZ_TARGET(golomb_rice) std::vector decoded_deltas; { - VectorReader stream{SER_NETWORK, 0, golomb_rice_data, 0}; - BitStreamReader bitreader(stream); + SpanReader stream{SER_NETWORK, 0, golomb_rice_data, 0}; + BitStreamReader bitreader{stream}; const uint32_t n = static_cast(ReadCompactSize(stream)); for (uint32_t i = 0; i < n; ++i) { decoded_deltas.push_back(GolombRiceDecode(bitreader, BASIC_FILTER_P)); @@ -94,14 +94,14 @@ FUZZ_TARGET(golomb_rice) { const std::vector random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider, 1024); - VectorReader stream{SER_NETWORK, 0, random_bytes, 0}; + SpanReader stream{SER_NETWORK, 0, random_bytes, 0}; uint32_t n; try { n = static_cast(ReadCompactSize(stream)); } catch (const std::ios_base::failure&) { return; } - BitStreamReader bitreader(stream); + BitStreamReader bitreader{stream}; for (uint32_t i = 0; i < std::min(n, 1024); ++i) { try { (void)GolombRiceDecode(bitreader, BASIC_FILTER_P); diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp index 4669f783aa..d661d79e84 100644 --- a/src/test/fuzz/script_assets_test_minimizer.cpp +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -54,7 +54,7 @@ CMutableTransaction TxFromHex(const std::string& str) { CMutableTransaction tx; try { - VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, CheckedParseHex(str), 0) >> tx; + SpanReader{SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, CheckedParseHex(str), 0} >> tx; } catch (const std::ios_base::failure&) { throw std::runtime_error("Tx deserialization failure"); } @@ -68,7 +68,7 @@ std::vector TxOutsFromJSON(const UniValue& univalue) for (size_t i = 0; i < univalue.size(); ++i) { CTxOut txout; try { - VectorReader(SER_DISK, 0, CheckedParseHex(univalue[i].get_str()), 0) >> txout; + SpanReader{SER_DISK, 0, CheckedParseHex(univalue[i].get_str()), 0} >> txout; } catch (const std::ios_base::failure&) { throw std::runtime_error("Prevout invalid format"); } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index a89eab68e9..af375f7842 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1473,7 +1473,7 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps) static CMutableTransaction TxFromHex(const std::string& str) { CMutableTransaction tx; - VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, ParseHex(str), 0) >> tx; + SpanReader{SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, ParseHex(str), 0} >> tx; return tx; } @@ -1483,7 +1483,7 @@ static std::vector TxOutsFromJSON(const UniValue& univalue) std::vector prevouts; for (size_t i = 0; i < univalue.size(); ++i) { CTxOut txout; - VectorReader(SER_DISK, 0, ParseHex(univalue[i].get_str()), 0) >> txout; + SpanReader{SER_DISK, 0, ParseHex(univalue[i].get_str()), 0} >> txout; prevouts.push_back(std::move(txout)); } return prevouts; @@ -1754,7 +1754,7 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors) for (const auto& vec : vectors.getValues()) { auto txhex = ParseHex(vec["given"]["rawUnsignedTx"].get_str()); CMutableTransaction tx; - VectorReader(SER_NETWORK, PROTOCOL_VERSION, txhex, 0) >> tx; + SpanReader{SER_NETWORK, PROTOCOL_VERSION, txhex, 0} >> tx; std::vector utxos; for (const auto& utxo_spent : vec["given"]["utxosSpent"].getValues()) { auto script_bytes = ParseHex(utxo_spent["scriptPubKey"].get_str()); diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index b8d76c9608..f551663789 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader) { std::vector vch = {1, 255, 3, 4, 5, 6}; - VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0); + SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, vch, 0}; BOOST_CHECK_EQUAL(reader.size(), 6U); BOOST_CHECK(!reader.empty()); @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader) BOOST_CHECK_THROW(reader >> d, std::ios_base::failure); // Read a 4 bytes as a signed int from the beginning of the buffer. - VectorReader new_reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0); + SpanReader new_reader{SER_NETWORK, INIT_PROTO_VERSION, vch, 0}; new_reader >> d; BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256 BOOST_CHECK_EQUAL(new_reader.size(), 2U); @@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader) BOOST_AUTO_TEST_CASE(streams_vector_reader_rvalue) { std::vector data{0x82, 0xa7, 0x31}; - VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, data, /* pos= */ 0); + SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, data, /* pos= */ 0}; uint32_t varint = 0; // Deserialize into r-value reader >> VARINT(varint); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 9842089cf8..6925d9ef2a 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -682,7 +682,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup) vw << (int32_t)0; vw << (int32_t)1; - VectorReader vr(0, 0, malformed_record, 0); + SpanReader vr{0, 0, malformed_record, 0}; WalletDescriptor w_desc; BOOST_CHECK_EXCEPTION(vr >> w_desc, std::ios_base::failure, malformed_descriptor); } -- cgit v1.2.3