Add OP_CHECKTEMPLATEVERIFY Opcode as OP_NOP4

Also modifies script_tests.json to enable OP_NOP4 as OP_CHECKTEMPLATEVERIFY.
This commit is contained in:
Jeremy Rubin 2019-10-16 14:48:23 -07:00 committed by James O'Beirne
parent 3e090231b8
commit a11706203d
No known key found for this signature in database
GPG key ID: 7A935DADB2C44F05
7 changed files with 66 additions and 15 deletions

View file

@ -591,7 +591,42 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
break;
}
case OP_NOP1: case OP_NOP4: case OP_NOP5:
case OP_CHECKTEMPLATEVERIFY:
{
if (flags & SCRIPT_VERIFY_DISCOURAGE_CHECKTEMPLATEVERIFY) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
}
// if flags not enabled; treat as a NOP4
if (!(flags & SCRIPT_VERIFY_CHECKTEMPLATEVERIFY)) {
break;
}
if (stack.size() < 1) {
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
}
// If the argument was not 32 bytes, treat as OP_NOP4:
switch (stack.back().size()) {
case 32:
{
const std::span<const unsigned char> hash{stack.back()};
if (!checker.CheckDefaultCheckTemplateVerifyHash(hash)) {
return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH);
}
break;
}
default:
// future upgrade can add semantics for this opcode with different length args
// so discourage use when applicable
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
}
}
}
break;
case OP_NOP1: case OP_NOP5:
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
{
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@ -1443,12 +1478,16 @@ uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, uint32_t input_index
return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequencesSHA256(tx), input_index);
}
template<typename TxType>
static bool NoScriptSigs(const TxType& tx)
{
return std::all_of(tx.vin.begin(), tx.vin.end(), [](const CTxIn& c) { return c.scriptSig.empty(); });
}
template<typename TxType>
uint256 GetDefaultCheckTemplateVerifyHash(
const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash, const uint32_t input_index) {
bool skip_scriptSigs = std::find_if(tx.vin.begin(), tx.vin.end(),
[](const CTxIn& c) { return c.scriptSig != CScript(); }) == tx.vin.end();
return skip_scriptSigs ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
return NoScriptSigs(tx) ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index);
}
@ -1847,7 +1886,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
}
template <class T>
bool GenericTransactionSignatureChecker<T>::CheckDefaultCheckTemplateVerifyHash(const std::vector<unsigned char>& hash) const
bool GenericTransactionSignatureChecker<T>::CheckDefaultCheckTemplateVerifyHash(const std::span<const unsigned char>& hash) const
{
// Should already be checked before calling...
assert(hash.size() == 32);

View file

@ -143,6 +143,15 @@ enum : uint32_t {
// Making unknown public key versions (in BIP 342 scripts) non-standard
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
// CHECKTEMPLATEVERIFY validation (BIP-119)
SCRIPT_VERIFY_CHECKTEMPLATEVERIFY = (1U << 21),
// discourage upgradable OP_CHECKTEMPLATEVERIFY hashes
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY = (1U << 22),
// discourage OP_CHECKTEMPLATEVERIFY
SCRIPT_VERIFY_DISCOURAGE_CHECKTEMPLATEVERIFY = (1U << 23),
// Constants to point to the highest flag in use. Add new flags above this line.
//
SCRIPT_VERIFY_END_MARKER
@ -276,7 +285,7 @@ public:
return false;
}
virtual bool CheckDefaultCheckTemplateVerifyHash(const std::vector<unsigned char>& hash) const
virtual bool CheckDefaultCheckTemplateVerifyHash(const std::span<const unsigned char>& hash) const
{
return false;
}
@ -317,7 +326,7 @@ public:
bool CheckSchnorrSignature(std::span<const unsigned char> sig, std::span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override;
bool CheckLockTime(const CScriptNum& nLockTime) const override;
bool CheckSequence(const CScriptNum& nSequence) const override;
bool CheckDefaultCheckTemplateVerifyHash(const std::vector<unsigned char>& hash) const override;
bool CheckDefaultCheckTemplateVerifyHash(const std::span<const unsigned char>& hash) const override;
};
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;

View file

@ -138,7 +138,7 @@ std::string GetOpName(opcodetype opcode)
case OP_NOP1 : return "OP_NOP1";
case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY";
case OP_NOP4 : return "OP_NOP4";
case OP_CHECKTEMPLATEVERIFY : return "OP_CHECKTEMPLATEVERIFY";
case OP_NOP5 : return "OP_NOP5";
case OP_NOP6 : return "OP_NOP6";
case OP_NOP7 : return "OP_NOP7";

View file

@ -198,7 +198,8 @@ enum opcodetype
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
OP_CHECKSEQUENCEVERIFY = 0xb2,
OP_NOP3 = OP_CHECKSEQUENCEVERIFY,
OP_NOP4 = 0xb3,
OP_CHECKTEMPLATEVERIFY = 0xb3,
OP_NOP4 = OP_CHECKTEMPLATEVERIFY,
OP_NOP5 = 0xb4,
OP_NOP6 = 0xb5,
OP_NOP7 = 0xb6,

View file

@ -25,6 +25,8 @@ std::string ScriptErrorString(const ScriptError serror)
return "Script failed an OP_CHECKSIGVERIFY operation";
case SCRIPT_ERR_NUMEQUALVERIFY:
return "Script failed an OP_NUMEQUALVERIFY operation";
case SCRIPT_ERR_TEMPLATE_MISMATCH:
return "Script failed an OP_CHECKTEMPLATEVERIFY operation";
case SCRIPT_ERR_SCRIPT_SIZE:
return "Script is too big";
case SCRIPT_ERR_PUSH_SIZE:

View file

@ -29,6 +29,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_CHECKMULTISIGVERIFY,
SCRIPT_ERR_CHECKSIGVERIFY,
SCRIPT_ERR_NUMEQUALVERIFY,
SCRIPT_ERR_TEMPLATE_MISMATCH,
/* Logical/Format/Canonical errors */
SCRIPT_ERR_BAD_OPCODE,

View file

@ -244,8 +244,8 @@
["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC", "OK"],
["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"],
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"],
["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"],
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"],
["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", "Discourage NOPx flag allows OP_NOP"],
@ -456,7 +456,7 @@
["NOP", "NOP1 1", "P2SH,STRICTENC", "OK"],
["NOP", "CHECKLOCKTIMEVERIFY 1", "P2SH,STRICTENC", "OK"],
["NOP", "CHECKSEQUENCEVERIFY 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP4 1", "P2SH,STRICTENC", "OK"],
["NOP", "CHECKTEMPLATEVERIFY 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP5 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP6 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP7 1", "P2SH,STRICTENC", "OK"],
@ -870,12 +870,11 @@
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["Ensure 100% coverage of discouraged NOPS"],
["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],