Skip to content

Commit fd1c9e2

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#23653: Generalize/simplify VectorReader into SpanReader
2c35a93 Generalize/simplify VectorReader into SpanReader (Pieter Wuille) Pull request description: Originally written for #21590 (safegcd-based MuHash inverses), but then found a better way that removed the need for it, so I'm submitting it independently. ACKs for top commit: MarcoFalke: re-ACK 2c35a93 🖨 shaavan: ACK 2c35a93 Tree-SHA512: 959e3251e0cfe20e13a50639b617c9dc2a561d613a0884d983c93d15dacb6d2305d760aa933d18ba055cef8a1651a344bcb6b3f93051ecf26d3f2efc5779efa4
2 parents 0ee9a00 + 2c35a93 commit fd1c9e2

File tree

8 files changed

+35
-36
lines changed

8 files changed

+35
-36
lines changed

src/blockfilter.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ GCSFilter::GCSFilter(const Params& params)
8181
GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter)
8282
: m_params(params), m_encoded(std::move(encoded_filter))
8383
{
84-
VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
84+
SpanReader stream{GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0};
8585

8686
uint64_t N = ReadCompactSize(stream);
8787
m_N = static_cast<uint32_t>(N);
@@ -92,7 +92,7 @@ GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_fi
9292

9393
// Verify that the encoded filter contains exactly N elements. If it has too much or too little
9494
// data, a std::ios_base::failure exception will be raised.
95-
BitStreamReader<VectorReader> bitreader(stream);
95+
BitStreamReader<SpanReader> bitreader{stream};
9696
for (uint64_t i = 0; i < m_N; ++i) {
9797
GolombRiceDecode(bitreader, m_params.m_P);
9898
}
@@ -133,13 +133,13 @@ GCSFilter::GCSFilter(const Params& params, const ElementSet& elements)
133133

134134
bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const
135135
{
136-
VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
136+
SpanReader stream{GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0};
137137

138138
// Seek forward by size of N
139139
uint64_t N = ReadCompactSize(stream);
140140
assert(N == m_N);
141141

142-
BitStreamReader<VectorReader> bitreader(stream);
142+
BitStreamReader<SpanReader> bitreader{stream};
143143

144144
uint64_t value = 0;
145145
size_t hashes_index = 0;

src/signet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ std::optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& c
9898
// no signet solution -- allow this to support OP_TRUE as trivial block challenge
9999
} else {
100100
try {
101-
VectorReader v(SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0);
101+
SpanReader v{SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0};
102102
v >> tx_spending.vin[0].scriptSig;
103103
v >> tx_spending.vin[0].scriptWitness.stack;
104104
if (!v.empty()) return std::nullopt; // extraneous data encountered

src/streams.h

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,14 @@ class CVectorWriter
128128
size_t nPos;
129129
};
130130

131-
/** Minimal stream for reading from an existing vector by reference
131+
/** Minimal stream for reading from an existing byte array by Span.
132132
*/
133-
class VectorReader
133+
class SpanReader
134134
{
135135
private:
136136
const int m_type;
137137
const int m_version;
138-
const std::vector<unsigned char>& m_data;
139-
size_t m_pos = 0;
138+
Span<const unsigned char> m_data;
140139

141140
public:
142141

@@ -146,28 +145,29 @@ class VectorReader
146145
* @param[in] data Referenced byte vector to overwrite/append
147146
* @param[in] pos Starting position. Vector index where reads should start.
148147
*/
149-
VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
150-
: m_type(type), m_version(version), m_data(data), m_pos(pos)
148+
SpanReader(int type, int version, Span<const unsigned char> data, size_t pos)
149+
: m_type(type), m_version(version), m_data(data)
151150
{
152-
if (m_pos > m_data.size()) {
153-
throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())");
151+
if (pos > m_data.size()) {
152+
throw std::ios_base::failure("SpanReader(...): end of data (pos > m_data.size())");
154153
}
154+
data = data.subspan(pos);
155155
}
156156

157157
/**
158158
* (other params same as above)
159159
* @param[in] args A list of items to deserialize starting at pos.
160160
*/
161161
template <typename... Args>
162-
VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos,
162+
SpanReader(int type, int version, Span<const unsigned char> data, size_t pos,
163163
Args&&... args)
164-
: VectorReader(type, version, data, pos)
164+
: SpanReader(type, version, data, pos)
165165
{
166166
::UnserializeMany(*this, std::forward<Args>(args)...);
167167
}
168168

169169
template<typename T>
170-
VectorReader& operator>>(T&& obj)
170+
SpanReader& operator>>(T&& obj)
171171
{
172172
// Unserialize from this stream
173173
::Unserialize(*this, obj);
@@ -177,8 +177,8 @@ class VectorReader
177177
int GetVersion() const { return m_version; }
178178
int GetType() const { return m_type; }
179179

180-
size_t size() const { return m_data.size() - m_pos; }
181-
bool empty() const { return m_data.size() == m_pos; }
180+
size_t size() const { return m_data.size(); }
181+
bool empty() const { return m_data.empty(); }
182182

183183
void read(char* dst, size_t n)
184184
{
@@ -187,12 +187,11 @@ class VectorReader
187187
}
188188

189189
// Read from the beginning of the buffer
190-
size_t pos_next = m_pos + n;
191-
if (pos_next > m_data.size()) {
192-
throw std::ios_base::failure("VectorReader::read(): end of data");
190+
if (n > m_data.size()) {
191+
throw std::ios_base::failure("SpanReader::read(): end of data");
193192
}
194-
memcpy(dst, m_data.data() + m_pos, n);
195-
m_pos = pos_next;
193+
memcpy(dst, m_data.data(), n);
194+
m_data = m_data.subspan(n);
196195
}
197196
};
198197

src/test/fuzz/golomb_rice.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ FUZZ_TARGET(golomb_rice)
8282

8383
std::vector<uint64_t> decoded_deltas;
8484
{
85-
VectorReader stream{SER_NETWORK, 0, golomb_rice_data, 0};
86-
BitStreamReader<VectorReader> bitreader(stream);
85+
SpanReader stream{SER_NETWORK, 0, golomb_rice_data, 0};
86+
BitStreamReader<SpanReader> bitreader{stream};
8787
const uint32_t n = static_cast<uint32_t>(ReadCompactSize(stream));
8888
for (uint32_t i = 0; i < n; ++i) {
8989
decoded_deltas.push_back(GolombRiceDecode(bitreader, BASIC_FILTER_P));
@@ -94,14 +94,14 @@ FUZZ_TARGET(golomb_rice)
9494

9595
{
9696
const std::vector<uint8_t> random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider, 1024);
97-
VectorReader stream{SER_NETWORK, 0, random_bytes, 0};
97+
SpanReader stream{SER_NETWORK, 0, random_bytes, 0};
9898
uint32_t n;
9999
try {
100100
n = static_cast<uint32_t>(ReadCompactSize(stream));
101101
} catch (const std::ios_base::failure&) {
102102
return;
103103
}
104-
BitStreamReader<VectorReader> bitreader(stream);
104+
BitStreamReader<SpanReader> bitreader{stream};
105105
for (uint32_t i = 0; i < std::min<uint32_t>(n, 1024); ++i) {
106106
try {
107107
(void)GolombRiceDecode(bitreader, BASIC_FILTER_P);

src/test/fuzz/script_assets_test_minimizer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ CMutableTransaction TxFromHex(const std::string& str)
5454
{
5555
CMutableTransaction tx;
5656
try {
57-
VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, CheckedParseHex(str), 0) >> tx;
57+
SpanReader{SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, CheckedParseHex(str), 0} >> tx;
5858
} catch (const std::ios_base::failure&) {
5959
throw std::runtime_error("Tx deserialization failure");
6060
}
@@ -68,7 +68,7 @@ std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue)
6868
for (size_t i = 0; i < univalue.size(); ++i) {
6969
CTxOut txout;
7070
try {
71-
VectorReader(SER_DISK, 0, CheckedParseHex(univalue[i].get_str()), 0) >> txout;
71+
SpanReader{SER_DISK, 0, CheckedParseHex(univalue[i].get_str()), 0} >> txout;
7272
} catch (const std::ios_base::failure&) {
7373
throw std::runtime_error("Prevout invalid format");
7474
}

src/test/script_tests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,7 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps)
14731473
static CMutableTransaction TxFromHex(const std::string& str)
14741474
{
14751475
CMutableTransaction tx;
1476-
VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, ParseHex(str), 0) >> tx;
1476+
SpanReader{SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, ParseHex(str), 0} >> tx;
14771477
return tx;
14781478
}
14791479

@@ -1483,7 +1483,7 @@ static std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue)
14831483
std::vector<CTxOut> prevouts;
14841484
for (size_t i = 0; i < univalue.size(); ++i) {
14851485
CTxOut txout;
1486-
VectorReader(SER_DISK, 0, ParseHex(univalue[i].get_str()), 0) >> txout;
1486+
SpanReader{SER_DISK, 0, ParseHex(univalue[i].get_str()), 0} >> txout;
14871487
prevouts.push_back(std::move(txout));
14881488
}
14891489
return prevouts;
@@ -1754,7 +1754,7 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
17541754
for (const auto& vec : vectors.getValues()) {
17551755
auto txhex = ParseHex(vec["given"]["rawUnsignedTx"].get_str());
17561756
CMutableTransaction tx;
1757-
VectorReader(SER_NETWORK, PROTOCOL_VERSION, txhex, 0) >> tx;
1757+
SpanReader{SER_NETWORK, PROTOCOL_VERSION, txhex, 0} >> tx;
17581758
std::vector<CTxOut> utxos;
17591759
for (const auto& utxo_spent : vec["given"]["utxosSpent"].getValues()) {
17601760
auto script_bytes = ParseHex(utxo_spent["scriptPubKey"].get_str());

src/test/streams_tests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader)
7171
{
7272
std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
7373

74-
VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0);
74+
SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, vch, 0};
7575
BOOST_CHECK_EQUAL(reader.size(), 6U);
7676
BOOST_CHECK(!reader.empty());
7777

@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader)
101101
BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
102102

103103
// Read a 4 bytes as a signed int from the beginning of the buffer.
104-
VectorReader new_reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0);
104+
SpanReader new_reader{SER_NETWORK, INIT_PROTO_VERSION, vch, 0};
105105
new_reader >> d;
106106
BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256
107107
BOOST_CHECK_EQUAL(new_reader.size(), 2U);
@@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader)
115115
BOOST_AUTO_TEST_CASE(streams_vector_reader_rvalue)
116116
{
117117
std::vector<uint8_t> data{0x82, 0xa7, 0x31};
118-
VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, data, /* pos= */ 0);
118+
SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, data, /* pos= */ 0};
119119
uint32_t varint = 0;
120120
// Deserialize into r-value
121121
reader >> VARINT(varint);

src/wallet/test/wallet_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup)
682682
vw << (int32_t)0;
683683
vw << (int32_t)1;
684684

685-
VectorReader vr(0, 0, malformed_record, 0);
685+
SpanReader vr{0, 0, malformed_record, 0};
686686
WalletDescriptor w_desc;
687687
BOOST_CHECK_EXCEPTION(vr >> w_desc, std::ios_base::failure, malformed_descriptor);
688688
}

0 commit comments

Comments
 (0)