mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-06 14:19:59 -05:00
Merge #18002: Abstract out script execution out of VerifyWitnessProgram()
c8e24ddce3
[REFACTOR] Abstract out script execution out of VerifyWitnessProgram() (Pieter Wuille) Pull request description: This is a refactoring cherry-picked out of #17977. As it touches consensus code, I don't think this would ordinarily meet the bar for review cost vs benefit. However, it simplifies the changes for Taproot significantly, and if it's going to be necessitated by inclusion of that code, I may as well give it some additional attention by PRing it independently. ACKs for top commit: fjahr: Re-ACKc8e24ddce3
theStack: re-ACKc8e24ddce3
Empact: Code Review Re-ACKc8e24ddce3
ajtowns: ACKc8e24ddce3
jnewbery: ACKc8e24ddce3
jonatack: ACKc8e24dd
Tree-SHA512: 96c2aa5d2f9c7c802bcc008f5cde55b1dfedfaf42e34101331e6c0d594acdf6437661102dc939718f0877c20451336855dfbaa8aa8f57d9e722a7fa7329e3a46
This commit is contained in:
commit
e5cb0dffd5
1 changed files with 25 additions and 23 deletions
|
@ -1414,9 +1414,26 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
|
||||||
template class GenericTransactionSignatureChecker<CTransaction>;
|
template class GenericTransactionSignatureChecker<CTransaction>;
|
||||||
template class GenericTransactionSignatureChecker<CMutableTransaction>;
|
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)
|
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;
|
CScript scriptPubKey;
|
||||||
|
|
||||||
if (witversion == 0) {
|
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);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
|
||||||
}
|
}
|
||||||
scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end());
|
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;
|
uint256 hashScriptPubKey;
|
||||||
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
|
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
|
||||||
if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) {
|
if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) {
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
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) {
|
} else if (program.size() == WITNESS_V0_KEYHASH_SIZE) {
|
||||||
// Special case for pay-to-pubkeyhash; signature + pubkey in witness
|
// Special case for pay-to-pubkeyhash; signature + pubkey in witness
|
||||||
if (witness.stack.size() != 2) {
|
if (witness.stack.size() != 2) {
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
|
||||||
}
|
}
|
||||||
scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG;
|
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 {
|
} else {
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
|
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 {
|
} 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
|
// Higher version witness scripts return true for future softfork compatibility
|
||||||
return set_success(serror);
|
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.
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
||||||
|
|
Loading…
Add table
Reference in a new issue