0
0
Fork 0
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-ACK c8e24ddce3
  theStack:
    re-ACK c8e24ddce3
  Empact:
    Code Review Re-ACK c8e24ddce3
  ajtowns:
    ACK c8e24ddce3
  jnewbery:
    ACK c8e24ddce3
  jonatack:
    ACK c8e24dd

Tree-SHA512: 96c2aa5d2f9c7c802bcc008f5cde55b1dfedfaf42e34101331e6c0d594acdf6437661102dc939718f0877c20451336855dfbaa8aa8f57d9e722a7fa7329e3a46
This commit is contained in:
Wladimir J. van der Laan 2020-03-13 22:28:34 +01:00
commit e5cb0dffd5
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D

View file

@ -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)