Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 1,578 Lines • ▼ Show 20 Lines | bool TransactionSignatureChecker::CheckSequence( | ||||
// simple numeric one. | // simple numeric one. | ||||
if (nSequenceMasked > txToSequenceMasked) { | if (nSequenceMasked > txToSequenceMasked) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, | bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, | ||||
deadalnix: This whole function is very convoluted and has a lot of unnecessary duplication. While I do not… | |||||
uint32_t flags, const BaseSignatureChecker &checker, | uint32_t flags, const BaseSignatureChecker &checker, | ||||
ScriptError *serror) { | ScriptError *serror) { | ||||
bool onlyRedeemScriptInScriptSig = false; | |||||
deadalnixUnsubmitted Done Inline ActionsDefine this closer to it's use. A comment to explain what this is would be useful. deadalnix: Define this closer to it's use. A comment to explain what this is would be useful. | |||||
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); | set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); | ||||
// If FORKID is enabled, we also ensure strict encoding. | // If FORKID is enabled, we also ensure strict encoding. | ||||
if (flags & SCRIPT_ENABLE_SIGHASH_FORKID) { | if (flags & SCRIPT_ENABLE_SIGHASH_FORKID) { | ||||
flags |= SCRIPT_VERIFY_STRICTENC; | flags |= SCRIPT_VERIFY_STRICTENC; | ||||
} | } | ||||
if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { | if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { | ||||
Show All 32 Lines | if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { | ||||
// stack cannot be empty here, because if it was the P2SH HASH <> EQUAL | // stack cannot be empty here, because if it was the P2SH HASH <> EQUAL | ||||
// scriptPubKey would be evaluated with an empty stack and the | // scriptPubKey would be evaluated with an empty stack and the | ||||
// EvalScript above would return false. | // EvalScript above would return false. | ||||
assert(!stack.empty()); | assert(!stack.empty()); | ||||
const valtype &pubKeySerialized = stack.back(); | const valtype &pubKeySerialized = stack.back(); | ||||
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); | CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); | ||||
popstack(stack); | popstack(stack); | ||||
onlyRedeemScriptInScriptSig = stack.empty(); | |||||
deadalnixUnsubmitted Done Inline ActionsIMO it is best to check for segwit specifically here. deadalnix: IMO it is best to check for segwit specifically here. | |||||
florianAuthorUnsubmitted Done Inline ActionsGood idea. I can limit all necessary changes to this P2SH conditional if I bail out early when all conditions are met, hence returning before the CLEANSTACK verification below. florian: Good idea. I can limit all necessary changes to this P2SH conditional if I bail out early when… | |||||
if (!EvalScript(stack, pubKey2, flags, checker, serror)) { | if (!EvalScript(stack, pubKey2, flags, checker, serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
if (stack.empty()) { | if (stack.empty()) { | ||||
return set_error(serror, SCRIPT_ERR_EVAL_FALSE); | return set_error(serror, SCRIPT_ERR_EVAL_FALSE); | ||||
} | } | ||||
if (!CastToBool(stack.back())) { | if (!CastToBool(stack.back())) { | ||||
return set_error(serror, SCRIPT_ERR_EVAL_FALSE); | return set_error(serror, SCRIPT_ERR_EVAL_FALSE); | ||||
} | } | ||||
} | } | ||||
// The CLEANSTACK check is only performed after potential P2SH evaluation, | // The CLEANSTACK check is only performed after potential P2SH evaluation, | ||||
// as the non-P2SH evaluation of a P2SH script will obviously not result in | // as the non-P2SH evaluation of a P2SH script will obviously not result in | ||||
// a clean stack (the P2SH inputs remain). The same holds for witness | // a clean stack (the P2SH inputs remain). The same holds for witness | ||||
// evaluation. | // evaluation. | ||||
if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { | // The CLEANSTACK_EXCEPTION ignores the CLEANSTACK check when the scriptSig | ||||
// for a P2SH coin contains only the redeem script | |||||
if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0 && | |||||
!((flags & SCRIPT_ENABLE_CLEANSTACK_EXCEPTION) != 0 && | |||||
onlyRedeemScriptInScriptSig)) { | |||||
deadalnixUnsubmitted Done Inline ActionsThis should be refactored as this is VERY unreadable atm. You can for instance bail early if stack.size() == 1 and then figure out if there is an error and if so what should be done about it. deadalnix: This should be refactored as this is VERY unreadable atm. You can for instance bail early if… | |||||
florianAuthorUnsubmitted Done Inline ActionsI'm returning this part to the original form, since no other change is needed for this diff. florian: I'm returning this part to the original form, since no other change is needed for this diff. | |||||
// Disallow CLEANSTACK without P2SH, as otherwise a switch | // Disallow CLEANSTACK without P2SH, as otherwise a switch | ||||
// CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a | // CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a | ||||
// softfork (and P2SH should be one). | // softfork (and P2SH should be one). | ||||
assert((flags & SCRIPT_VERIFY_P2SH) != 0); | assert((flags & SCRIPT_VERIFY_P2SH) != 0); | ||||
if (stack.size() != 1) { | if (stack.size() != 1) { | ||||
return set_error(serror, SCRIPT_ERR_CLEANSTACK); | return set_error(serror, SCRIPT_ERR_CLEANSTACK); | ||||
} | } | ||||
} | } | ||||
return set_success(serror); | return set_success(serror); | ||||
} | } |
This whole function is very convoluted and has a lot of unnecessary duplication. While I do not expect it to fix it all, at least we should make sure that this isn't getting worse.