Bitcoin Core  26.1.0
P2P Digital Currency
deserialize.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2021 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/utxo_snapshot.h>
21 #include <primitives/block.h>
22 #include <protocol.h>
23 #include <psbt.h>
24 #include <pubkey.h>
25 #include <script/keyorigin.h>
26 #include <streams.h>
27 #include <test/fuzz/fuzz.h>
28 #include <test/fuzz/util.h>
29 #include <test/util/setup_common.h>
30 #include <undo.h>
31 #include <version.h>
32 
33 #include <exception>
34 #include <optional>
35 #include <stdexcept>
36 #include <stdint.h>
37 #include <unistd.h>
38 
40 
41 namespace {
42 const 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 
60 namespace {
61 
62 struct invalid_fuzzing_input_exception : public std::exception {
63 };
64 
65 template <typename T, typename P>
66 DataStream Serialize(const T& obj, const P& params)
67 {
68  DataStream ds{};
69  ds << WithParams(params, obj);
70  return ds;
71 }
72 
73 template <typename T, typename P>
74 T Deserialize(DataStream&& ds, const P& params)
75 {
76  T obj;
77  ds >> WithParams(params, obj);
78  return obj;
79 }
80 
81 template <typename T, typename P>
82 void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params)
83 {
84  DataStream ds{buffer};
85  try {
86  ds >> WithParams(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 
93 template <typename T>
94 CDataStream Serialize(const T& obj)
95 {
97  ds << obj;
98  return ds;
99 }
100 
101 template <typename T>
102 T Deserialize(CDataStream ds)
103 {
104  T obj;
105  ds >> obj;
106  return obj;
107 }
108 
109 template <typename T>
110 void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj)
111 {
113  {
114  try {
115  int version;
116  ds >> version;
117  ds.SetVersion(version);
118  } catch (const std::ios_base::failure&) {
119  throw invalid_fuzzing_input_exception();
120  }
121  }
122  try {
123  ds >> obj;
124  } catch (const std::ios_base::failure&) {
125  throw invalid_fuzzing_input_exception();
126  }
127  assert(buffer.empty() || !Serialize(obj).empty());
128 }
129 
130 template <typename T, typename P>
131 void AssertEqualAfterSerializeDeserialize(const T& obj, const P& params)
132 {
133  assert(Deserialize<T>(Serialize(obj, params), params) == obj);
134 }
135 template <typename T>
136 void AssertEqualAfterSerializeDeserialize(const T& obj)
137 {
138  assert(Deserialize<T>(Serialize(obj)) == obj);
139 }
140 
141 } // namespace
142 
143 FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, {
144  BlockFilter block_filter;
145  DeserializeFromFuzzingInput(buffer, block_filter);
146 })
147 FUZZ_TARGET(addr_info_deserialize, .init = initialize_deserialize)
148 {
149  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
150  (void)ConsumeDeserializable<AddrInfo>(fdp, ConsumeDeserializationParams<CAddress::SerParams>(fdp));
151 }
152 FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, {
153  CBlockFileInfo block_file_info;
154  DeserializeFromFuzzingInput(buffer, block_file_info);
155 })
156 FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, {
157  CBlockHeaderAndShortTxIDs block_header_and_short_txids;
158  DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
159 })
160 FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, {
161  CFeeRate fee_rate;
162  DeserializeFromFuzzingInput(buffer, fee_rate);
163  AssertEqualAfterSerializeDeserialize(fee_rate);
164 })
165 FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, {
166  CMerkleBlock merkle_block;
167  DeserializeFromFuzzingInput(buffer, merkle_block);
168 })
169 FUZZ_TARGET_DESERIALIZE(out_point_deserialize, {
170  COutPoint out_point;
171  DeserializeFromFuzzingInput(buffer, out_point);
172  AssertEqualAfterSerializeDeserialize(out_point);
173 })
174 FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, {
175  CPartialMerkleTree partial_merkle_tree;
176  DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
177 })
178 FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, {
179  CPubKey pub_key;
180  DeserializeFromFuzzingInput(buffer, pub_key);
181  AssertEqualAfterSerializeDeserialize(pub_key);
182 })
183 FUZZ_TARGET_DESERIALIZE(script_deserialize, {
184  CScript script;
185  DeserializeFromFuzzingInput(buffer, script);
186 })
187 FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, {
188  CTxIn tx_in;
189  DeserializeFromFuzzingInput(buffer, tx_in);
190  AssertEqualAfterSerializeDeserialize(tx_in);
191 })
192 FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, {
193  FlatFilePos flat_file_pos;
194  DeserializeFromFuzzingInput(buffer, flat_file_pos);
195  AssertEqualAfterSerializeDeserialize(flat_file_pos);
196 })
197 FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, {
198  KeyOriginInfo key_origin_info;
199  DeserializeFromFuzzingInput(buffer, key_origin_info);
200  AssertEqualAfterSerializeDeserialize(key_origin_info);
201 })
202 FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, {
203  PartiallySignedTransaction partially_signed_transaction;
204  DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
205 })
206 FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, {
207  PrefilledTransaction prefilled_transaction;
208  DeserializeFromFuzzingInput(buffer, prefilled_transaction);
209 })
210 FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, {
211  PSBTInput psbt_input;
212  DeserializeFromFuzzingInput(buffer, psbt_input);
213 })
214 FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, {
215  PSBTOutput psbt_output;
216  DeserializeFromFuzzingInput(buffer, psbt_output);
217 })
218 FUZZ_TARGET_DESERIALIZE(block_deserialize, {
219  CBlock block;
220  DeserializeFromFuzzingInput(buffer, block);
221 })
222 FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, {
223  CBlockLocator bl;
224  DeserializeFromFuzzingInput(buffer, bl);
225 })
226 FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
227  CBlock block;
228  DeserializeFromFuzzingInput(buffer, block);
229  bool mutated;
230  BlockMerkleRoot(block, &mutated);
231 })
232 FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {
233  CBlockHeader bh;
234  DeserializeFromFuzzingInput(buffer, bh);
235 })
236 FUZZ_TARGET_DESERIALIZE(txundo_deserialize, {
237  CTxUndo tu;
238  DeserializeFromFuzzingInput(buffer, tu);
239 })
240 FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, {
241  CBlockUndo bu;
242  DeserializeFromFuzzingInput(buffer, bu);
243 })
244 FUZZ_TARGET_DESERIALIZE(coins_deserialize, {
245  Coin coin;
246  DeserializeFromFuzzingInput(buffer, coin);
247 })
248 FUZZ_TARGET(netaddr_deserialize, .init = initialize_deserialize)
249 {
250  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
251  const auto maybe_na{ConsumeDeserializable<CNetAddr>(fdp, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp))};
252  if (!maybe_na) return;
253  const CNetAddr& na{*maybe_na};
254  if (na.IsAddrV1Compatible()) {
255  AssertEqualAfterSerializeDeserialize(na, CNetAddr::V1);
256  }
257  AssertEqualAfterSerializeDeserialize(na, CNetAddr::V2);
258 }
259 FUZZ_TARGET(service_deserialize, .init = initialize_deserialize)
260 {
261  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
262  const auto ser_params{ConsumeDeserializationParams<CNetAddr::SerParams>(fdp)};
263  const auto maybe_s{ConsumeDeserializable<CService>(fdp, ser_params)};
264  if (!maybe_s) return;
265  const CService& s{*maybe_s};
266  if (s.IsAddrV1Compatible()) {
267  AssertEqualAfterSerializeDeserialize(s, CNetAddr::V1);
268  }
269  AssertEqualAfterSerializeDeserialize(s, CNetAddr::V2);
270  if (ser_params.enc == CNetAddr::Encoding::V1) {
271  assert(s.IsAddrV1Compatible());
272  }
273 }
274 FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
275  CMessageHeader mh;
276  DeserializeFromFuzzingInput(buffer, mh);
277  (void)mh.IsCommandValid();
278 })
279 FUZZ_TARGET(address_deserialize, .init = initialize_deserialize)
280 {
281  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
282  const auto ser_enc{ConsumeDeserializationParams<CAddress::SerParams>(fdp)};
283  const auto maybe_a{ConsumeDeserializable<CAddress>(fdp, ser_enc)};
284  if (!maybe_a) return;
285  const CAddress& a{*maybe_a};
286  // A CAddress in V1 mode will roundtrip
287  // in all 4 formats (v1/v2, network/disk)
288  if (ser_enc.enc == CNetAddr::Encoding::V1) {
289  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
290  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
291  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
292  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
293  } else {
294  // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats
295  // if it's V1 compatible.
296  if (a.IsAddrV1Compatible()) {
297  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
298  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
299  }
300  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
301  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
302  }
303 }
304 FUZZ_TARGET_DESERIALIZE(inv_deserialize, {
305  CInv i;
306  DeserializeFromFuzzingInput(buffer, i);
307 })
308 FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, {
309  CBloomFilter bf;
310  DeserializeFromFuzzingInput(buffer, bf);
311 })
312 FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, {
313  CDiskBlockIndex dbi;
314  DeserializeFromFuzzingInput(buffer, dbi);
315 })
316 FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, {
317  CTxOut to;
318  auto toc = Using<TxOutCompression>(to);
319  DeserializeFromFuzzingInput(buffer, toc);
320 })
321 FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, {
323  DeserializeFromFuzzingInput(buffer, bt);
324 })
325 FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, {
327  DeserializeFromFuzzingInput(buffer, btr);
328 })
329 FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, {
330  SnapshotMetadata snapshot_metadata;
331  DeserializeFromFuzzingInput(buffer, snapshot_metadata);
332 })
333 FUZZ_TARGET_DESERIALIZE(uint160_deserialize, {
334  uint160 u160;
335  DeserializeFromFuzzingInput(buffer, u160);
336  AssertEqualAfterSerializeDeserialize(u160);
337 })
338 FUZZ_TARGET_DESERIALIZE(uint256_deserialize, {
339  uint256 u256;
340  DeserializeFromFuzzingInput(buffer, u256);
341  AssertEqualAfterSerializeDeserialize(u256);
342 })
343 // Classes intentionally not covered in this file since their deserialization code is
344 // fuzzed elsewhere:
345 // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp
346 // * 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:123
A UTXO entry.
Definition: coins.h:31
Definition: block.h:68
inv message data
Definition: protocol.h:488
BloomFilter is a probabilistic filter which SPV clients provide so that we can filter the transaction...
Definition: bloom.h:44
static constexpr SerParams V2_NETWORK
Definition: protocol.h:405
static constexpr SerParams V1_DISK
Definition: protocol.h:406
A version of CTransaction with the PSBT format.
Definition: psbt.h:946
Data structure that represents a partial merkle tree.
Definition: merkleblock.h:54
bool IsCommandValid() const
Definition: protocol.cpp:110
Basic testing setup.
Definition: setup_common.h:49
A structure for PSBTs which contains per output information.
Definition: psbt.h:710
static constexpr SerParams V2_DISK
Definition: protocol.h:407
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
Definition: merkleblock.h:124
An input of a transaction.
Definition: transaction.h:74
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:192
static const int INIT_PROTO_VERSION
initial proto version, to be increased after version/verack negotiation
Definition: version.h:15
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:114
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:534
An encapsulated public key.
Definition: pubkey.h:33
static constexpr SerParams V1
Definition: netaddress.h:235
void Serialize(Stream &, char)=delete
A CService with information about it as peer.
Definition: protocol.h:362
A structure for PSBTs which contain per-input information.
Definition: psbt.h:191
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
Definition: merkle.cpp:65
static auto WithParams(const Params &params, T &&t)
Return a wrapper around t that (de)serializes it with specified parameter params. ...
Definition: serialize.h:1191
An output of a transaction.
Definition: transaction.h:157
Used to marshal pointers into hashes for db storage.
Definition: chain.h:379
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:35
Network address.
Definition: netaddress.h:115
256-bit opaque blob.
Definition: uint256.h:106
Undo information for a CBlock.
Definition: undo.h:63
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:412
Undo information for a CTransaction.
Definition: undo.h:53
#define FUZZ_TARGET_DESERIALIZE(name, code)
Definition: deserialize.cpp:51
constexpr bool empty() const noexcept
Definition: span.h:188
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
Definition: feerate.h:32
160-bit opaque blob.
Definition: uint256.h:95
static constexpr SerParams V2
Definition: netaddress.h:236
void initialize_deserialize()
Definition: deserialize.cpp:45
A Span is an object that can refer to a contiguous sequence of objects.
Definition: solver.h:20
#define FUZZ_TARGET(...)
Definition: fuzz.h:34
void SetVersion(int n)
Definition: streams.h:346
static constexpr SerParams V1_NETWORK
Definition: protocol.h:404
#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:21
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:24
Message header.
Definition: protocol.h:28