/root/bitcoin/src/test/fuzz/descriptor_parse.cpp
Line | Count | Source |
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 <chainparams.h> |
6 | | #include <key_io.h> |
7 | | #include <pubkey.h> |
8 | | #include <script/descriptor.h> |
9 | | #include <test/fuzz/fuzz.h> |
10 | | #include <test/fuzz/util/descriptor.h> |
11 | | #include <util/chaintype.h> |
12 | | #include <util/strencodings.h> |
13 | | |
14 | | //! The converter of mocked descriptors, needs to be initialized when the target is. |
15 | | MockedDescriptorConverter MOCKED_DESC_CONVERTER; |
16 | | |
17 | | /** Test a successfully parsed descriptor. */ |
18 | | static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy, std::optional<bool>& is_ranged, std::optional<bool>& is_solvable) |
19 | 37.5k | { |
20 | | // Trivial helpers. |
21 | 37.5k | (void)desc.IsRange(); |
22 | 37.5k | (void)desc.IsSingleType(); |
23 | 37.5k | (void)desc.GetOutputType(); |
24 | | |
25 | 37.5k | if (is_ranged.has_value()) { Branch (25:9): [True: 31.7k, False: 5.77k]
|
26 | 31.7k | assert(desc.IsRange() == *is_ranged); Branch (26:9): [True: 31.7k, False: 0]
|
27 | 31.7k | } else { |
28 | 5.77k | is_ranged = desc.IsRange(); |
29 | 5.77k | } |
30 | 37.5k | if (is_solvable.has_value()) { Branch (30:9): [True: 31.7k, False: 5.77k]
|
31 | 31.7k | assert(desc.IsSolvable() == *is_solvable); Branch (31:9): [True: 31.7k, False: 0]
|
32 | 31.7k | } else { |
33 | 5.77k | is_solvable = desc.IsSolvable(); |
34 | 5.77k | } |
35 | | |
36 | | // Serialization to string representation. |
37 | 37.5k | (void)desc.ToString(); |
38 | 37.5k | (void)desc.ToPrivateString(sig_provider, dummy); |
39 | 37.5k | (void)desc.ToNormalizedString(sig_provider, dummy); |
40 | | |
41 | | // Serialization to Script. |
42 | 37.5k | DescriptorCache cache; |
43 | 37.5k | std::vector<CScript> out_scripts; |
44 | 37.5k | (void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache); |
45 | 37.5k | (void)desc.ExpandPrivate(0, sig_provider, sig_provider); |
46 | 37.5k | (void)desc.ExpandFromCache(0, cache, out_scripts, sig_provider); |
47 | | |
48 | | // If we could serialize to script we must be able to infer using the same provider. |
49 | 37.5k | if (!out_scripts.empty()) { Branch (49:9): [True: 35.8k, False: 1.72k]
|
50 | 35.8k | assert(InferDescriptor(out_scripts.back(), sig_provider)); Branch (50:9): [True: 35.8k, False: 0]
|
51 | | |
52 | | // The ScriptSize() must match the size of the serialized Script. (ScriptSize() is set for all descs but 'combo()'.) |
53 | 35.8k | const bool is_combo{!desc.IsSingleType()}; |
54 | 35.8k | assert(is_combo || desc.ScriptSize() == out_scripts.back().size()); Branch (54:9): [True: 730, False: 35.1k]
Branch (54:9): [True: 35.1k, False: 0]
Branch (54:9): [True: 35.8k, False: 0]
|
55 | 35.8k | } |
56 | | |
57 | 37.5k | const auto max_sat_maxsig{desc.MaxSatisfactionWeight(true)}; |
58 | 37.5k | const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(false)}; |
59 | | // Whether an estimate is available must not depend on the signature-size |
60 | | // assumption, and assuming non-max-size signatures must never increase it. |
61 | 37.5k | assert(max_sat_maxsig.has_value() == max_sat_nonmaxsig.has_value()); Branch (61:5): [True: 37.5k, False: 0]
|
62 | 37.5k | assert(max_sat_nonmaxsig <= max_sat_maxsig); Branch (62:5): [True: 37.5k, False: 0]
|
63 | 37.5k | const auto max_elems{desc.MaxSatisfactionElems()}; |
64 | | // We must be able to estimate the max satisfaction size for any solvable descriptor (but combo). |
65 | 37.5k | const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()}; Branch (65:41): [True: 359, False: 37.1k]
Branch (65:58): [True: 1.49k, False: 35.7k]
|
66 | 37.5k | const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems}; Branch (66:39): [True: 36.3k, False: 1.24k]
Branch (66:57): [True: 36.3k, False: 0]
Branch (66:78): [True: 36.3k, False: 0]
|
67 | 37.5k | assert(is_input_size_info_set || is_nontop_or_nonsolvable); Branch (67:5): [True: 36.3k, False: 1.24k]
Branch (67:5): [True: 1.24k, False: 0]
Branch (67:5): [True: 37.5k, False: 0]
|
68 | | |
69 | 37.5k | auto max_key_expr = desc.GetMaxKeyExpr(); |
70 | 37.5k | auto key_count = desc.GetKeyCount(); |
71 | 37.5k | assert((max_key_expr == 0 && key_count == 0) || max_key_expr + 1 == key_count); Branch (71:5): [True: 9.08k, False: 28.4k]
Branch (71:5): [True: 359, False: 8.72k]
Branch (71:5): [True: 37.1k, False: 0]
Branch (71:5): [True: 37.5k, False: 0]
|
72 | 37.5k | } |
73 | | |
74 | | void initialize_descriptor_parse() |
75 | 0 | { |
76 | 0 | static ECC_Context ecc_context{}; |
77 | 0 | SelectParams(ChainType::MAIN); |
78 | 0 | } |
79 | | |
80 | | void initialize_mocked_descriptor_parse() |
81 | 0 | { |
82 | 0 | initialize_descriptor_parse(); |
83 | 0 | MOCKED_DESC_CONVERTER.Init(); |
84 | 0 | } |
85 | | |
86 | | FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse) |
87 | 5.95k | { |
88 | 5.95k | const std::string mocked_descriptor{buffer.begin(), buffer.end()}; |
89 | 5.95k | if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) { Branch (89:20): [True: 5.93k, False: 25]
|
90 | 5.93k | if (IsTooExpensive(MakeUCharSpan(*descriptor))) return; Branch (90:13): [True: 20, False: 5.91k]
|
91 | 5.91k | FlatSigningProvider signing_provider; |
92 | 5.91k | std::string error; |
93 | 5.91k | const auto desc = Parse(*descriptor, signing_provider, error); |
94 | 5.91k | std::optional<bool> is_ranged; |
95 | 5.91k | std::optional<bool> is_solvable; |
96 | 24.3k | for (const auto& d : desc) { Branch (96:28): [True: 24.3k, False: 5.91k]
|
97 | 24.3k | assert(d); Branch (97:13): [True: 24.3k, False: 0]
|
98 | 24.3k | TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable); |
99 | 24.3k | } |
100 | 5.91k | } |
101 | 5.95k | } |
102 | | |
103 | | FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse) |
104 | 4.60k | { |
105 | 4.60k | if (IsTooExpensive(buffer)) return; Branch (105:9): [True: 11, False: 4.59k]
|
106 | | |
107 | 4.59k | const std::string descriptor(buffer.begin(), buffer.end()); |
108 | 4.59k | FlatSigningProvider signing_provider; |
109 | 4.59k | std::string error; |
110 | 9.18k | for (const bool require_checksum : {true, false}) { Branch (110:38): [True: 9.18k, False: 4.59k]
|
111 | 9.18k | const auto desc = Parse(descriptor, signing_provider, error, require_checksum); |
112 | 9.18k | std::optional<bool> is_ranged; |
113 | 9.18k | std::optional<bool> is_solvable; |
114 | 13.2k | for (const auto& d : desc) { Branch (114:28): [True: 13.2k, False: 9.18k]
|
115 | 13.2k | assert(d); Branch (115:13): [True: 13.2k, False: 0]
|
116 | 13.2k | TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable); |
117 | 13.2k | } |
118 | 9.18k | } |
119 | 4.59k | } |