Line data Source code
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 2 : #include <script/sign.h> 18 2 : #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 2 : #include <algorithm> 28 : #include <cassert> 29 : #include <cstdint> 30 : #include <optional> 31 : #include <string> 32 : #include <vector> 33 : 34 0 : void initialize_script() 35 : { 36 0 : SelectParams(ChainType::REGTEST); 37 0 : } 38 : 39 4 : FUZZ_TARGET(script, .init = initialize_script) 40 : { 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 : TxoutType which_type; 56 0 : bool is_standard_ret = IsStandard(script, std::nullopt, which_type); 57 0 : if (!is_standard_ret) { 58 0 : assert(which_type == TxoutType::NONSTANDARD || 59 : which_type == TxoutType::NULL_DATA || 60 : 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 : which_type == TxoutType::NONSTANDARD); 71 0 : } 72 : 73 0 : CTxDestination address; 74 2 : bool extract_destination_ret = ExtractDestination(script, address); 75 0 : if (!extract_destination_ret) { 76 0 : assert(which_type == TxoutType::PUBKEY || 77 : which_type == TxoutType::NONSTANDARD || 78 : which_type == TxoutType::NULL_DATA || 79 : 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.IsPayToScriptHash(); 98 0 : (void)script.IsPayToWitnessScriptHash(); 99 0 : (void)script.IsPushOnly(); 100 0 : (void)script.GetSigOpCount(/* fAccurate= */ false); 101 : 102 : { 103 0 : const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); 104 0 : CompressedScript compressed_script; 105 0 : compressed_script.assign(bytes.begin(), bytes.end()); 106 : // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short 107 0 : if (compressed_script.size() >= 32) { 108 0 : CScript decompressed_script; 109 0 : DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script); 110 0 : } 111 0 : } 112 : 113 0 : const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider); 114 0 : if (other_script) { 115 : { 116 0 : CScript script_mut{script}; 117 0 : (void)FindAndDelete(script_mut, *other_script); 118 0 : } 119 0 : const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider); 120 0 : const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; 121 0 : const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH}; 122 : { 123 0 : CScriptWitness wit; 124 0 : for (const auto& s : random_string_vector) { 125 0 : wit.stack.emplace_back(s.begin(), s.end()); 126 : } 127 0 : (void)CountWitnessSigOps(script, *other_script, &wit, flags); 128 0 : wit.SetNull(); 129 0 : } 130 0 : } 131 : 132 0 : (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider)); 133 0 : (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT))); 134 : 135 : { 136 0 : const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); 137 0 : CScript append_script{bytes.begin(), bytes.end()}; 138 0 : append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>(); 139 0 : append_script << ConsumeOpcodeType(fuzzed_data_provider); 140 0 : append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()}; 141 0 : append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider); 142 0 : } 143 : 144 : { 145 0 : const CTxDestination tx_destination_1{ 146 0 : fuzzed_data_provider.ConsumeBool() ? 147 0 : DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) : 148 0 : ConsumeTxDestination(fuzzed_data_provider)}; 149 0 : const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)}; 150 0 : const std::string encoded_dest{EncodeDestination(tx_destination_1)}; 151 0 : const UniValue json_dest{DescribeAddress(tx_destination_1)}; 152 0 : (void)GetKeyForDestination(/*store=*/{}, tx_destination_1); 153 0 : const CScript dest{GetScriptForDestination(tx_destination_1)}; 154 0 : const bool valid{IsValidDestination(tx_destination_1)}; 155 : 156 0 : if (!std::get_if<PubKeyDestination>(&tx_destination_1)) { 157 : // Only try to round trip non-pubkey destinations since PubKeyDestination has no encoding 158 0 : Assert(dest.empty() != valid); 159 0 : Assert(tx_destination_1 == DecodeDestination(encoded_dest)); 160 0 : Assert(valid == IsValidDestinationString(encoded_dest)); 161 0 : } 162 : 163 0 : (void)(tx_destination_1 < tx_destination_2); 164 0 : if (tx_destination_1 == tx_destination_2) { 165 0 : Assert(encoded_dest == EncodeDestination(tx_destination_2)); 166 0 : Assert(json_dest.write() == DescribeAddress(tx_destination_2).write()); 167 0 : Assert(dest == GetScriptForDestination(tx_destination_2)); 168 0 : } 169 0 : } 170 0 : }