Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 1,687 Lines • ▼ Show 20 Lines | |||||
// explicit instantiation | // explicit instantiation | ||||
template class GenericTransactionSignatureChecker<CTransaction>; | template class GenericTransactionSignatureChecker<CTransaction>; | ||||
template class GenericTransactionSignatureChecker<CMutableTransaction>; | template class GenericTransactionSignatureChecker<CMutableTransaction>; | ||||
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, | bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, | ||||
uint32_t flags, const BaseSignatureChecker &checker, | uint32_t flags, const BaseSignatureChecker &checker, | ||||
ScriptError *serror) { | ScriptError *serror) { | ||||
ScriptExecutionMetrics metrics; | |||||
deadalnix: Declare before use. Declaring variable at the beginning of function has not been useful since… | |||||
set_error(serror, ScriptError::UNKNOWN); | set_error(serror, ScriptError::UNKNOWN); | ||||
// 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()) { | ||||
return set_error(serror, ScriptError::SIG_PUSHONLY); | return set_error(serror, ScriptError::SIG_PUSHONLY); | ||||
} | } | ||||
std::vector<valtype> stack, stackCopy; | std::vector<valtype> stack, stackCopy; | ||||
if (!EvalScript(stack, scriptSig, flags, checker, serror)) { | if (!EvalScript(stack, scriptSig, flags, checker, metrics, serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
if (flags & SCRIPT_VERIFY_P2SH) { | if (flags & SCRIPT_VERIFY_P2SH) { | ||||
stackCopy = stack; | stackCopy = stack; | ||||
} | } | ||||
if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) { | if (!EvalScript(stack, scriptPubKey, flags, checker, metrics, serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
if (stack.empty()) { | if (stack.empty()) { | ||||
return set_error(serror, ScriptError::EVAL_FALSE); | return set_error(serror, ScriptError::EVAL_FALSE); | ||||
} | } | ||||
if (CastToBool(stack.back()) == false) { | if (CastToBool(stack.back()) == false) { | ||||
return set_error(serror, ScriptError::EVAL_FALSE); | return set_error(serror, ScriptError::EVAL_FALSE); | ||||
Show All 21 Lines | if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { | ||||
// Bail out early if SCRIPT_DISALLOW_SEGWIT_RECOVERY is not set, the | // Bail out early if SCRIPT_DISALLOW_SEGWIT_RECOVERY is not set, the | ||||
// redeem script is a p2sh segwit program, and it was the only item | // redeem script is a p2sh segwit program, and it was the only item | ||||
// pushed onto the stack. | // pushed onto the stack. | ||||
if ((flags & SCRIPT_DISALLOW_SEGWIT_RECOVERY) == 0 && stack.empty() && | if ((flags & SCRIPT_DISALLOW_SEGWIT_RECOVERY) == 0 && stack.empty() && | ||||
pubKey2.IsWitnessProgram()) { | pubKey2.IsWitnessProgram()) { | ||||
return set_success(serror); | return set_success(serror); | ||||
} | } | ||||
if (!EvalScript(stack, pubKey2, flags, checker, serror)) { | if (!EvalScript(stack, pubKey2, flags, checker, metrics, serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
if (stack.empty()) { | if (stack.empty()) { | ||||
return set_error(serror, ScriptError::EVAL_FALSE); | return set_error(serror, ScriptError::EVAL_FALSE); | ||||
} | } | ||||
if (!CastToBool(stack.back())) { | if (!CastToBool(stack.back())) { | ||||
return set_error(serror, ScriptError::EVAL_FALSE); | return set_error(serror, ScriptError::EVAL_FALSE); | ||||
Show All 9 Lines | if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { | ||||
// 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, ScriptError::CLEANSTACK); | return set_error(serror, ScriptError::CLEANSTACK); | ||||
} | } | ||||
} | } | ||||
if (flags & SCRIPT_VERIFY_INPUT_SIGCHECKS) { | |||||
// This limit is intended for standard use, and is based on an | |||||
// examination of typical and historical standard uses. | |||||
// - allowing P2SH ECDSA multisig with compressed keys, which at an | |||||
// extreme (1-of-15) may have 15 SigChecks in ~590 bytes of scriptSig. | |||||
// - allowing Bare ECDSA multisig, which at an extreme (1-of-3) may have | |||||
// 3 sigchecks in ~72 bytes of scriptSig. | |||||
// - Since the size of an input is 41 bytes + length of scriptSig, then | |||||
// the most dense possible inputs satisfying this rule would be: | |||||
// 2 sigchecks and 26 bytes: 1/33.50 sigchecks/byte. | |||||
// 3 sigchecks and 69 bytes: 1/36.66 sigchecks/byte. | |||||
// The latter can be readily done with 1-of-3 bare multisignatures, | |||||
// however the former is not practically doable with standard scripts, | |||||
// so the practical density limit is 1/36.66. | |||||
static_assert(INT_MAX > MAX_SCRIPT_SIZE, | |||||
"overflow sanity check on max script size"); | |||||
static_assert(INT_MAX / 43 / 3 > MAX_OPS_PER_SCRIPT, | |||||
"overflow sanity check on maximum possible sigchecks " | |||||
"from sig+redeem+pub scripts"); | |||||
if (int(scriptSig.size()) < metrics.nSigChecks * 43 - 60) { | |||||
deadalnixUnsubmitted Done Inline ActionsIt looks like it wasn't a great idea to make nSigCheck signed. deadalnix: It looks like it wasn't a great idea to make nSigCheck signed. | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsThe quantity metrics.nSigChecks * 43 - 60 becomes negative here, so it definitely should be signed comparison. I'm not sure what rounding differences you're alluding to... can you give an example? markblundeberg: The quantity `metrics.nSigChecks * 43 - 60` becomes negative here, so it definitely should be… | |||||
deadalnixUnsubmitted Not Done Inline ActionsI think I was wrong about the rounding this, but my level of confidence is not high. The negative problem can be fixed easily by adding 60 on the left side rather than subtracting on the right side. It also happens to be "more correct" as it'll work even if the script size is more than 4G, which I'm sure will happen any time. deadalnix: I think I was wrong about the rounding this, but my level of confidence is not high. The… | |||||
deadalnixUnsubmitted Done Inline ActionsNote that this is also different from (L+60) / 43 due to rounding being different. deadalnix: Note that this is also different from (L+60) / 43 due to rounding being different. | |||||
return set_error(serror, ScriptError::INPUT_SIGCHECKS); | |||||
} | |||||
} | |||||
return set_success(serror); | return set_success(serror); | ||||
} | } |
Declare before use. Declaring variable at the beginning of function has not been useful since the 80s.