Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 328 Lines • ▼ Show 20 Lines | try { | ||||
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, SCRIPT_ERR_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, SCRIPT_ERR_OP_COUNT); | ||||
} | } | ||||
if (opcode == OP_INVERT || opcode == OP_2MUL || opcode == OP_2DIV || | |||||
opcode == OP_MUL || opcode == OP_LSHIFT || opcode == OP_RSHIFT) { | if (opcode == OP_CAT || opcode == OP_SUBSTR || opcode == OP_LEFT || | ||||
opcode == OP_RIGHT || opcode == OP_INVERT || opcode == OP_2MUL || | |||||
opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV || | |||||
opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) { | |||||
// Disabled opcodes. | // Disabled opcodes. | ||||
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); | return set_error(serror, SCRIPT_ERR_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, SCRIPT_ERR_MINIMALDATA); | ||||
▲ Show 20 Lines • Show All 432 Lines • ▼ Show 20 Lines | try { | ||||
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, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype& vch1 = stacktop(-2); | valtype& vch1 = stacktop(-2); | ||||
valtype& vch2 = stacktop(-1); | valtype& vch2 = stacktop(-1); | ||||
// throw error if inputs are not the same size | // throw error if inputs are not the same size | ||||
if (vch1.size() != vch2.size()) { | if (vch1.size() != vch2.size()) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_BITWISE_OPERATION); | serror, SCRIPT_ERR_INVALID_BITWISE_OPERATION); | ||||
} | } | ||||
if (opcode == OP_AND) { | switch (opcode) { | ||||
for (size_t i = 0; i < vch1.size(); i++) | case OP_AND: | ||||
for (size_t i = 0; i < vch1.size(); i++) { | |||||
vch1[i] &= vch2[i]; | vch1[i] &= vch2[i]; | ||||
} | } | ||||
else if (opcode == OP_OR) { | break; | ||||
for (size_t i = 0; i < vch1.size(); i++) | case OP_OR: | ||||
for (size_t i = 0; i < vch1.size(); i++) { | |||||
vch1[i] |= vch2[i]; | vch1[i] |= vch2[i]; | ||||
} | } | ||||
else if (opcode == OP_XOR) { | break; | ||||
for (size_t i = 0; i < vch1.size(); i++) | case OP_XOR: | ||||
for (size_t i = 0; i < vch1.size(); i++) { | |||||
vch1[i] ^= vch2[i]; | vch1[i] ^= vch2[i]; | ||||
} | } | ||||
stack.pop_back(); | |||||
} | |||||
break; | break; | ||||
default: //avoid enumeration value not handled in switch compiler warning | |||||
break; | |||||
} | |||||
stack.pop_back(); | |||||
} break; | |||||
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( | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | try { | ||||
break; | break; | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
stack.push_back(bn.getvch()); | stack.push_back(bn.getvch()); | ||||
} break; | } break; | ||||
case OP_ADD: | case OP_ADD: | ||||
case OP_SUB: | case OP_SUB: | ||||
case OP_DIV: | |||||
case OP_MOD: | |||||
case OP_BOOLAND: | case OP_BOOLAND: | ||||
case OP_BOOLOR: | case OP_BOOLOR: | ||||
case OP_NUMEQUAL: | case OP_NUMEQUAL: | ||||
case OP_NUMEQUALVERIFY: | case OP_NUMEQUALVERIFY: | ||||
case OP_NUMNOTEQUAL: | case OP_NUMNOTEQUAL: | ||||
case OP_LESSTHAN: | case OP_LESSTHAN: | ||||
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, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
// first two inputs must be minimally encoded numbers | |||||
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: | |||||
// bn2 must not be 0 | |||||
if (bn2 == 0) { | |||||
return set_error( | |||||
serror, SCRIPT_ERR_DIV_BY_ZERO); | |||||
} | |||||
bn = bn1 / bn2; | |||||
break; | |||||
case OP_MOD: | |||||
// 2nd operand must be positive | |||||
if (bn2 <= 0) { | |||||
return set_error( | |||||
serror, SCRIPT_ERR_MOD_BY_ZERO); | |||||
} | |||||
bn = bn1 % bn2; | |||||
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: | ||||
bn = (bn1 != bnZero || bn2 != bnZero); | bn = (bn1 != bnZero || bn2 != bnZero); | ||||
break; | break; | ||||
case OP_NUMEQUAL: | case OP_NUMEQUAL: | ||||
bn = (bn1 == bn2); | bn = (bn1 == bn2); | ||||
▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | try { | ||||
popstack(stack); | popstack(stack); | ||||
} else { | } else { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); | serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); | ||||
} | } | ||||
} | } | ||||
} break; | } break; | ||||
case OP_CAT: { | |||||
// (x1 x2 -- out) | |||||
if (stack.size() < 2) { | |||||
return set_error( | |||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
} | |||||
valtype& vch1 = stacktop(-2); | |||||
valtype& vch2 = stacktop(-1); | |||||
if (vch1.size() + vch2.size() > MAX_SCRIPT_ELEMENT_SIZE) { | |||||
return set_error(serror, SCRIPT_ERR_PUSH_SIZE); | |||||
} | |||||
vch1.insert(vch1.end(), vch2.begin(), vch2.end()); | |||||
stack.pop_back(); | |||||
} break; | |||||
case OP_SPLIT: { | |||||
// (in position -- x1 x2) | |||||
if (stack.size() < 2) { | |||||
return set_error( | |||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
} | |||||
valtype vch = stacktop(-2); | |||||
int64_t nPosition = CScriptNum(stacktop(-1), fRequireMinimal).getint(); | |||||
// if nPosition is less than 0 or is larger than the input then throw error | |||||
if (nPosition < 0 || static_cast<size_t>(nPosition) > vch.size()) { | |||||
return set_error( | |||||
serror, SCRIPT_ERR_INVALID_SPLIT_RANGE); | |||||
} | |||||
stack.pop_back(); | |||||
stack.pop_back(); | |||||
// initialize outputs | |||||
if (nPosition == 0) { | |||||
stack.push_back(valtype()); | |||||
stack.push_back(vch); | |||||
} | |||||
else if (static_cast<size_t>(nPosition) == vch.size()) { | |||||
stack.push_back(vch); | |||||
stack.push_back(valtype()); | |||||
} | |||||
else { | |||||
valtype vchOut1, vchOut2; | |||||
vchOut1.insert(vchOut1.end(), vch.begin(), vch.begin() + nPosition); | |||||
vchOut2.insert(vchOut2.end(), vch.begin() + nPosition, vch.end()); | |||||
stack.emplace_back(move(vchOut1)); | |||||
stack.emplace_back(move(vchOut2)); | |||||
} | |||||
} break; | |||||
case OP_BIN2NUM: { | |||||
// (in -- out) | |||||
if (stack.size() < 1) { | |||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
} | |||||
valtype bin=stacktop(-1); | |||||
std::reverse(bin.begin(),bin.end()); //be2le | |||||
CScriptNum num(bin, false); | |||||
if (num > (INT_MAX>>1) || num < (INT_MIN>>1)) | |||||
return set_error(serror, SCRIPT_ERR_INVALID_BIN2NUM_OPERATION); | |||||
stack.pop_back(); | |||||
stack.push_back(num.getvch()); | |||||
} break; | |||||
case OP_NUM2BIN: { | |||||
if (stack.size() < 2) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
CScriptNum bn(stacktop(-2), fRequireMinimal); | |||||
int64_t sz = CScriptNum(stacktop(-1), fRequireMinimal).getint(); | |||||
if (sz<1 || static_cast<uint64_t>(sz) > MAX_NUM2BIN_SIZE) | |||||
return set_error(serror, SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); | |||||
valtype v=bn.getvch(); //LE | |||||
if (static_cast<uint64_t>(sz) < v.size()) | |||||
return set_error(serror, SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); | |||||
valtype ans; | |||||
ans.reserve(sz); | |||||
bool neg{false}; | |||||
if (!v.empty()) { | |||||
neg=*v.rbegin()&0x80; | |||||
*v.rbegin()&=~0x80; //make it positive | |||||
} | |||||
size_t pad=sz-v.size(); | |||||
for (uint8_t i=0; i<pad; ++i) { | |||||
ans.push_back(0); | |||||
} | |||||
for (auto i=v.rbegin(); i!=v.rend(); ++i) ans.push_back(*i); | |||||
if (neg) *ans.begin()|=0x80; | |||||
stack.pop_back(); | |||||
stack.pop_back(); | |||||
stack.push_back(ans); | |||||
} break; | |||||
default: | default: | ||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE); | return set_error(serror, SCRIPT_ERR_BAD_OPCODE); | ||||
} | } | ||||
// Size limits | // Size limits | ||||
if (stack.size() + altstack.size() > 1000) { | if (stack.size() + altstack.size() > 1000) { | ||||
return set_error(serror, SCRIPT_ERR_STACK_SIZE); | return set_error(serror, SCRIPT_ERR_STACK_SIZE); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 437 Lines • Show Last 20 Lines |