Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14362732
D1295.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Subscribers
None
D1295.diff
View Options
diff --git a/src/core_read.cpp b/src/core_read.cpp
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -50,6 +50,8 @@
size_t push_size = 0, next_push_size = 0;
size_t script_size = 0;
+ // Deal with PUSHDATA1 operation with some more hacks.
+ size_t push_data_size = 0;
for (const auto &w : words) {
if (w.empty()) {
@@ -65,6 +67,7 @@
push_size = next_push_size;
next_push_size = 0;
+ // Decimal numbers
if (all(w, boost::algorithm::is_digit()) ||
(boost::algorithm::starts_with(w, "-") &&
all(std::string(w.begin() + 1, w.end()),
@@ -75,6 +78,7 @@
goto next;
}
+ // Hex Data
if (boost::algorithm::starts_with(w, "0x") &&
(w.begin() + 2 != w.end())) {
if (!IsHex(std::string(w.begin() + 2, w.end()))) {
@@ -87,11 +91,6 @@
// Raw hex data, inserted NOT pushed onto stack:
std::vector<uint8_t> raw =
ParseHex(std::string(w.begin() + 2, w.end()));
- // If we have what looks like an immediate push, figure out its
- // size.
- if (!push_size && raw.size() == 1 && raw[0] < OP_PUSHDATA1) {
- next_push_size = raw[0];
- }
result.insert(result.end(), raw.begin(), raw.end());
goto next;
@@ -111,30 +110,66 @@
// opcode, e.g. OP_ADD or ADD:
opcodetype op = mapOpNames[w];
+ result << op;
+ goto next;
+ }
+
+ throw std::runtime_error("Error parsing script: " + s);
+
+ next:
+ size_t size_change = result.size() - script_size;
+
+ // If push_size is set, ensure have added the right amount of stuff.
+ if (push_size != 0 && size_change != push_size) {
+ throw std::runtime_error("Wrong number of bytes being pushed.");
+ }
+
+ // If push_size is set, and we have push_data_size set, then we have a
+ // PUSHDATAX opcode. We need to read it's push size as a LE value for
+ // the next iteration of this loop.
+ if (push_size != 0 && push_data_size != 0) {
+ auto offset = &result[script_size];
+
+ // Push data size is not a CScriptNum (Because it is
+ // 2's-complement instead of 1's complement). We need to use
+ // ReadLE(N) instead of converting to a CScriptNum.
+ if (push_data_size == 1) {
+ next_push_size = *offset;
+ } else if (push_data_size == 2) {
+ next_push_size = ReadLE16(offset);
+ } else if (push_data_size == 4) {
+ next_push_size = ReadLE32(offset);
+ }
+
+ push_data_size = 0;
+ }
+
+ // If push_size is unset, but size_change is 1, that means we have an
+ // opcode in the form of `0x00` or <opcodename>. We will check to see
+ // if it is a push operation and set state accordingly
+ if (push_size == 0 && size_change == 1) {
+ opcodetype op = opcodetype(*result.rbegin());
+
+ // If we have what looks like an immediate push, figure out its
+ // size.
+ if (op < OP_PUSHDATA1) {
+ next_push_size = op;
+ continue;
+ }
+
switch (op) {
case OP_PUSHDATA1:
- next_push_size = 1;
+ push_data_size = next_push_size = 1;
break;
case OP_PUSHDATA2:
- next_push_size = 2;
+ push_data_size = next_push_size = 2;
break;
case OP_PUSHDATA4:
- next_push_size = 4;
+ push_data_size = next_push_size = 4;
break;
default:
break;
}
-
- result << op;
- goto next;
- }
-
- throw std::runtime_error("Error parsing script: " + s);
-
- next:
- size_t size_change = result.size() - script_size;
- if (push_size && size_change != push_size) {
- throw std::runtime_error("Wrong number of bytes being pushed.");
}
}
diff --git a/src/test/core_io_tests.cpp b/src/test/core_io_tests.cpp
--- a/src/test/core_io_tests.cpp
+++ b/src/test/core_io_tests.cpp
@@ -25,6 +25,57 @@
}
}
+static void PrintLE(std::ostringstream &testString, size_t bytes,
+ size_t pushLength) {
+ testString << "0x";
+ while (bytes != 0) {
+ testString << std::setfill('0') << std::setw(2) << std::hex
+ << pushLength % 256;
+ pushLength /= 256;
+ bytes--;
+ }
+}
+
+static std::string TestPushOpcode(size_t pushWidth, size_t pushLength,
+ size_t actualLength) {
+ std::ostringstream testString;
+
+ switch (pushWidth) {
+ case 1:
+ testString << "PUSHDATA1 ";
+ break;
+ case 2:
+ testString << "PUSHDATA2 ";
+ break;
+ case 4:
+ testString << "PUSHDATA4 ";
+ break;
+ default:
+ assert(false);
+ }
+ PrintLE(testString, pushWidth, pushLength);
+ testString << " 0x";
+
+ for (size_t i = 0; i < actualLength; i++) {
+ testString << "01";
+ }
+
+ return testString.str();
+}
+
+BOOST_AUTO_TEST_CASE(printle_tests) {
+ // Ensure the test generator is doing what we think it is.
+ std::ostringstream testString;
+ PrintLE(testString, 04, 0x8001);
+ BOOST_CHECK_EQUAL(testString.str(), "0x01800000");
+}
+
+BOOST_AUTO_TEST_CASE(testpushopcode_tests) {
+ BOOST_CHECK_EQUAL(TestPushOpcode(1, 2, 2), "PUSHDATA1 0x02 0x0101");
+ BOOST_CHECK_EQUAL(TestPushOpcode(2, 2, 2), "PUSHDATA2 0x0200 0x0101");
+ BOOST_CHECK_EQUAL(TestPushOpcode(4, 2, 2), "PUSHDATA4 0x02000000 0x0101");
+}
+
BOOST_AUTO_TEST_CASE(parse_push_test) {
BOOST_CHECK_NO_THROW(ParseScript("0x01 0x01"));
BOOST_CHECK_NO_THROW(ParseScript("0x01 XOR"));
@@ -42,6 +93,56 @@
BOOST_CHECK_THROW(ParseScript("0x02 ''"), std::runtime_error);
BOOST_CHECK_THROW(ParseScript("0x02 0x010101"), std::runtime_error);
BOOST_CHECK_THROW(ParseScript("0x02 'ab'"), std::runtime_error);
+
+ // Note sizes are LE encoded. Also, some of these values are not
+ // minimally encoded intentionally -- nor are they being required to be
+ // minimally encoded.
+ BOOST_CHECK_NO_THROW(ParseScript("PUSHDATA4 0x02000000 0x0101"));
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x03000000 0x0101"),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x02000000 0x010101"),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x020000 0x0101"),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x0200000000 0x0101"),
+ std::runtime_error);
+
+ BOOST_CHECK_NO_THROW(ParseScript("PUSHDATA2 0x0200 0x0101"));
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA2 0x0300 0x0101"),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA2 0x030000 0x0101"),
+ std::runtime_error);
+ BOOST_CHECK_NO_THROW(ParseScript("PUSHDATA1 0x02 0x0101"));
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA1 0x02 0x010101"),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript("PUSHDATA1 0x0200 0x010101"),
+ std::runtime_error);
+
+ // Ensure pushdata handling is not using 1's complement
+ BOOST_CHECK_NO_THROW(ParseScript(TestPushOpcode(1, 0xC8, 0xC8)));
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(1, 0xC8, 0xC9)),
+ std::runtime_error);
+
+ BOOST_CHECK_NO_THROW(ParseScript(TestPushOpcode(2, 0x8000, 0x8000)));
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x8000, 0x8001)),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x8001, 0x8000)),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x80, 0x81)),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x80, 0x7F)),
+ std::runtime_error);
+
+ // Can't build something too long.
+ BOOST_CHECK_NO_THROW(ParseScript(TestPushOpcode(4, 0x8000, 0x8000)));
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x8000, 0x8001)),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x8001, 0x8000)),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x80, 0x81)),
+ std::runtime_error);
+ BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x80, 0x7F)),
+ std::runtime_error);
}
BOOST_AUTO_TEST_SUITE_END()
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, May 12, 01:43 (21 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5775263
Default Alt Text
D1295.diff (8 KB)
Attached To
D1295: Ensure checks are enforced in core_read.cpp for all push types
Event Timeline
Log In to Comment