From fa879db735281d2cce123dbd59d20c7339b2b4ee Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Mon, 2 Feb 2026 16:35:08 +0100 Subject: [PATCH 1/6] 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. --- test/functional/p2p_segwit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 88b2bcbb158..17f8085b44f 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -1198,8 +1198,8 @@ class SegWitTest(BitcoinTestFramework): block.vtx = [block.vtx[0]] self.update_witness_block_with_transactions(block, [tx2]) # This block doesn't result in a specific reject reason, but an iostream exception: - # "Exception 'CDataStream::read(): end of data: unspecified iostream_category error' (...) caught" - test_witness_block(self.nodes[0], self.test_node, block, accepted=False) + with self.nodes[0].assert_debug_log(["Exception 'DataStream::read(): end of data"]): + test_witness_block(self.nodes[0], self.test_node, block, accepted=False) # Now make one of the intermediate witnesses be incorrect tx2.wit.vtxinwit.append(CTxInWitness()) From fa20bc2ec27522959cdf1ad35d54f080aafbfc47 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Mon, 2 Feb 2026 17:56:13 +0100 Subject: [PATCH 2/6] refactor: 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. --- src/net.cpp | 2 +- src/serialize.h | 2 +- src/streams.h | 1 - src/test/dbwrapper_tests.cpp | 2 +- src/wallet/walletdb.cpp | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 16591461efb..3ed7fd2778e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -202,7 +202,7 @@ static std::vector ConvertSeeds(const std::vector &vSeedsIn) std::vector vSeedsOut; FastRandomContext rng; ParamsStream s{DataStream{vSeedsIn}, CAddress::V2_NETWORK}; - while (!s.eof()) { + while (!s.empty()) { CService endpoint; s >> endpoint; CAddress addr{endpoint, SeedsServiceFlags()}; diff --git a/src/serialize.h b/src/serialize.h index 4da48a0bb31..21b3325f7a7 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1127,7 +1127,7 @@ public: void write(std::span src) { GetStream().write(src); } void read(std::span dst) { GetStream().read(dst); } void ignore(size_t num) { GetStream().ignore(num); } - bool eof() const { return GetStream().eof(); } + bool empty() const { return GetStream().empty(); } size_t size() const { return GetStream().size(); } //! Get reference to stream parameters. diff --git a/src/streams.h b/src/streams.h index 466084e9fa0..e5a18c56b74 100644 --- a/src/streams.h +++ b/src/streams.h @@ -195,7 +195,6 @@ public: // // Stream subset // - bool eof() const { return size() == 0; } int in_avail() const { return size(); } void read(std::span dst) diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 53cd0046c3a..d3a9e54348b 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -364,7 +364,7 @@ struct StringContentsSerializer { { str.clear(); uint8_t c{0}; - while (!s.eof()) { + while (!s.empty()) { s >> c; str.push_back(c); } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 617b8282d9d..637cf4c57b7 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -377,7 +377,7 @@ bool LoadCryptedKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, st // Get the checksum and check it bool checksum_valid = false; - if (!ssValue.eof()) { + if (!ssValue.empty()) { uint256 checksum; ssValue >> checksum; if (!(checksum_valid = Hash(vchPrivKey) == checksum)) { From fabd4d2e2e3ce734730c56660a958f9cf9dc7d38 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Mon, 2 Feb 2026 18:38:58 +0100 Subject: [PATCH 3/6] refactor: 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::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. --- src/streams.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/streams.h b/src/streams.h index e5a18c56b74..be6b7452a86 100644 --- a/src/streams.h +++ b/src/streams.h @@ -117,6 +117,9 @@ public: void ignore(size_t n) { + if (n > m_data.size()) { + throw std::ios_base::failure("SpanReader::ignore(): end of data"); + } m_data = m_data.subspan(n); } }; From fa06e26764bbd00fc225df5f4601dd4f687273e0 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Mon, 2 Feb 2026 15:47:39 +0100 Subject: [PATCH 4/6] refactor: [qt] Use SpanReader to avoid two vector copies --- src/qt/recentrequeststablemodel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index d8ef0695ced..70b628aeb97 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -189,8 +189,7 @@ void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient // called from ctor when loading from wallet void RecentRequestsTableModel::addNewRequest(const std::string &recipient) { - std::vector data(recipient.begin(), recipient.end()); - DataStream ss{data}; + SpanReader ss{MakeByteSpan(recipient)}; RecentRequestEntry entry; ss >> entry; From fad3eb39564569e7b09982bec68ae41e45a04f87 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Mon, 2 Feb 2026 16:57:18 +0100 Subject: [PATCH 5/6] refactor: 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. --- src/dbwrapper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dbwrapper.h b/src/dbwrapper.h index b2ce67c7c2e..2eee6c1c023 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -214,9 +214,9 @@ public: return false; } try { - DataStream ssValue{MakeByteSpan(*strValue)}; + std::span ssValue{MakeWritableByteSpan(*strValue)}; m_obfuscation(ssValue); - ssValue >> value; + SpanReader{ssValue} >> value; } catch (const std::exception&) { return false; } From fa0677d131191d7db9868c4c1b3d780cb6991226 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Mon, 2 Feb 2026 16:55:11 +0100 Subject: [PATCH 6/6] refactor: 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). --- src/bench/readwriteblock.cpp | 3 +-- src/core_io.cpp | 10 ++++------ src/kernel/bitcoinkernel.cpp | 6 +++--- src/net.cpp | 2 +- src/psbt.cpp | 2 +- src/qt/test/wallettests.cpp | 2 +- src/rest.cpp | 3 +-- src/rpc/blockchain.cpp | 3 +-- src/rpc/txoutproof.cpp | 3 +-- src/test/bloom_tests.cpp | 2 +- src/test/coins_tests.cpp | 15 +++++---------- src/test/fuzz/block.cpp | 3 +-- src/test/fuzz/deserialize.cpp | 6 ++---- src/test/fuzz/script_flags.cpp | 4 ++-- src/test/fuzz/transaction.cpp | 5 ++--- src/test/fuzz/tx_in.cpp | 3 +-- src/test/fuzz/tx_out.cpp | 3 +-- src/test/fuzz/util.h | 4 ++-- src/test/net_tests.cpp | 3 +-- src/test/netbase_tests.cpp | 6 ++---- src/test/sighash_tests.cpp | 3 +-- src/test/transaction_tests.cpp | 3 +-- src/wallet/rpc/backup.cpp | 3 +-- 23 files changed, 37 insertions(+), 60 deletions(-) diff --git a/src/bench/readwriteblock.cpp b/src/bench/readwriteblock.cpp index e1372a26b73..b8e226c6eb9 100644 --- a/src/bench/readwriteblock.cpp +++ b/src/bench/readwriteblock.cpp @@ -21,9 +21,8 @@ static CBlock CreateTestBlock() { - DataStream 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 a4b726cd669..ec446debeec 100644 --- a/src/core_io.cpp +++ b/src/core_io.cpp @@ -174,7 +174,7 @@ static bool DecodeTx(CMutableTransaction& tx, const std::vector& // Try decoding with extended serialization support, and remember if the result successfully // consumes the entire input. if (try_witness) { - DataStream ssData(tx_data); + SpanReader ssData{tx_data}; try { ssData >> TX_WITH_WITNESS(tx_extended); if (ssData.empty()) ok_extended = true; @@ -192,7 +192,7 @@ static bool DecodeTx(CMutableTransaction& tx, const std::vector& // Try decoding with legacy serialization, and remember if the result successfully consumes the entire input. if (try_no_witness) { - DataStream ssData(tx_data); + SpanReader ssData{tx_data}; try { ssData >> TX_NO_WITNESS(tx_legacy); if (ssData.empty()) ok_legacy = true; @@ -239,9 +239,8 @@ bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header) if (!IsHex(hex_header)) return false; const std::vector header_data{ParseHex(hex_header)}; - DataStream 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 blockData(ParseHex(strHexBlk)); - DataStream ssBlock(blockData); try { - ssBlock >> TX_WITH_WITNESS(block); + SpanReader{blockData} >> TX_WITH_WITNESS(block); } catch (const std::exception&) { return false; diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp index c8189b629b6..23aa0ec2a83 100644 --- a/src/kernel/bitcoinkernel.cpp +++ b/src/kernel/bitcoinkernel.cpp @@ -504,7 +504,7 @@ btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t ra return nullptr; } try { - DataStream stream{std::span{reinterpret_cast(raw_transaction), raw_transaction_len}}; + SpanReader stream{std::span{reinterpret_cast(raw_transaction), raw_transaction_len}}; return btck_Transaction::create(std::make_shared(deserialize, TX_WITH_WITNESS, stream)); } catch (...) { return nullptr; @@ -1093,7 +1093,7 @@ btck_Block* btck_block_create(const void* raw_block, size_t raw_block_length) } auto block{std::make_shared()}; - DataStream stream{std::span{reinterpret_cast(raw_block), raw_block_length}}; + SpanReader stream{std::span{reinterpret_cast(raw_block), raw_block_length}}; try { stream >> TX_WITH_WITNESS(*block); @@ -1344,7 +1344,7 @@ btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t return nullptr; } auto header{std::make_unique()}; - DataStream stream{std::span{reinterpret_cast(raw_block_header), raw_block_header_len}}; + SpanReader stream{std::span{reinterpret_cast(raw_block_header), raw_block_header_len}}; try { stream >> *header; diff --git a/src/net.cpp b/src/net.cpp index 3ed7fd2778e..f99a76f2c0f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -201,7 +201,7 @@ static std::vector ConvertSeeds(const std::vector &vSeedsIn) const auto one_week{7 * 24h}; std::vector vSeedsOut; FastRandomContext rng; - ParamsStream s{DataStream{vSeedsIn}, CAddress::V2_NETWORK}; + ParamsStream s{SpanReader{vSeedsIn}, CAddress::V2_NETWORK}; while (!s.empty()) { CService endpoint; s >> endpoint; diff --git a/src/psbt.cpp b/src/psbt.cpp index a1eafbc001d..4ee5f5bdd30 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -617,7 +617,7 @@ bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base6 bool DecodeRawPSBT(PartiallySignedTransaction& psbt, std::span tx_data, std::string& error) { - DataStream ss_data{tx_data}; + SpanReader ss_data{tx_data}; try { ss_data >> psbt; if (!ss_data.empty()) { diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index b62b2a3b82f..1350b11ed4f 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -365,7 +365,7 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr& wallet) std::vector requests = walletModel.wallet().getAddressReceiveRequests(); QCOMPARE(requests.size(), size_t{1}); RecentRequestEntry entry; - DataStream{MakeUCharSpan(requests[0])} >> entry; + SpanReader{MakeByteSpan(requests[0])} >> entry; QCOMPARE(entry.nVersion, int{1}); QCOMPARE(entry.id, int64_t{1}); QVERIFY(entry.date.isValid()); diff --git a/src/rest.cpp b/src/rest.cpp index b91b229a1f0..9d73c1e6043 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{}; - DataStream 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 a883570f94b..d5c9987697c 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -832,9 +832,8 @@ static RPCHelpMan getblock() return HexStr(block_data); } - DataStream 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/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp index 7e8e3bdb682..89611a0c41f 100644 --- a/src/rpc/txoutproof.cpp +++ b/src/rpc/txoutproof.cpp @@ -144,9 +144,8 @@ static RPCHelpMan verifytxoutproof() RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - DataStream ssMB{ParseHexV(request.params[0], "proof")}; CMerkleBlock merkleBlock; - ssMB >> merkleBlock; + SpanReader{ParseHexV(request.params[0], "proof")} >> merkleBlock; UniValue res(UniValue::VARR); diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 938aa233ed0..8e02cfd08c6 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 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 4d6ee6613ec..8c0756d8528 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/block.cpp b/src/test/fuzz/block.cpp index 43e3df366ae..7b874429852 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) { - DataStream 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 97985ef0edb..70cad07d69d 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 void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params) { - DataStream 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 void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj) { - DataStream 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/script_flags.cpp b/src/test/fuzz/script_flags.cpp index 310f0e86002..3ab5880035c 100644 --- a/src/test/fuzz/script_flags.cpp +++ b/src/test/fuzz/script_flags.cpp @@ -15,7 +15,7 @@ #include #include -static DataStream& operator>>(DataStream& ds, script_verify_flags& f) +static SpanReader& operator>>(SpanReader& ds, script_verify_flags& f) { script_verify_flags::value_type n{0}; ds >> n; @@ -27,7 +27,7 @@ static DataStream& operator>>(DataStream& ds, script_verify_flags& f) FUZZ_TARGET(script_flags) { if (buffer.size() > 100'000) return; - DataStream ds{buffer}; + SpanReader ds{buffer}; try { const CTransaction tx(deserialize, TX_WITH_WITNESS, ds); diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index da915713f7e..8f9c9426666 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -30,7 +30,7 @@ void initialize_transaction() FUZZ_TARGET(transaction, .init = initialize_transaction) { SeedRandomStateForTest(SeedRand::ZEROS); - DataStream ds{buffer}; + SpanReader ds{buffer}; bool valid_tx = true; const CTransaction tx = [&] { try { @@ -41,10 +41,9 @@ FUZZ_TARGET(transaction, .init = initialize_transaction) } }(); bool valid_mutable_tx = true; - DataStream 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 932c0e18ce0..10618d60e06 100644 --- a/src/test/fuzz/tx_in.cpp +++ b/src/test/fuzz/tx_in.cpp @@ -13,10 +13,9 @@ FUZZ_TARGET(tx_in) { - DataStream 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 392300ceafc..ce39d14f1a7 100644 --- a/src/test/fuzz/tx_out.cpp +++ b/src/test/fuzz/tx_out.cpp @@ -12,10 +12,9 @@ FUZZ_TARGET(tx_out) { - DataStream 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/fuzz/util.h b/src/test/fuzz/util.h index 3947ee12a60..ccc9e72febb 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -105,7 +105,7 @@ template [[nodiscard]] std::optional ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const P& params, const std::optional& max_length = std::nullopt) noexcept { const std::vector buffer{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)}; - DataStream ds{buffer}; + SpanReader ds{buffer}; T obj; try { ds >> params(obj); @@ -119,7 +119,7 @@ template [[nodiscard]] inline std::optional ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional& max_length = std::nullopt) noexcept { const std::vector buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); - DataStream ds{buffer}; + SpanReader ds{buffer}; T obj; try { ds >> obj; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index aea29169bb3..136728a0439 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 data, bool is_incoming) -> void { if (!is_incoming && msg_type == "addr") { - DataStream s{data}; std::vector addresses; - s >> CAddress::V1_NETWORK(addresses); + SpanReader{data} >> CAddress::V1_NETWORK(addresses); for (const auto& addr : addresses) { if (addr == expected) { diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 722ba2eb694..f765c57f04e 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 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 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 4272821640e..5d65c35a8cd 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(); 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 3919f226d69..d0be15a00db 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 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."); diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 2aa1e9f71eb..9b70f5bbb07 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -57,9 +57,8 @@ RPCHelpMan importprunedfunds() throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); } - DataStream ssMB{ParseHexV(request.params[1], "proof")}; CMerkleBlock merkleBlock; - ssMB >> merkleBlock; + SpanReader{ParseHexV(request.params[1], "proof")} >> merkleBlock; //Search partial merkle tree in proof for our transaction and index in valid block std::vector vMatch;