From c8e24ddce31a8de6255b23c19d958c1cd44a8847 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 6 Oct 2019 12:13:20 -0700 Subject: [REFACTOR] Abstract out script execution out of VerifyWitnessProgram() This removes the unclear reliance on "falling through" to get to the script execution part. Also fix some code style issues. --- src/script/interpreter.cpp | 48 ++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 23 deletions(-) (limited to 'src/script/interpreter.cpp') diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index d0865d2793..e4e86031e6 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1414,9 +1414,26 @@ bool GenericTransactionSignatureChecker::CheckSequence(const CScriptNum& nSeq template class GenericTransactionSignatureChecker; template class GenericTransactionSignatureChecker; +static bool ExecuteWitnessScript(std::vector::const_iterator begin, std::vector::const_iterator end, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror) +{ + std::vector stack{begin, end}; + + // Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack + for (const valtype& elem : stack) { + if (elem.size() > MAX_SCRIPT_ELEMENT_SIZE) return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + } + + // Run the script interpreter. + if (!EvalScript(stack, scriptPubKey, flags, checker, sigversion, serror)) return false; + + // Scripts inside witness implicitly require cleanstack behaviour + if (stack.size() != 1) return set_error(serror, SCRIPT_ERR_CLEANSTACK); + if (!CastToBool(stack.back())) return set_error(serror, SCRIPT_ERR_EVAL_FALSE); + return true; +} + static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { - std::vector > stack; CScript scriptPubKey; if (witversion == 0) { @@ -1426,45 +1443,30 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY); } scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end()); - stack = std::vector >(witness.stack.begin(), witness.stack.end() - 1); uint256 hashScriptPubKey; CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin()); if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); } + return ExecuteWitnessScript(witness.stack.begin(), witness.stack.end() - 1, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror); } else if (program.size() == WITNESS_V0_KEYHASH_SIZE) { // Special case for pay-to-pubkeyhash; signature + pubkey in witness if (witness.stack.size() != 2) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness } scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG; - stack = witness.stack; + return ExecuteWitnessScript(witness.stack.begin(), witness.stack.end(), scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror); } else { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH); } - } else if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { - return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); } else { + if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); + } // Higher version witness scripts return true for future softfork compatibility - return set_success(serror); - } - - // Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack - for (unsigned int i = 0; i < stack.size(); i++) { - if (stack.at(i).size() > MAX_SCRIPT_ELEMENT_SIZE) - return set_error(serror, SCRIPT_ERR_PUSH_SIZE); - } - - if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::WITNESS_V0, serror)) { - return false; + return true; } - - // Scripts inside witness implicitly require cleanstack behaviour - if (stack.size() != 1) - return set_error(serror, SCRIPT_ERR_CLEANSTACK); - if (!CastToBool(stack.back())) - return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - return true; + // 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. } bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) -- cgit v1.2.3