diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index e78c86731d..dbac2335f9 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -815,6 +815,7 @@ bool EvalScript(std::vector >& stack, const CScript& break; case OP_SUBSTR: + case OP_SUBSTR_LAZY: { if (stack.size() < 3) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); @@ -823,6 +824,30 @@ bool EvalScript(std::vector >& stack, const CScript& CScriptNum start(stacktop(-2), fRequireMinimal); CScriptNum length(stacktop(-1), fRequireMinimal); + if (opcode == OP_SUBSTR_LAZY) { + if (start < 0) + start = 0; + + if (length < 0) + length = 0; + + if (start >= vch1.size()) { + popstack(stack); + popstack(stack); + popstack(stack); + stack.push_back(vchZero); + break; + } + + if (length > MAX_SCRIPT_ELEMENT_SIZE) + length = MAX_SCRIPT_ELEMENT_SIZE; + + // start + length cannot overflow because of the restrictions immediately abo + if (start + length > vch1.size()) { + length = CScriptNum(vch1.size()) - start; + } + } + if (length < 0 || start < 0) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); diff --git a/src/script/script.cpp b/src/script/script.cpp index 532860fe18..b27f4eaa89 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -72,6 +72,7 @@ const char* GetOpName(opcodetype opcode) // splice ops case OP_CAT : return "OP_CAT"; case OP_SUBSTR : return "OP_SUBSTR"; + case OP_SUBSTR_LAZY : return "OP_SUBSTR_LAZY"; case OP_LEFT : return "OP_LEFT"; case OP_RIGHT : return "OP_RIGHT"; case OP_SIZE : return "OP_SIZE"; diff --git a/src/script/script.h b/src/script/script.h index e811bab302..5fbbb891b6 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -116,6 +116,7 @@ enum opcodetype // splice ops OP_CAT = 0x7e, OP_SUBSTR = 0x7f, + OP_SUBSTR_LAZY = 0xc3, OP_LEFT = 0x80, OP_RIGHT = 0x81, OP_SIZE = 0x82, @@ -195,7 +196,7 @@ enum opcodetype }; // Maximum value that an opcode can be -static const unsigned int MAX_OPCODE = OP_CHECKSIGFROMSTACKVERIFY; +static const unsigned int MAX_OPCODE = OP_SUBSTR_LAZY; // 0xc3 const char* GetOpName(opcodetype opcode); diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 359b5e613f..8e0da29cfa 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -876,7 +876,6 @@ ["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], -["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 0c23b7a353..33dc6054eb 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1474,7 +1474,7 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps) BOOST_CHECK(script.HasValidOps()); script = ScriptFromHex("ff88ac"); // Script with OP_INVALIDOPCODE explicit BOOST_CHECK(!script.HasValidOps()); - script = ScriptFromHex("88acc3"); // Script with undefined opcode: one higher then MAX_OPCODE + script = ScriptFromHex("88acc4"); // Script with undefined opcode: one higher then MAX_OPCODE BOOST_CHECK(!script.HasValidOps()); }