script.cpp
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 (void)script.HasValidOps(); 97 (void)script.IsPayToAnchor(); 98 (void)script.IsPayToScriptHash(); 99 (void)script.IsPayToWitnessScriptHash(); 100 (void)script.IsPushOnly(); 101 (void)script.GetSigOpCount(/* fAccurate= */ false); 102 103 { 104 const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); 105 CompressedScript compressed_script; 106 compressed_script.assign(bytes.begin(), bytes.end()); 107 // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short 108 if (compressed_script.size() >= 32) { 109 CScript decompressed_script; 110 DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script); 111 } 112 } 113 114 const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider); 115 if (other_script) { 116 { 117 CScript script_mut{script}; 118 (void)FindAndDelete(script_mut, *other_script); 119 } 120 const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider); 121 const auto flags_rand{fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>()}; 122 const auto flags = script_verify_flags::from_int(flags_rand) | SCRIPT_VERIFY_P2SH; 123 { 124 CScriptWitness wit; 125 for (const auto& s : random_string_vector) { 126 wit.stack.emplace_back(s.begin(), s.end()); 127 } 128 (void)CountWitnessSigOps(script, *other_script, wit, flags); 129 wit.SetNull(); 130 } 131 } 132 133 (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider)); 134 (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT))); 135 136 { 137 const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); 138 CScript append_script{bytes.begin(), bytes.end()}; 139 append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>(); 140 append_script << ConsumeOpcodeType(fuzzed_data_provider); 141 append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()}; 142 append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider); 143 } 144 145 { 146 const CTxDestination tx_destination_1{ 147 fuzzed_data_provider.ConsumeBool() ? 148 DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) : 149 ConsumeTxDestination(fuzzed_data_provider)}; 150 const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)}; 151 const std::string encoded_dest{EncodeDestination(tx_destination_1)}; 152 const UniValue json_dest{DescribeAddress(tx_destination_1)}; 153 (void)GetKeyForDestination(/*store=*/{}, tx_destination_1); 154 const CScript dest{GetScriptForDestination(tx_destination_1)}; 155 const bool valid{IsValidDestination(tx_destination_1)}; 156 157 if (!std::get_if<PubKeyDestination>(&tx_destination_1)) { 158 // Only try to round trip non-pubkey destinations since PubKeyDestination has no encoding 159 Assert(dest.empty() != valid); 160 Assert(tx_destination_1 == DecodeDestination(encoded_dest)); 161 Assert(valid == IsValidDestinationString(encoded_dest)); 162 } 163 164 (void)(tx_destination_1 < tx_destination_2); 165 if (tx_destination_1 == tx_destination_2) { 166 Assert(encoded_dest == EncodeDestination(tx_destination_2)); 167 Assert(json_dest.write() == DescribeAddress(tx_destination_2).write()); 168 Assert(dest == GetScriptForDestination(tx_destination_2)); 169 } 170 } 171 }