Page MenuHomePhabricator

D1295.diff
No OneTemporary

D1295.diff

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

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)

Event Timeline