Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <test/data/tx_invalid.json.h>6#include <test/data/tx_valid.json.h>7#include <test/util/setup_common.h>9#include <chain.h>10#include <checkqueue.h>11#include <clientversion.h>12#include <consensus/amount.h>13#include <consensus/consensus.h>14#include <consensus/tx_check.h>15#include <consensus/tx_verify.h>16#include <consensus/validation.h>17#include <core_io.h>18#include <key.h>19#include <policy/policy.h>20#include <policy/settings.h>21#include <primitives/transaction_identifier.h>22#include <script/interpreter.h>23#include <script/script.h>24#include <script/script_error.h>25#include <script/sigcache.h>26#include <script/sign.h>27#include <script/signingprovider.h>28#include <script/solver.h>29#include <streams.h>30#include <test/util/common.h>31#include <test/util/json.h>32#include <test/util/random.h>33#include <test/util/script.h>34#include <test/util/transaction_utils.h>35#include <util/strencodings.h>36#include <util/string.h>37#include <validation.h>39#include <functional>40#include <map>41#include <string>43#include <boost/test/unit_test.hpp>45#include <univalue.h>47using namespace util::hex_literals;48using util::SplitString;49using util::ToString;51typedef std::vector<unsigned char> valtype;53static CFeeRate g_dust{DUST_RELAY_TX_FEE};54static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};56static const std::map<std::string, script_verify_flag_name>& mapFlagNames = ScriptFlagNamesToEnum();58script_verify_flags ParseScriptFlags(std::string strFlags)59{60script_verify_flags flags = SCRIPT_VERIFY_NONE;61if (strFlags.empty() || strFlags == "NONE") return flags;63std::vector<std::string> words = SplitString(strFlags, ',');64for (const std::string& word : words)65{66if (!mapFlagNames.contains(word)) {67BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");68continue;69}70flags |= mapFlagNames.at(word);71}72return flags;73}75// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames.76bool CheckMapFlagNames()77{78script_verify_flags standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};79for (const auto& pair : mapFlagNames) {80standard_flags_missing &= ~(pair.second);81}82return standard_flags_missing == 0;83}85/*86* Check that the input scripts of a transaction are valid/invalid as expected.87*/88bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>& map_prevout_scriptPubKeys,89const std::map<COutPoint, int64_t>& map_prevout_values, script_verify_flags flags,90const PrecomputedTransactionData& txdata, const std::string& strTest, bool expect_valid)91{92bool tx_valid = true;93ScriptError err = expect_valid ? SCRIPT_ERR_UNKNOWN_ERROR : SCRIPT_ERR_OK;94for (unsigned int i = 0; i < tx.vin.size() && tx_valid; ++i) {95const CTxIn input = tx.vin[i];96const CAmount amount = map_prevout_values.contains(input.prevout) ? map_prevout_values.at(input.prevout) : 0;97try {98tx_valid = VerifyScript(input.scriptSig, map_prevout_scriptPubKeys.at(input.prevout),99&input.scriptWitness, flags, TransactionSignatureChecker(&tx, i, amount, txdata, MissingDataBehavior::ASSERT_FAIL), &err);100} catch (...) {101BOOST_ERROR("Bad test: " << strTest);102return true; // The test format is bad and an error is thrown. Return true to silence further error.103}104if (expect_valid) {105BOOST_CHECK_MESSAGE(tx_valid, strTest);106BOOST_CHECK_MESSAGE((err == SCRIPT_ERR_OK), ScriptErrorString(err));107err = SCRIPT_ERR_UNKNOWN_ERROR;108}109}110if (!expect_valid) {111BOOST_CHECK_MESSAGE(!tx_valid, strTest);112BOOST_CHECK_MESSAGE((err != SCRIPT_ERR_OK), ScriptErrorString(err));113}114return (tx_valid == expect_valid);115}117/*118* Trim or fill flags to make the combination valid:119* WITNESS must be used with P2SH120* CLEANSTACK must be used WITNESS and P2SH121*/123script_verify_flags TrimFlags(script_verify_flags flags)124{125// WITNESS requires P2SH126if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~SCRIPT_VERIFY_WITNESS;128// CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH)129if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~SCRIPT_VERIFY_CLEANSTACK;130Assert(IsValidFlagCombination(flags));131return flags;132}134script_verify_flags FillFlags(script_verify_flags flags)135{136// CLEANSTACK implies WITNESS137if (flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_WITNESS;139// WITNESS implies P2SH (and transitively CLEANSTACK implies P2SH)140if (flags & SCRIPT_VERIFY_WITNESS) flags |= SCRIPT_VERIFY_P2SH;141Assert(IsValidFlagCombination(flags));142return flags;143}145// Exclude each possible script verify flag from flags. Returns a set of these flag combinations146// that are valid and without duplicates. For example: if flags=1111 and the 4 possible flags are147// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}.148// Assumes that mapFlagNames contains all script verify flags.149std::set<script_verify_flags> ExcludeIndividualFlags(script_verify_flags flags)150{151std::set<script_verify_flags> flags_combos;152for (const auto& pair : mapFlagNames) {153script_verify_flags flags_excluding_one = TrimFlags(flags & ~(pair.second));154if (flags != flags_excluding_one) {155flags_combos.insert(flags_excluding_one);156}157}158return flags_combos;159}161BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup)163BOOST_AUTO_TEST_CASE(tx_valid)164{165BOOST_CHECK_MESSAGE(CheckMapFlagNames(), "mapFlagNames is missing a script verification flag");166// Read tests from test/data/tx_valid.json167UniValue tests = read_json(json_tests::tx_valid);169for (unsigned int idx = 0; idx < tests.size(); idx++) {170const UniValue& test = tests[idx];171std::string strTest = test.write();172if (test[0].isArray())173{174if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())175{176BOOST_ERROR("Bad test: " << strTest);177continue;178}180std::map<COutPoint, CScript> mapprevOutScriptPubKeys;181std::map<COutPoint, int64_t> mapprevOutValues;182UniValue inputs = test[0].get_array();183bool fValid = true;184for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {185const UniValue& input = inputs[inpIdx];186if (!input.isArray()) {187fValid = false;188break;189}190const UniValue& vinput = input.get_array();191if (vinput.size() < 3 || vinput.size() > 4)192{193fValid = false;194break;195}196COutPoint outpoint{Txid::FromHex(vinput[0].get_str()).value(), uint32_t(vinput[1].getInt<int>())};197mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str());198if (vinput.size() >= 4)199{200mapprevOutValues[outpoint] = vinput[3].getInt<int64_t>();201}202}203if (!fValid)204{205BOOST_ERROR("Bad test: " << strTest);206continue;207}209std::string transaction = test[1].get_str();210DataStream stream(ParseHex(transaction));211CTransaction tx(deserialize, TX_WITH_WITNESS, stream);213TxValidationState state;214BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);215BOOST_CHECK(state.IsValid());217PrecomputedTransactionData txdata(tx);218script_verify_flags verify_flags = ParseScriptFlags(test[2].get_str());220// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.221if (~verify_flags != FillFlags(~verify_flags)) {222BOOST_ERROR("Bad test flags: " << strTest);223}225BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~verify_flags, txdata, strTest, /*expect_valid=*/true),226"Tx unexpectedly failed: " << strTest);228// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction229for (const auto& [name, flag] : mapFlagNames) {230// Removing individual flags231script_verify_flags flags = TrimFlags(~(verify_flags | flag));232if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {233BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);234}235// Removing random combinations of flags236flags = TrimFlags(~(verify_flags | script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS))));237if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {238BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags.as_int()) << ": " << strTest);239}240}242// Check that flags are maximal: transaction should fail if any unset flags are set.243for (auto flags_excluding_one : ExcludeIndividualFlags(verify_flags)) {244if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~flags_excluding_one, txdata, strTest, /*expect_valid=*/false)) {245BOOST_ERROR("Too many flags unset: " << strTest);246}247}248}249}250}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.