Bitcoin Core 30.99.0
P2P Digital Currency
deserialize.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <addrdb.h>
6#include <addrman.h>
7#include <addrman_impl.h>
8#include <blockencodings.h>
9#include <blockfilter.h>
10#include <chain.h>
11#include <coins.h>
12#include <common/args.h>
13#include <compressor.h>
14#include <consensus/merkle.h>
15#include <key.h>
16#include <merkleblock.h>
17#include <net.h>
18#include <netbase.h>
19#include <netgroup.h>
20#include <node/blockstorage.h>
21#include <node/utxo_snapshot.h>
22#include <primitives/block.h>
23#include <protocol.h>
24#include <psbt.h>
25#include <pubkey.h>
26#include <script/keyorigin.h>
27#include <streams.h>
28#include <test/fuzz/fuzz.h>
29#include <test/fuzz/util.h>
31#include <undo.h>
32
33#include <cstdint>
34#include <exception>
35#include <optional>
36#include <stdexcept>
37
40
41namespace {
42const BasicTestingSetup* g_setup;
43} // namespace
44
46{
47 static const auto testing_setup = MakeNoLogFileContext<>();
48 g_setup = testing_setup.get();
49}
50
51#define FUZZ_TARGET_DESERIALIZE(name, code) \
52 FUZZ_TARGET(name, .init = initialize_deserialize) \
53 { \
54 try { \
55 code \
56 } catch (const invalid_fuzzing_input_exception&) { \
57 } \
58 }
59
60namespace {
61
62struct invalid_fuzzing_input_exception : public std::exception {
63};
64
65template <typename T, typename P>
66DataStream Serialize(const T& obj, const P& params)
67{
68 DataStream ds{};
69 ds << params(obj);
70 return ds;
71}
72
73template <typename T, typename P>
74T Deserialize(DataStream&& ds, const P& params)
75{
76 T obj;
77 ds >> params(obj);
78 return obj;
79}
80
81template <typename T, typename P>
82void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params)
83{
84 DataStream ds{buffer};
85 try {
86 ds >> params(obj);
87 } catch (const std::ios_base::failure&) {
88 throw invalid_fuzzing_input_exception();
89 }
90 assert(buffer.empty() || !Serialize(obj, params).empty());
91}
92
93template <typename T>
94DataStream Serialize(const T& obj)
95{
96 DataStream ds{};
97 ds << obj;
98 return ds;
99}
100
101template <typename T>
102T Deserialize(DataStream ds)
103{
104 T obj;
105 ds >> obj;
106 return obj;
107}
108
109template <typename T>
110void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj)
111{
112 DataStream ds{buffer};
113 try {
114 ds >> obj;
115 } catch (const std::ios_base::failure&) {
116 throw invalid_fuzzing_input_exception();
117 }
118 assert(buffer.empty() || !Serialize(obj).empty());
119}
120
121template <typename T, typename P>
122void AssertEqualAfterSerializeDeserialize(const T& obj, const P& params)
123{
124 assert(Deserialize<T>(Serialize(obj, params), params) == obj);
125}
126template <typename T>
127void AssertEqualAfterSerializeDeserialize(const T& obj)
128{
129 assert(Deserialize<T>(Serialize(obj)) == obj);
130}
131
132} // namespace
133
134FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, {
135 BlockFilter block_filter;
136 DeserializeFromFuzzingInput(buffer, block_filter);
137})
138FUZZ_TARGET(addr_info_deserialize, .init = initialize_deserialize)
139{
140 FuzzedDataProvider fdp{buffer.data(), buffer.size()};
141 (void)ConsumeDeserializable<AddrInfo>(fdp, ConsumeDeserializationParams<CAddress::SerParams>(fdp));
142}
143FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, {
144 CBlockFileInfo block_file_info;
145 DeserializeFromFuzzingInput(buffer, block_file_info);
146})
147FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, {
148 CBlockHeaderAndShortTxIDs block_header_and_short_txids;
149 DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
150})
151FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, {
152 CFeeRate fee_rate;
153 DeserializeFromFuzzingInput(buffer, fee_rate);
154 AssertEqualAfterSerializeDeserialize(fee_rate);
155})
156FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, {
157 CMerkleBlock merkle_block;
158 DeserializeFromFuzzingInput(buffer, merkle_block);
159})
160FUZZ_TARGET_DESERIALIZE(out_point_deserialize, {
161 COutPoint out_point;
162 DeserializeFromFuzzingInput(buffer, out_point);
163 AssertEqualAfterSerializeDeserialize(out_point);
164})
165FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, {
166 CPartialMerkleTree partial_merkle_tree;
167 DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
168})
169FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, {
170 CPubKey pub_key;
171 DeserializeFromFuzzingInput(buffer, pub_key);
172 AssertEqualAfterSerializeDeserialize(pub_key);
173})
174FUZZ_TARGET_DESERIALIZE(script_deserialize, {
176 DeserializeFromFuzzingInput(buffer, script);
177})
178FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, {
179 CTxIn tx_in;
180 DeserializeFromFuzzingInput(buffer, tx_in);
181 AssertEqualAfterSerializeDeserialize(tx_in);
182})
183FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, {
184 FlatFilePos flat_file_pos;
185 DeserializeFromFuzzingInput(buffer, flat_file_pos);
186 AssertEqualAfterSerializeDeserialize(flat_file_pos);
187})
188FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, {
189 KeyOriginInfo key_origin_info;
190 DeserializeFromFuzzingInput(buffer, key_origin_info);
191 AssertEqualAfterSerializeDeserialize(key_origin_info);
192})
193FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, {
194 PartiallySignedTransaction partially_signed_transaction;
195 DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
196})
197FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, {
198 PrefilledTransaction prefilled_transaction;
199 DeserializeFromFuzzingInput(buffer, prefilled_transaction);
200})
201FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, {
202 PSBTInput psbt_input;
203 DeserializeFromFuzzingInput(buffer, psbt_input);
204})
205FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, {
206 PSBTOutput psbt_output;
207 DeserializeFromFuzzingInput(buffer, psbt_output);
208})
209FUZZ_TARGET_DESERIALIZE(block_deserialize, {
210 CBlock block;
211 DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
212})
213FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, {
214 CBlockLocator bl;
215 DeserializeFromFuzzingInput(buffer, bl);
216})
217FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
218 CBlock block;
219 DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
220 bool mutated;
221 BlockMerkleRoot(block, &mutated);
222})
223FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {
224 CBlockHeader bh;
225 DeserializeFromFuzzingInput(buffer, bh);
226})
227FUZZ_TARGET_DESERIALIZE(txundo_deserialize, {
228 CTxUndo tu;
229 DeserializeFromFuzzingInput(buffer, tu);
230})
231FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, {
232 CBlockUndo bu;
233 DeserializeFromFuzzingInput(buffer, bu);
234})
235FUZZ_TARGET_DESERIALIZE(coins_deserialize, {
236 Coin coin;
237 DeserializeFromFuzzingInput(buffer, coin);
238})
239FUZZ_TARGET(netaddr_deserialize, .init = initialize_deserialize)
240{
241 FuzzedDataProvider fdp{buffer.data(), buffer.size()};
242 const auto maybe_na{ConsumeDeserializable<CNetAddr>(fdp, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp))};
243 if (!maybe_na) return;
244 const CNetAddr& na{*maybe_na};
245 if (na.IsAddrV1Compatible()) {
246 AssertEqualAfterSerializeDeserialize(na, CNetAddr::V1);
247 }
248 AssertEqualAfterSerializeDeserialize(na, CNetAddr::V2);
249}
250FUZZ_TARGET(service_deserialize, .init = initialize_deserialize)
251{
252 FuzzedDataProvider fdp{buffer.data(), buffer.size()};
253 const auto ser_params{ConsumeDeserializationParams<CNetAddr::SerParams>(fdp)};
254 const auto maybe_s{ConsumeDeserializable<CService>(fdp, ser_params)};
255 if (!maybe_s) return;
256 const CService& s{*maybe_s};
257 if (s.IsAddrV1Compatible()) {
258 AssertEqualAfterSerializeDeserialize(s, CNetAddr::V1);
259 }
260 AssertEqualAfterSerializeDeserialize(s, CNetAddr::V2);
261 if (ser_params.enc == CNetAddr::Encoding::V1) {
262 assert(s.IsAddrV1Compatible());
263 }
264}
265FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
267 DeserializeFromFuzzingInput(buffer, mh);
268 (void)mh.IsMessageTypeValid();
269})
270FUZZ_TARGET(address_deserialize, .init = initialize_deserialize)
271{
272 FuzzedDataProvider fdp{buffer.data(), buffer.size()};
273 const auto ser_enc{ConsumeDeserializationParams<CAddress::SerParams>(fdp)};
274 const auto maybe_a{ConsumeDeserializable<CAddress>(fdp, ser_enc)};
275 if (!maybe_a) return;
276 const CAddress& a{*maybe_a};
277 // A CAddress in V1 mode will roundtrip
278 // in all 4 formats (v1/v2, network/disk)
279 if (ser_enc.enc == CNetAddr::Encoding::V1) {
280 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
281 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
282 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
283 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
284 } else {
285 // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats
286 // if it's V1 compatible.
287 if (a.IsAddrV1Compatible()) {
288 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
289 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
290 }
291 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
292 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
293 }
294}
295FUZZ_TARGET_DESERIALIZE(inv_deserialize, {
296 CInv i;
297 DeserializeFromFuzzingInput(buffer, i);
298})
299FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, {
300 CBloomFilter bf;
301 DeserializeFromFuzzingInput(buffer, bf);
302})
303FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, {
304 CDiskBlockIndex dbi;
305 DeserializeFromFuzzingInput(buffer, dbi);
306})
307FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, {
308 CTxOut to;
309 auto toc = Using<TxOutCompression>(to);
310 DeserializeFromFuzzingInput(buffer, toc);
311})
312FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, {
314 DeserializeFromFuzzingInput(buffer, bt);
315})
316FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, {
318 DeserializeFromFuzzingInput(buffer, btr);
319})
320FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, {
321 auto msg_start = Params().MessageStart();
322 SnapshotMetadata snapshot_metadata{msg_start};
323 DeserializeFromFuzzingInput(buffer, snapshot_metadata);
324})
325FUZZ_TARGET_DESERIALIZE(uint160_deserialize, {
326 uint160 u160;
327 DeserializeFromFuzzingInput(buffer, u160);
328 AssertEqualAfterSerializeDeserialize(u160);
329})
330FUZZ_TARGET_DESERIALIZE(uint256_deserialize, {
331 uint256 u256;
332 DeserializeFromFuzzingInput(buffer, u256);
333 AssertEqualAfterSerializeDeserialize(u256);
334})
335// Classes intentionally not covered in this file since their deserialization code is
336// fuzzed elsewhere:
337// * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp
338// * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp
const CChainParams & Params()
Return the currently selected parameters.
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:116
A CService with information about it as peer.
Definition: protocol.h:367
static constexpr SerParams V1_NETWORK
Definition: protocol.h:408
static constexpr SerParams V2_NETWORK
Definition: protocol.h:409
static constexpr SerParams V1_DISK
Definition: protocol.h:410
static constexpr SerParams V2_DISK
Definition: protocol.h:411
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:22
Definition: block.h:69
Undo information for a CBlock.
Definition: undo.h:63
BloomFilter is a probabilistic filter which SPV clients provide so that we can filter the transaction...
Definition: bloom.h:45
const MessageStartChars & MessageStart() const
Definition: chainparams.h:91
Used to marshal pointers into hashes for db storage.
Definition: chain.h:319
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
Definition: feerate.h:35
inv message data
Definition: protocol.h:494
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
Definition: merkleblock.h:127
Message header.
Definition: protocol.h:29
bool IsMessageTypeValid() const
Definition: protocol.cpp:26
Network address.
Definition: netaddress.h:113
static constexpr SerParams V1
Definition: netaddress.h:232
static constexpr SerParams V2
Definition: netaddress.h:233
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
Data structure that represents a partial merkle tree.
Definition: merkleblock.h:57
An encapsulated public key.
Definition: pubkey.h:34
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:413
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:532
An input of a transaction.
Definition: transaction.h:67
An output of a transaction.
Definition: transaction.h:150
Undo information for a CTransaction.
Definition: undo.h:53
A UTXO entry.
Definition: coins.h:33
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:130
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:34
160-bit opaque blob.
Definition: uint256.h:184
256-bit opaque blob.
Definition: uint256.h:196
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
Definition: merkle.cpp:66
#define FUZZ_TARGET_DESERIALIZE(name, code)
Definition: deserialize.cpp:51
void initialize_deserialize()
Definition: deserialize.cpp:45
#define FUZZ_TARGET(...)
Definition: fuzz.h:35
std::span< const uint8_t > FuzzBufferType
Definition: fuzz.h:25
#define T(expected, seed, data)
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:195
void Serialize(Stream &, V)=delete
Basic testing setup.
Definition: setup_common.h:64
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
Definition: block.h:124
A structure for PSBTs which contain per-input information.
Definition: psbt.h:248
A structure for PSBTs which contains per output information.
Definition: psbt.h:864
A version of CTransaction with the PSBT format.
Definition: psbt.h:1125
assert(!tx.IsCoinBase())