Changeset View
Changeset View
Standalone View
Standalone View
src/test/monolith_opcodes.cpp
Show First 20 Lines • Show All 82 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); | |||||
if (r.size() > 0) { | |||||
int msbIndex = r.size() - 1; | |||||
if (r[msbIndex] & 0x80) { | |||||
r[msbIndex] &= ~0x80; | |||||
} else { | |||||
r[msbIndex] |= 0x80; | |||||
} | |||||
deadalnixUnsubmitted Done Inline Actionsdeadalnix: r[r.size() - 1] ^= 0x80; | |||||
} | |||||
CScriptNum::MinimallyEncode(r); | |||||
return r; | |||||
} | |||||
BOOST_AUTO_TEST_CASE(negative_valtype_test) { | |||||
// Test zero values | |||||
BOOST_CHECK(valtype{} == NegativeValtype(valtype{})); | |||||
BOOST_CHECK(valtype{} == NegativeValtype(valtype{0x00})); | |||||
BOOST_CHECK(valtype{} == NegativeValtype(valtype{0x80})); | |||||
BOOST_CHECK(valtype{} == NegativeValtype(valtype{0x00, 0x00})); | |||||
BOOST_CHECK(valtype{} == NegativeValtype(valtype{0x00, 0x80})); | |||||
deadalnixUnsubmitted Done Inline ActionsYou don't need to say valtype everywhere if you put the function call on the left. deadalnix: You don't need to say valtype everywhere if you put the function call on the left. | |||||
// Non-zero values | |||||
BOOST_CHECK((valtype{0x81} == NegativeValtype(valtype{0x01}))); | |||||
BOOST_CHECK((valtype{0x01} == NegativeValtype(valtype{0x81}))); | |||||
BOOST_CHECK((valtype{0x02, 0x81} == NegativeValtype(valtype{0x02, 0x01}))); | |||||
BOOST_CHECK((valtype{0x02, 0x01} == NegativeValtype(valtype{0x02, 0x81}))); | |||||
BOOST_CHECK((valtype{0xff, 0x02, 0x81} == | |||||
NegativeValtype(valtype{0xff, 0x02, 0x01}))); | |||||
BOOST_CHECK((valtype{0xff, 0x02, 0x01} == | |||||
NegativeValtype(valtype{0xff, 0x02, 0x81}))); | |||||
BOOST_CHECK((valtype{0xff, 0xff, 0x02, 0x81} == | |||||
NegativeValtype(valtype{0xff, 0xff, 0x02, 0x01}))); | |||||
BOOST_CHECK((valtype{0xff, 0xff, 0x02, 0x01} == | |||||
NegativeValtype(valtype{0xff, 0xff, 0x02, 0x81}))); | |||||
// Should not be overly-minimized | |||||
BOOST_CHECK((valtype{0xff, 0x00} == NegativeValtype(valtype{0xff, 0x80}))); | |||||
BOOST_CHECK((valtype{0xff, 0x80} == NegativeValtype(valtype{0xff, 0x00}))); | |||||
} | |||||
deadalnixUnsubmitted Done Inline Actionsdeadalnix: likestamp | |||||
/** | /** | ||||
* 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 CheckDivMod(const valtype &a, const valtype &b, | |||||
const valtype &divExpected, | |||||
const valtype &modExpected) { | |||||
CheckOp(a, b, OP_DIV, divExpected); | |||||
CheckOp(a, NegativeValtype(b), OP_DIV, NegativeValtype(divExpected)); | |||||
CheckOp(NegativeValtype(a), b, OP_DIV, NegativeValtype(divExpected)); | |||||
CheckOp(NegativeValtype(a), NegativeValtype(b), OP_DIV, divExpected); | |||||
CheckOp(a, b, OP_MOD, modExpected); | |||||
CheckOp(a, NegativeValtype(b), OP_MOD, modExpected); | |||||
CheckOp(NegativeValtype(a), b, OP_MOD, NegativeValtype(modExpected)); | |||||
CheckOp(NegativeValtype(a), NegativeValtype(b), OP_MOD, | |||||
NegativeValtype(modExpected)); | |||||
} | |||||
deadalnixUnsubmitted Done Inline Actionsdeadalnix: sealofaproval | |||||
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); | |||||
deadalnixUnsubmitted Done Inline ActionsYou don't need to specify stacktype all over the place. deadalnix: You don't need to specify `stacktype` all over the place. | |||||
// 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}); | |||||
deadalnixUnsubmitted Done Inline ActionsWhy no CheckDivMod ? deadalnix: Why no `CheckDivMod` ? | |||||
// Identity: 15/1 = 15 (and negative operands) | |||||
CheckDivMod(valtype{0x0f}, valtype{0x01}, valtype{0x0f}, valtype{}); | |||||
deadalnixUnsubmitted Done Inline ActionsKnown results, such as a/a = 1 and a/1 = a and can also be added to CheckDivMod so they get grilled with many values of a. deadalnix: Known results, such as `a/a = 1` and `a/1 = a` and can also be added to `CheckDivMod` so they… | |||||
// 15/4 = 3 (and negative operands) | |||||
CheckDivMod(valtype{0x0f}, valtype{0x04}, valtype{0x03}, valtype{0x03}); | |||||
// 15000/4 = 3750 (and negative operands) | |||||
CheckDivMod(valtype{0x98, 0x3a}, valtype{0x04}, valtype{0xa6, 0x0e}, | |||||
valtype{}); | |||||
// 15000/4000 = 3 (and negative operands) | |||||
CheckDivMod(valtype{0x98, 0x3a}, valtype{0xa0, 0x0f}, valtype{0x03}, | |||||
valtype{0xb8, 0x0b}); | |||||
// 15000000/4000 = 3750 (and negative operands) | |||||
CheckDivMod(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0xa0, 0x0f}, | |||||
valtype{0xa6, 0x0e}, valtype{}); | |||||
// 15000000/4 = 3750000 (and negative operands) | |||||
CheckDivMod(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0x04}, | |||||
valtype{0x70, 0x38, 0x39}, valtype{}); | |||||
} | |||||
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); | |||||
deadalnixUnsubmitted Done Inline ActionsPut positive and negative zeros in there. deadalnix: Put positive and negative zeros in there. | |||||
// 56488123 % 321 = 148 (and negative operands) | |||||
// 56488123 % 3 = 1 (and negative operands) | |||||
// 56488123 % 564881230 = 56488123 (and negative operands) | |||||
CheckDivMod(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x41, 0x01}, | |||||
valtype{0x67, 0xaf, 0x02}, valtype{0x94, 0x00}); | |||||
CheckDivMod(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x03}, | |||||
valtype{0x3e, 0x50, 0x1f, 0x01}, valtype{0x01}); | |||||
CheckDivMod(valtype{0xbb, 0xf0, 0x5d, 0x03}, | |||||
valtype{0x4e, 0x67, 0xab, 0x21}, valtype{}, | |||||
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}}); | |||||
} | |||||
} | |||||
deadalnixUnsubmitted Done Inline ActionsThis is also a property that can be checked by CheckDivMod on many values. deadalnix: This is also a property that can be checked by `CheckDivMod` on many values. | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |