Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/policy/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRI
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 script_verify_flags STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
Expand Down
41 changes: 36 additions & 5 deletions src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,16 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& 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 ||
Expand Down Expand Up @@ -519,6 +525,19 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& 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)) {
Expand Down Expand Up @@ -1844,10 +1863,19 @@ static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, con
}
// 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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SCRIPT_VERIFY_DISCOURAGE_OP_CAT is acting as a CAT-specific SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS that can be turned off while still not relaying transasctions with other OP_SUCCESS opcodes. Since this is the first time we're carving out an OP_SUCCESS and doing this, it would be great to have a test that exercises the combinations of SCRIPT_VERIFY_DISCOURAGE_OP_CAT and SCRIPT_VERIFY_OP_CAT

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion! Added some additional unit tests to script_tests.json testing different combinations of scripts with and without (SCRIPT_VERIFY_DISCOURAGE_OP_CAT, SCRIPT_VERIFY_OP_CAT and SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to the inquisition PR in bitcoin-inquisition#68

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);
}
}

Expand Down Expand Up @@ -2190,6 +2218,9 @@ const std::map<std::string, script_verify_flag_name>& ScriptFlagNamesToEnum()
FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE),
FLAG_NAME(DISCOURAGE_OP_SUCCESS),
FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION),
FLAG_NAME(OP_CAT),
FLAG_NAME(DISCOURAGE_OP_CAT),

};
#undef FLAG_NAME
return g_names_to_enum;
Expand Down
4 changes: 4 additions & 0 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ enum class script_verify_flag_name : uint8_t {
// Making unknown public key versions (in BIP 342 scripts) non-standard
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE,

// Support OP_CAT in tapscript
SCRIPT_VERIFY_OP_CAT,
SCRIPT_VERIFY_DISCOURAGE_OP_CAT,

// Constants to point to the highest flag in use. Add new flags above this line.
//
SCRIPT_VERIFY_END_MARKER
Expand Down
1 change: 1 addition & 0 deletions src/script/script_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
3 changes: 3 additions & 0 deletions src/script/script_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading