Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 955 Lines • ▼ Show 20 Lines | try { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | SCRIPT_ERR_CHECKDATASIGVERIFY); | ||||
} | } | ||||
} | } | ||||
} break; | } break; | ||||
case OP_CHECKMULTISIG: | case OP_CHECKMULTISIG: | ||||
case OP_CHECKMULTISIGVERIFY: { | case OP_CHECKMULTISIGVERIFY: { | ||||
// ([sig ...] num_of_signatures [pubkey ...] | // ([dummy] [sig ...] num_of_signatures [pubkey ...] | ||||
// num_of_pubkeys -- bool) | // num_of_pubkeys -- bool) | ||||
const size_t idxKeyCount = 1; | |||||
size_t i = 1; | if (stack.size() < idxKeyCount) { | ||||
if (stack.size() < i) { | |||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
const int nKeysCount = | |||||
int nKeysCount = | CScriptNum(stacktop(-idxKeyCount), fRequireMinimal) | ||||
CScriptNum(stacktop(-i), fRequireMinimal).getint(); | .getint(); | ||||
if (nKeysCount < 0 || | if (nKeysCount < 0 || | ||||
nKeysCount > MAX_PUBKEYS_PER_MULTISIG) { | nKeysCount > MAX_PUBKEYS_PER_MULTISIG) { | ||||
return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); | return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); | ||||
} | } | ||||
nOpCount += nKeysCount; | nOpCount += nKeysCount; | ||||
if (nOpCount > MAX_OPS_PER_SCRIPT) { | if (nOpCount > MAX_OPS_PER_SCRIPT) { | ||||
return set_error(serror, SCRIPT_ERR_OP_COUNT); | return set_error(serror, SCRIPT_ERR_OP_COUNT); | ||||
} | } | ||||
size_t ikey = ++i; | |||||
// ikey2 is the position of last non-signature item in | // stack depth of the top pubkey | ||||
// the stack. Top stack item = 1. With | const size_t idxTopKey = idxKeyCount + 1; | ||||
// SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if | |||||
// operation fails. | // stack depth of nSigsCount | ||||
size_t ikey2 = nKeysCount + 2; | const size_t idxSigCount = idxTopKey + nKeysCount; | ||||
i += nKeysCount; | if (stack.size() < idxSigCount) { | ||||
if (stack.size() < i) { | |||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
const int nSigsCount = | |||||
int nSigsCount = | CScriptNum(stacktop(-idxSigCount), fRequireMinimal) | ||||
CScriptNum(stacktop(-i), fRequireMinimal).getint(); | .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); | ||||
} | } | ||||
size_t isig = ++i; | |||||
i += nSigsCount; | // stack depth of the top signature | ||||
if (stack.size() < i) { | const size_t idxTopSig = idxSigCount + 1; | ||||
// stack depth of the dummy element | |||||
const size_t idxDummy = idxTopSig + nSigsCount; | |||||
if (stack.size() < idxDummy) { | |||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
// 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); | ||||
// 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(-idxTopSig - k); | ||||
CleanupScriptCode(scriptCode, vchSig, flags); | CleanupScriptCode(scriptCode, vchSig, flags); | ||||
} | } | ||||
bool fSuccess = true; | bool fSuccess = true; | ||||
while (fSuccess && nSigsCount > 0) { | size_t ikey = idxTopKey; | ||||
size_t isig = idxTopSig; | |||||
int nSigsRemaining = nSigsCount; | |||||
int nKeysRemaining = nKeysCount; | |||||
while (fSuccess && nSigsRemaining > 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. | ||||
if (!CheckTransactionECDSASignatureEncoding( | if (!CheckTransactionECDSASignatureEncoding( | ||||
vchSig, flags, serror) || | vchSig, flags, serror) || | ||||
!CheckPubKeyEncoding(vchPubKey, flags, | !CheckPubKeyEncoding(vchPubKey, flags, | ||||
serror)) { | serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
// Check signature | // Check signature | ||||
bool fOk = checker.CheckSig(vchSig, vchPubKey, | bool fOk = checker.CheckSig(vchSig, vchPubKey, | ||||
scriptCode, flags); | scriptCode, flags); | ||||
if (fOk) { | if (fOk) { | ||||
isig++; | isig++; | ||||
nSigsCount--; | nSigsRemaining--; | ||||
} | } | ||||
ikey++; | ikey++; | ||||
nKeysCount--; | nKeysRemaining--; | ||||
// If there are more signatures left than keys left, | // If there are more signatures left than keys left, | ||||
// then too many signatures have failed. Exit early, | // then too many signatures have failed. Exit early, | ||||
// without checking any further signatures. | // without checking any further signatures. | ||||
if (nSigsCount > nKeysCount) { | if (nSigsRemaining > nKeysRemaining) { | ||||
fSuccess = false; | fSuccess = false; | ||||
} | } | ||||
} | } | ||||
// Clean up stack of actual arguments | // Clean up stack of actual arguments | ||||
size_t i = idxDummy; | |||||
size_t ikey2 = idxSigCount; | |||||
while (i-- > 1) { | while (i-- > 1) { | ||||
// If the operation failed, we require that all | // If the operation failed, we require that all | ||||
// signatures must be empty vector | // signatures must be empty vector | ||||
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | ||||
!ikey2 && stacktop(-1).size()) { | !ikey2 && stacktop(-1).size()) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | SCRIPT_ERR_SIG_NULLFAIL); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 610 Lines • Show Last 20 Lines |