Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | bool EvalScript(std::vector<valtype> &stack, const CScript &script, | ||||
CScript::const_iterator pc = script.begin(); | CScript::const_iterator pc = script.begin(); | ||||
CScript::const_iterator pend = script.end(); | CScript::const_iterator pend = script.end(); | ||||
CScript::const_iterator pbegincodehash = script.begin(); | CScript::const_iterator pbegincodehash = script.begin(); | ||||
opcodetype opcode; | opcodetype opcode; | ||||
valtype vchPushValue; | valtype vchPushValue; | ||||
std::vector<bool> vfExec; | std::vector<bool> vfExec; | ||||
std::vector<valtype> altstack; | std::vector<valtype> altstack; | ||||
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); | set_error(serror, ScriptError::UNKNOWN); | ||||
if (script.size() > MAX_SCRIPT_SIZE) { | if (script.size() > MAX_SCRIPT_SIZE) { | ||||
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); | return set_error(serror, ScriptError::SCRIPT_SIZE); | ||||
} | } | ||||
int nOpCount = 0; | int nOpCount = 0; | ||||
bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; | bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; | ||||
try { | try { | ||||
while (pc < pend) { | while (pc < pend) { | ||||
bool fExec = !count(vfExec.begin(), vfExec.end(), false); | bool fExec = !count(vfExec.begin(), vfExec.end(), false); | ||||
// | // | ||||
// Read instruction | // Read instruction | ||||
// | // | ||||
if (!script.GetOp(pc, opcode, vchPushValue)) { | if (!script.GetOp(pc, opcode, vchPushValue)) { | ||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE); | return set_error(serror, ScriptError::BAD_OPCODE); | ||||
} | } | ||||
if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) { | if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) { | ||||
return set_error(serror, SCRIPT_ERR_PUSH_SIZE); | return set_error(serror, ScriptError::PUSH_SIZE); | ||||
} | } | ||||
// Note how OP_RESERVED does not count towards the opcode limit. | // Note how OP_RESERVED does not count towards the opcode limit. | ||||
if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) { | if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) { | ||||
return set_error(serror, SCRIPT_ERR_OP_COUNT); | return set_error(serror, ScriptError::OP_COUNT); | ||||
} | } | ||||
// Some opcodes are disabled. | // Some opcodes are disabled. | ||||
if (IsOpcodeDisabled(opcode, flags)) { | if (IsOpcodeDisabled(opcode, flags)) { | ||||
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); | return set_error(serror, ScriptError::DISABLED_OPCODE); | ||||
} | } | ||||
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { | if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { | ||||
if (fRequireMinimal && | if (fRequireMinimal && | ||||
!CheckMinimalPush(vchPushValue, opcode)) { | !CheckMinimalPush(vchPushValue, opcode)) { | ||||
return set_error(serror, SCRIPT_ERR_MINIMALDATA); | return set_error(serror, ScriptError::MINIMALDATA); | ||||
} | } | ||||
stack.push_back(vchPushValue); | stack.push_back(vchPushValue); | ||||
} else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) { | } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) { | ||||
switch (opcode) { | switch (opcode) { | ||||
// | // | ||||
// Push value | // Push value | ||||
// | // | ||||
case OP_1NEGATE: | case OP_1NEGATE: | ||||
Show All 29 Lines | try { | ||||
case OP_CHECKLOCKTIMEVERIFY: { | case OP_CHECKLOCKTIMEVERIFY: { | ||||
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { | if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { | ||||
// not enabled; treat as a NOP2 | // not enabled; treat as a NOP2 | ||||
if (flags & | if (flags & | ||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { | ||||
return set_error( | return set_error( | ||||
serror, | serror, | ||||
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); | ScriptError::DISCOURAGE_UPGRADABLE_NOPS); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
// Note that elsewhere numeric opcodes are limited to | // Note that elsewhere numeric opcodes are limited to | ||||
// operands in the range -2**31+1 to 2**31-1, however it | // operands in the range -2**31+1 to 2**31-1, however it | ||||
// is legal for opcodes to produce results exceeding | // is legal for opcodes to produce results exceeding | ||||
// that range. This limitation is implemented by | // that range. This limitation is implemented by | ||||
// CScriptNum's default 4-byte limit. | // CScriptNum's default 4-byte limit. | ||||
// | // | ||||
Show All 9 Lines | try { | ||||
const CScriptNum nLockTime(stacktop(-1), | const CScriptNum nLockTime(stacktop(-1), | ||||
fRequireMinimal, 5); | fRequireMinimal, 5); | ||||
// In the rare event that the argument may be < 0 due to | // In the rare event that the argument may be < 0 due to | ||||
// some arithmetic being done first, you can always use | // some arithmetic being done first, you can always use | ||||
// 0 MAX CHECKLOCKTIMEVERIFY. | // 0 MAX CHECKLOCKTIMEVERIFY. | ||||
if (nLockTime < 0) { | if (nLockTime < 0) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_NEGATIVE_LOCKTIME); | ScriptError::NEGATIVE_LOCKTIME); | ||||
} | } | ||||
// Actually compare the specified lock time with the | // Actually compare the specified lock time with the | ||||
// transaction. | // transaction. | ||||
if (!checker.CheckLockTime(nLockTime)) { | if (!checker.CheckLockTime(nLockTime)) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_UNSATISFIED_LOCKTIME); | ScriptError::UNSATISFIED_LOCKTIME); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case OP_CHECKSEQUENCEVERIFY: { | case OP_CHECKSEQUENCEVERIFY: { | ||||
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) { | if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) { | ||||
// not enabled; treat as a NOP3 | // not enabled; treat as a NOP3 | ||||
if (flags & | if (flags & | ||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { | ||||
return set_error( | return set_error( | ||||
serror, | serror, | ||||
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); | ScriptError::DISCOURAGE_UPGRADABLE_NOPS); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
// nSequence, like nLockTime, is a 32-bit unsigned | // nSequence, like nLockTime, is a 32-bit unsigned | ||||
// integer field. See the comment in CHECKLOCKTIMEVERIFY | // integer field. See the comment in CHECKLOCKTIMEVERIFY | ||||
// regarding 5-byte numeric operands. | // regarding 5-byte numeric operands. | ||||
const CScriptNum nSequence(stacktop(-1), | const CScriptNum nSequence(stacktop(-1), | ||||
fRequireMinimal, 5); | fRequireMinimal, 5); | ||||
// In the rare event that the argument may be < 0 due to | // In the rare event that the argument may be < 0 due to | ||||
// some arithmetic being done first, you can always use | // some arithmetic being done first, you can always use | ||||
// 0 MAX CHECKSEQUENCEVERIFY. | // 0 MAX CHECKSEQUENCEVERIFY. | ||||
if (nSequence < 0) { | if (nSequence < 0) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_NEGATIVE_LOCKTIME); | ScriptError::NEGATIVE_LOCKTIME); | ||||
} | } | ||||
// To provide for future soft-fork extensibility, if the | // To provide for future soft-fork extensibility, if the | ||||
// operand has the disabled lock-time flag set, | // operand has the disabled lock-time flag set, | ||||
// CHECKSEQUENCEVERIFY behaves as a NOP. | // CHECKSEQUENCEVERIFY behaves as a NOP. | ||||
if ((nSequence & | if ((nSequence & | ||||
CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) { | CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) { | ||||
break; | break; | ||||
} | } | ||||
// Compare the specified sequence number with the input. | // Compare the specified sequence number with the input. | ||||
if (!checker.CheckSequence(nSequence)) { | if (!checker.CheckSequence(nSequence)) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_UNSATISFIED_LOCKTIME); | ScriptError::UNSATISFIED_LOCKTIME); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case OP_NOP1: | case OP_NOP1: | ||||
case OP_NOP4: | case OP_NOP4: | ||||
case OP_NOP5: | case OP_NOP5: | ||||
case OP_NOP6: | case OP_NOP6: | ||||
case OP_NOP7: | case OP_NOP7: | ||||
case OP_NOP8: | case OP_NOP8: | ||||
case OP_NOP9: | case OP_NOP9: | ||||
case OP_NOP10: { | case OP_NOP10: { | ||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { | if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); | serror, | ||||
ScriptError::DISCOURAGE_UPGRADABLE_NOPS); | |||||
} | } | ||||
} break; | } break; | ||||
case OP_IF: | case OP_IF: | ||||
case OP_NOTIF: { | case OP_NOTIF: { | ||||
// <expression> if [statements] [else [statements]] | // <expression> if [statements] [else [statements]] | ||||
// endif | // endif | ||||
bool fValue = false; | bool fValue = false; | ||||
if (fExec) { | if (fExec) { | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); | serror, | ||||
ScriptError::UNBALANCED_CONDITIONAL); | |||||
} | } | ||||
valtype &vch = stacktop(-1); | valtype &vch = stacktop(-1); | ||||
if (flags & SCRIPT_VERIFY_MINIMALIF) { | if (flags & SCRIPT_VERIFY_MINIMALIF) { | ||||
if (vch.size() > 1) { | if (vch.size() > 1) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_MINIMALIF); | ScriptError::MINIMALIF); | ||||
} | } | ||||
if (vch.size() == 1 && vch[0] != 1) { | if (vch.size() == 1 && vch[0] != 1) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_MINIMALIF); | ScriptError::MINIMALIF); | ||||
} | } | ||||
} | } | ||||
fValue = CastToBool(vch); | fValue = CastToBool(vch); | ||||
if (opcode == OP_NOTIF) { | if (opcode == OP_NOTIF) { | ||||
fValue = !fValue; | fValue = !fValue; | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
} | } | ||||
vfExec.push_back(fValue); | vfExec.push_back(fValue); | ||||
} break; | } break; | ||||
case OP_ELSE: { | case OP_ELSE: { | ||||
if (vfExec.empty()) { | if (vfExec.empty()) { | ||||
return set_error(serror, | return set_error( | ||||
SCRIPT_ERR_UNBALANCED_CONDITIONAL); | serror, ScriptError::UNBALANCED_CONDITIONAL); | ||||
} | } | ||||
vfExec.back() = !vfExec.back(); | vfExec.back() = !vfExec.back(); | ||||
} break; | } break; | ||||
case OP_ENDIF: { | case OP_ENDIF: { | ||||
if (vfExec.empty()) { | if (vfExec.empty()) { | ||||
return set_error(serror, | return set_error( | ||||
SCRIPT_ERR_UNBALANCED_CONDITIONAL); | serror, ScriptError::UNBALANCED_CONDITIONAL); | ||||
} | } | ||||
vfExec.pop_back(); | vfExec.pop_back(); | ||||
} break; | } break; | ||||
case OP_VERIFY: { | case OP_VERIFY: { | ||||
// (true -- ) or | // (true -- ) or | ||||
// (false -- false) and return | // (false -- false) and return | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
bool fValue = CastToBool(stacktop(-1)); | bool fValue = CastToBool(stacktop(-1)); | ||||
if (fValue) { | if (fValue) { | ||||
popstack(stack); | popstack(stack); | ||||
} else { | } else { | ||||
return set_error(serror, SCRIPT_ERR_VERIFY); | return set_error(serror, ScriptError::VERIFY); | ||||
} | } | ||||
} break; | } break; | ||||
case OP_RETURN: { | case OP_RETURN: { | ||||
return set_error(serror, SCRIPT_ERR_OP_RETURN); | return set_error(serror, ScriptError::OP_RETURN); | ||||
} break; | } break; | ||||
// | // | ||||
// Stack ops | // Stack ops | ||||
// | // | ||||
case OP_TOALTSTACK: { | case OP_TOALTSTACK: { | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
altstack.push_back(stacktop(-1)); | altstack.push_back(stacktop(-1)); | ||||
popstack(stack); | popstack(stack); | ||||
} break; | } break; | ||||
case OP_FROMALTSTACK: { | case OP_FROMALTSTACK: { | ||||
if (altstack.size() < 1) { | if (altstack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION); | serror, | ||||
ScriptError::INVALID_ALTSTACK_OPERATION); | |||||
} | } | ||||
stack.push_back(altstacktop(-1)); | stack.push_back(altstacktop(-1)); | ||||
popstack(altstack); | popstack(altstack); | ||||
} break; | } break; | ||||
case OP_2DROP: { | case OP_2DROP: { | ||||
// (x1 x2 -- ) | // (x1 x2 -- ) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
} break; | } break; | ||||
case OP_2DUP: { | case OP_2DUP: { | ||||
// (x1 x2 -- x1 x2 x1 x2) | // (x1 x2 -- x1 x2 x1 x2) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch1 = stacktop(-2); | valtype vch1 = stacktop(-2); | ||||
valtype vch2 = stacktop(-1); | valtype vch2 = stacktop(-1); | ||||
stack.push_back(vch1); | stack.push_back(vch1); | ||||
stack.push_back(vch2); | stack.push_back(vch2); | ||||
} break; | } break; | ||||
case OP_3DUP: { | case OP_3DUP: { | ||||
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) | // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) | ||||
if (stack.size() < 3) { | if (stack.size() < 3) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch1 = stacktop(-3); | valtype vch1 = stacktop(-3); | ||||
valtype vch2 = stacktop(-2); | valtype vch2 = stacktop(-2); | ||||
valtype vch3 = stacktop(-1); | valtype vch3 = stacktop(-1); | ||||
stack.push_back(vch1); | stack.push_back(vch1); | ||||
stack.push_back(vch2); | stack.push_back(vch2); | ||||
stack.push_back(vch3); | stack.push_back(vch3); | ||||
} break; | } break; | ||||
case OP_2OVER: { | case OP_2OVER: { | ||||
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) | // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) | ||||
if (stack.size() < 4) { | if (stack.size() < 4) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch1 = stacktop(-4); | valtype vch1 = stacktop(-4); | ||||
valtype vch2 = stacktop(-3); | valtype vch2 = stacktop(-3); | ||||
stack.push_back(vch1); | stack.push_back(vch1); | ||||
stack.push_back(vch2); | stack.push_back(vch2); | ||||
} break; | } break; | ||||
case OP_2ROT: { | case OP_2ROT: { | ||||
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) | // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) | ||||
if (stack.size() < 6) { | if (stack.size() < 6) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch1 = stacktop(-6); | valtype vch1 = stacktop(-6); | ||||
valtype vch2 = stacktop(-5); | valtype vch2 = stacktop(-5); | ||||
stack.erase(stack.end() - 6, stack.end() - 4); | stack.erase(stack.end() - 6, stack.end() - 4); | ||||
stack.push_back(vch1); | stack.push_back(vch1); | ||||
stack.push_back(vch2); | stack.push_back(vch2); | ||||
} break; | } break; | ||||
case OP_2SWAP: { | case OP_2SWAP: { | ||||
// (x1 x2 x3 x4 -- x3 x4 x1 x2) | // (x1 x2 x3 x4 -- x3 x4 x1 x2) | ||||
if (stack.size() < 4) { | if (stack.size() < 4) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
swap(stacktop(-4), stacktop(-2)); | swap(stacktop(-4), stacktop(-2)); | ||||
swap(stacktop(-3), stacktop(-1)); | swap(stacktop(-3), stacktop(-1)); | ||||
} break; | } break; | ||||
case OP_IFDUP: { | case OP_IFDUP: { | ||||
// (x - 0 | x x) | // (x - 0 | x x) | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch = stacktop(-1); | valtype vch = stacktop(-1); | ||||
if (CastToBool(vch)) { | if (CastToBool(vch)) { | ||||
stack.push_back(vch); | stack.push_back(vch); | ||||
} | } | ||||
} break; | } break; | ||||
case OP_DEPTH: { | case OP_DEPTH: { | ||||
// -- stacksize | // -- stacksize | ||||
CScriptNum bn(stack.size()); | CScriptNum bn(stack.size()); | ||||
stack.push_back(bn.getvch()); | stack.push_back(bn.getvch()); | ||||
} break; | } break; | ||||
case OP_DROP: { | case OP_DROP: { | ||||
// (x -- ) | // (x -- ) | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
} break; | } break; | ||||
case OP_DUP: { | case OP_DUP: { | ||||
// (x -- x x) | // (x -- x x) | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch = stacktop(-1); | valtype vch = stacktop(-1); | ||||
stack.push_back(vch); | stack.push_back(vch); | ||||
} break; | } break; | ||||
case OP_NIP: { | case OP_NIP: { | ||||
// (x1 x2 -- x2) | // (x1 x2 -- x2) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
stack.erase(stack.end() - 2); | stack.erase(stack.end() - 2); | ||||
} break; | } break; | ||||
case OP_OVER: { | case OP_OVER: { | ||||
// (x1 x2 -- x1 x2 x1) | // (x1 x2 -- x1 x2 x1) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch = stacktop(-2); | valtype vch = stacktop(-2); | ||||
stack.push_back(vch); | stack.push_back(vch); | ||||
} break; | } break; | ||||
case OP_PICK: | case OP_PICK: | ||||
case OP_ROLL: { | case OP_ROLL: { | ||||
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) | // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) | ||||
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) | // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
int n = | int n = | ||||
CScriptNum(stacktop(-1), fRequireMinimal).getint(); | CScriptNum(stacktop(-1), fRequireMinimal).getint(); | ||||
popstack(stack); | popstack(stack); | ||||
if (n < 0 || n >= (int)stack.size()) { | if (n < 0 || n >= (int)stack.size()) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch = stacktop(-n - 1); | valtype vch = stacktop(-n - 1); | ||||
if (opcode == OP_ROLL) { | if (opcode == OP_ROLL) { | ||||
stack.erase(stack.end() - n - 1); | stack.erase(stack.end() - n - 1); | ||||
} | } | ||||
stack.push_back(vch); | stack.push_back(vch); | ||||
} break; | } break; | ||||
case OP_ROT: { | case OP_ROT: { | ||||
// (x1 x2 x3 -- x2 x3 x1) | // (x1 x2 x3 -- x2 x3 x1) | ||||
// x2 x1 x3 after first swap | // x2 x1 x3 after first swap | ||||
// x2 x3 x1 after second swap | // x2 x3 x1 after second swap | ||||
if (stack.size() < 3) { | if (stack.size() < 3) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
swap(stacktop(-3), stacktop(-2)); | swap(stacktop(-3), stacktop(-2)); | ||||
swap(stacktop(-2), stacktop(-1)); | swap(stacktop(-2), stacktop(-1)); | ||||
} break; | } break; | ||||
case OP_SWAP: { | case OP_SWAP: { | ||||
// (x1 x2 -- x2 x1) | // (x1 x2 -- x2 x1) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
swap(stacktop(-2), stacktop(-1)); | swap(stacktop(-2), stacktop(-1)); | ||||
} break; | } break; | ||||
case OP_TUCK: { | case OP_TUCK: { | ||||
// (x1 x2 -- x2 x1 x2) | // (x1 x2 -- x2 x1 x2) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype vch = stacktop(-1); | valtype vch = stacktop(-1); | ||||
stack.insert(stack.end() - 2, vch); | stack.insert(stack.end() - 2, vch); | ||||
} break; | } break; | ||||
case OP_SIZE: { | case OP_SIZE: { | ||||
// (in -- in size) | // (in -- in size) | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
CScriptNum bn(stacktop(-1).size()); | CScriptNum bn(stacktop(-1).size()); | ||||
stack.push_back(bn.getvch()); | stack.push_back(bn.getvch()); | ||||
} break; | } break; | ||||
// | // | ||||
// Bitwise logic | // Bitwise logic | ||||
// | // | ||||
case OP_AND: | case OP_AND: | ||||
case OP_OR: | case OP_OR: | ||||
case OP_XOR: { | case OP_XOR: { | ||||
// (x1 x2 - out) | // (x1 x2 - out) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &vch1 = stacktop(-2); | valtype &vch1 = stacktop(-2); | ||||
valtype &vch2 = stacktop(-1); | valtype &vch2 = stacktop(-1); | ||||
// Inputs must be the same size | // Inputs must be the same size | ||||
if (vch1.size() != vch2.size()) { | if (vch1.size() != vch2.size()) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_INVALID_OPERAND_SIZE); | ScriptError::INVALID_OPERAND_SIZE); | ||||
} | } | ||||
// To avoid allocating, we modify vch1 in place. | // To avoid allocating, we modify vch1 in place. | ||||
switch (opcode) { | switch (opcode) { | ||||
case OP_AND: | case OP_AND: | ||||
for (size_t i = 0; i < vch1.size(); ++i) { | for (size_t i = 0; i < vch1.size(); ++i) { | ||||
vch1[i] &= vch2[i]; | vch1[i] &= vch2[i]; | ||||
} | } | ||||
Show All 18 Lines | try { | ||||
case OP_EQUAL: | case OP_EQUAL: | ||||
case OP_EQUALVERIFY: | case OP_EQUALVERIFY: | ||||
// case OP_NOTEQUAL: // use OP_NUMNOTEQUAL | // case OP_NOTEQUAL: // use OP_NUMNOTEQUAL | ||||
{ | { | ||||
// (x1 x2 - bool) | // (x1 x2 - bool) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, | ||||
ScriptError::INVALID_STACK_OPERATION); | |||||
} | } | ||||
valtype &vch1 = stacktop(-2); | valtype &vch1 = stacktop(-2); | ||||
valtype &vch2 = stacktop(-1); | valtype &vch2 = stacktop(-1); | ||||
bool fEqual = (vch1 == vch2); | bool fEqual = (vch1 == vch2); | ||||
// OP_NOTEQUAL is disabled because it would be too | // OP_NOTEQUAL is disabled because it would be too | ||||
// easy to say something like n != 1 and have some | // easy to say something like n != 1 and have some | ||||
// wiseguy pass in 1 with extra zero bytes after it | // wiseguy pass in 1 with extra zero bytes after it | ||||
// (numerically, 0x01 == 0x0001 == 0x000001) | // (numerically, 0x01 == 0x0001 == 0x000001) | ||||
// if (opcode == OP_NOTEQUAL) | // if (opcode == OP_NOTEQUAL) | ||||
// fEqual = !fEqual; | // fEqual = !fEqual; | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
stack.push_back(fEqual ? vchTrue : vchFalse); | stack.push_back(fEqual ? vchTrue : vchFalse); | ||||
if (opcode == OP_EQUALVERIFY) { | if (opcode == OP_EQUALVERIFY) { | ||||
if (fEqual) { | if (fEqual) { | ||||
popstack(stack); | popstack(stack); | ||||
} else { | } else { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_EQUALVERIFY); | ScriptError::EQUALVERIFY); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
// | // | ||||
// Numeric | // Numeric | ||||
// | // | ||||
case OP_1ADD: | case OP_1ADD: | ||||
case OP_1SUB: | case OP_1SUB: | ||||
case OP_NEGATE: | case OP_NEGATE: | ||||
case OP_ABS: | case OP_ABS: | ||||
case OP_NOT: | case OP_NOT: | ||||
case OP_0NOTEQUAL: { | case OP_0NOTEQUAL: { | ||||
// (in -- out) | // (in -- out) | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
CScriptNum bn(stacktop(-1), fRequireMinimal); | CScriptNum bn(stacktop(-1), fRequireMinimal); | ||||
switch (opcode) { | switch (opcode) { | ||||
case OP_1ADD: | case OP_1ADD: | ||||
bn += bnOne; | bn += bnOne; | ||||
break; | break; | ||||
case OP_1SUB: | case OP_1SUB: | ||||
bn -= bnOne; | bn -= bnOne; | ||||
Show All 33 Lines | try { | ||||
case OP_GREATERTHAN: | case OP_GREATERTHAN: | ||||
case OP_LESSTHANOREQUAL: | case OP_LESSTHANOREQUAL: | ||||
case OP_GREATERTHANOREQUAL: | case OP_GREATERTHANOREQUAL: | ||||
case OP_MIN: | case OP_MIN: | ||||
case OP_MAX: { | case OP_MAX: { | ||||
// (x1 x2 -- out) | // (x1 x2 -- out) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
CScriptNum bn1(stacktop(-2), fRequireMinimal); | CScriptNum bn1(stacktop(-2), fRequireMinimal); | ||||
CScriptNum bn2(stacktop(-1), fRequireMinimal); | CScriptNum bn2(stacktop(-1), fRequireMinimal); | ||||
CScriptNum bn(0); | CScriptNum bn(0); | ||||
switch (opcode) { | switch (opcode) { | ||||
case OP_ADD: | case OP_ADD: | ||||
bn = bn1 + bn2; | bn = bn1 + bn2; | ||||
break; | break; | ||||
case OP_SUB: | case OP_SUB: | ||||
bn = bn1 - bn2; | bn = bn1 - bn2; | ||||
break; | break; | ||||
case OP_DIV: | case OP_DIV: | ||||
// denominator must not be 0 | // denominator must not be 0 | ||||
if (bn2 == 0) { | if (bn2 == 0) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_DIV_BY_ZERO); | ScriptError::DIV_BY_ZERO); | ||||
} | } | ||||
bn = bn1 / bn2; | bn = bn1 / bn2; | ||||
break; | break; | ||||
case OP_MOD: | case OP_MOD: | ||||
// divisor must not be 0 | // divisor must not be 0 | ||||
if (bn2 == 0) { | if (bn2 == 0) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_MOD_BY_ZERO); | ScriptError::MOD_BY_ZERO); | ||||
} | } | ||||
bn = bn1 % bn2; | bn = bn1 % bn2; | ||||
break; | break; | ||||
case OP_BOOLAND: | case OP_BOOLAND: | ||||
bn = (bn1 != bnZero && bn2 != bnZero); | bn = (bn1 != bnZero && bn2 != bnZero); | ||||
break; | break; | ||||
case OP_BOOLOR: | case OP_BOOLOR: | ||||
Show All 34 Lines | try { | ||||
popstack(stack); | popstack(stack); | ||||
stack.push_back(bn.getvch()); | stack.push_back(bn.getvch()); | ||||
if (opcode == OP_NUMEQUALVERIFY) { | if (opcode == OP_NUMEQUALVERIFY) { | ||||
if (CastToBool(stacktop(-1))) { | if (CastToBool(stacktop(-1))) { | ||||
popstack(stack); | popstack(stack); | ||||
} else { | } else { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_NUMEQUALVERIFY); | ScriptError::NUMEQUALVERIFY); | ||||
} | } | ||||
} | } | ||||
} break; | } break; | ||||
case OP_WITHIN: { | case OP_WITHIN: { | ||||
// (x min max -- out) | // (x min max -- out) | ||||
if (stack.size() < 3) { | if (stack.size() < 3) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
CScriptNum bn1(stacktop(-3), fRequireMinimal); | CScriptNum bn1(stacktop(-3), fRequireMinimal); | ||||
CScriptNum bn2(stacktop(-2), fRequireMinimal); | CScriptNum bn2(stacktop(-2), fRequireMinimal); | ||||
CScriptNum bn3(stacktop(-1), fRequireMinimal); | CScriptNum bn3(stacktop(-1), fRequireMinimal); | ||||
bool fValue = (bn2 <= bn1 && bn1 < bn3); | bool fValue = (bn2 <= bn1 && bn1 < bn3); | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
stack.push_back(fValue ? vchTrue : vchFalse); | stack.push_back(fValue ? vchTrue : vchFalse); | ||||
} break; | } break; | ||||
// | // | ||||
// Crypto | // Crypto | ||||
// | // | ||||
case OP_RIPEMD160: | case OP_RIPEMD160: | ||||
case OP_SHA1: | case OP_SHA1: | ||||
case OP_SHA256: | case OP_SHA256: | ||||
case OP_HASH160: | case OP_HASH160: | ||||
case OP_HASH256: { | case OP_HASH256: { | ||||
// (in -- hash) | // (in -- hash) | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &vch = stacktop(-1); | valtype &vch = stacktop(-1); | ||||
valtype vchHash((opcode == OP_RIPEMD160 || | valtype vchHash((opcode == OP_RIPEMD160 || | ||||
opcode == OP_SHA1 || | opcode == OP_SHA1 || | ||||
opcode == OP_HASH160) | opcode == OP_HASH160) | ||||
? 20 | ? 20 | ||||
: 32); | : 32); | ||||
if (opcode == OP_RIPEMD160) { | if (opcode == OP_RIPEMD160) { | ||||
Show All 26 Lines | try { | ||||
pbegincodehash = pc; | pbegincodehash = pc; | ||||
} break; | } break; | ||||
case OP_CHECKSIG: | case OP_CHECKSIG: | ||||
case OP_CHECKSIGVERIFY: { | case OP_CHECKSIGVERIFY: { | ||||
// (sig pubkey -- bool) | // (sig pubkey -- bool) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &vchSig = stacktop(-2); | valtype &vchSig = stacktop(-2); | ||||
valtype &vchPubKey = stacktop(-1); | valtype &vchPubKey = stacktop(-1); | ||||
if (!CheckTransactionSignatureEncoding(vchSig, flags, | if (!CheckTransactionSignatureEncoding(vchSig, flags, | ||||
serror) || | serror) || | ||||
!CheckPubKeyEncoding(vchPubKey, flags, serror)) { | !CheckPubKeyEncoding(vchPubKey, flags, serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
// 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 | ||||
CleanupScriptCode(scriptCode, vchSig, flags); | CleanupScriptCode(scriptCode, vchSig, flags); | ||||
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, | bool fSuccess = checker.CheckSig(vchSig, vchPubKey, | ||||
scriptCode, flags); | scriptCode, flags); | ||||
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | ||||
vchSig.size()) { | vchSig.size()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); | return set_error(serror, ScriptError::SIG_NULLFAIL); | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
stack.push_back(fSuccess ? vchTrue : vchFalse); | stack.push_back(fSuccess ? vchTrue : vchFalse); | ||||
if (opcode == OP_CHECKSIGVERIFY) { | if (opcode == OP_CHECKSIGVERIFY) { | ||||
if (fSuccess) { | if (fSuccess) { | ||||
popstack(stack); | popstack(stack); | ||||
} else { | } else { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_CHECKSIGVERIFY); | ScriptError::CHECKSIGVERIFY); | ||||
} | } | ||||
} | } | ||||
} break; | } break; | ||||
case OP_CHECKDATASIG: | case OP_CHECKDATASIG: | ||||
case OP_CHECKDATASIGVERIFY: { | case OP_CHECKDATASIGVERIFY: { | ||||
// (sig message pubkey -- bool) | // (sig message pubkey -- bool) | ||||
if (stack.size() < 3) { | if (stack.size() < 3) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &vchSig = stacktop(-3); | valtype &vchSig = stacktop(-3); | ||||
valtype &vchMessage = stacktop(-2); | valtype &vchMessage = stacktop(-2); | ||||
valtype &vchPubKey = stacktop(-1); | valtype &vchPubKey = stacktop(-1); | ||||
if (!CheckDataSignatureEncoding(vchSig, flags, | if (!CheckDataSignatureEncoding(vchSig, flags, | ||||
serror) || | serror) || | ||||
Show All 9 Lines | try { | ||||
.Write(vchMessage.data(), vchMessage.size()) | .Write(vchMessage.data(), vchMessage.size()) | ||||
.Finalize(vchHash.data()); | .Finalize(vchHash.data()); | ||||
fSuccess = checker.VerifySignature( | fSuccess = checker.VerifySignature( | ||||
vchSig, CPubKey(vchPubKey), uint256(vchHash)); | vchSig, CPubKey(vchPubKey), uint256(vchHash)); | ||||
} | } | ||||
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | ||||
vchSig.size()) { | vchSig.size()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); | return set_error(serror, ScriptError::SIG_NULLFAIL); | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
stack.push_back(fSuccess ? vchTrue : vchFalse); | stack.push_back(fSuccess ? vchTrue : vchFalse); | ||||
if (opcode == OP_CHECKDATASIGVERIFY) { | if (opcode == OP_CHECKDATASIGVERIFY) { | ||||
if (fSuccess) { | if (fSuccess) { | ||||
popstack(stack); | popstack(stack); | ||||
} else { | } else { | ||||
return set_error(serror, | return set_error( | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | serror, ScriptError::CHECKDATASIGVERIFY); | ||||
} | } | ||||
} | } | ||||
} break; | } break; | ||||
case OP_CHECKMULTISIG: | case OP_CHECKMULTISIG: | ||||
case OP_CHECKMULTISIGVERIFY: { | case OP_CHECKMULTISIGVERIFY: { | ||||
// ([dummy] [sig ...] num_of_signatures [pubkey ...] | // ([dummy] [sig ...] num_of_signatures [pubkey ...] | ||||
// num_of_pubkeys -- bool) | // num_of_pubkeys -- bool) | ||||
const size_t idxKeyCount = 1; | const size_t idxKeyCount = 1; | ||||
if (stack.size() < idxKeyCount) { | if (stack.size() < idxKeyCount) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
const int nKeysCount = | const int nKeysCount = | ||||
CScriptNum(stacktop(-idxKeyCount), fRequireMinimal) | CScriptNum(stacktop(-idxKeyCount), 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, ScriptError::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, ScriptError::OP_COUNT); | ||||
} | } | ||||
// stack depth of the top pubkey | // stack depth of the top pubkey | ||||
const size_t idxTopKey = idxKeyCount + 1; | const size_t idxTopKey = idxKeyCount + 1; | ||||
// stack depth of nSigsCount | // stack depth of nSigsCount | ||||
const size_t idxSigCount = idxTopKey + nKeysCount; | const size_t idxSigCount = idxTopKey + nKeysCount; | ||||
if (stack.size() < idxSigCount) { | if (stack.size() < idxSigCount) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
const int nSigsCount = | const int nSigsCount = | ||||
CScriptNum(stacktop(-idxSigCount), fRequireMinimal) | CScriptNum(stacktop(-idxSigCount), 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, ScriptError::SIG_COUNT); | ||||
} | } | ||||
// stack depth of the top signature | // stack depth of the top signature | ||||
const size_t idxTopSig = idxSigCount + 1; | const size_t idxTopSig = idxSigCount + 1; | ||||
// stack depth of the dummy element | // stack depth of the dummy element | ||||
const size_t idxDummy = idxTopSig + nSigsCount; | const size_t idxDummy = idxTopSig + nSigsCount; | ||||
if (stack.size() < idxDummy) { | if (stack.size() < idxDummy) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
// A bug causes CHECKMULTISIG to consume one extra | // A bug causes CHECKMULTISIG to consume one extra | ||||
// argument whose contents were not checked in any way. | // argument whose contents were not checked in any way. | ||||
// | // | ||||
// Unfortunately this is a potential source of | // Unfortunately this is a potential source of | ||||
// mutability, so optionally verify it is exactly equal | // mutability, so optionally verify it is exactly equal | ||||
// to zero. | // to zero. | ||||
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && | if ((flags & SCRIPT_VERIFY_NULLDUMMY) && | ||||
stacktop(-idxDummy).size()) { | stacktop(-idxDummy).size()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); | return set_error(serror, | ||||
ScriptError::SIG_NULLDUMMY); | |||||
} | } | ||||
// 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++) { | ||||
Show All 40 Lines | try { | ||||
} | } | ||||
// 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)) { | ||||
for (int i = 0; i < nSigsCount; i++) { | for (int i = 0; i < nSigsCount; i++) { | ||||
if (stacktop(-idxTopSig - i).size()) { | if (stacktop(-idxTopSig - i).size()) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Clean up stack of all arguments | // Clean up stack of all arguments | ||||
for (size_t i = 0; i < idxDummy; i++) { | for (size_t i = 0; i < idxDummy; i++) { | ||||
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 { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); | serror, ScriptError::CHECKMULTISIGVERIFY); | ||||
} | } | ||||
} | } | ||||
} break; | } break; | ||||
// | // | ||||
// Byte string operations | // Byte string operations | ||||
// | // | ||||
case OP_CAT: { | case OP_CAT: { | ||||
// (x1 x2 -- out) | // (x1 x2 -- out) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &vch1 = stacktop(-2); | valtype &vch1 = stacktop(-2); | ||||
valtype &vch2 = stacktop(-1); | valtype &vch2 = stacktop(-1); | ||||
if (vch1.size() + vch2.size() > | if (vch1.size() + vch2.size() > | ||||
MAX_SCRIPT_ELEMENT_SIZE) { | MAX_SCRIPT_ELEMENT_SIZE) { | ||||
return set_error(serror, SCRIPT_ERR_PUSH_SIZE); | return set_error(serror, ScriptError::PUSH_SIZE); | ||||
} | } | ||||
vch1.insert(vch1.end(), vch2.begin(), vch2.end()); | vch1.insert(vch1.end(), vch2.begin(), vch2.end()); | ||||
popstack(stack); | popstack(stack); | ||||
} break; | } break; | ||||
case OP_SPLIT: { | case OP_SPLIT: { | ||||
// (in position -- x1 x2) | // (in position -- x1 x2) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
const valtype &data = stacktop(-2); | const valtype &data = stacktop(-2); | ||||
// Make sure the split point is appropriate. | // Make sure the split point is appropriate. | ||||
uint64_t position = | uint64_t position = | ||||
CScriptNum(stacktop(-1), fRequireMinimal).getint(); | CScriptNum(stacktop(-1), fRequireMinimal).getint(); | ||||
if (position > data.size()) { | if (position > data.size()) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_INVALID_SPLIT_RANGE); | ScriptError::INVALID_SPLIT_RANGE); | ||||
} | } | ||||
// Prepare the results in their own buffer as `data` | // Prepare the results in their own buffer as `data` | ||||
// will be invalidated. | // will be invalidated. | ||||
valtype n1(data.begin(), data.begin() + position); | valtype n1(data.begin(), data.begin() + position); | ||||
valtype n2(data.begin() + position, data.end()); | valtype n2(data.begin() + position, data.end()); | ||||
// Replace existing stack values by the new values. | // Replace existing stack values by the new values. | ||||
stacktop(-2) = std::move(n1); | stacktop(-2) = std::move(n1); | ||||
stacktop(-1) = std::move(n2); | stacktop(-1) = std::move(n2); | ||||
} break; | } break; | ||||
// | // | ||||
// Conversion operations | // Conversion operations | ||||
// | // | ||||
case OP_NUM2BIN: { | case OP_NUM2BIN: { | ||||
// (in size -- out) | // (in size -- out) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
uint64_t size = | uint64_t size = | ||||
CScriptNum(stacktop(-1), fRequireMinimal).getint(); | CScriptNum(stacktop(-1), fRequireMinimal).getint(); | ||||
if (size > MAX_SCRIPT_ELEMENT_SIZE) { | if (size > MAX_SCRIPT_ELEMENT_SIZE) { | ||||
return set_error(serror, SCRIPT_ERR_PUSH_SIZE); | return set_error(serror, ScriptError::PUSH_SIZE); | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
valtype &rawnum = stacktop(-1); | valtype &rawnum = stacktop(-1); | ||||
// Try to see if we can fit that number in the number of | // Try to see if we can fit that number in the number of | ||||
// byte requested. | // byte requested. | ||||
CScriptNum::MinimallyEncode(rawnum); | CScriptNum::MinimallyEncode(rawnum); | ||||
if (rawnum.size() > size) { | if (rawnum.size() > size) { | ||||
// We definitively cannot. | // We definitively cannot. | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_IMPOSSIBLE_ENCODING); | ScriptError::IMPOSSIBLE_ENCODING); | ||||
} | } | ||||
// We already have an element of the right size, we | // We already have an element of the right size, we | ||||
// don't need to do anything. | // don't need to do anything. | ||||
if (rawnum.size() == size) { | if (rawnum.size() == size) { | ||||
break; | break; | ||||
} | } | ||||
Show All 10 Lines | |||||
rawnum.push_back(signbit); | rawnum.push_back(signbit); | ||||
} break; | } break; | ||||
case OP_BIN2NUM: { | case OP_BIN2NUM: { | ||||
// (in -- out) | // (in -- out) | ||||
if (stack.size() < 1) { | if (stack.size() < 1) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, ScriptError::INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &n = stacktop(-1); | valtype &n = stacktop(-1); | ||||
CScriptNum::MinimallyEncode(n); | CScriptNum::MinimallyEncode(n); | ||||
// The resulting number must be a valid number. | // The resulting number must be a valid number. | ||||
if (!CScriptNum::IsMinimallyEncoded(n)) { | if (!CScriptNum::IsMinimallyEncoded(n)) { | ||||
return set_error(serror, | return set_error(serror, | ||||
SCRIPT_ERR_INVALID_NUMBER_RANGE); | ScriptError::INVALID_NUMBER_RANGE); | ||||
} | } | ||||
} break; | } break; | ||||
default: | default: | ||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE); | return set_error(serror, ScriptError::BAD_OPCODE); | ||||
} | } | ||||
} | } | ||||
// Size limits | // Size limits | ||||
if (stack.size() + altstack.size() > MAX_STACK_SIZE) { | if (stack.size() + altstack.size() > MAX_STACK_SIZE) { | ||||
return set_error(serror, SCRIPT_ERR_STACK_SIZE); | return set_error(serror, ScriptError::STACK_SIZE); | ||||
} | } | ||||
} | } | ||||
} catch (...) { | } catch (...) { | ||||
return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); | return set_error(serror, ScriptError::UNKNOWN); | ||||
} | } | ||||
if (!vfExec.empty()) { | if (!vfExec.empty()) { | ||||
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); | return set_error(serror, ScriptError::UNBALANCED_CONDITIONAL); | ||||
} | } | ||||
return set_success(serror); | return set_success(serror); | ||||
} | } | ||||
namespace { | namespace { | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 348 Lines • ▼ Show 20 Lines | bool TransactionSignatureChecker::CheckSequence( | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
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) { | ||||
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); | 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, SCRIPT_ERR_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, 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, 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, ScriptError::EVAL_FALSE); | ||||
} | } | ||||
if (CastToBool(stack.back()) == false) { | if (CastToBool(stack.back()) == false) { | ||||
return set_error(serror, SCRIPT_ERR_EVAL_FALSE); | return set_error(serror, ScriptError::EVAL_FALSE); | ||||
} | } | ||||
// Additional validation for spend-to-script-hash transactions: | // Additional validation for spend-to-script-hash transactions: | ||||
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { | if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { | ||||
// scriptSig must be literals-only or validation fails | // scriptSig must be literals-only or validation fails | ||||
if (!scriptSig.IsPushOnly()) { | if (!scriptSig.IsPushOnly()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); | return set_error(serror, ScriptError::SIG_PUSHONLY); | ||||
} | } | ||||
// Restore stack. | // Restore stack. | ||||
swap(stack, stackCopy); | swap(stack, stackCopy); | ||||
// 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. | ||||
Show All 11 Lines | if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { | ||||
return set_success(serror); | return set_success(serror); | ||||
} | } | ||||
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, ScriptError::EVAL_FALSE); | ||||
} | } | ||||
if (!CastToBool(stack.back())) { | if (!CastToBool(stack.back())) { | ||||
return set_error(serror, SCRIPT_ERR_EVAL_FALSE); | return set_error(serror, ScriptError::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) { | if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { | ||||
// 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, ScriptError::CLEANSTACK); | ||||
} | } | ||||
} | } | ||||
return set_success(serror); | return set_success(serror); | ||||
} | } |