This changes all places, where possible, to use SpanReader over DataStream. This makes the code easier to read and reason about, because SpanReader can never write data. Also, the code should be minimally faster, because it avoids a full redundant copy of the whole vector of bytes.
refactor: Use SpanReader over DataStream #34483
pull maflcko wants to merge 6 commits into bitcoin:master from maflcko:2602-span-reader changing 30 files +49 −71-
maflcko commented at 3:54 PM on February 2, 2026: member
-
fa879db735
test: Read debug log for self-checking comment
The DataStream comment was a bit stale, because it was using CDataStream. Fix it by using assert_debug_log for a self-documenting and self-checking test code.
- DrahtBot renamed this:
refactor: Use SpanReader over DataStream
refactor: Use SpanReader over DataStream
on Feb 2, 2026 - DrahtBot added the label Refactoring on Feb 2, 2026
-
DrahtBot commented at 3:55 PM on February 2, 2026: contributor
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--021abf342d371248e50ceaed478a90ca-->
Reviews
See the guideline for information on the review process.
Type Reviewers ACK janb84, sipa, stickies-v, achow101 Concept ACK davidgumberg Stale ACK darosior If your review is incorrectly listed, please copy-paste <code><!--meta-tag:bot-skip--></code> into the comment that the bot should ignore.
<!--174a7506f384e20aa4161008e828411d-->
Conflicts
Reviewers, this pull request conflicts with the following ones:
- #34132 (coins: fail fast on database read deserialization errors by l0rinc)
- #32554 (bench: replace embedded raw block with configurable block generator by l0rinc)
- #31682 ([IBD] specialize CheckBlock's input & coinbase checks by l0rinc)
- #31449 (coins,refactor: Reduce
getblockstatsRPC UTXO overhead estimation by l0rinc)
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
<!--5faf32d7da4f0f540f40219e4f7537a3-->
-
in src/streams.h:103 in fa498e4512 outdated
99 | @@ -100,6 +100,7 @@ class SpanReader 100 | 101 | size_t size() const { return m_data.size(); } 102 | bool empty() const { return m_data.empty(); } 103 | + bool eof() const { return m_data.empty(); }
darosior commented at 4:06 PM on February 2, 2026:Is it not less confusing to change the one call site (that you are already touching) to use
empty()rather than introducing aneofmethod to a class that is not reading from a file?
maflcko commented at 4:14 PM on February 2, 2026:Then, I'd have to add
empty()to the "streams interface", at which point theeof()alias can be removed. Let me push that ...
maflcko commented at 6:36 PM on February 2, 2026:(done)
darosior commented at 4:07 PM on February 2, 2026: memberCode looks good to me, just got one question.
stickies-v commented at 4:38 PM on February 2, 2026: contributorConcept ACK
fa20bc2ec2refactor: Use empty() over eof() in the streams interface
End-of-file does not really make sense for streams that wrap buffers. So replace it by the equivalent empty() checks.
DrahtBot added the label CI failed on Feb 2, 2026DrahtBot commented at 5:09 PM on February 2, 2026: contributor<!--85328a0da195eb286784d51f73fa0af9-->
🚧 At least one of the CI tasks failed. <sub>Task
fuzzer,address,undefined,integer: https://github.com/bitcoin/bitcoin/actions/runs/21597138806/job/62232912845</sub> <sub>LLM reason (✨ experimental): AddressSanitizer heap-buffer-overflow in fuzz target during seed corpus processing.</sub><details><summary>Hints</summary>
Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:
Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.
A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.
An intermittent issue.
Leave a comment here, if you need help tracking down a confusing failure.
</details>
fabd4d2e2erefactor: Avoid UB in SpanReader::ignore
Currently std::span::subspan is called without checking the size first. This is UB, unless the std lib is hardened. With a hardened stdlib, the program aborts: > include/c++/v1/span:512: libc++ Hardening assertion __offset <= size() > failed: span<T>::subspan(offset, count): offset out of range Fix the UB and the abort by using the implementation from DataStream, which throws when hitting end-of-data. This commit should not change any behavior, because the UB is currently unreachable. Also, the newly added throw should properly be caught by any code that calls any streams function.
refactor: [qt] Use SpanReader to avoid two vector copies fa06e26764fad3eb3956refactor: Use SpanReader over DataStream
The mutable temporary strValue can be re-used to apply the obfuscation, which allows to avoid a redundant copy of the value.
maflcko force-pushed on Feb 2, 2026maflcko force-pushed on Feb 2, 2026maflcko commented at 5:51 PM on February 2, 2026: memberHmm, I guess there is some unrelated pre-existing UB. This isn't remote-triggerable, so I fixed it in a "refactor" commit.
introduced in commit 82a379eca82, which I reviewed :(
godbolt: https://godbolt.org/z/YKsavqGqx
janb84 commented at 7:54 PM on February 2, 2026: contributorConcept ACK fa52b210e03879386e5582114cfefa51ec61396d
Did an extensive search, most are converted. Listed below are some leftovers, maybe intentional not converted?
Possible NIT;
/src/rpc/txoutproof.cpp: L147-149from:
DataStream ssMB{ParseHexV(request.params[0], "proof")}; CMerkleBlock merkleBlock; ssMB >> merkleBlock;CMerkleBlock merkleBlock; SpanReader{ParseHexV(request.params[0], "proof")} >> merkleBlock;or
src/wallet/rpc/backup.cpp:L60-62from:
DataStream ssMB{ParseHexV(request.params[1], "proof")}; CMerkleBlock merkleBlock; ssMB >> merkleBlock;to:
CMerkleBlock merkleBlock; SpanReader{ParseHexV(request.params[1], "proof")} >> merkleBlock;DrahtBot removed the label CI failed on Feb 2, 2026maflcko force-pushed on Feb 2, 2026sipa commented at 8:19 PM on February 2, 2026: memberConcept ACK
DrahtBot added the label CI failed on Feb 2, 2026maflcko closed this on Feb 3, 2026maflcko reopened this on Feb 3, 2026DrahtBot removed the label CI failed on Feb 3, 2026davidgumberg commented at 8:19 AM on February 3, 2026: contributorConcept ACK. I think this should bring some measurable performance improvements because
SpanReaderdoes not use the zero after free allocator thatDataStreamdoes, which zero's memory and prevents compiler optimizations in order to guarantee that memory is zeroed. I came to the conclusion in #30987 at the time that there was nowhereDataStreamwas used at that time where one should be worried about data being left in memory after destruction.maflcko commented at 8:32 AM on February 3, 2026: memberJust to clarify: This should have no impact on IBD time, because only the dbwrapper is changed, but I don't expect that to give any end-to-end performance improvement.
When i tested this on btck_block_create last month, it gave a 1%-5% speed-up. I guess for all fuzz targets, the speedup is also shadowed by the remainder of the fuzz target. That is I don't expect the
blockfuzz target to be end-to-end faster at all.This is mostly a style cleanup and the UB fix doesn't seem too bad either.
l0rinc commented at 11:58 AM on February 3, 2026: contributorthis should bring some measurable performance improvements because SpanReader does not use the zero after free allocator that DataStream does
I have measured something similar in https://github.com/l0rinc/bitcoin/pull/31 but couldn't find any difference in higher level benchmarks. The difference is only really measurable in debug mode and in the narrow micro-bench of not zeroing DataStream bytes on destruction, but it's probably optimized away on higher level.
darosior approveddarosior commented at 10:17 PM on February 3, 2026: memberutACK fae650c2950f3b6d99eb7c062389de0bf6a64ac9
DrahtBot requested review from stickies-v on Feb 3, 2026DrahtBot requested review from davidgumberg on Feb 3, 2026DrahtBot requested review from janb84 on Feb 3, 2026DrahtBot requested review from sipa on Feb 3, 2026in src/rpc/blockchain.cpp:835 in fae650c295
831 | @@ -832,7 +832,7 @@ static RPCHelpMan getblock() 832 | return HexStr(block_data); 833 | } 834 | 835 | - DataStream block_stream{block_data}; 836 | + SpanReader block_stream{block_data};
stickies-v commented at 1:37 PM on February 5, 2026:nit: a bunch more of these can be inlined, avoiding the variables named "stream" etc:
<details> <summary>git diff on fae650c295</summary>
diff --git a/src/bench/readwriteblock.cpp b/src/bench/readwriteblock.cpp index 690818f659..b8e226c6eb 100644 --- a/src/bench/readwriteblock.cpp +++ b/src/bench/readwriteblock.cpp @@ -21,9 +21,8 @@ static CBlock CreateTestBlock() { - SpanReader stream{benchmark::data::block413567}; CBlock block; - stream >> TX_WITH_WITNESS(block); + SpanReader{benchmark::data::block413567} >> TX_WITH_WITNESS(block); return block; } diff --git a/src/core_io.cpp b/src/core_io.cpp index 094f1ec8cc..ec446debee 100644 --- a/src/core_io.cpp +++ b/src/core_io.cpp @@ -239,9 +239,8 @@ bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header) if (!IsHex(hex_header)) return false; const std::vector<unsigned char> header_data{ParseHex(hex_header)}; - SpanReader ser_header{header_data}; try { - ser_header >> header; + SpanReader{header_data} >> header; } catch (const std::exception&) { return false; } @@ -254,9 +253,8 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk) return false; std::vector<unsigned char> blockData(ParseHex(strHexBlk)); - SpanReader ssBlock{blockData}; try { - ssBlock >> TX_WITH_WITNESS(block); + SpanReader{blockData} >> TX_WITH_WITNESS(block); } catch (const std::exception&) { return false; diff --git a/src/rest.cpp b/src/rest.cpp index 4ecd0f451e..9d73c1e604 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -451,8 +451,7 @@ static bool rest_block(const std::any& context, case RESTResponseFormat::JSON: { if (tx_verbosity) { CBlock block{}; - SpanReader block_stream{*block_data}; - block_stream >> TX_WITH_WITNESS(block); + SpanReader{*block_data} >> TX_WITH_WITNESS(block); UniValue objBlock = blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, *tx_verbosity, chainman.GetConsensus().powLimit); std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6d4ced7364..d5c9987697 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -832,9 +832,8 @@ static RPCHelpMan getblock() return HexStr(block_data); } - SpanReader block_stream{block_data}; CBlock block{}; - block_stream >> TX_WITH_WITNESS(block); + SpanReader{block_data} >> TX_WITH_WITNESS(block); TxVerbosity tx_verbosity; if (verbosity == 1) { diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp index 6e45cc251f..7b87442985 100644 --- a/src/test/fuzz/block.cpp +++ b/src/test/fuzz/block.cpp @@ -24,10 +24,9 @@ void initialize_block() FUZZ_TARGET(block, .init = initialize_block) { - SpanReader ds{buffer}; CBlock block; try { - ds >> TX_WITH_WITNESS(block); + SpanReader{buffer} >> TX_WITH_WITNESS(block); } catch (const std::ios_base::failure&) { return; } diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index 820538a54b..70cad07d69 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -81,9 +81,8 @@ T Deserialize(DataStream&& ds, const P& params) template <typename T, typename P> void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params) { - SpanReader ds{buffer}; try { - ds >> params(obj); + SpanReader{buffer} >> params(obj); } catch (const std::ios_base::failure&) { throw invalid_fuzzing_input_exception(); } @@ -109,9 +108,8 @@ T Deserialize(DataStream ds) template <typename T> void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj) { - SpanReader ds{buffer}; try { - ds >> obj; + SpanReader{buffer} >> obj; } catch (const std::ios_base::failure&) { throw invalid_fuzzing_input_exception(); } diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index 224cd9d9b7..8f9c942666 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -41,10 +41,9 @@ FUZZ_TARGET(transaction, .init = initialize_transaction) } }(); bool valid_mutable_tx = true; - SpanReader ds_mtx{buffer}; CMutableTransaction mutable_tx; try { - ds_mtx >> TX_WITH_WITNESS(mutable_tx); + SpanReader{buffer} >> TX_WITH_WITNESS(mutable_tx); } catch (const std::ios_base::failure&) { valid_mutable_tx = false; } diff --git a/src/test/fuzz/tx_in.cpp b/src/test/fuzz/tx_in.cpp index 4146d96162..10618d60e0 100644 --- a/src/test/fuzz/tx_in.cpp +++ b/src/test/fuzz/tx_in.cpp @@ -13,10 +13,9 @@ FUZZ_TARGET(tx_in) { - SpanReader ds{buffer}; CTxIn tx_in; try { - ds >> tx_in; + SpanReader{buffer} >> tx_in; } catch (const std::ios_base::failure&) { return; } diff --git a/src/test/fuzz/tx_out.cpp b/src/test/fuzz/tx_out.cpp index 1c1016eb92..ce39d14f1a 100644 --- a/src/test/fuzz/tx_out.cpp +++ b/src/test/fuzz/tx_out.cpp @@ -12,10 +12,9 @@ FUZZ_TARGET(tx_out) { - SpanReader ds{buffer}; CTxOut tx_out; try { - ds >> tx_out; + SpanReader{buffer} >> tx_out; } catch (const std::ios_base::failure&) { return; } diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index e55e1e6f03..136728a043 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -872,10 +872,9 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) std::span<const unsigned char> data, bool is_incoming) -> void { if (!is_incoming && msg_type == "addr") { - SpanReader s{data}; std::vector<CAddress> addresses; - s >> CAddress::V1_NETWORK(addresses); + SpanReader{data} >> CAddress::V1_NETWORK(addresses); for (const auto& addr : addresses) { if (addr == expected) {</details>
maflcko commented at 6:23 PM on February 5, 2026:sure, and thx, pushed your diff as-is
stickies-v approvedstickies-v commented at 2:53 PM on February 5, 2026: contributorACK fae650c2950f3b6d99eb7c062389de0bf6a64ac9
Found a few more instances that could be replaced:
<details> <summary>git diff on fae650c295</summary>
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 938aa233ed..8e02cfd08c 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE(bloom_match) // and one which spends it (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; std::vector<unsigned char> vch(ch, ch + sizeof(ch) -1); - DataStream spendStream{vch}; + SpanReader spendStream{vch}; CTransaction spendingTx(deserialize, TX_WITH_WITNESS, spendStream); CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 4d6ee6613e..8c0756d852 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -517,37 +517,33 @@ BOOST_FIXTURE_TEST_CASE(updatecoins_simulation_test, UpdateTest) BOOST_AUTO_TEST_CASE(ccoins_serialization) { // Good example - DataStream ss1{"97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"_hex}; Coin cc1; - ss1 >> cc1; + SpanReader{"97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"_hex} >> cc1; BOOST_CHECK_EQUAL(cc1.fCoinBase, false); BOOST_CHECK_EQUAL(cc1.nHeight, 203998U); BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000}); BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("816115944e077fe7c803cfa57f29b36bf87c1d35"_hex_u8))))); // Good example - DataStream ss2{"8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex}; Coin cc2; - ss2 >> cc2; + SpanReader{"8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex} >> cc2; BOOST_CHECK_EQUAL(cc2.fCoinBase, true); BOOST_CHECK_EQUAL(cc2.nHeight, 120891U); BOOST_CHECK_EQUAL(cc2.out.nValue, 110397); BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex_u8))))); // Smallest possible example - DataStream ss3{"000006"_hex}; Coin cc3; - ss3 >> cc3; + SpanReader{"000006"_hex} >> cc3; BOOST_CHECK_EQUAL(cc3.fCoinBase, false); BOOST_CHECK_EQUAL(cc3.nHeight, 0U); BOOST_CHECK_EQUAL(cc3.out.nValue, 0); BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0U); // scriptPubKey that ends beyond the end of the stream - DataStream ss4{"000007"_hex}; try { Coin cc4; - ss4 >> cc4; + SpanReader{"000007"_hex} >> cc4; BOOST_CHECK_MESSAGE(false, "We should have thrown"); } catch (const std::ios_base::failure&) { } @@ -557,10 +553,9 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) uint64_t x = 3000000000ULL; tmp << VARINT(x); BOOST_CHECK_EQUAL(HexStr(tmp), "8a95c0bb00"); - DataStream ss5{"00008a95c0bb00"_hex}; try { Coin cc5; - ss5 >> cc5; + SpanReader{"00008a95c0bb00"_hex} >> cc5; BOOST_CHECK_MESSAGE(false, "We should have thrown"); } catch (const std::ios_base::failure&) { } diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 88260b272f..c9ab49078a 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -9,6 +9,7 @@ #include <common/args.h> #include <merkleblock.h> #include <random.h> +#include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -121,9 +122,8 @@ FUZZ_TARGET(addrman, .init = initialize_addrman) auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio()); if (fuzzed_data_provider.ConsumeBool()) { const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; - DataStream ds{serialized_data}; try { - ds >> *addr_man_ptr; + SpanReader{serialized_data} >> *addr_man_ptr; } catch (const std::ios_base::failure&) { addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio()); } diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index 4a8b7b2155..933baa4810 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -9,6 +9,7 @@ #include <net_processing.h> #include <netaddress.h> #include <protocol.h> +#include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -45,9 +46,8 @@ FUZZ_TARGET(connman, .init = initialize_connman) auto addr_man_ptr{std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio())}; if (fuzzed_data_provider.ConsumeBool()) { const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; - DataStream ds{serialized_data}; try { - ds >> *addr_man_ptr; + SpanReader{serialized_data} >> *addr_man_ptr; } catch (const std::ios_base::failure&) { addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio()); } diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 722ba2eb69..f765c57f04 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -575,10 +575,9 @@ BOOST_AUTO_TEST_CASE(caddress_serialize_v1) BOOST_AUTO_TEST_CASE(caddress_unserialize_v1) { - DataStream s{ParseHex(stream_addrv1_hex)}; std::vector<CAddress> addresses_unserialized; - s >> CAddress::V1_NETWORK(addresses_unserialized); + SpanReader{ParseHex(stream_addrv1_hex)} >> CAddress::V1_NETWORK(addresses_unserialized); BOOST_CHECK(fixture_addresses == addresses_unserialized); } @@ -592,10 +591,9 @@ BOOST_AUTO_TEST_CASE(caddress_serialize_v2) BOOST_AUTO_TEST_CASE(caddress_unserialize_v2) { - DataStream s{ParseHex(stream_addrv2_hex)}; std::vector<CAddress> addresses_unserialized; - s >> CAddress::V2_NETWORK(addresses_unserialized); + SpanReader{ParseHex(stream_addrv2_hex)} >> CAddress::V2_NETWORK(addresses_unserialized); BOOST_CHECK(fixture_addresses == addresses_unserialized); } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 4272821640..5d65c35a8c 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -189,8 +189,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) nHashType = test[3].getInt<int>(); sigHashHex = test[4].get_str(); - DataStream stream(ParseHex(raw_tx)); - stream >> TX_WITH_WITNESS(tx); + SpanReader{ParseHex(raw_tx)} >> TX_WITH_WITNESS(tx); TxValidationState state; BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 3919f226d6..d0be15a00d 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -377,9 +377,8 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; std::vector<unsigned char> vch(ch, ch + sizeof(ch) -1); - DataStream stream(vch); CMutableTransaction tx; - stream >> TX_WITH_WITNESS(tx); + SpanReader{vch} >> TX_WITH_WITNESS(tx); TxValidationState state; BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid.");</details>
maflcko force-pushed on Feb 5, 2026stickies-v commented at 8:38 PM on February 5, 2026: contributorre-ACK faaf01fbd87644d597cb691b535ba5c24544efa5
DrahtBot requested review from darosior on Feb 5, 2026fa0677d131refactor: Use SpanReader over DataStream
This refactor does not change behavior. However, it avoids a vector copy, which can lead to a minimal speed-up of 1%-5%, depending on the call-site. This is mostly relevant for the fuzz tests and utils that read large blobs of data (like a full block).
maflcko force-pushed on Feb 6, 2026maflcko commented at 7:30 AM on February 6, 2026: membersry, didn't realize there were two diffs. I pushed the other one as well. However addrman has DataStream in it's interface, so this replacement is more involved and this diff does not compile as-is:
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 88260b272f..0d77ddfb3a 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -11,2 +11,3 @@ #include <random.h> +#include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> @@ -123,5 +124,4 @@ FUZZ_TARGET(addrman, .init = initialize_addrman) const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; - DataStream ds{serialized_data}; try { - ds >> *addr_man_ptr; + DataStream{serialized_data} >> *addr_man_ptr; } catch (const std::ios_base::failure&) { diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index 4a8b7b2155..90a798501f 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -11,2 +11,3 @@ #include <protocol.h> +#include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> @@ -47,5 +48,4 @@ FUZZ_TARGET(connman, .init = initialize_connman) const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; - DataStream ds{serialized_data}; try { - ds >> *addr_man_ptr; + DataStream{serialized_data} >> *addr_man_ptr; } catch (const std::ios_base::failure&) {janb84 commented at 4:01 PM on February 6, 2026: contributorre ACK fa0677d131191d7db9868c4c1b3d780cb6991226
DrahtBot requested review from stickies-v on Feb 6, 2026sipa commented at 4:42 PM on February 6, 2026: membercrACK fa0677d131191d7db9868c4c1b3d780cb6991226
stickies-v commented at 11:50 PM on February 6, 2026: contributorre-ACK fa0677d131191d7db9868c4c1b3d780cb6991226
However addrman has DataStream in it's interface, so this replacement is more involved and this diff does not compile as-is:
Apologies, wasn't compiling the fuzz binary so I missed this, you're right.
achow101 commented at 1:48 AM on February 7, 2026: memberACK fa0677d131191d7db9868c4c1b3d780cb6991226
achow101 merged this on Feb 7, 2026achow101 closed this on Feb 7, 2026maflcko deleted the branch on Feb 9, 2026
This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-22 06:12 UTC
More mirrored repositories can be found on mirror.b10c.me