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 #include <unistd.h>
37 
39 
40 namespace {
41 const BasicTestingSetup* g_setup;
42 } // namespace
43 
45 {
46  static const auto testing_setup = MakeNoLogFileContext<>();
47  g_setup = testing_setup.get();
48 }
49 
50 #define FUZZ_TARGET_DESERIALIZE(name, code) \
51  FUZZ_TARGET(name, .init = initialize_deserialize) \
52  { \
53  try { \
54  code \
55  } catch (const invalid_fuzzing_input_exception&) { \
56  } \
57  }
58 
59 namespace {
60 
61 struct invalid_fuzzing_input_exception : public std::exception {
62 };
63 
64 template <typename T, typename P>
65 DataStream Serialize(const T& obj, const P& params)
66 {
67  DataStream ds{};
68  ds << params(obj);
69  return ds;
70 }
71 
72 template <typename T, typename P>
73 T Deserialize(DataStream&& ds, const P& params)
74 {
75  T obj;
76  ds >> params(obj);
77  return obj;
78 }
79 
80 template <typename T, typename P>
81 void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params)
82 {
83  DataStream ds{buffer};
84  try {
85  ds >> params(obj);
86  } catch (const std::ios_base::failure&) {
87  throw invalid_fuzzing_input_exception();
88  }
89  assert(buffer.empty() || !Serialize(obj, params).empty());
90 }
91 
92 template <typename T>
93 DataStream Serialize(const T& obj)
94 {
95  DataStream ds{};
96  ds << obj;
97  return ds;
98 }
99 
100 template <typename T>
101 T Deserialize(DataStream ds)
102 {
103  T obj;
104  ds >> obj;
105  return obj;
106 }
107 
108 template <typename T>
109 void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj)
110 {
111  DataStream ds{buffer};
112  try {
113  ds >> obj;
114  } catch (const std::ios_base::failure&) {
115  throw invalid_fuzzing_input_exception();
116  }
117  assert(buffer.empty() || !Serialize(obj).empty());
118 }
119 
120 template <typename T, typename P>
121 void AssertEqualAfterSerializeDeserialize(const T& obj, const P& params)
122 {
123  assert(Deserialize<T>(Serialize(obj, params), params) == obj);
124 }
125 template <typename T>
126 void AssertEqualAfterSerializeDeserialize(const T& obj)
127 {
128  assert(Deserialize<T>(Serialize(obj)) == obj);
129 }
130 
131 } // namespace
132 
133 FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, {
134  BlockFilter block_filter;
135  DeserializeFromFuzzingInput(buffer, block_filter);
136 })
137 FUZZ_TARGET(addr_info_deserialize, .init = initialize_deserialize)
138 {
139  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
140  (void)ConsumeDeserializable<AddrInfo>(fdp, ConsumeDeserializationParams<CAddress::SerParams>(fdp));
141 }
142 FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, {
143  CBlockFileInfo block_file_info;
144  DeserializeFromFuzzingInput(buffer, block_file_info);
145 })
146 FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, {
147  CBlockHeaderAndShortTxIDs block_header_and_short_txids;
148  DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
149 })
150 FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, {
151  CFeeRate fee_rate;
152  DeserializeFromFuzzingInput(buffer, fee_rate);
153  AssertEqualAfterSerializeDeserialize(fee_rate);
154 })
155 FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, {
156  CMerkleBlock merkle_block;
157  DeserializeFromFuzzingInput(buffer, merkle_block);
158 })
159 FUZZ_TARGET_DESERIALIZE(out_point_deserialize, {
160  COutPoint out_point;
161  DeserializeFromFuzzingInput(buffer, out_point);
162  AssertEqualAfterSerializeDeserialize(out_point);
163 })
164 FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, {
165  CPartialMerkleTree partial_merkle_tree;
166  DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
167 })
168 FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, {
169  CPubKey pub_key;
170  DeserializeFromFuzzingInput(buffer, pub_key);
171  AssertEqualAfterSerializeDeserialize(pub_key);
172 })
173 FUZZ_TARGET_DESERIALIZE(script_deserialize, {
174  CScript script;
175  DeserializeFromFuzzingInput(buffer, script);
176 })
177 FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, {
178  CTxIn tx_in;
179  DeserializeFromFuzzingInput(buffer, tx_in);
180  AssertEqualAfterSerializeDeserialize(tx_in);
181 })
182 FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, {
183  FlatFilePos flat_file_pos;
184  DeserializeFromFuzzingInput(buffer, flat_file_pos);
185  AssertEqualAfterSerializeDeserialize(flat_file_pos);
186 })
187 FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, {
188  KeyOriginInfo key_origin_info;
189  DeserializeFromFuzzingInput(buffer, key_origin_info);
190  AssertEqualAfterSerializeDeserialize(key_origin_info);
191 })
192 FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, {
193  PartiallySignedTransaction partially_signed_transaction;
194  DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
195 })
196 FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, {
197  PrefilledTransaction prefilled_transaction;
198  DeserializeFromFuzzingInput(buffer, prefilled_transaction);
199 })
200 FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, {
201  PSBTInput psbt_input;
202  DeserializeFromFuzzingInput(buffer, psbt_input);
203 })
204 FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, {
205  PSBTOutput psbt_output;
206  DeserializeFromFuzzingInput(buffer, psbt_output);
207 })
208 FUZZ_TARGET_DESERIALIZE(block_deserialize, {
209  CBlock block;
210  DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
211 })
212 FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, {
213  CBlockLocator bl;
214  DeserializeFromFuzzingInput(buffer, bl);
215 })
216 FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
217  CBlock block;
218  DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
219  bool mutated;
220  BlockMerkleRoot(block, &mutated);
221 })
222 FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {
223  CBlockHeader bh;
224  DeserializeFromFuzzingInput(buffer, bh);
225 })
226 FUZZ_TARGET_DESERIALIZE(txundo_deserialize, {
227  CTxUndo tu;
228  DeserializeFromFuzzingInput(buffer, tu);
229 })
230 FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, {
231  CBlockUndo bu;
232  DeserializeFromFuzzingInput(buffer, bu);
233 })
234 FUZZ_TARGET_DESERIALIZE(coins_deserialize, {
235  Coin coin;
236  DeserializeFromFuzzingInput(buffer, coin);
237 })
238 FUZZ_TARGET(netaddr_deserialize, .init = initialize_deserialize)
239 {
240  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
241  const auto maybe_na{ConsumeDeserializable<CNetAddr>(fdp, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp))};
242  if (!maybe_na) return;
243  const CNetAddr& na{*maybe_na};
244  if (na.IsAddrV1Compatible()) {
245  AssertEqualAfterSerializeDeserialize(na, CNetAddr::V1);
246  }
247  AssertEqualAfterSerializeDeserialize(na, CNetAddr::V2);
248 }
249 FUZZ_TARGET(service_deserialize, .init = initialize_deserialize)
250 {
251  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
252  const auto ser_params{ConsumeDeserializationParams<CNetAddr::SerParams>(fdp)};
253  const auto maybe_s{ConsumeDeserializable<CService>(fdp, ser_params)};
254  if (!maybe_s) return;
255  const CService& s{*maybe_s};
256  if (s.IsAddrV1Compatible()) {
257  AssertEqualAfterSerializeDeserialize(s, CNetAddr::V1);
258  }
259  AssertEqualAfterSerializeDeserialize(s, CNetAddr::V2);
260  if (ser_params.enc == CNetAddr::Encoding::V1) {
261  assert(s.IsAddrV1Compatible());
262  }
263 }
264 FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
265  CMessageHeader mh;
266  DeserializeFromFuzzingInput(buffer, mh);
267  (void)mh.IsCommandValid();
268 })
269 FUZZ_TARGET(address_deserialize, .init = initialize_deserialize)
270 {
271  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
272  const auto ser_enc{ConsumeDeserializationParams<CAddress::SerParams>(fdp)};
273  const auto maybe_a{ConsumeDeserializable<CAddress>(fdp, ser_enc)};
274  if (!maybe_a) return;
275  const CAddress& a{*maybe_a};
276  // A CAddress in V1 mode will roundtrip
277  // in all 4 formats (v1/v2, network/disk)
278  if (ser_enc.enc == CNetAddr::Encoding::V1) {
279  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
280  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
281  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
282  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
283  } else {
284  // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats
285  // if it's V1 compatible.
286  if (a.IsAddrV1Compatible()) {
287  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
288  AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
289  }
290  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
291  AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
292  }
293 }
294 FUZZ_TARGET_DESERIALIZE(inv_deserialize, {
295  CInv i;
296  DeserializeFromFuzzingInput(buffer, i);
297 })
298 FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, {
299  CBloomFilter bf;
300  DeserializeFromFuzzingInput(buffer, bf);
301 })
302 FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, {
303  CDiskBlockIndex dbi;
304  DeserializeFromFuzzingInput(buffer, dbi);
305 })
306 FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, {
307  CTxOut to;
308  auto toc = Using<TxOutCompression>(to);
309  DeserializeFromFuzzingInput(buffer, toc);
310 })
311 FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, {
313  DeserializeFromFuzzingInput(buffer, bt);
314 })
315 FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, {
317  DeserializeFromFuzzingInput(buffer, btr);
318 })
319 FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, {
320  SnapshotMetadata snapshot_metadata;
321  DeserializeFromFuzzingInput(buffer, snapshot_metadata);
322 })
323 FUZZ_TARGET_DESERIALIZE(uint160_deserialize, {
324  uint160 u160;
325  DeserializeFromFuzzingInput(buffer, u160);
326  AssertEqualAfterSerializeDeserialize(u160);
327 })
328 FUZZ_TARGET_DESERIALIZE(uint256_deserialize, {
329  uint256 u256;
330  DeserializeFromFuzzingInput(buffer, u256);
331  AssertEqualAfterSerializeDeserialize(u256);
332 })
333 // Classes intentionally not covered in this file since their deserialization code is
334 // fuzzed elsewhere:
335 // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp
336 // * 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:458
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:50
void initialize_deserialize()
Definition: deserialize.cpp:44
#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:52
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())