diff --git a/src/policy/policy.h b/src/policy/policy.h index a82488a28c9589..28ead8d6b5dc51 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -113,7 +113,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI SCRIPT_VERIFY_CONST_SCRIPTCODE | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION | SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE}; + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE | + SCRIPT_VERIFY_DISCOURAGE_OP_CAT}; /** For convenience, standard but not mandatory verify flags. */ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS}; diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 9d0e9b5e3cfb22..317d14e14180b0 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -451,10 +451,16 @@ bool EvalScript(std::vector >& stack, const CScript& if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) { return set_error(serror, SCRIPT_ERR_OP_COUNT); } + + // When OP_SUCCESS disabled opcodes (CVE-2010-5137) are + // redefined in tapscript, remove them from the if below + // and put them here + if (opcode == OP_CAT) { + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes (CVE-2010-5137). + } } - if (opcode == OP_CAT || - opcode == OP_SUBSTR || + if (opcode == OP_SUBSTR || opcode == OP_LEFT || opcode == OP_RIGHT || opcode == OP_INVERT || @@ -518,6 +524,19 @@ bool EvalScript(std::vector >& stack, const CScript& case OP_NOP: break; + case OP_CAT: + { + if (stack.size() < 2) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + valtype& vch1 = stacktop(-2); + valtype& vch2 = stacktop(-1); + if (vch1.size() + vch2.size() > MAX_SCRIPT_ELEMENT_SIZE) + return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + vch1.insert(vch1.end(), vch2.begin(), vch2.end()); + stack.pop_back(); + } + break; + case OP_CHECKLOCKTIMEVERIFY: { if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { @@ -1800,10 +1819,19 @@ static bool ExecuteWitnessScript(const Span& stack_span, const CS } // New opcodes will be listed here. May use a different sigversion to modify existing opcodes. if (IsOpSuccess(opcode)) { - if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) { - return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS); + if (opcode == OP_CAT) { + if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_CAT) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_CAT); + } else if (!(flags & SCRIPT_VERIFY_OP_CAT)) { + return set_success(serror); + } + } else { + // OP_SUCCESS behaviour + if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS); + } + return set_success(serror); } - return set_success(serror); } } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 8ba0018c23ca54..0079ce4d5fc833 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -143,6 +143,10 @@ enum : uint32_t { // Making unknown public key versions (in BIP 342 scripts) non-standard SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20), + // Support OP_CAT in tapscript + SCRIPT_VERIFY_OP_CAT = (1U << 21), + SCRIPT_VERIFY_DISCOURAGE_OP_CAT = (1U << 22), + // Constants to point to the highest flag in use. Add new flags above this line. // SCRIPT_VERIFY_END_MARKER diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index fadc04262c3146..7fc2dd7706b742 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -76,6 +76,7 @@ std::string ScriptErrorString(const ScriptError serror) case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION: return "Taproot version reserved for soft-fork upgrades"; case SCRIPT_ERR_DISCOURAGE_OP_SUCCESS: + case SCRIPT_ERR_DISCOURAGE_OP_CAT: return "OP_SUCCESSx reserved for soft-fork upgrades"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE: return "Public key version reserved for soft-fork upgrades"; diff --git a/src/script/script_error.h b/src/script/script_error.h index 44e68fe0fae306..bb0d2f91f72558 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -78,6 +78,9 @@ typedef enum ScriptError_t SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG, SCRIPT_ERR_TAPSCRIPT_MINIMALIF, + /* OP_CAT re-activation */ + SCRIPT_ERR_DISCOURAGE_OP_CAT, + /* Constant scriptCode */ SCRIPT_ERR_OP_CODESEPARATOR, SCRIPT_ERR_SIG_FINDANDDELETE, diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 575f4147317b3f..fff235f3ef5b09 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -69,6 +69,8 @@ static std::map mapFlagNames = { {std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE}, {std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS}, {std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION}, + {std::string("OP_CAT"), (unsigned int)SCRIPT_VERIFY_OP_CAT}, + {std::string("DISCOURAGE_OP_CAT"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_CAT}, }; unsigned int ParseScriptFlags(std::string strFlags)