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