diff --git a/src/script/script.cpp b/src/script/script.cpp index 70eb8a139b0..a71fee19cfe 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -267,3 +267,15 @@ std::string CScriptWitness::ToString() const } return ret + ")"; } + +bool CScript::HasValidOps() const +{ + CScript::const_iterator it = begin(); + while (it < end()) { + opcodetype opcode; + if (!GetOp(it, opcode) || opcode > 0xb9) { + return false; + } + } + return true; +} diff --git a/src/script/script.h b/src/script/script.h index 95a5999a13b..25b80ef62bf 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -630,6 +630,9 @@ public: bool IsPushOnly(const_iterator pc) const; bool IsPushOnly() const; + /** Check if the script contains valid OP_CODES */ + bool HasValidOps() const; + /** * Returns whether the script is guaranteed to fail at execution, * regardless of the initial stack. This allows outputs to be pruned diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 343c645cb1b..70544cacd6a 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1438,4 +1438,18 @@ BOOST_AUTO_TEST_CASE(script_FindAndDelete) BOOST_CHECK(s == expect); } +BOOST_AUTO_TEST_CASE(script_HasValidOps) +{ + // Exercise the HasValidOps functionality + CScript script; + script = ScriptFromHex("76a9141234567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac"); // Normal script + BOOST_CHECK(script.HasValidOps()); + script = ScriptFromHex("76a914ff34567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac"); + BOOST_CHECK(script.HasValidOps()); + script = ScriptFromHex("ff88ac"); // Script with OP_INVALIDOPCODE explicit + BOOST_CHECK(!script.HasValidOps()); + script = ScriptFromHex("88acc0"); // Script with undefined opcode + BOOST_CHECK(!script.HasValidOps()); +} + BOOST_AUTO_TEST_SUITE_END()