Skip to content

Commit c8e24dd

Browse files
committed
[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.
1 parent 2bdc476 commit c8e24dd

File tree

1 file changed

+25
-23
lines changed

1 file changed

+25
-23
lines changed

src/script/interpreter.cpp

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,9 +1414,26 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
14141414
template class GenericTransactionSignatureChecker<CTransaction>;
14151415
template class GenericTransactionSignatureChecker<CMutableTransaction>;
14161416

1417+
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)
1418+
{
1419+
std::vector<valtype> stack{begin, end};
1420+
1421+
// Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
1422+
for (const valtype& elem : stack) {
1423+
if (elem.size() > MAX_SCRIPT_ELEMENT_SIZE) return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
1424+
}
1425+
1426+
// Run the script interpreter.
1427+
if (!EvalScript(stack, scriptPubKey, flags, checker, sigversion, serror)) return false;
1428+
1429+
// Scripts inside witness implicitly require cleanstack behaviour
1430+
if (stack.size() != 1) return set_error(serror, SCRIPT_ERR_CLEANSTACK);
1431+
if (!CastToBool(stack.back())) return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
1432+
return true;
1433+
}
1434+
14171435
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
14181436
{
1419-
std::vector<std::vector<unsigned char> > stack;
14201437
CScript scriptPubKey;
14211438

14221439
if (witversion == 0) {
@@ -1426,45 +1443,30 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
14261443
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
14271444
}
14281445
scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end());
1429-
stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 1);
14301446
uint256 hashScriptPubKey;
14311447
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
14321448
if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) {
14331449
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
14341450
}
1451+
return ExecuteWitnessScript(witness.stack.begin(), witness.stack.end() - 1, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
14351452
} else if (program.size() == WITNESS_V0_KEYHASH_SIZE) {
14361453
// Special case for pay-to-pubkeyhash; signature + pubkey in witness
14371454
if (witness.stack.size() != 2) {
14381455
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
14391456
}
14401457
scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG;
1441-
stack = witness.stack;
1458+
return ExecuteWitnessScript(witness.stack.begin(), witness.stack.end(), scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
14421459
} else {
14431460
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
14441461
}
1445-
} else if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
1446-
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
14471462
} else {
1463+
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
1464+
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
1465+
}
14481466
// Higher version witness scripts return true for future softfork compatibility
1449-
return set_success(serror);
1450-
}
1451-
1452-
// Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
1453-
for (unsigned int i = 0; i < stack.size(); i++) {
1454-
if (stack.at(i).size() > MAX_SCRIPT_ELEMENT_SIZE)
1455-
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
1456-
}
1457-
1458-
if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::WITNESS_V0, serror)) {
1459-
return false;
1467+
return true;
14601468
}
1461-
1462-
// Scripts inside witness implicitly require cleanstack behaviour
1463-
if (stack.size() != 1)
1464-
return set_error(serror, SCRIPT_ERR_CLEANSTACK);
1465-
if (!CastToBool(stack.back()))
1466-
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
1467-
return true;
1469+
// 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.
14681470
}
14691471

14701472
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)

0 commit comments

Comments
 (0)