LCOV - code coverage report
Current view: top level - src/test/fuzz - descriptor_parse.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 100.0 % 69 69
Test Date: 2024-12-04 04:00:22 Functions: 100.0 % 7 7
Branches: 68.8 % 96 66

             Branch data     Line data    Source code
       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 <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                 :       10930 : 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                 :       10930 :     (void)desc.IsRange();
      22                 :       10930 :     (void)desc.IsSingleType();
      23                 :       10930 :     (void)desc.GetOutputType();
      24                 :             : 
      25         [ +  + ]:       10930 :     if (is_ranged.has_value()) {
      26         [ -  + ]:        8235 :         assert(desc.IsRange() == *is_ranged);
      27                 :             :     } else {
      28                 :        2695 :         is_ranged = desc.IsRange();
      29                 :             :     }
      30         [ +  + ]:       10930 :     if (is_solvable.has_value()) {
      31         [ -  + ]:        8235 :         assert(desc.IsSolvable() == *is_solvable);
      32                 :             :     } else {
      33                 :        2695 :         is_solvable = desc.IsSolvable();
      34                 :             :     }
      35                 :             : 
      36                 :             :     // Serialization to string representation.
      37                 :       10930 :     (void)desc.ToString();
      38                 :       10930 :     (void)desc.ToPrivateString(sig_provider, dummy);
      39                 :       10930 :     (void)desc.ToNormalizedString(sig_provider, dummy);
      40                 :             : 
      41                 :             :     // Serialization to Script.
      42                 :       10930 :     DescriptorCache cache;
      43                 :       10930 :     std::vector<CScript> out_scripts;
      44         [ +  - ]:       10930 :     (void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache);
      45         [ +  - ]:       10930 :     (void)desc.ExpandPrivate(0, sig_provider, sig_provider);
      46         [ +  - ]:       10930 :     (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         [ +  + ]:       10930 :     if (!out_scripts.empty()) {
      50   [ +  -  -  + ]:       10242 :         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         [ +  - ]:       10242 :         const bool is_combo{!desc.IsSingleType()};
      54   [ +  +  +  +  :       18064 :         assert(is_combo || desc.ScriptSize() == out_scripts.back().size());
                   +  - ]
      55                 :             :     }
      56                 :             : 
      57         [ +  - ]:       10930 :     const auto max_sat_maxsig{desc.MaxSatisfactionWeight(true)};
      58         [ +  - ]:       10930 :     const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)};
      59         [ +  - ]:       10930 :     const auto max_elems{desc.MaxSatisfactionElems()};
      60                 :             :     // We must be able to estimate the max satisfaction size for any solvable descriptor (but combo).
      61   [ +  +  +  -  :       10930 :     const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()};
                   +  + ]
      62   [ +  +  +  -  :       10930 :     const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
                   -  + ]
      63         [ -  + ]:         581 :     assert(is_input_size_info_set || is_nontop_or_nonsolvable);
      64                 :       10930 : }
      65                 :             : 
      66                 :           2 : void initialize_descriptor_parse()
      67                 :             : {
      68   [ +  -  +  -  :           2 :     static ECC_Context ecc_context{};
                   +  - ]
      69                 :           2 :     SelectParams(ChainType::MAIN);
      70                 :           2 : }
      71                 :             : 
      72                 :           1 : void initialize_mocked_descriptor_parse()
      73                 :             : {
      74                 :           1 :     initialize_descriptor_parse();
      75                 :           1 :     MOCKED_DESC_CONVERTER.Init();
      76                 :           1 : }
      77                 :             : 
      78         [ +  - ]:        3453 : FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse)
      79                 :             : {
      80                 :             :     // Key derivation is expensive. Deriving deep derivation paths take a lot of compute and we'd
      81                 :             :     // rather spend time elsewhere in this target, like on the actual descriptor syntax. So rule
      82                 :             :     // out strings which could correspond to a descriptor containing a too large derivation path.
      83         [ +  + ]:        3041 :     if (HasDeepDerivPath(buffer)) return;
      84                 :             : 
      85                 :             :     // Some fragments can take a virtually unlimited number of sub-fragments (thresh, multi_a) but
      86                 :             :     // may perform quadratic operations on them. Limit the number of sub-fragments per fragment.
      87         [ +  + ]:        3040 :     if (HasTooManySubFrag(buffer)) return;
      88                 :             : 
      89                 :             :     // The script building logic performs quadratic copies in the number of nested wrappers. Limit
      90                 :             :     // the number of nested wrappers per fragment.
      91         [ +  + ]:        3038 :     if (HasTooManyWrappers(buffer)) return;
      92                 :             : 
      93         [ +  - ]:        3036 :     const std::string mocked_descriptor{buffer.begin(), buffer.end()};
      94   [ +  -  +  + ]:        3036 :     if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) {
      95                 :        3013 :         FlatSigningProvider signing_provider;
      96         [ +  - ]:        3013 :         std::string error;
      97         [ +  - ]:        3013 :         const auto desc = Parse(*descriptor, signing_provider, error);
      98                 :        3013 :         std::optional<bool> is_ranged;
      99                 :        3013 :         std::optional<bool> is_solvable;
     100         [ +  + ]:       12889 :         for (const auto& d : desc) {
     101         [ -  + ]:        9876 :             assert(d);
     102         [ +  - ]:        9876 :             TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
     103                 :             :         }
     104                 :        6049 :     }
     105                 :        3036 : }
     106                 :             : 
     107         [ +  - ]:        2902 : FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse)
     108                 :             : {
     109                 :             :     // See comments above for rationales.
     110         [ +  + ]:        2490 :     if (HasDeepDerivPath(buffer)) return;
     111         [ +  + ]:        2489 :     if (HasTooManySubFrag(buffer)) return;
     112         [ +  + ]:        2486 :     if (HasTooManyWrappers(buffer)) return;
     113                 :             : 
     114                 :        2483 :     const std::string descriptor(buffer.begin(), buffer.end());
     115                 :        2483 :     FlatSigningProvider signing_provider;
     116                 :        2483 :     std::string error;
     117         [ +  + ]:        7449 :     for (const bool require_checksum : {true, false}) {
     118         [ +  - ]:        4966 :         const auto desc = Parse(descriptor, signing_provider, error, require_checksum);
     119                 :        4966 :         std::optional<bool> is_ranged;
     120                 :        4966 :         std::optional<bool> is_solvable;
     121         [ +  + ]:        6020 :         for (const auto& d : desc) {
     122         [ -  + ]:        1054 :             assert(d);
     123         [ +  - ]:        1054 :             TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
     124                 :             :         }
     125                 :        4966 :     }
     126                 :        2483 : }
        

Generated by: LCOV version 2.0-1