descriptor_parse.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 <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 { 20 // Trivial helpers. 21 (void)desc.IsRange(); 22 (void)desc.IsSingleType(); 23 (void)desc.GetOutputType(); 24 25 if (is_ranged.has_value()) { 26 assert(desc.IsRange() == *is_ranged); 27 } else { 28 is_ranged = desc.IsRange(); 29 } 30 if (is_solvable.has_value()) { 31 assert(desc.IsSolvable() == *is_solvable); 32 } else { 33 is_solvable = desc.IsSolvable(); 34 } 35 36 // Serialization to string representation. 37 (void)desc.ToString(); 38 (void)desc.ToPrivateString(sig_provider, dummy); 39 (void)desc.ToNormalizedString(sig_provider, dummy); 40 41 // Serialization to Script. 42 DescriptorCache cache; 43 std::vector<CScript> out_scripts; 44 (void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache); 45 (void)desc.ExpandPrivate(0, sig_provider, sig_provider); 46 (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 if (!out_scripts.empty()) { 50 assert(InferDescriptor(out_scripts.back(), sig_provider)); 51 52 // The ScriptSize() must match the size of the serialized Script. (ScriptSize() is set for all descs but 'combo()'.) 53 const bool is_combo{!desc.IsSingleType()}; 54 assert(is_combo || desc.ScriptSize() == out_scripts.back().size()); 55 } 56 57 const auto max_sat_maxsig{desc.MaxSatisfactionWeight(true)}; 58 const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)}; 59 const auto max_elems{desc.MaxSatisfactionElems()}; 60 // We must be able to estimate the max satisfaction size for any solvable descriptor (but combo). 61 const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()}; 62 const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems}; 63 assert(is_input_size_info_set || is_nontop_or_nonsolvable); 64 65 auto max_key_expr = desc.GetMaxKeyExpr(); 66 auto key_count = desc.GetKeyCount(); 67 assert((max_key_expr == 0 && key_count == 0) || max_key_expr + 1 == key_count); 68 } 69 70 void initialize_descriptor_parse() 71 { 72 static ECC_Context ecc_context{}; 73 SelectParams(ChainType::MAIN); 74 } 75 76 void initialize_mocked_descriptor_parse() 77 { 78 initialize_descriptor_parse(); 79 MOCKED_DESC_CONVERTER.Init(); 80 } 81 82 FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse) 83 { 84 const std::string mocked_descriptor{buffer.begin(), buffer.end()}; 85 if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) { 86 if (IsTooExpensive(MakeUCharSpan(*descriptor))) return; 87 FlatSigningProvider signing_provider; 88 std::string error; 89 const auto desc = Parse(*descriptor, signing_provider, error); 90 std::optional<bool> is_ranged; 91 std::optional<bool> is_solvable; 92 for (const auto& d : desc) { 93 assert(d); 94 TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable); 95 } 96 } 97 } 98 99 FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse) 100 { 101 if (IsTooExpensive(buffer)) return; 102 103 const std::string descriptor(buffer.begin(), buffer.end()); 104 FlatSigningProvider signing_provider; 105 std::string error; 106 for (const bool require_checksum : {true, false}) { 107 const auto desc = Parse(descriptor, signing_provider, error, require_checksum); 108 std::optional<bool> is_ranged; 109 std::optional<bool> is_solvable; 110 for (const auto& d : desc) { 111 assert(d); 112 TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable); 113 } 114 } 115 }