Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115722
D1220.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Subscribers
None
D1220.diff
View Options
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -295,7 +295,6 @@
switch (opcode) {
case OP_CAT:
case OP_SPLIT:
- case OP_BIN2NUM:
case OP_NUM2BIN:
case OP_INVERT:
case OP_2MUL:
@@ -311,6 +310,7 @@
case OP_AND:
case OP_OR:
case OP_XOR:
+ case OP_BIN2NUM:
// Opcodes that have been reenabled.
if ((flags & SCRIPT_ENABLE_MONOLITH_OPCODES) == 0) {
return true;
@@ -858,6 +858,7 @@
}
valtype &vch1 = stacktop(-2);
valtype &vch2 = stacktop(-1);
+
bool fEqual = (vch1 == vch2);
// OP_NOTEQUAL is disabled because it would be too
// easy to say something like n != 1 and have some
@@ -1246,6 +1247,26 @@
}
} break;
+ //
+ // Conversion operations
+ //
+ case OP_BIN2NUM: {
+ // (in -- out)
+ if (stack.size() < 1) {
+ return set_error(
+ serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
+ }
+
+ valtype &n = stacktop(-1);
+ CScriptNum::MinimallyEncode(n);
+
+ // The resulting number must be a valid number.
+ if (!CScriptNum::IsMinimallyEncoded(n)) {
+ return set_error(serror,
+ SCRIPT_ERR_INVALID_NUMBER_RANGE);
+ }
+ } break;
+
default:
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
diff --git a/src/script/script_error.h b/src/script/script_error.h
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -22,6 +22,7 @@
/* Operands checks */
SCRIPT_ERR_INVALID_OPERAND_SIZE,
+ SCRIPT_ERR_INVALID_NUMBER_RANGE,
/* Failed verify operations */
SCRIPT_ERR_VERIFY,
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -36,6 +36,9 @@
return "Pubkey count negative or limit exceeded";
case SCRIPT_ERR_INVALID_OPERAND_SIZE:
return "Invalid operand size";
+ case SCRIPT_ERR_INVALID_NUMBER_RANGE:
+ return "Given operand is not a number within the valid range "
+ "[-2^31...2^31]";
case SCRIPT_ERR_BAD_OPCODE:
return "Opcode missing or not understood";
case SCRIPT_ERR_DISABLED_OPCODE:
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -828,7 +828,33 @@
["'abc' 2 0", "IF NUM2BIN ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "NUM2BIN disabled"],
["'abc' 2 0", "IF NUM2BIN ELSE 1 ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "NUM2BIN disabled"],
["'abc' 2 0", "IF BIN2NUM ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "BIN2NUM disabled"],
-["'abc' 2 0", "IF BIN2NUM ELSE 1 ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "BIN2NUM disabled"],
+["'abc' 2 0", "IF BIN2NUM ELSE 1 ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM enabled"],
+
+["BIN2NUM"],
+["", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "BIN2NUM, empty stack"],
+["0", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical arguement"],
+["1", "BIN2NUM 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical arguement"],
+["-42", "BIN2NUM -42 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical arguement"],
+["0x01 0x00", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, non-canonical arguement"],
+["0x04 0xffffff7f", "BIN2NUM 2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, maximum size arguement"],
+["0x04 0xffffffff", "BIN2NUM -2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, maximum size arguement"],
+["0x05 0xffffffff00", "BIN2NUM 2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_NUMBER_RANGE", "BIN2NUM, oversized arguement"],
+["0x05 0xffffff7f80", "BIN2NUM -2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, non-canonical maximum size arguement"],
+["0x05 0x0100000000", "BIN2NUM 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"],
+["0x05 0xFE00000000", "BIN2NUM 254 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"],
+["0x05 0x0500000080", "BIN2NUM 0x01 0x85 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"],
+["0x03 0x800000", "BIN2NUM 128 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Pad where MSB of number is set"],
+["0x03 0x800080", "BIN2NUM -128 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Pad where MSB of number is set"],
+["0x02 0x8000", "BIN2NUM 128 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Pad where MSB of number is set"],
+["0x02 0x8080", "BIN2NUM -128 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Pad where MSB of number is set"],
+["0x03 0x0f0000", "BIN2NUM 15 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Don't pad where MSB of number is not set"],
+["0x03 0x0f0080", "BIN2NUM -15 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Don't pad where MSB of number is not set"],
+["0x02 0x0f00", "BIN2NUM 15 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Don't pad where MSB of number is not set"],
+["0x02 0x0f80", "BIN2NUM -15 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Don't pad where MSB of number is not set"],
+["0x05 0x0100800000", "BIN2NUM 8388609 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Ensure significant zero bytes are retained"],
+["0x05 0x0100800080", "BIN2NUM -8388609 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Ensure significant zero bytes are retained"],
+["0x05 0x01000f0000", "BIN2NUM 983041 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Ensure significant zero bytes are retained"],
+["0x05 0x01000f0080", "BIN2NUM -983041 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Ensure significant zero bytes are retained"],
["NOP", "SIZE 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"],
diff --git a/src/test/monolith_opcodes.cpp b/src/test/monolith_opcodes.cpp
--- a/src/test/monolith_opcodes.cpp
+++ b/src/test/monolith_opcodes.cpp
@@ -352,4 +352,95 @@
CheckAllBitwiseOpErrors({b, {}}, SCRIPT_ERR_INVALID_OPERAND_SIZE);
}
+static void CheckBin2NumOp(const valtype &n, const valtype &expected) {
+ BaseSignatureChecker sigchecker;
+
+ for (uint32_t flags : flagset) {
+ ScriptError err = SCRIPT_ERR_OK;
+ std::vector<valtype> stack{n};
+ bool r = EvalScript(stack, CScript() << OP_BIN2NUM,
+ flags | SCRIPT_ENABLE_MONOLITH_OPCODES, sigchecker,
+ &err);
+ BOOST_CHECK(r);
+
+ std::vector<valtype> expected_stack{expected};
+ BOOST_CHECK(stack == expected_stack);
+
+ // Make sure that if we do not pass the monolith flag, opcodes are still
+ // disabled.
+ err = SCRIPT_ERR_OK;
+ stack = {n};
+ r = EvalScript(stack, CScript() << OP_BIN2NUM, flags, sigchecker, &err);
+ BOOST_CHECK(!r);
+ BOOST_CHECK_EQUAL(err, SCRIPT_ERR_DISABLED_OPCODE);
+
+ // TODO: Check roundtrip with NUM2BIN when NUM2BIN is implemented.
+ }
+}
+
+static void CheckBin2NumError(const std::vector<valtype> &original_stack,
+ ScriptError expected_error) {
+ BaseSignatureChecker sigchecker;
+
+ for (uint32_t flags : flagset) {
+ ScriptError err = SCRIPT_ERR_OK;
+ std::vector<valtype> stack{original_stack};
+ bool r = EvalScript(stack, CScript() << OP_BIN2NUM,
+ flags | SCRIPT_ENABLE_MONOLITH_OPCODES, sigchecker,
+ &err);
+ BOOST_CHECK(!r);
+ BOOST_CHECK_EQUAL(err, expected_error);
+
+ // Make sure that if we do not pass the monolith flag, opcodes are still
+ // disabled.
+ err = SCRIPT_ERR_OK;
+ stack = {original_stack};
+ r = EvalScript(stack, CScript() << OP_BIN2NUM, flags, sigchecker, &err);
+ BOOST_CHECK(!r);
+ BOOST_CHECK_EQUAL(err, SCRIPT_ERR_DISABLED_OPCODE);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(type_conversion_test) {
+ valtype empty;
+ CheckBin2NumOp(empty, empty);
+
+ valtype paddedzero, paddednegzero;
+ for (size_t i = 0; i <= MAX_SCRIPT_ELEMENT_SIZE; i++) {
+ CheckBin2NumOp(paddedzero, empty);
+ paddedzero.push_back(0x00);
+
+ paddednegzero.push_back(0x80);
+ CheckBin2NumOp(paddednegzero, empty);
+ paddednegzero[paddednegzero.size() - 1] = 0x00;
+ }
+
+ // Merge leading byte when sign bit isn't used.
+ std::vector<uint8_t> k{0x7f}, negk{0xff};
+ std::vector<uint8_t> kpadded = k, negkpadded = negk;
+ for (size_t i = 0; i < MAX_SCRIPT_ELEMENT_SIZE; i++) {
+ CheckBin2NumOp(kpadded, k);
+ kpadded.push_back(0x00);
+
+ CheckBin2NumOp(negkpadded, negk);
+ negkpadded[negkpadded.size() - 1] &= 0x7f;
+ negkpadded.push_back(0x80);
+ }
+
+ // Some known values.
+ CheckBin2NumOp({0xab, 0xcd, 0xef, 0x00}, {0xab, 0xcd, 0xef, 0x00});
+ CheckBin2NumOp({0xab, 0xcd, 0x7f, 0x00}, {0xab, 0xcd, 0x7f});
+
+ // Reductions
+ CheckBin2NumOp({0xab, 0xcd, 0xef, 0x42, 0x80}, {0xab, 0xcd, 0xef, 0xc2});
+ CheckBin2NumOp({0xab, 0xcd, 0x7f, 0x42, 0x00}, {0xab, 0xcd, 0x7f, 0x42});
+
+ // Empty stack is an error.
+ CheckBin2NumError({}, SCRIPT_ERR_INVALID_STACK_OPERATION);
+ CheckBin2NumError({{0xab, 0xcd, 0xef, 0xc2, 0x80}},
+ SCRIPT_ERR_INVALID_NUMBER_RANGE);
+ CheckBin2NumError({{0x00, 0x00, 0x00, 0x80, 0x80}},
+ SCRIPT_ERR_INVALID_NUMBER_RANGE);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -63,6 +63,7 @@
{SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"},
{SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"},
{SCRIPT_ERR_INVALID_OPERAND_SIZE, "OPERAND_SIZE"},
+ {SCRIPT_ERR_INVALID_NUMBER_RANGE, "INVALID_NUMBER_RANGE"},
{SCRIPT_ERR_VERIFY, "VERIFY"},
{SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"},
{SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"},
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 1, 11:53 (6 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187711
Default Alt Text
D1220.diff (10 KB)
Attached To
D1220: Add support for BIN2NUM opcode
Event Timeline
Log In to Comment