Changeset View
Changeset View
Standalone View
Standalone View
src/test/monolith_opcodes.cpp
Show First 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | static void CheckAllBitwiseOpErrors(const stacktype &stack, | ||||
CheckOpError(stack, OP_XOR, expected_error); | CheckOpError(stack, OP_XOR, expected_error); | ||||
} | } | ||||
static void CheckOp(const valtype &a, const valtype &b, opcodetype op, | static void CheckOp(const valtype &a, const valtype &b, opcodetype op, | ||||
const valtype &expected) { | const valtype &expected) { | ||||
CheckTestResultForAllFlags({a, b}, CScript() << op, {expected}); | CheckTestResultForAllFlags({a, b}, CScript() << op, {expected}); | ||||
} | } | ||||
static valtype NegativeValtype(const valtype &v) { | |||||
valtype r(v); | |||||
r[r.size() - 1] |= 0x80; | |||||
return r; | |||||
} | |||||
deadalnix: This won't handle zero properly. An empty valtype should return a valtype with {0x80} when… | |||||
/** | /** | ||||
* Bitwise Opcodes | * Bitwise Opcodes | ||||
*/ | */ | ||||
static void RunTestForAllBitwiseOpcodes(const valtype &a, const valtype &b, | static void RunTestForAllBitwiseOpcodes(const valtype &a, const valtype &b, | ||||
const valtype &expected_and, | const valtype &expected_and, | ||||
const valtype &expected_or, | const valtype &expected_or, | ||||
const valtype &expected_xor) { | const valtype &expected_xor) { | ||||
// Bitwise ops are commutative, so we check both ways. | // Bitwise ops are commutative, so we check both ways. | ||||
▲ Show 20 Lines • Show All 381 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(type_conversion_test) { | ||||
CheckNum2BinError({{}, {0x09, 0x02}}, SCRIPT_ERR_PUSH_SIZE); | CheckNum2BinError({{}, {0x09, 0x02}}, SCRIPT_ERR_PUSH_SIZE); | ||||
// Check that the requested encoding is possible. | // Check that the requested encoding is possible. | ||||
CheckNum2BinError({{0xab, 0xcd, 0xef, 0x80}, {0x03}}, | CheckNum2BinError({{0xab, 0xcd, 0xef, 0x80}, {0x03}}, | ||||
SCRIPT_ERR_IMPOSSIBLE_ENCODING); | SCRIPT_ERR_IMPOSSIBLE_ENCODING); | ||||
} | } | ||||
/** | |||||
* Arithmetic Opcodes | |||||
*/ | |||||
static void CheckDiv(const valtype &a, const valtype &b, | |||||
const valtype &baseResult) { | |||||
CheckOp(a, b, OP_DIV, baseResult); | |||||
CheckOp(a, NegativeValtype(b), OP_DIV, NegativeValtype(baseResult)); | |||||
CheckOp(NegativeValtype(a), b, OP_DIV, NegativeValtype(baseResult)); | |||||
CheckOp(NegativeValtype(a), NegativeValtype(b), OP_DIV, baseResult); | |||||
} | |||||
static void CheckMod(const valtype &a, const valtype &b, | |||||
deadalnixUnsubmitted Done Inline ActionsI think you should really have one check function that take result for div and mod. This ensure by design that you all test cases for both. It's not a big deal to have too many tests cases for one or the other. deadalnix: I think you should really have one check function that take result for div and mod. This ensure… | |||||
const valtype &baseResult) { | |||||
CheckOp(a, b, OP_MOD, baseResult); | |||||
CheckOp(a, NegativeValtype(b), OP_MOD, baseResult); | |||||
CheckOp(NegativeValtype(a), b, OP_MOD, NegativeValtype(baseResult)); | |||||
CheckOp(NegativeValtype(a), NegativeValtype(b), OP_MOD, | |||||
NegativeValtype(baseResult)); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(div_opcode_tests) { | |||||
CheckOpError(stacktype{}, OP_DIV, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
CheckOpError(stacktype{{}}, OP_DIV, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
// CheckOps not valid numbers | |||||
CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, | |||||
{0x01, 0x02, 0x03, 0x04, 0x05}}, | |||||
OP_DIV, SCRIPT_ERR_UNKNOWN_ERROR); | |||||
CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, {0x01}}, OP_DIV, | |||||
SCRIPT_ERR_UNKNOWN_ERROR); | |||||
CheckOpError(stacktype{{0x01, 0x05}, {0x01, 0x02, 0x03, 0x04, 0x05}}, | |||||
OP_DIV, SCRIPT_ERR_UNKNOWN_ERROR); | |||||
// b == 0 ; b is equal to any type of zero | |||||
CheckOpError(stacktype{{0x01, 0x05}, {}}, OP_DIV, SCRIPT_ERR_DIV_BY_ZERO); | |||||
CheckOpError(stacktype{{}, {}}, OP_DIV, SCRIPT_ERR_DIV_BY_ZERO); | |||||
for (uint32_t flags : flagset) { | |||||
if (flags & SCRIPT_VERIFY_MINIMALDATA) { | |||||
CheckError(flags, stacktype{{}, {0x00}}, CScript() << OP_DIV, | |||||
SCRIPT_ERR_UNKNOWN_ERROR); | |||||
CheckError(flags, stacktype{{}, {0x00, 0x00}}, CScript() << OP_DIV, | |||||
SCRIPT_ERR_UNKNOWN_ERROR); | |||||
} else { | |||||
CheckError(flags, stacktype{{}, {0x00}}, CScript() << OP_DIV, | |||||
SCRIPT_ERR_DIV_BY_ZERO); | |||||
CheckError(flags, stacktype{{}, {0x00, 0x00}}, CScript() << OP_DIV, | |||||
SCRIPT_ERR_DIV_BY_ZERO); | |||||
} | |||||
} | |||||
// 185377af/85f41b01 =-4 | |||||
// 185377af/00001b01 =E69D | |||||
CheckOp(valtype{0xaf, 0x77, 0x53, 0x18}, valtype{0x01, 0x1b, 0xf4, 0x85}, | |||||
OP_DIV, valtype{0x84}); | |||||
CheckOp(valtype{0xaf, 0x77, 0x53, 0x18}, valtype{0x01, 0x1b}, OP_DIV, | |||||
valtype{0x9D, 0xE6, 0x00}); | |||||
// Identity: 15/1 = 15 (and negative operands) | |||||
CheckDiv(valtype{0x0f}, valtype{0x01}, valtype{0x0f}); | |||||
// 15/4 = 3 (and negative operands) | |||||
CheckDiv(valtype{0x0f}, valtype{0x04}, valtype{0x03}); | |||||
// 15000/4 = 3750 (and negative operands) | |||||
CheckDiv(valtype{0x98, 0x3a}, valtype{0x04}, valtype{0xa6, 0x0e}); | |||||
// 15000/4000 = 3 (and negative operands) | |||||
CheckDiv(valtype{0x98, 0x3a}, valtype{0xa0, 0x0f}, valtype{0x03}); | |||||
// 15000000/4000 = 3750 (and negative operands) | |||||
CheckDiv(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0xa0, 0x0f}, | |||||
valtype{0xa6, 0x0e}); | |||||
// 15000000/4 = 3750000 (and negative operands) | |||||
CheckDiv(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0x04}, | |||||
valtype{0x70, 0x38, 0x39}); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(mod_opcode_tests) { | |||||
CheckOpError(stacktype{}, OP_MOD, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
CheckOpError(stacktype{{}}, OP_MOD, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
// test not valid numbers | |||||
CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, | |||||
{0x01, 0x02, 0x03, 0x04, 0x05}}, | |||||
OP_MOD, SCRIPT_ERR_UNKNOWN_ERROR); | |||||
CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, {0x01}}, OP_MOD, | |||||
SCRIPT_ERR_UNKNOWN_ERROR); | |||||
CheckOpError(stacktype{{0x01, 0x05}, {0x01, 0x02, 0x03, 0x04, 0x05}}, | |||||
OP_MOD, SCRIPT_ERR_UNKNOWN_ERROR); | |||||
// mod by 0 | |||||
CheckOpError(stacktype{{0x01, 0x05}, {}}, OP_MOD, SCRIPT_ERR_MOD_BY_ZERO); | |||||
// 56488123 % 321 = 148 (and negative operands) | |||||
// 56488123 % 3 = 1 (and negative operands) | |||||
// 56488123 % 564881230 = 56488123 (and negative operands) | |||||
CheckMod(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x41, 0x01}, | |||||
valtype{0x94, 0x00}); | |||||
CheckMod(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x03}, valtype{0x01}); | |||||
CheckMod(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x4e, 0x67, 0xab, 0x21}, | |||||
valtype{0xbb, 0xf0, 0x5d, 0x03}); | |||||
// Identity: a % b % b = a % b | |||||
for (uint8_t a = OP_1; a <= OP_16; a++) { | |||||
for (uint8_t b = OP_1; b <= OP_16; b++) { | |||||
CheckTestResultForAllFlags(stacktype{{a}, {b}}, | |||||
CScript() << OP_MOD << b << OP_MOD << a | |||||
<< b << OP_MOD << OP_EQUAL, | |||||
stacktype{{0x01}}); | |||||
} | |||||
} | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |
This won't handle zero properly. An empty valtype should return a valtype with {0x80} when negated.
This also calls for a test for NegativeValtype.