Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 958 Lines • ▼ Show 20 Lines | try { | ||||
} | } | ||||
} break; | } break; | ||||
case OP_CHECKMULTISIG: | case OP_CHECKMULTISIG: | ||||
case OP_CHECKMULTISIGVERIFY: { | case OP_CHECKMULTISIGVERIFY: { | ||||
// ([sig ...] num_of_signatures [pubkey ...] | // ([sig ...] num_of_signatures [pubkey ...] | ||||
// num_of_pubkeys -- bool) | // num_of_pubkeys -- bool) | ||||
int i = 1; | int i = 1; | ||||
deadalnix: This gradual incrementalist of i is bullshit. If you are refactoring this, you can do it right. | |||||
if ((int)stack.size() < i) { | if ((int)stack.size() < i) { | ||||
deadalnixUnsubmitted Not Done Inline ActionsOnce you use fixed indices, and don't save them in ints, you won't need these casts. deadalnix: Once you use fixed indices, and don't save them in ints, you won't need these casts. | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsThey do need to be saved in ints, since we perform negation on them, e.g., stacktop(-idummy) markblundeberg: They do need to be saved in ints, since we perform negation on them, e.g., `stacktop(-idummy)` | |||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
int nKeysCount = | int nKeysCount = | ||||
CScriptNum(stacktop(-i), fRequireMinimal).getint(); | CScriptNum(stacktop(-i), fRequireMinimal).getint(); | ||||
if (nKeysCount < 0 || | if (nKeysCount < 0 || | ||||
nKeysCount > MAX_PUBKEYS_PER_MULTISIG) { | nKeysCount > MAX_PUBKEYS_PER_MULTISIG) { | ||||
Show All 17 Lines | try { | ||||
int nSigsCount = | int nSigsCount = | ||||
CScriptNum(stacktop(-i), fRequireMinimal).getint(); | CScriptNum(stacktop(-i), fRequireMinimal).getint(); | ||||
if (nSigsCount < 0 || nSigsCount > nKeysCount) { | if (nSigsCount < 0 || nSigsCount > nKeysCount) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_COUNT); | return set_error(serror, SCRIPT_ERR_SIG_COUNT); | ||||
} | } | ||||
int isig = ++i; | int isig = ++i; | ||||
i += nSigsCount; | i += nSigsCount; | ||||
if ((int)stack.size() < i) { | int idummy = i; | ||||
if ((int)stack.size() < idummy) { | |||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
bool fSuccess = true; | |||||
// Subset of script starting at the most recent | // Subset of script starting at the most recent | ||||
// codeseparator | // codeseparator | ||||
CScript scriptCode(pbegincodehash, pend); | CScript scriptCode(pbegincodehash, pend); | ||||
// A bug causes CHECKMULTISIG to consume one extra | |||||
// argument whose contents were not checked in any way. | |||||
// | |||||
// Unfortunately this is a potential source of | |||||
// mutability, so optionally verify it is exactly equal | |||||
// to zero. | |||||
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && | |||||
stacktop(-idummy).size()) { | |||||
return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); | |||||
} | |||||
// Remove signature for pre-fork scripts | // Remove signature for pre-fork scripts | ||||
for (int k = 0; k < nSigsCount; k++) { | for (int k = 0; k < nSigsCount; k++) { | ||||
valtype &vchSig = stacktop(-isig - k); | valtype &vchSig = stacktop(-isig - k); | ||||
CleanupScriptCode(scriptCode, vchSig, flags); | CleanupScriptCode(scriptCode, vchSig, flags); | ||||
} | } | ||||
bool fSuccess = true; | |||||
while (fSuccess && nSigsCount > 0) { | while (fSuccess && nSigsCount > 0) { | ||||
valtype &vchSig = stacktop(-isig); | valtype &vchSig = stacktop(-isig); | ||||
valtype &vchPubKey = stacktop(-ikey); | valtype &vchPubKey = stacktop(-ikey); | ||||
// Note how this makes the exact order of | // Note how this makes the exact order of | ||||
// pubkey/signature evaluation distinguishable by | // pubkey/signature evaluation distinguishable by | ||||
// CHECKMULTISIG NOT if the STRICTENC flag is set. | // CHECKMULTISIG NOT if the STRICTENC flag is set. | ||||
// See the script_(in)valid tests for details. | // See the script_(in)valid tests for details. | ||||
Show All 34 Lines | try { | ||||
SCRIPT_ERR_SIG_NULLFAIL); | SCRIPT_ERR_SIG_NULLFAIL); | ||||
} | } | ||||
if (ikey2 > 0) { | if (ikey2 > 0) { | ||||
ikey2--; | ikey2--; | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
} | } | ||||
// A bug causes CHECKMULTISIG to consume one extra | // Pop dummy element | ||||
// argument whose contents were not checked in any way. | |||||
// | |||||
// Unfortunately this is a potential source of | |||||
// mutability, so optionally verify it is exactly equal | |||||
// to zero prior to removing it from the stack. | |||||
if (stack.size() < 1) { | |||||
return set_error( | |||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
} | |||||
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && | |||||
stacktop(-1).size()) { | |||||
return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); | |||||
} | |||||
popstack(stack); | popstack(stack); | ||||
stack.push_back(fSuccess ? vchTrue : vchFalse); | stack.push_back(fSuccess ? vchTrue : vchFalse); | ||||
if (opcode == OP_CHECKMULTISIGVERIFY) { | if (opcode == OP_CHECKMULTISIGVERIFY) { | ||||
if (fSuccess) { | if (fSuccess) { | ||||
popstack(stack); | popstack(stack); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 582 Lines • Show Last 20 Lines |
This gradual incrementalist of i is bullshit. If you are refactoring this, you can do it right. Compute the indices once and save them in const variables. Don't be afraid of doing a set of very small change for this type of code. Compute the indices and use that instead of i. Then move some piece of code around. etc...