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