Bitcoin Core 28.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>
30#include <undo.h>
31
32#include <exception>
33#include <optional>
34#include <stdexcept>
35#include <stdint.h>
36
38
39namespace {
40const 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
58namespace {
59
60struct invalid_fuzzing_input_exception : public std::exception {
61};
62
63template <typename T, typename P>
64DataStream Serialize(const T& obj, const P& params)
65{
66 DataStream ds{};
67 ds << params(obj);
68 return ds;
69}
70
71template <typename T, typename P>
72T Deserialize(DataStream&& ds, const P& params)
73{
74 T obj;
75 ds >> params(obj);
76 return obj;
77}
78
79template <typename T, typename P>
80void 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
91template <typename T>
92DataStream Serialize(const T& obj)
93{
94 DataStream ds{};
95 ds << obj;
96 return ds;
97}
98
99template <typename T>
100T Deserialize(DataStream ds)
101{
102 T obj;
103 ds >> obj;
104 return obj;
105}
106
107template <typename T>
108void 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
119template <typename T, typename P>
120void AssertEqualAfterSerializeDeserialize(const T& obj, const P& params)
121{
122 assert(Deserialize<T>(Serialize(obj, params), params) == obj);
123}
124template <typename T>
125void AssertEqualAfterSerializeDeserialize(const T& obj)
126{
127 assert(Deserialize<T>(Serialize(obj)) == obj);
128}
129
130} // namespace
131
132FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, {
133 BlockFilter block_filter;
134 DeserializeFromFuzzingInput(buffer, block_filter);
135})
136FUZZ_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}
141FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, {
142 CBlockFileInfo block_file_info;
143 DeserializeFromFuzzingInput(buffer, block_file_info);
144})
145FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, {
146 CBlockHeaderAndShortTxIDs block_header_and_short_txids;
147 DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
148})
149FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, {
150 CFeeRate fee_rate;
151 DeserializeFromFuzzingInput(buffer, fee_rate);
152 AssertEqualAfterSerializeDeserialize(fee_rate);
153})
154FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, {
155 CMerkleBlock merkle_block;
156 DeserializeFromFuzzingInput(buffer, merkle_block);
157})
158FUZZ_TARGET_DESERIALIZE(out_point_deserialize, {
159 COutPoint out_point;
160 DeserializeFromFuzzingInput(buffer, out_point);
161 AssertEqualAfterSerializeDeserialize(out_point);
162})
163FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, {
164 CPartialMerkleTree partial_merkle_tree;
165 DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
166})
167FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, {
168 CPubKey pub_key;
169 DeserializeFromFuzzingInput(buffer, pub_key);
170 AssertEqualAfterSerializeDeserialize(pub_key);
171})
172FUZZ_TARGET_DESERIALIZE(script_deserialize, {
174 DeserializeFromFuzzingInput(buffer, script);
175})
176FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, {
177 CTxIn tx_in;
178 DeserializeFromFuzzingInput(buffer, tx_in);
179 AssertEqualAfterSerializeDeserialize(tx_in);
180})
181FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, {
182 FlatFilePos flat_file_pos;
183 DeserializeFromFuzzingInput(buffer, flat_file_pos);
184 AssertEqualAfterSerializeDeserialize(flat_file_pos);
185})
186FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, {
187 KeyOriginInfo key_origin_info;
188 DeserializeFromFuzzingInput(buffer, key_origin_info);
189 AssertEqualAfterSerializeDeserialize(key_origin_info);
190})
191FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, {
192 PartiallySignedTransaction partially_signed_transaction;
193 DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
194})
195FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, {
196 PrefilledTransaction prefilled_transaction;
197 DeserializeFromFuzzingInput(buffer, prefilled_transaction);
198})
199FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, {
200 PSBTInput psbt_input;
201 DeserializeFromFuzzingInput(buffer, psbt_input);
202})
203FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, {
204 PSBTOutput psbt_output;
205 DeserializeFromFuzzingInput(buffer, psbt_output);
206})
207FUZZ_TARGET_DESERIALIZE(block_deserialize, {
208 CBlock block;
209 DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
210})
211FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, {
212 CBlockLocator bl;
213 DeserializeFromFuzzingInput(buffer, bl);
214})
215FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
216 CBlock block;
217 DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
218 bool mutated;
219 BlockMerkleRoot(block, &mutated);
220})
221FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {
222 CBlockHeader bh;
223 DeserializeFromFuzzingInput(buffer, bh);
224})
225FUZZ_TARGET_DESERIALIZE(txundo_deserialize, {
226 CTxUndo tu;
227 DeserializeFromFuzzingInput(buffer, tu);
228})
229FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, {
230 CBlockUndo bu;
231 DeserializeFromFuzzingInput(buffer, bu);
232})
233FUZZ_TARGET_DESERIALIZE(coins_deserialize, {
234 Coin coin;
235 DeserializeFromFuzzingInput(buffer, coin);
236})
237FUZZ_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}
248FUZZ_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}
263FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
265 DeserializeFromFuzzingInput(buffer, mh);
266 (void)mh.IsMessageTypeValid();
267})
268FUZZ_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}
293FUZZ_TARGET_DESERIALIZE(inv_deserialize, {
294 CInv i;
295 DeserializeFromFuzzingInput(buffer, i);
296})
297FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, {
298 CBloomFilter bf;
299 DeserializeFromFuzzingInput(buffer, bf);
300})
301FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, {
302 CDiskBlockIndex dbi;
303 DeserializeFromFuzzingInput(buffer, dbi);
304})
305FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, {
306 CTxOut to;
307 auto toc = Using<TxOutCompression>(to);
308 DeserializeFromFuzzingInput(buffer, toc);
309})
310FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, {
312 DeserializeFromFuzzingInput(buffer, bt);
313})
314FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, {
316 DeserializeFromFuzzingInput(buffer, btr);
317})
318FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, {
319 auto msg_start = Params().MessageStart();
320 SnapshotMetadata snapshot_metadata{msg_start};
321 DeserializeFromFuzzingInput(buffer, snapshot_metadata);
322})
323FUZZ_TARGET_DESERIALIZE(uint160_deserialize, {
324 uint160 u160;
325 DeserializeFromFuzzingInput(buffer, u160);
326 AssertEqualAfterSerializeDeserialize(u160);
327})
328FUZZ_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
const CChainParams & Params()
Return the currently selected parameters.
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:115
A CService with information about it as peer.
Definition: protocol.h:367
static constexpr SerParams V1_NETWORK
Definition: protocol.h:408
static constexpr SerParams V2_NETWORK
Definition: protocol.h:409
static constexpr SerParams V1_DISK
Definition: protocol.h:410
static constexpr SerParams V2_DISK
Definition: protocol.h:411
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
const MessageStartChars & MessageStart() const
Definition: chainparams.h:94
Used to marshal pointers into hashes for db storage.
Definition: chain.h:355
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
Definition: feerate.h:33
inv message data
Definition: protocol.h:494
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
Definition: merkleblock.h:126
Message header.
Definition: protocol.h:29
bool IsMessageTypeValid() const
Definition: protocol.cpp:26
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:415
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:33
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:34
160-bit opaque blob.
Definition: uint256.h:178
256-bit opaque blob.
Definition: uint256.h:190
#define FUZZ_TARGET_DESERIALIZE(name, code)
Definition: deserialize.cpp:49
void initialize_deserialize()
Definition: deserialize.cpp:43
#define FUZZ_TARGET(...)
Definition: fuzz.h:35
std::span< const uint8_t > FuzzBufferType
Definition: fuzz.h:25
#define T(expected, seed, data)
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
Definition: merkle.cpp:66
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:195
void Serialize(Stream &, V)=delete
Basic testing setup.
Definition: setup_common.h:63
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:198
A structure for PSBTs which contains per output information.
Definition: psbt.h:715
A version of CTransaction with the PSBT format.
Definition: psbt.h:951
assert(!tx.IsCoinBase())