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