Inside Bitcoin
Opening the selected file…
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.
2001return true;2002} else {2003if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {2004return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);2005}2006// Other version/size/p2sh combinations return true for future softfork compatibility2007return true;2008}2009// There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above.2010}2012bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror)2013{2014static const CScriptWitness emptyWitness;2015if (witness == nullptr) {2016witness = &emptyWitness;2017}2018bool hadWitness = false;2020set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);2022if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {2023return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);2024}2026// scriptSig and scriptPubKey must be evaluated sequentially on the same stack2027// rather than being simply concatenated (see CVE-2010-5141)2028std::vector<std::vector<unsigned char> > stack, stackCopy;2029if (!EvalScript(stack, scriptSig, flags, checker, SigVersion::BASE, serror))2030// serror is set2031return false;2032if (flags & SCRIPT_VERIFY_P2SH)2033stackCopy = stack;2034if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::BASE, serror))2035// serror is set2036return false;2037if (stack.empty())2038return set_error(serror, SCRIPT_ERR_EVAL_FALSE);2039if (CastToBool(stack.back()) == false)2040return set_error(serror, SCRIPT_ERR_EVAL_FALSE);2042// Bare witness programs2043int witnessversion;2044std::vector<unsigned char> witnessprogram;2045if (flags & SCRIPT_VERIFY_WITNESS) {2046if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {2047hadWitness = true;2048if (scriptSig.size() != 0) {2049// The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability.2050return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED);2051}2052if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror, /*is_p2sh=*/false)) {2053return false;2054}2055// Bypass the cleanstack check at the end. The actual stack is obviously not clean2056// for witness programs.2057stack.resize(1);2058}2059}2061// Additional validation for spend-to-script-hash transactions:2062if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())2063{2064// scriptSig must be literals-only or validation fails2065if (!scriptSig.IsPushOnly())2066return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);2068// Restore stack.2069swap(stack, stackCopy);2071// stack cannot be empty here, because if it was the2072// P2SH HASH <> EQUAL scriptPubKey would be evaluated with2073// an empty stack and the EvalScript above would return false.2074assert(!stack.empty());2076const valtype& pubKeySerialized = stack.back();2077CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());2078popstack(stack);2080if (!EvalScript(stack, pubKey2, flags, checker, SigVersion::BASE, serror))2081// serror is set2082return false;2083if (stack.empty())2084return set_error(serror, SCRIPT_ERR_EVAL_FALSE);2085if (!CastToBool(stack.back()))2086return set_error(serror, SCRIPT_ERR_EVAL_FALSE);2088// P2SH witness program2089if (flags & SCRIPT_VERIFY_WITNESS) {2090if (pubKey2.IsWitnessProgram(witnessversion, witnessprogram)) {2091hadWitness = true;2092if (scriptSig != CScript() << std::vector<unsigned char>(pubKey2.begin(), pubKey2.end())) {2093// The scriptSig must be _exactly_ a single push of the redeemScript. Otherwise we2094// reintroduce malleability.2095return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED_P2SH);2096}2097if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror, /*is_p2sh=*/true)) {2098return false;2099}2100// Bypass the cleanstack check at the end. The actual stack is obviously not clean2101// for witness programs.2102stack.resize(1);2103}2104}2105}2107// The CLEANSTACK check is only performed after potential P2SH evaluation,2108// as the non-P2SH evaluation of a P2SH script will obviously not result in2109// a clean stack (the P2SH inputs remain). The same holds for witness evaluation.2110if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) {2111// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK2112// would be possible, which is not a softfork (and P2SH should be one).2113assert((flags & SCRIPT_VERIFY_P2SH) != 0);2114assert((flags & SCRIPT_VERIFY_WITNESS) != 0);2115if (stack.size() != 1) {2116return set_error(serror, SCRIPT_ERR_CLEANSTACK);2117}2118}2120if (flags & SCRIPT_VERIFY_WITNESS) {2121// We can't check for correct unexpected witness data if P2SH was off, so require2122// that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be2123// possible, which is not a softfork.2124assert((flags & SCRIPT_VERIFY_P2SH) != 0);2125if (!hadWitness && !witness->IsNull()) {2126return set_error(serror, SCRIPT_ERR_WITNESS_UNEXPECTED);2127}2128}2130return set_success(serror);2131}2133size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& witprogram, const CScriptWitness& witness)2134{2135if (witversion == 0) {2136if (witprogram.size() == WITNESS_V0_KEYHASH_SIZE)2137return 1;2139if (witprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE && witness.stack.size() > 0) {2140CScript subscript(witness.stack.back().begin(), witness.stack.back().end());2141return subscript.GetSigOpCount(true);2142}2143}2145// Future flags may be implemented here.2146return 0;2147}2149size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness& witness, script_verify_flags flags)2150{2151if ((flags & SCRIPT_VERIFY_WITNESS) == 0) {2152return 0;2153}2154assert((flags & SCRIPT_VERIFY_P2SH) != 0);2156int witnessversion;2157std::vector<unsigned char> witnessprogram;2158if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {2159return WitnessSigOps(witnessversion, witnessprogram, witness);2160}2162if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) {2163CScript::const_iterator pc = scriptSig.begin();2164std::vector<unsigned char> data;2165while (pc < scriptSig.end()) {2166opcodetype opcode;2167scriptSig.GetOp(pc, opcode, data);2168}2169CScript subscript(data.begin(), data.end());2170if (subscript.IsWitnessProgram(witnessversion, witnessprogram)) {2171return WitnessSigOps(witnessversion, witnessprogram, witness);2172}2173}2175return 0;2176}2178const std::map<std::string, script_verify_flag_name>& ScriptFlagNamesToEnum()2179{2180#define FLAG_NAME(flag) {std::string(#flag), SCRIPT_VERIFY_##flag}2181static const std::map<std::string, script_verify_flag_name> g_names_to_enum{2182FLAG_NAME(P2SH),2183FLAG_NAME(STRICTENC),2184FLAG_NAME(DERSIG),2185FLAG_NAME(LOW_S),2186FLAG_NAME(SIGPUSHONLY),2187FLAG_NAME(MINIMALDATA),2188FLAG_NAME(NULLDUMMY),2189FLAG_NAME(DISCOURAGE_UPGRADABLE_NOPS),2190FLAG_NAME(CLEANSTACK),2191FLAG_NAME(MINIMALIF),2192FLAG_NAME(NULLFAIL),2193FLAG_NAME(CHECKLOCKTIMEVERIFY),2194FLAG_NAME(CHECKSEQUENCEVERIFY),2195FLAG_NAME(WITNESS),2196FLAG_NAME(DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM),2197FLAG_NAME(WITNESS_PUBKEYTYPE),2198FLAG_NAME(CONST_SCRIPTCODE),2199FLAG_NAME(TAPROOT),2200FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE),2201FLAG_NAME(DISCOURAGE_OP_SUCCESS),2202FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION),2203};2204#undef FLAG_NAME2205return g_names_to_enum;2206}2208std::vector<std::string> GetScriptFlagNames(script_verify_flags flags)2209{2210std::vector<std::string> res;2211if (flags == SCRIPT_VERIFY_NONE) {2212return res;2213}2214script_verify_flags leftover = flags;2215for (const auto& [name, flag] : ScriptFlagNamesToEnum()) {2216if ((flags & flag) != 0) {2217res.push_back(name);2218leftover &= ~flag;2219}2220}2221if (leftover != 0) {2222res.push_back(strprintf("0x%08x", leftover.as_int()));2223}2224return res;2225}