script.cpp raw
1 // Copyright (c) 2019-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 <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 {
36 SelectParams(ChainType::REGTEST);
37 }
38
39 FUZZ_TARGET(script, .init = initialize_script)
40 {
41 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
42 const CScript script{ConsumeScript(fuzzed_data_provider)};
43
44 CompressedScript compressed;
45 if (CompressScript(script, compressed)) {
46 const unsigned int size = compressed[0];
47 compressed.erase(compressed.begin());
48 assert(size <= 5);
49 CScript decompressed_script;
50 const bool ok = DecompressScript(decompressed_script, size, compressed);
51 assert(ok);
52 assert(script == decompressed_script);
53 }
54
55 TxoutType which_type;
56 bool is_standard_ret = IsStandard(script, which_type);
57 if (!is_standard_ret) {
58 assert(which_type == TxoutType::NONSTANDARD ||
59 which_type == TxoutType::NULL_DATA ||
60 which_type == TxoutType::MULTISIG);
61 }
62 if (which_type == TxoutType::NONSTANDARD) {
63 assert(!is_standard_ret);
64 }
65 if (which_type == TxoutType::NULL_DATA) {
66 assert(script.IsUnspendable());
67 }
68 if (script.IsUnspendable()) {
69 assert(which_type == TxoutType::NULL_DATA ||
70 which_type == TxoutType::NONSTANDARD);
71 }
72
73 CTxDestination address;
74 bool extract_destination_ret = ExtractDestination(script, address);
75 if (!extract_destination_ret) {
76 assert(which_type == TxoutType::PUBKEY ||
77 which_type == TxoutType::NONSTANDARD ||
78 which_type == TxoutType::NULL_DATA ||
79 which_type == TxoutType::MULTISIG);
80 }
81 if (which_type == TxoutType::NONSTANDARD ||
82 which_type == TxoutType::NULL_DATA ||
83 which_type == TxoutType::MULTISIG) {
84 assert(!extract_destination_ret);
85 }
86
87 const FlatSigningProvider signing_provider;
88 (void)InferDescriptor(script, signing_provider);
89 (void)IsSegWitOutput(signing_provider, script);
90
91 (void)RecursiveDynamicUsage(script);
92
93 std::vector<std::vector<unsigned char>> solutions;
94 (void)Solver(script, solutions);
95
96 {
97 const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
98 CompressedScript compressed_script;
99 compressed_script.assign(bytes.begin(), bytes.end());
100 // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short
101 if (compressed_script.size() >= 32) {
102 CScript decompressed_script;
103 DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script);
104 }
105 }
106
107 const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
108 if (other_script) {
109 {
110 CScript script_mut{script};
111 (void)FindAndDelete(script_mut, *other_script);
112 }
113 const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
114 const auto flags_rand{fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>()};
115 const auto flags = script_verify_flags::from_int(flags_rand) | SCRIPT_VERIFY_P2SH;
116 {
117 CScriptWitness wit;
118 for (const auto& s : random_string_vector) {
119 wit.stack.emplace_back(s.begin(), s.end());
120 }
121 (void)CountWitnessSigOps(script, *other_script, wit, flags);
122 wit.SetNull();
123 }
124 }
125
126 (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider));
127 (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT)));
128
129 {
130 const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
131 CScript append_script{bytes.begin(), bytes.end()};
132 append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
133 append_script << ConsumeOpcodeType(fuzzed_data_provider);
134 append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
135 append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
136 }
137
138 {
139 const CTxDestination tx_destination_1{
140 fuzzed_data_provider.ConsumeBool() ?
141 DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) :
142 ConsumeTxDestination(fuzzed_data_provider)};
143 const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)};
144 const std::string encoded_dest{EncodeDestination(tx_destination_1)};
145 const UniValue json_dest{DescribeAddress(tx_destination_1)};
146 (void)GetKeyForDestination(/*store=*/{}, tx_destination_1);
147 const CScript dest{GetScriptForDestination(tx_destination_1)};
148 const bool valid{IsValidDestination(tx_destination_1)};
149
150 if (!std::get_if<PubKeyDestination>(&tx_destination_1)) {
151 // Only try to round trip non-pubkey destinations since PubKeyDestination has no encoding
152 Assert(dest.empty() != valid);
153 Assert(tx_destination_1 == DecodeDestination(encoded_dest));
154 Assert(valid == IsValidDestinationString(encoded_dest));
155 }
156
157 (void)(tx_destination_1 < tx_destination_2);
158 if (tx_destination_1 == tx_destination_2) {
159 Assert(encoded_dest == EncodeDestination(tx_destination_2));
160 Assert(json_dest.write() == DescribeAddress(tx_destination_2).write());
161 Assert(dest == GetScriptForDestination(tx_destination_2));
162 }
163 }
164 }
165