script_flags.cpp
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 }