Branch data 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 : }