aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2019-10-06 12:13:20 -0700
committerPieter Wuille <pieter.wuille@gmail.com>2020-02-12 11:20:38 -0800
commitc8e24ddce31a8de6255b23c19d958c1cd44a8847 (patch)
tree5c60d7e0fe185c91cdfc08c6ae9a3a34ca56dba4
parent2bdc476d4d23256d8396bb9051a511f540d87392 (diff)
[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.
-rw-r--r--src/script/interpreter.cpp48
1 files changed, 25 insertions, 23 deletions
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<T>::CheckSequence(const CScriptNum& nSeq
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
+static bool ExecuteWitnessScript(std::vector<valtype>::const_iterator begin, std::vector<valtype>::const_iterator end, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror)
+{
+ std::vector<valtype> 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<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
- std::vector<std::vector<unsigned char> > 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<std::vector<unsigned char> >(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)