mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
Add OP_CHECKTEMPLATEVERIFY Opcode as OP_NOP4
Also modifies script_tests.json to enable OP_NOP4 as OP_CHECKTEMPLATEVERIFY.
This commit is contained in:
parent
3e090231b8
commit
a11706203d
7 changed files with 66 additions and 15 deletions
|
@ -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);
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"],
|
||||
|
|
Loading…
Add table
Reference in a new issue