Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
| Show All 23 Lines | for (size_t i = 0; i < vch.size(); i++) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| inline uint8_t make_rshift_mask(size_t n) { | |||||
| static uint8_t mask[] = {0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80}; | |||||
| return mask[n]; | |||||
| } | |||||
| inline uint8_t make_lshift_mask(size_t n) { | |||||
| static uint8_t mask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01}; | |||||
| return mask[n]; | |||||
| } | |||||
| static valtype RShift(const valtype &x, int n) { | |||||
| int bit_shift_left = n % 8; | |||||
| int byte_shift_left = n / 8; | |||||
| uint8_t mask = make_rshift_mask(bit_shift_left); | |||||
| uint8_t overflow_mask = ~mask; | |||||
| valtype result(x.size(), 0x00); | |||||
| for (int i = x.size() - 1; i >= 0; i--) { | |||||
| int k = i - byte_shift_left; | |||||
| if (k >= 0) { | |||||
| uint8_t val = (x[i] & mask); | |||||
| val >>= bit_shift_left; | |||||
| result[k] |= val; | |||||
| } | |||||
| if (k - 1 >= 0) { | |||||
| uint8_t carryval = (x[i] & overflow_mask); | |||||
| carryval <<= 8 - bit_shift_left; | |||||
| result[k - 1] |= carryval; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| static valtype LShift(const valtype &x, int n) { | |||||
| int bit_shift_right = n % 8; | |||||
| int byte_shift_right = n / 8; | |||||
| uint8_t mask = make_lshift_mask(bit_shift_right); | |||||
| uint8_t overflow_mask = ~mask; | |||||
| valtype result(x.size(), 0x00); | |||||
| for (int i = 0; i < (int)x.size(); i++) { | |||||
| int k = i + byte_shift_right; | |||||
| if (k < (int)x.size()) { | |||||
| uint8_t val = (x[i] & mask); | |||||
| val <<= bit_shift_right; | |||||
| result[k] |= val; | |||||
| } | |||||
| if (k + 1 < (int)x.size()) { | |||||
| uint8_t carryval = (x[i] & overflow_mask); | |||||
| carryval >>= 8 - bit_shift_right; | |||||
| result[k + 1] |= carryval; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| /** | /** | ||||
| * Script is a stack machine (like Forth) that evaluates a predicate | * Script is a stack machine (like Forth) that evaluates a predicate | ||||
| * returning a bool indicating valid or not. There are no loops. | * returning a bool indicating valid or not. There are no loops. | ||||
| */ | */ | ||||
| #define stacktop(i) (stack.at(stack.size() + (i))) | #define stacktop(i) (stack.at(stack.size() + (i))) | ||||
| #define altstacktop(i) (altstack.at(altstack.size() + (i))) | #define altstacktop(i) (altstack.at(altstack.size() + (i))) | ||||
| static inline void popstack(std::vector<valtype> &stack) { | static inline void popstack(std::vector<valtype> &stack) { | ||||
| if (stack.empty()) { | if (stack.empty()) { | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (fEnabledOpCodesMagnetic) { | ||||
| switch (opcode) { | switch (opcode) { | ||||
| case OP_INVERT: | case OP_INVERT: | ||||
| return true; | return true; | ||||
| case OP_MUL: | case OP_MUL: | ||||
| return true; | return true; | ||||
| case OP_LSHIFT: | case OP_LSHIFT: | ||||
| return true; | return false; | ||||
| case OP_RSHIFT: | case OP_RSHIFT: | ||||
| return true; | return false; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| switch (opcode) { | switch (opcode) { | ||||
| case OP_INVERT: | case OP_INVERT: | ||||
| ▲ Show 20 Lines • Show All 1,120 Lines • ▼ Show 20 Lines | |||||
| // 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); | SCRIPT_ERR_INVALID_NUMBER_RANGE); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case OP_LSHIFT: { | |||||
| // (x n -- out) | |||||
| if (stack.size() < 2) { | |||||
| return set_error( | |||||
| serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
| } | |||||
| const valtype x = stacktop(-2); | |||||
| CScriptNum n(stacktop(-1), fRequireMinimal); | |||||
| if (n < 0) { | |||||
| return set_error(serror, | |||||
| SCRIPT_ERR_INVALID_NUMBER_RANGE); | |||||
| } | |||||
| popstack(stack); | |||||
| popstack(stack); | |||||
| stack.push_back(LShift(x, n.getint())); | |||||
| } break; | |||||
| case OP_RSHIFT: { | |||||
| // (x n -- out) | |||||
| if (stack.size() < 2) { | |||||
| return set_error( | |||||
| serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
| } | |||||
| const valtype x = stacktop(-2); | |||||
| CScriptNum n(stacktop(-1), fRequireMinimal); | |||||
| if (n < 0) { | |||||
| return set_error(serror, | |||||
| SCRIPT_ERR_INVALID_NUMBER_RANGE); | |||||
| } | |||||
| popstack(stack); | |||||
| popstack(stack); | |||||
| stack.push_back(RShift(x, n.getint())); | |||||
| } 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 445 Lines • Show Last 20 Lines | |||||