script_flags.cpp raw

   1  // Copyright (c) 2009-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 <consensus/amount.h>
   6  #include <primitives/transaction.h>
   7  #include <script/interpreter.h>
   8  #include <serialize.h>
   9  #include <streams.h>
  10  #include <test/fuzz/fuzz.h>
  11  #include <test/util/script.h>
  12  
  13  #include <cassert>
  14  #include <ios>
  15  #include <utility>
  16  #include <vector>
  17  
  18  static SpanReader& operator>>(SpanReader& ds, script_verify_flags& f)
  19  {
  20      script_verify_flags::value_type n{0};
  21      ds >> n;
  22      f = script_verify_flags::from_int(n);
  23      assert(n == f.as_int());
  24      return ds;
  25  }
  26  
  27  FUZZ_TARGET(script_flags)
  28  {
  29      if (buffer.size() > 100'000) return;
  30      SpanReader ds{buffer};
  31      try {
  32          const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
  33  
  34          script_verify_flags verify_flags;
  35          ds >> verify_flags;
  36  
  37          assert(verify_flags == script_verify_flags::from_int(verify_flags.as_int()));
  38  
  39          if (!IsValidFlagCombination(verify_flags)) return;
  40  
  41          script_verify_flags fuzzed_flags;
  42          ds >> fuzzed_flags;
  43  
  44          std::vector<CTxOut> spent_outputs;
  45          for (unsigned i = 0; i < tx.vin.size(); ++i) {
  46              CTxOut prevout;
  47              ds >> prevout;
  48              if (!MoneyRange(prevout.nValue)) {
  49                  // prevouts should be consensus-valid
  50                  prevout.nValue = 1;
  51              }
  52              spent_outputs.push_back(prevout);
  53          }
  54          PrecomputedTransactionData txdata;
  55          txdata.Init(tx, std::move(spent_outputs));
  56  
  57          for (unsigned i = 0; i < tx.vin.size(); ++i) {
  58              const CTxOut& prevout = txdata.m_spent_outputs.at(i);
  59              const TransactionSignatureChecker checker{&tx, i, prevout.nValue, txdata, MissingDataBehavior::ASSERT_FAIL};
  60  
  61              ScriptError serror;
  62              const bool ret = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror);
  63              assert(ret == (serror == SCRIPT_ERR_OK));
  64  
  65              // Verify that removing flags from a passing test or adding flags to a failing test does not change the result
  66              if (ret) {
  67                  verify_flags &= ~fuzzed_flags;
  68              } else {
  69                  verify_flags |= fuzzed_flags;
  70              }
  71              if (!IsValidFlagCombination(verify_flags)) return;
  72  
  73              ScriptError serror_fuzzed;
  74              const bool ret_fuzzed = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror_fuzzed);
  75              assert(ret_fuzzed == (serror_fuzzed == SCRIPT_ERR_OK));
  76  
  77              assert(ret_fuzzed == ret);
  78          }
  79      } catch (const std::ios_base::failure&) {
  80          return;
  81      }
  82  }
  83