Coverage Report

Created: 2025-09-19 18:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/test/fuzz/script.cpp
Line
Count
Source
1
// Copyright (c) 2019-2022 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 <compressor.h>
7
#include <core_io.h>
8
#include <core_memusage.h>
9
#include <key_io.h>
10
#include <policy/policy.h>
11
#include <pubkey.h>
12
#include <rpc/util.h>
13
#include <script/descriptor.h>
14
#include <script/interpreter.h>
15
#include <script/script.h>
16
#include <script/script_error.h>
17
#include <script/sign.h>
18
#include <script/signingprovider.h>
19
#include <script/solver.h>
20
#include <streams.h>
21
#include <test/fuzz/FuzzedDataProvider.h>
22
#include <test/fuzz/fuzz.h>
23
#include <test/fuzz/util.h>
24
#include <univalue.h>
25
#include <util/chaintype.h>
26
27
#include <algorithm>
28
#include <cassert>
29
#include <cstdint>
30
#include <optional>
31
#include <string>
32
#include <vector>
33
34
void initialize_script()
35
0
{
36
0
    SelectParams(ChainType::REGTEST);
37
0
}
38
39
FUZZ_TARGET(script, .init = initialize_script)
40
0
{
41
0
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
42
0
    const CScript script{ConsumeScript(fuzzed_data_provider)};
43
44
0
    CompressedScript compressed;
45
0
    if (CompressScript(script, compressed)) {
46
0
        const unsigned int size = compressed[0];
47
0
        compressed.erase(compressed.begin());
48
0
        assert(size <= 5);
49
0
        CScript decompressed_script;
50
0
        const bool ok = DecompressScript(decompressed_script, size, compressed);
51
0
        assert(ok);
52
0
        assert(script == decompressed_script);
53
0
    }
54
55
0
    TxoutType which_type;
56
0
    bool is_standard_ret = IsStandard(script, which_type);
57
0
    if (!is_standard_ret) {
58
0
        assert(which_type == TxoutType::NONSTANDARD ||
59
0
               which_type == TxoutType::NULL_DATA ||
60
0
               which_type == TxoutType::MULTISIG);
61
0
    }
62
0
    if (which_type == TxoutType::NONSTANDARD) {
63
0
        assert(!is_standard_ret);
64
0
    }
65
0
    if (which_type == TxoutType::NULL_DATA) {
66
0
        assert(script.IsUnspendable());
67
0
    }
68
0
    if (script.IsUnspendable()) {
69
0
        assert(which_type == TxoutType::NULL_DATA ||
70
0
               which_type == TxoutType::NONSTANDARD);
71
0
    }
72
73
0
    CTxDestination address;
74
0
    bool extract_destination_ret = ExtractDestination(script, address);
75
0
    if (!extract_destination_ret) {
76
0
        assert(which_type == TxoutType::PUBKEY ||
77
0
               which_type == TxoutType::NONSTANDARD ||
78
0
               which_type == TxoutType::NULL_DATA ||
79
0
               which_type == TxoutType::MULTISIG);
80
0
    }
81
0
    if (which_type == TxoutType::NONSTANDARD ||
82
0
        which_type == TxoutType::NULL_DATA ||
83
0
        which_type == TxoutType::MULTISIG) {
84
0
        assert(!extract_destination_ret);
85
0
    }
86
87
0
    const FlatSigningProvider signing_provider;
88
0
    (void)InferDescriptor(script, signing_provider);
89
0
    (void)IsSegWitOutput(signing_provider, script);
90
91
0
    (void)RecursiveDynamicUsage(script);
92
93
0
    std::vector<std::vector<unsigned char>> solutions;
94
0
    (void)Solver(script, solutions);
95
96
0
    (void)script.HasValidOps();
97
0
    (void)script.IsPayToAnchor();
98
0
    (void)script.IsPayToScriptHash();
99
0
    (void)script.IsPayToWitnessScriptHash();
100
0
    (void)script.IsPushOnly();
101
0
    (void)script.GetSigOpCount(/* fAccurate= */ false);
102
103
0
    {
104
0
        const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
105
0
        CompressedScript compressed_script;
106
0
        compressed_script.assign(bytes.begin(), bytes.end());
107
        // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short
108
0
        if (compressed_script.size() >= 32) {
109
0
            CScript decompressed_script;
110
0
            DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script);
111
0
        }
112
0
    }
113
114
0
    const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
115
0
    if (other_script) {
116
0
        {
117
0
            CScript script_mut{script};
118
0
            (void)FindAndDelete(script_mut, *other_script);
119
0
        }
120
0
        const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
121
0
        const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
122
0
        const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
123
0
        {
124
0
            CScriptWitness wit;
125
0
            for (const auto& s : random_string_vector) {
126
0
                wit.stack.emplace_back(s.begin(), s.end());
127
0
            }
128
0
            (void)CountWitnessSigOps(script, *other_script, &wit, flags);
129
0
            wit.SetNull();
130
0
        }
131
0
    }
132
133
0
    (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider));
134
0
    (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT)));
135
136
0
    {
137
0
        const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
138
0
        CScript append_script{bytes.begin(), bytes.end()};
139
0
        append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
140
0
        append_script << ConsumeOpcodeType(fuzzed_data_provider);
141
0
        append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
142
0
        append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
143
0
    }
144
145
0
    {
146
0
        const CTxDestination tx_destination_1{
147
0
            fuzzed_data_provider.ConsumeBool() ?
148
0
                DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) :
149
0
                ConsumeTxDestination(fuzzed_data_provider)};
150
0
        const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)};
151
0
        const std::string encoded_dest{EncodeDestination(tx_destination_1)};
152
0
        const UniValue json_dest{DescribeAddress(tx_destination_1)};
153
0
        (void)GetKeyForDestination(/*store=*/{}, tx_destination_1);
154
0
        const CScript dest{GetScriptForDestination(tx_destination_1)};
155
0
        const bool valid{IsValidDestination(tx_destination_1)};
156
157
0
        if (!std::get_if<PubKeyDestination>(&tx_destination_1)) {
158
            // Only try to round trip non-pubkey destinations since PubKeyDestination has no encoding
159
0
            Assert(dest.empty() != valid);
160
0
            Assert(tx_destination_1 == DecodeDestination(encoded_dest));
161
0
            Assert(valid == IsValidDestinationString(encoded_dest));
162
0
        }
163
164
0
        (void)(tx_destination_1 < tx_destination_2);
165
0
        if (tx_destination_1 == tx_destination_2) {
166
0
            Assert(encoded_dest == EncodeDestination(tx_destination_2));
167
0
            Assert(json_dest.write() == DescribeAddress(tx_destination_2).write());
168
0
            Assert(dest == GetScriptForDestination(tx_destination_2));
169
0
        }
170
0
    }
171
0
}