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