/ src / test / fuzz / deserialize.cpp
deserialize.cpp
  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  
 38  using kernel::CBlockFileInfo;
 39  using node::SnapshotMetadata;
 40  
 41  void initialize_deserialize()
 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, {
306      BlockTransactions bt;
307      DeserializeFromFuzzingInput(buffer, bt);
308  })
309  FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, {
310      BlockTransactionsRequest btr;
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