Changeset View
Changeset View
Standalone View
Standalone View
src/test/monolith_opcodes.cpp
Show First 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | |||||
BOOST_AUTO_TEST_CASE(bitwise_opcodes_test) { | BOOST_AUTO_TEST_CASE(bitwise_opcodes_test) { | ||||
// Check that empty ops works. | // Check that empty ops works. | ||||
RunTestForAllBitwiseOpcodes({}, {}, {}, {}, {}); | RunTestForAllBitwiseOpcodes({}, {}, {}, {}, {}); | ||||
// Run all variations of zeros and ones. | // Run all variations of zeros and ones. | ||||
valtype allzeros(MAX_SCRIPT_ELEMENT_SIZE, 0); | valtype allzeros(MAX_SCRIPT_ELEMENT_SIZE, 0); | ||||
valtype allones(MAX_SCRIPT_ELEMENT_SIZE, 0xff); | valtype allones(MAX_SCRIPT_ELEMENT_SIZE, 0xff); | ||||
BOOST_CHECK_EQUAL(allzeros.size(), MAX_SCRIPT_ELEMENT_SIZE); | |||||
BOOST_CHECK_EQUAL(allones.size(), MAX_SCRIPT_ELEMENT_SIZE); | |||||
TestBitwiseOpcodes(allzeros, allzeros, allzeros, allzeros); | TestBitwiseOpcodes(allzeros, allzeros, allzeros, allzeros); | ||||
TestBitwiseOpcodes(allzeros, allones, allzeros, allones); | TestBitwiseOpcodes(allzeros, allones, allzeros, allones); | ||||
TestBitwiseOpcodes(allones, allones, allones, allones); | TestBitwiseOpcodes(allones, allones, allones, allones); | ||||
// Let's use two random a and b. | // Let's use two random a and b. | ||||
valtype a{ | valtype a{ | ||||
0x34, 0x0e, 0x7e, 0x17, 0x83, 0x66, 0x1a, 0x81, 0x45, 0x8d, 0x26, 0x26, | 0x34, 0x0e, 0x7e, 0x17, 0x83, 0x66, 0x1a, 0x81, 0x45, 0x8d, 0x26, 0x26, | ||||
0xbc, 0xbd, 0x56, 0xe7, 0xf2, 0x1c, 0xec, 0xf6, 0x79, 0x8c, 0x3e, 0x58, | 0xbc, 0xbd, 0x56, 0xe7, 0xf2, 0x1c, 0xec, 0xf6, 0x79, 0x8c, 0x3e, 0x58, | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | CheckAllBitwiseOpErrors({{0xab, 0xcd, 0xef}, {0x00}}, | ||||
SCRIPT_ERR_INVALID_OPERAND_SIZE); | SCRIPT_ERR_INVALID_OPERAND_SIZE); | ||||
CheckAllBitwiseOpErrors({{}, a}, SCRIPT_ERR_INVALID_OPERAND_SIZE); | CheckAllBitwiseOpErrors({{}, a}, SCRIPT_ERR_INVALID_OPERAND_SIZE); | ||||
CheckAllBitwiseOpErrors({b, {}}, SCRIPT_ERR_INVALID_OPERAND_SIZE); | CheckAllBitwiseOpErrors({b, {}}, SCRIPT_ERR_INVALID_OPERAND_SIZE); | ||||
} | } | ||||
/** | /** | ||||
* Type conversion opcodes. | * Type conversion opcodes. | ||||
*/ | */ | ||||
static void CheckBin2NumOp(const valtype &n, const valtype &expected) { | static void CheckTypeConversionOp(const valtype &bin, const valtype &num) { | ||||
CheckTestResultForAllFlags({n}, CScript() << OP_BIN2NUM, {expected}); | // Check BIN2NUM. | ||||
CheckTestResultForAllFlags({bin}, CScript() << OP_BIN2NUM, {num}); | |||||
// TODO: Check roundtrip with NUM2BIN when NUM2BIN is implemented. | |||||
// Check NUM2BIN. Negative 0 is rebuilt as regular zero, so we need a tweak. | |||||
valtype rebuilt_bin{bin}; | |||||
if (num.size() == 0 && bin.size() > 0) { | |||||
rebuilt_bin[rebuilt_bin.size() - 1] &= 0x7f; | |||||
} | |||||
CheckTestResultForAllFlags({num}, CScript() << bin.size() << OP_NUM2BIN, | |||||
{rebuilt_bin}); | |||||
// Check roundtrip with NUM2BIN. | |||||
CheckTestResultForAllFlags( | |||||
{bin}, CScript() << OP_BIN2NUM << bin.size() << OP_NUM2BIN, | |||||
{rebuilt_bin}); | |||||
// Grow and shrink back down using NUM2BIN. | |||||
CheckTestResultForAllFlags({bin}, | |||||
CScript() | |||||
<< MAX_SCRIPT_ELEMENT_SIZE << OP_NUM2BIN | |||||
<< bin.size() << OP_NUM2BIN, | |||||
{rebuilt_bin}); | |||||
CheckTestResultForAllFlags({num}, | |||||
CScript() | |||||
<< MAX_SCRIPT_ELEMENT_SIZE << OP_NUM2BIN | |||||
<< bin.size() << OP_NUM2BIN, | |||||
{rebuilt_bin}); | |||||
// BIN2NUM is indempotent. | |||||
CheckTestResultForAllFlags({bin}, CScript() << OP_BIN2NUM << OP_BIN2NUM, | |||||
{num}); | |||||
} | } | ||||
static void CheckBin2NumError(const std::vector<valtype> &original_stack, | static void CheckBin2NumError(const std::vector<valtype> &original_stack, | ||||
ScriptError expected_error) { | ScriptError expected_error) { | ||||
CheckErrorForAllFlags(original_stack, CScript() << OP_BIN2NUM, | CheckErrorForAllFlags(original_stack, CScript() << OP_BIN2NUM, | ||||
expected_error); | expected_error); | ||||
} | } | ||||
static void CheckNum2BinError(const std::vector<valtype> &original_stack, | |||||
ScriptError expected_error) { | |||||
CheckErrorForAllFlags(original_stack, CScript() << OP_NUM2BIN, | |||||
expected_error); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(type_conversion_test) { | BOOST_AUTO_TEST_CASE(type_conversion_test) { | ||||
valtype empty; | valtype empty; | ||||
CheckBin2NumOp(empty, empty); | CheckTypeConversionOp(empty, empty); | ||||
valtype paddedzero, paddednegzero; | valtype paddedzero, paddednegzero; | ||||
for (size_t i = 0; i <= MAX_SCRIPT_ELEMENT_SIZE; i++) { | for (size_t i = 0; i < MAX_SCRIPT_ELEMENT_SIZE; i++) { | ||||
CheckBin2NumOp(paddedzero, empty); | CheckTypeConversionOp(paddedzero, empty); | ||||
paddedzero.push_back(0x00); | paddedzero.push_back(0x00); | ||||
paddednegzero.push_back(0x80); | paddednegzero.push_back(0x80); | ||||
CheckBin2NumOp(paddednegzero, empty); | CheckTypeConversionOp(paddednegzero, empty); | ||||
paddednegzero[paddednegzero.size() - 1] = 0x00; | paddednegzero[paddednegzero.size() - 1] = 0x00; | ||||
} | } | ||||
// Merge leading byte when sign bit isn't used. | // Merge leading byte when sign bit isn't used. | ||||
std::vector<uint8_t> k{0x7f}, negk{0xff}; | std::vector<uint8_t> k{0x7f}, negk{0xff}; | ||||
std::vector<uint8_t> kpadded = k, negkpadded = negk; | std::vector<uint8_t> kpadded = k, negkpadded = negk; | ||||
for (size_t i = 0; i < MAX_SCRIPT_ELEMENT_SIZE; i++) { | for (size_t i = 0; i < MAX_SCRIPT_ELEMENT_SIZE; i++) { | ||||
CheckBin2NumOp(kpadded, k); | CheckTypeConversionOp(kpadded, k); | ||||
kpadded.push_back(0x00); | kpadded.push_back(0x00); | ||||
CheckBin2NumOp(negkpadded, negk); | CheckTypeConversionOp(negkpadded, negk); | ||||
negkpadded[negkpadded.size() - 1] &= 0x7f; | negkpadded[negkpadded.size() - 1] &= 0x7f; | ||||
negkpadded.push_back(0x80); | negkpadded.push_back(0x80); | ||||
} | } | ||||
// Some known values. | // Some known values. | ||||
CheckBin2NumOp({0xab, 0xcd, 0xef, 0x00}, {0xab, 0xcd, 0xef, 0x00}); | CheckTypeConversionOp({0xab, 0xcd, 0xef, 0x00}, {0xab, 0xcd, 0xef, 0x00}); | ||||
CheckBin2NumOp({0xab, 0xcd, 0x7f, 0x00}, {0xab, 0xcd, 0x7f}); | CheckTypeConversionOp({0xab, 0xcd, 0x7f, 0x00}, {0xab, 0xcd, 0x7f}); | ||||
// Reductions | // Reductions | ||||
CheckBin2NumOp({0xab, 0xcd, 0xef, 0x42, 0x80}, {0xab, 0xcd, 0xef, 0xc2}); | CheckTypeConversionOp({0xab, 0xcd, 0xef, 0x42, 0x80}, | ||||
CheckBin2NumOp({0xab, 0xcd, 0x7f, 0x42, 0x00}, {0xab, 0xcd, 0x7f, 0x42}); | {0xab, 0xcd, 0xef, 0xc2}); | ||||
CheckTypeConversionOp({0xab, 0xcd, 0x7f, 0x42, 0x00}, | |||||
{0xab, 0xcd, 0x7f, 0x42}); | |||||
// Empty stack is an error. | // Empty stack is an error. | ||||
CheckBin2NumError({}, SCRIPT_ERR_INVALID_STACK_OPERATION); | CheckBin2NumError({}, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
CheckNum2BinError({}, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
// NUM2BIN require 2 elements on the stack. | |||||
CheckNum2BinError({{0x00}}, SCRIPT_ERR_INVALID_STACK_OPERATION); | |||||
// Values that do not fit in 4 bytes are considered out of range for | |||||
// BIN2NUM. | |||||
CheckBin2NumError({{0xab, 0xcd, 0xef, 0xc2, 0x80}}, | CheckBin2NumError({{0xab, 0xcd, 0xef, 0xc2, 0x80}}, | ||||
SCRIPT_ERR_INVALID_NUMBER_RANGE); | SCRIPT_ERR_INVALID_NUMBER_RANGE); | ||||
CheckBin2NumError({{0x00, 0x00, 0x00, 0x80, 0x80}}, | CheckBin2NumError({{0x00, 0x00, 0x00, 0x80, 0x80}}, | ||||
SCRIPT_ERR_INVALID_NUMBER_RANGE); | SCRIPT_ERR_INVALID_NUMBER_RANGE); | ||||
// NUM2BIN must not generate oversized push. | |||||
valtype largezero(MAX_SCRIPT_ELEMENT_SIZE, 0); | |||||
BOOST_CHECK_EQUAL(largezero.size(), MAX_SCRIPT_ELEMENT_SIZE); | |||||
CheckTypeConversionOp(largezero, {}); | |||||
CheckNum2BinError({{}, {0x09, 0x02}}, SCRIPT_ERR_PUSH_SIZE); | |||||
// Check that the requested encoding is possible. | |||||
CheckNum2BinError({{0xab, 0xcd, 0xef, 0x80}, {0x03}}, | |||||
SCRIPT_ERR_IMPOSSIBLE_ENCODING); | |||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |