/ src / test / fuzz / script_flags.cpp
script_flags.cpp
 1  // Copyright (c) 2009-2021 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  FUZZ_TARGET(script_flags)
19  {
20      if (buffer.size() > 100'000) return;
21      DataStream ds{buffer};
22      try {
23          const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
24  
25          unsigned int verify_flags;
26          ds >> verify_flags;
27  
28          if (!IsValidFlagCombination(verify_flags)) return;
29  
30          unsigned int fuzzed_flags;
31          ds >> fuzzed_flags;
32  
33          std::vector<CTxOut> spent_outputs;
34          for (unsigned i = 0; i < tx.vin.size(); ++i) {
35              CTxOut prevout;
36              ds >> prevout;
37              if (!MoneyRange(prevout.nValue)) {
38                  // prevouts should be consensus-valid
39                  prevout.nValue = 1;
40              }
41              spent_outputs.push_back(prevout);
42          }
43          PrecomputedTransactionData txdata;
44          txdata.Init(tx, std::move(spent_outputs));
45  
46          for (unsigned i = 0; i < tx.vin.size(); ++i) {
47              const CTxOut& prevout = txdata.m_spent_outputs.at(i);
48              const TransactionSignatureChecker checker{&tx, i, prevout.nValue, txdata, MissingDataBehavior::ASSERT_FAIL};
49  
50              ScriptError serror;
51              const bool ret = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror);
52              assert(ret == (serror == SCRIPT_ERR_OK));
53  
54              // Verify that removing flags from a passing test or adding flags to a failing test does not change the result
55              if (ret) {
56                  verify_flags &= ~fuzzed_flags;
57              } else {
58                  verify_flags |= fuzzed_flags;
59              }
60              if (!IsValidFlagCombination(verify_flags)) return;
61  
62              ScriptError serror_fuzzed;
63              const bool ret_fuzzed = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror_fuzzed);
64              assert(ret_fuzzed == (serror_fuzzed == SCRIPT_ERR_OK));
65  
66              assert(ret_fuzzed == ret);
67          }
68      } catch (const std::ios_base::failure&) {
69          return;
70      }
71  }