Coverage Report

Created: 2026-08-25 19:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}