BIP 0119: Difference between revisions
Update BIP text with latest version from https://github.com/bitcoin/bips/blob/cf0b529e78860fa2/bip-0119.mediawiki |
Update BIP text with latest version from https://github.com/bitcoin/bips/blob/edffe529056f6dfd/bip-0119.mediawiki |
||
Line 31: | Line 31: | ||
* There is at least one element on the stack, fail otherwise | * There is at least one element on the stack, fail otherwise | ||
* The element on the stack is 32 bytes long, NOP otherwise | * The element on the stack is 32 bytes long, NOP otherwise | ||
* The | * The DefaultCheckTemplateVerifyHash of the transaction at the current input index is equal to the element on the stack, fail otherwise | ||
The | The DefaultCheckTemplateVerifyHash commits to the serialized version, locktime, scriptSigs hash (if any | ||
non-null scriptSigs), number of inputs, sequences hash, number of outputs, outputs hash, and | non-null scriptSigs), number of inputs, sequences hash, number of outputs, outputs hash, and | ||
currently executing input index. | currently executing input index. | ||
Line 60: | Line 60: | ||
be expanded out of that UTXO when the demand for blockspace is decreased. These payments can be | be expanded out of that UTXO when the demand for blockspace is decreased. These payments can be | ||
structured in a tree-like fashion to reduce individual costs of redemption. | structured in a tree-like fashion to reduce individual costs of redemption. | ||
The below chart showcases the structure of these transactions in comparison to | The below chart showcases the structure of these transactions in comparison to | ||
Line 75: | Line 74: | ||
===Payment Channels=== | ===Payment Channels=== | ||
There are numerous payment channel related uses. | There are numerous payment channel related uses. | ||
Line 88: | Line 88: | ||
====Non-Interactive Channels==== | ====Non-Interactive Channels==== | ||
When opening a traditional payment channel, both parties to the channel must participate. This is | When opening a traditional payment channel, both parties to the channel must participate. This is | ||
because the channel uses pre-signed multi-sig transactions to ensure that a channel can always be | because the channel uses pre-signed multi-sig transactions to ensure that a channel can always be | ||
Line 98: | Line 99: | ||
====Increased Channel Routes==== | ====Increased Channel Routes==== | ||
In the Lightning Network protocol, Hashed Time Locked Contracts (HTLCS) are used in the construction | In the Lightning Network protocol, Hashed Time Locked Contracts (HTLCS) are used in the construction | ||
of channels. A new HTLC is required per route that the channel is serving in. | of channels. A new HTLC is required per route that the channel is serving in. | ||
Line 110: | Line 112: | ||
Because each HTLC can have its own relative time lock in the tree, this also improves the latency | Because each HTLC can have its own relative time lock in the tree, this also improves the latency | ||
sensitivity of the lightning protocol on contested channel close. | sensitivity of the lightning protocol on contested channel close. | ||
===Wallet Vaults=== | ===Wallet Vaults=== | ||
Line 137: | Line 138: | ||
==Detailed Specification== | ==Detailed Specification== | ||
The below code is the main logic for verifying CHECKTEMPLATEVERIFY, and is the canonical | The below code is the main logic for verifying CHECKTEMPLATEVERIFY, and is the canonical | ||
specification for the semantics of OP_CHECKTEMPLATEVERIFY. | specification for the semantics of OP_CHECKTEMPLATEVERIFY. | ||
Line 143: | Line 145: | ||
{ | { | ||
// if flags not enabled; treat as a NOP4 | // if flags not enabled; treat as a NOP4 | ||
if (!(flags & | if (!(flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH)) { | ||
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) | |||
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); | |||
break; | |||
} | |||
if (stack.size() < 1) | if (stack.size() < 1) | ||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||
// If the argument was not 32 bytes, treat as OP_NOP4: | // If the argument was not 32 bytes, treat as OP_NOP4: | ||
switch (stack.back().size()) { | switch (stack.back().size()) { | ||
case 32: | case 32: | ||
if (!checker. | if (!checker.CheckDefaultCheckTemplateVerifyHash(stack.back())) { | ||
return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH); | return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH); | ||
} | } | ||
Line 165: | Line 173: | ||
The hash is computed as follows: | The hash is computed as follows: | ||
uint256 | uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, uint32_t input_index) { | ||
return | return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequenceSHA256(tx), input_index); | ||
} | } | ||
uint256 | uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash, | ||
const uint32_t input_index) { | const uint32_t input_index) { | ||
bool skip_scriptSigs = std::find_if(tx.vin.begin(), tx.vin.end(), | bool skip_scriptSigs = std::find_if(tx.vin.begin(), tx.vin.end(), | ||
[](const CTxIn& c) { return c.scriptSig != CScript(); }) == tx.vin.end(); | [](const CTxIn& c) { return c.scriptSig != CScript(); }) == tx.vin.end(); | ||
return skip_scriptSigs ? | return skip_scriptSigs ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) : | ||
GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index); | |||
} | } | ||
uint256 | uint256 GetDefaultCheckTemplateVerifyHashWithScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash, | ||
const uint256& scriptSig_hash, const uint32_t input_index) { | const uint256& scriptSig_hash, const uint32_t input_index) { | ||
auto h = CHashWriter(SER_GETHASH, 0) | auto h = CHashWriter(SER_GETHASH, 0) | ||
Line 188: | Line 196: | ||
return h.GetSHA256(); | return h.GetSHA256(); | ||
} | } | ||
uint256 | uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash, | ||
const uint32_t input_index) { | const uint32_t input_index) { | ||
auto h = CHashWriter(SER_GETHASH, 0) | auto h = CHashWriter(SER_GETHASH, 0) | ||
Line 201: | Line 209: | ||
} | } | ||
A PayToBareDefaultCheckTemplateVerifyHash output matches the following template: | |||
bool CScript::IsPayToBareDefaultCheckTemplateVerifyHash() const | |||
bool CScript:: | |||
{ | { | ||
// Extra-fast test for pay-to-basic-standard-template CScripts: | // Extra-fast test for pay-to-basic-standard-template CScripts: | ||
Line 214: | Line 221: | ||
==Deployment== | ==Deployment== | ||
Deployment should be done via BIP 9 VersionBits. | Deployment should be done via BIP 9 VersionBits deployed through Speedy Trial. | ||
The start time and bit in the implementation are currently set to bit 5 and | The start time and bit in the implementation are currently set to bit 5 and | ||
NEVER_ACTIVE/NO_TIMEOUT, but this is subject to change while the BIP is a draft. | |||
For the avoidance of unclarity, the parameters are: | For the avoidance of unclarity, the parameters to be determined are: | ||
// Deployment of CTV (BIP 119) | |||
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].bit = 5; | consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].bit = 5; | ||
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].nStartTime = | consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; | ||
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].nTimeout = | consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; | ||
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].min_activation_height = 0; | |||
Until BIP-119 reaches ACTIVE state and the | |||
SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH flag is set, the network should | |||
execute a NOP4 as SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS for policy and a NOP for | |||
consensus. | |||
In order to facilitate using CHECKTEMPLATEVERIFY, the common case of a | In order to facilitate using CHECKTEMPLATEVERIFY, the common case of a | ||
PayToBareDefaultCheckTemplateVerifyHash | |||
with no scriptSig data shall be made standard to permit relaying. Future template types may be | with no scriptSig data shall be made standard to permit relaying. Future template types may be | ||
standardized later as policy changes. | standardized later as policy changes. | ||
Line 233: | Line 248: | ||
A reference implementation and tests are available here: | A reference implementation and tests are available here: | ||
https://github.com/JeremyRubin/bitcoin/tree/checktemplateverify. | https://github.com/JeremyRubin/bitcoin/tree/checktemplateverify. | ||
==Rationale== | ==Rationale== | ||
Line 239: | Line 253: | ||
The goal of CHECKTEMPLATEVERIFY is to be minimal impact on the existing codebase -- in the | The goal of CHECKTEMPLATEVERIFY is to be minimal impact on the existing codebase -- in the | ||
future, as we become aware of more complex but shown to be safe use cases new template types can be added. | future, as we become aware of more complex but shown to be safe use cases new template types can be added. | ||
Below we'll discuss the rules one-by-one: | Below we'll discuss the rules one-by-one: | ||
====The DefaultCheckTemplateVerifyHash of the transaction at the current input index matches the top of the stack==== | |||
====The | |||
The set of data committed to is a superset of data which can impact the TXID of the transaction, | The set of data committed to is a superset of data which can impact the TXID of the transaction, | ||
Line 251: | Line 262: | ||
of time. Otherwise, CHECKTEMPLATEVERIFY would not be usable for Channel Factory type constructions | of time. Otherwise, CHECKTEMPLATEVERIFY would not be usable for Channel Factory type constructions | ||
as the redemption TXID could be malleated and pre-signed transactions invalidated. | as the redemption TXID could be malleated and pre-signed transactions invalidated. | ||
=====Committing to the version and locktime===== | =====Committing to the version and locktime===== | ||
Line 276: | Line 285: | ||
If no scriptSigs are set in the transaction, there is no purpose in hashing the data or including it | If no scriptSigs are set in the transaction, there is no purpose in hashing the data or including it | ||
in the | in the DefaultCheckTemplateVerifyHash, so we elide it. It is expected to be common that no scriptSigs will be | ||
set as segwit mandates that the scriptSig must be empty (to avoid malleability). | set as segwit mandates that the scriptSig must be empty (to avoid malleability). | ||
Line 282: | Line 291: | ||
precomputed for each transaction to optimize SIGHASH_ALL signatures. | precomputed for each transaction to optimize SIGHASH_ALL signatures. | ||
Committing to the hash additionally makes it simpler to construct | Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from | ||
script. | script. | ||
=====Committing to the number of inputs===== | =====Committing to the number of inputs===== | ||
Line 318: | Line 326: | ||
In principal, committing to the Sequences Hash (below) implicitly commits to the number of inputs, | In principal, committing to the Sequences Hash (below) implicitly commits to the number of inputs, | ||
making this field strictly redundant. However, separately committing to this number makes it easier | making this field strictly redundant. However, separately committing to this number makes it easier | ||
to construct | to construct DefaultCheckTemplateVerifyHash from script. | ||
We treat the number of inputs as a `uint32_t` because signature checking code expects nIn to be an | We treat the number of inputs as a `uint32_t` because signature checking code expects nIn to be an | ||
Line 333: | Line 341: | ||
precomputed for each transaction to optimize SIGHASH_ALL signatures. | precomputed for each transaction to optimize SIGHASH_ALL signatures. | ||
Committing to the hash additionally makes it simpler to construct | Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from | ||
script. | script. | ||
Line 340: | Line 348: | ||
In principal, committing to the Outputs Hash (below) implicitly commits to the number of outputs, | In principal, committing to the Outputs Hash (below) implicitly commits to the number of outputs, | ||
making this field strictly redundant. However, separately committing to this number makes it easier | making this field strictly redundant. However, separately committing to this number makes it easier | ||
to construct | to construct DefaultCheckTemplateVerifyHash from script. | ||
We treat the number of outputs as a `uint32_t` because a `COutpoint` index is a `uint32_t`, even | We treat the number of outputs as a `uint32_t` because a `COutpoint` index is a `uint32_t`, even | ||
Line 353: | Line 361: | ||
precomputed for each transaction to optimize SIGHASH_ALL signatures. | precomputed for each transaction to optimize SIGHASH_ALL signatures. | ||
Committing to the hash additionally makes it simpler to construct | Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from | ||
script. | script. | ||
Line 374: | Line 382: | ||
=====Committing to Values by Hash===== | =====Committing to Values by Hash===== | ||
Committing to values by hash makes it easier and more efficient to construct a | Committing to values by hash makes it easier and more efficient to construct a | ||
DefaultCheckTemplateVerifyHash | |||
from script. Fields which are not intended to be set may be committed to by hash without incurring | from script. Fields which are not intended to be set may be committed to by hash without incurring | ||
O(n) overhead to re-hash. | O(n) overhead to re-hash. | ||
Line 382: | Line 391: | ||
a hash midstate in the script. | a hash midstate in the script. | ||
=====Using SHA256===== | |||
SHA256 is a 32 byte hash which meets Bitcoin's security standards and is | |||
available already inside of Bitcoin Script for programmatic creation of template | |||
programs. | |||
RIPEMD160, a 20 byte hash, might also be a viable hash in some contexts and has some benefits. For fee efficiency, | |||
RIPEMD160 saves 12 bytes. However, RIPEMD160 was not chosen for BIP-119 because it introduces | |||
risks around the verification of programs created by third parties to be subject to a | |||
[birthday-attack https://bitcoin.stackexchange.com/questions/54841/birthday-attack-on-p2sh] on | |||
transaction preimages. | |||
=====Using Non-Tagged Hashes===== | |||
The Taproot/Schnorr BIPs use Tagged Hashes | |||
(`SHA256(SHA256(tag)||SHA256(tag)||msg)`) to prevent taproot leafs, branches, | |||
tweaks, and signatures from overlapping in a way that might introduce a security | |||
[vulnerability https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-June/016091.html]. | |||
OP_CHECKTEMPLATEVERIFY is not subject to this sort of vulnerability as the | |||
hashes are effectively tagged externally, that is, by OP_CHECKTEMPLATEVERIFY | |||
itself and therefore cannot be confused for another hash. | |||
It would be a conservative design decisison to make it a tagged hash even if | |||
there was no obvious benefit and no cost. However, in the future, if OP_CAT were | |||
to be introduced to Bitcoin, it would make programs which dynamically build | |||
OP_CHECKTEMPLATEVERIFY hashes less space-efficient. Therefore, bare untagged hashes | |||
are used in BIP-119. | |||
=====The Ordering of Fields===== | =====The Ordering of Fields===== | ||
Strictly speaking, the ordering of fields is insignificant. However, with a carefully selected | Strictly speaking, the ordering of fields is insignificant. However, with a | ||
order, the efficiency of future scripts (e.g., those using a OP_CAT or OP_SHA256STREAM) may be | carefully selected order, the efficiency of future scripts (e.g., those using a | ||
OP_CAT or OP_SHA256STREAM) may be improved (as described in the Future Upgrades | |||
section). | |||
In particular, the order is selected in order of least likely to change to most. | In particular, the order is selected in order of least likely to change to most. | ||
Line 417: | Line 455: | ||
able to express a "don't care" index easily (e.g., for decentralized kickstarter-type transactions), | able to express a "don't care" index easily (e.g., for decentralized kickstarter-type transactions), | ||
this value is placed last. | this value is placed last. | ||
===Design Tradeoffs and Risks=== | ===Design Tradeoffs and Risks=== | ||
Line 438: | Line 469: | ||
Furthermore, templates are restricted to be spendable as a known number of inputs only, preventing | Furthermore, templates are restricted to be spendable as a known number of inputs only, preventing | ||
unintentional introduction of the 'half spend' problem. | unintentional introduction of the 'half spend' problem. | ||
Templates, as restricted as they are, bear some risks. | Templates, as restricted as they are, bear some risks. | ||
====Permanently Unspendable Outputs==== | ====Permanently Unspendable Outputs==== | ||
The preimage argument passed to CHECKTEMPLATEVERIFY may be unknown or otherwise unsatisfiable. | The preimage argument passed to CHECKTEMPLATEVERIFY may be unknown or otherwise unsatisfiable. | ||
However, requiring knowledge that an address is spendable from is incompatible with sender's ability | However, requiring knowledge that an address is spendable from is incompatible with sender's ability | ||
Line 450: | Line 481: | ||
====Forwarding Addresses==== | ====Forwarding Addresses==== | ||
Key-reuse with CHECKTEMPLATEVERIFY may be used as a form of "forwarding address contract". | Key-reuse with CHECKTEMPLATEVERIFY may be used as a form of "forwarding address contract". | ||
A forwarding address is an address which can automatically execute in a predefined way. | A forwarding address is an address which can automatically execute in a predefined way. | ||
Line 474: | Line 506: | ||
Because CHECKTEMPLATEVERIFY commits to the input index currently being spent, reused-keys are | Because CHECKTEMPLATEVERIFY commits to the input index currently being spent, reused-keys are | ||
guaranteed to execute in separate transactions which reduces the risk of "half-spend" type issues. | guaranteed to execute in separate transactions which reduces the risk of "half-spend" type issues. | ||
====NOP-Default and Standardness Rules==== | ====NOP-Default and Standardness Rules==== | ||
Line 488: | Line 519: | ||
consensus-valid transaction may be caused, leading to a potential loss of funds. | consensus-valid transaction may be caused, leading to a potential loss of funds. | ||
====Feature Redundancy==== | |||
CHECKTEMPLATEVERIFY templates are substantially less risky than other covenant systems. If | CHECKTEMPLATEVERIFY templates are substantially less risky than other covenant systems. If | ||
implemented, other covenant systems could make the CHECKTEMPLATEVERIFY's functionality redundant. | implemented, other covenant systems could make the CHECKTEMPLATEVERIFY's functionality redundant. | ||
Line 502: | Line 533: | ||
Alternatively, SIGHASH_ANYPREVOUTANYSCRIPT based covenant designs can implement | Alternatively, SIGHASH_ANYPREVOUTANYSCRIPT based covenant designs can implement | ||
something similar to templates, via a scriptPubKey like: | something similar to templates, via a scriptPubKey like: | ||
<sig of desired TX with PK and fixed nonce R || SIGHASH_ANYPREVOUTANYSCRIPT <PK with public SK> OP_CHECKSIG | <sig of desired TX with PK and fixed nonce R || SIGHASH_ANYPREVOUTANYSCRIPT <PK with public SK> OP_CHECKSIG | ||
SIGHASH_ANYPREVOUTANYSCRIPT bears additional technical and implementation risks that may preclude | SIGHASH_ANYPREVOUTANYSCRIPT bears additional technical and implementation risks | ||
its viability for inclusion in Bitcoin, but the capabilities above are similar to what | that may preclude its viability for inclusion in Bitcoin, but the capabilities | ||
CHECKTEMPLATEVERIFY offers. | above are similar to what CHECKTEMPLATEVERIFY offers. The key functional | ||
speed, as | difference between SIGHASH_ANYPREVOUTANYSCRIPT and OP_CHECKTEMPLATEVERIFY is | ||
significant when constructing large payment trees or programmatic compilations. CHECKTEMPLATEVERIFY | that OP_CHECKTEMPLATEVERIFY restricts the number of additional inputs and | ||
also has a feature-wise benefit in that it provides a robust pathway for future template upgrades | precludes dynamically determined change outputs while | ||
SIGHASH_ANYPREVOUTANYSCRIPT can be combined with SIGHASH_SINGLE or | |||
SIGHASH_ANYONECANPAY. For the additional inputs, OP_CHECKTEMPLATEVERIFY also | |||
commits to the scriptsig and sequence, which allows for specifying specific P2SH | |||
scripts (or segwit v0 P2SH) which have some use cases. Furthermore, | |||
CHECKTEMPLATEVERIFY has benefits in terms of script size (depending on choice of | |||
PK, SIGHASH_ANYPREVOUTANYSCRIPT may use about 2x-3x the bytes) and verification | |||
speed, as OP_CHECKTEMPLATEVERIFY requires only hash computation rather than | |||
signature operations. This can be significant when constructing large payment | |||
trees or programmatic compilations. CHECKTEMPLATEVERIFY also has a feature-wise | |||
benefit in that it provides a robust pathway for future template upgrades. | |||
OP_CHECKSIGFROMSTACKVERIFY along with OP_CAT may also be used to emulate | |||
CHECKTEMPLATEVERIFY. However such constructions are more complicated to use | |||
than CHECKTEMPLATEVERIFY, and encumbers additional verification overhead absent | |||
from CHECKTEMPLATEVERIFY. These types of covenants also bear similar potential | |||
recursion issues to OP_COV which make it unlikely for inclusion in Bitcoin. | |||
Given the simplicity of this approach to implement and analyze, and the benefits realizable by user | Given the simplicity of this approach to implement and analyze, and the benefits realizable by user | ||
applications, CHECKTEMPLATEVERIFY's template based approach is proposed in lieu of more complete | applications, CHECKTEMPLATEVERIFY's template based approach is proposed in lieu of more complete | ||
covenants system. | covenants system. | ||
====Future Upgrades==== | |||
This section describes updates to OP_CHECKTEMPLATEVERIFY that are possible in | |||
the future as well as synergies with other possible upgrades. | |||
=====CHECKTEMPLATEVERIFY Versions===== | |||
OP_CHECKTEMPLATEVERIFY currently only verifies properties of 32 byte arguments. | |||
In the future, meaning could be ascribed to other length arguments. For | |||
example, a 33-byte argument could just the last byte as a control program. In | |||
that case, DefaultCheckTemplateVerifyHash could be computed when the flag byte | |||
is set to CTVHASH_ALL. Other programs could be added similar to SIGHASH_TYPEs. | |||
For example, CTVHASH_GROUP could read data from the Taproot Annex for | |||
compatibility with SIGHASH_GROUP type proposals and allow dynamic malleability | |||
of which indexes get hashed for bundling. | |||
=====Eltoo with OP_CHECKSIGFROMSTACKVERIFY===== | |||
Were both OP_CHECKTEMPLATEVERIFY and OP_CHECKSIGFROMSTACKVERIFY to be added to | |||
Bitcoin, it would be possible to implement a variant of Eltoo's floating | |||
transactions using the following script: | |||
witness(S+n): <sig> <H(tx with nLockTime S+n paying to program(S+n))> | |||
program(S): OP_CHECKTEMPLATEVERIFY <musig_key(pk_update_a, pk_update_b)> OP_CHECKSIGFROMSTACKVERIFY <S+1> OP_CHECKLOCKTIMEVERIFY | |||
Compared to SIGHASH_ANYPREVOUTANYSCRIPT, because OP_CHECKTEMPLATEVERIFY does not | |||
allow something similar to SIGHASH_ANYONECANPAY or SIGHASH_SINGLE, protocol | |||
implementers might elect to sign multiple versions of transactions with CPFP | |||
Anchor Outputs or Inputs for paying fees or an alternative such as transaction | |||
sponsors might be considered. | |||
=====OP_AMOUNTVERIFY===== | |||
An opcode which verifies the exact amount that is being spent in the | |||
transaction, the amount paid as fees, or made available in a given output could | |||
be used to make safer OP_CHECKTEMPLATEVERIFY addressses. For instance, if the | |||
OP_CHECKTEMPLATEVERIFY program P expects exactly S satoshis, sending S-1 | |||
satoshis would result in a frozen UTXO and sending S+n satoshis would result in | |||
n satoshis being paid to fee. A range check could restrict the program to only | |||
apply for expected values and default to a keypath otherwise, e.g.: | |||
IF OP_AMOUNTVERIFY <N> OP_GREATER <PK> CHECKSIG ELSE <H> OP_CHECKTEMPLATEVERIFY | |||
=====OP_CAT/OP_SHA256STREAM===== | |||
OP_CHECKTEMPLATEVERIFY is (as described in the Ordering of Fields section) | |||
efficient for building covenants dynamically should Bitcoin get enhanced string | |||
manipulation opcodes. | |||
As an example, the following code checks an input index argument and | |||
concatenates it to the template and checks the template matches the transaction. | |||
OP_SIZE 4 OP_EQUALVERIF | |||
<nVersion || nLockTime || input count || sequences hash || output count || outputs hash> | |||
OP_SWAP OP_CAT OP_SHA256 OP_CHECKTEMPLATEVERIFY | |||
== Backwards Compatibility == | == Backwards Compatibility == | ||
Line 530: | Line 626: | ||
for mining and block validation. Similar soft forks for OP_CHECKSEQUENCEVERIFY and OP_CHECKLOCKTIMEVERIFY | for mining and block validation. Similar soft forks for OP_CHECKSEQUENCEVERIFY and OP_CHECKLOCKTIMEVERIFY | ||
(see BIP-0065 and BIP-0112) have similarly changed OP_NOP semantics without introducing compatibility issues. | (see BIP-0065 and BIP-0112) have similarly changed OP_NOP semantics without introducing compatibility issues. | ||
In contrast to previous forks, OP_CHECKTEMPLATEVERIFY will not make scripts | |||
valid for policy until the new rule is active. | |||
Older wallet software will be able to accept spends from OP_CHECKTEMPLATEVERIFY outputs, but will | Older wallet software will be able to accept spends from OP_CHECKTEMPLATEVERIFY outputs, but will | ||
require an upgrade in order to treat | require an upgrade in order to treat PayToBareDefaultCheckTemplateVerifyHash chains with a confirmed ancestor as | ||
being "trusted" (i.e., eligible for spending before the transaction is confirmed). | being "trusted" (i.e., eligible for spending before the transaction is confirmed). | ||
Line 538: | Line 637: | ||
for older node versions that can be patched but not upgraded to a newer major release. | for older node versions that can be patched but not upgraded to a newer major release. | ||
== References == | |||
*[https://utxos.org utxos.org informational site] | *[https://utxos.org utxos.org informational site] | ||
*[https://www.youtube.com/watch?v=YxsjdIl0034&t=2451 Scaling Bitcoin Presentation] | *[https://www.youtube.com/watch?v=YxsjdIl0034&t=2451 Scaling Bitcoin Presentation] | ||
Line 551: | Line 650: | ||
===Note on Similar Alternatives=== | ===Note on Similar Alternatives=== | ||
An earlier version of CHECKTEMPLATEVERIFY, CHECKOUTPUTSHASHVERIFY, is withdrawn | An earlier version of CHECKTEMPLATEVERIFY, CHECKOUTPUTSHASHVERIFY, is withdrawn | ||
in favor of CHECKTEMPLATEVERIFY. CHECKOUTPUTSHASHVERIFY did not commit to the | in favor of CHECKTEMPLATEVERIFY. CHECKOUTPUTSHASHVERIFY did not commit to the | ||
Line 563: | Line 663: | ||
==Copyright== | ==Copyright== | ||
This document is licensed under the 3-clause BSD license. | This document is licensed under the 3-clause BSD license. |
Revision as of 16:00, 15 December 2021
This page describes a BIP (Bitcoin Improvement Proposal). |
Please do not modify this page. This is a mirror of the BIP from the source Git repository here. |
BIP: 119 Layer: Consensus (soft fork) Title: CHECKTEMPLATEVERIFY Author: Jeremy Rubin <j@rubin.io> Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0119 Status: Draft Type: Standards Track Created: 2020-01-06 License: BSD-3-Clause
Abstract
This BIP proposes a new opcode, OP_CHECKTEMPLATEVERIFY, to be activated as a change to the semantics of OP_NOP4.
The new opcode has applications for transaction congestion control and payment channel instantiation, among others, which are described in the Motivation section of this BIP.
Summary
OP_CHECKTEMPLATEVERIFY uses opcode OP_NOP4 (0xb3) as a soft fork upgrade.
OP_CHECKTEMPLATEVERIFY does the following:
- There is at least one element on the stack, fail otherwise
- The element on the stack is 32 bytes long, NOP otherwise
- The DefaultCheckTemplateVerifyHash of the transaction at the current input index is equal to the element on the stack, fail otherwise
The DefaultCheckTemplateVerifyHash commits to the serialized version, locktime, scriptSigs hash (if any non-null scriptSigs), number of inputs, sequences hash, number of outputs, outputs hash, and currently executing input index.
The recommended standardness rules additionally:
- Reject non-32 byte as SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS.
Motivation
Covenants are restrictions on how a coin may be spent beyond key ownership. Covenants can be useful to construct smart contracts. As covenants are complex to implement and risk of introducing fungibility discriminants they have not been seriously considered for inclusion in Bitcoin.
This BIP introduces a simple covenant called a *template* which enables a limited set of highly valuable use cases without significant risk.
A few examples are described below, which should be the subject of future non-consensus standardization efforts.
Congestion Controlled Transactions
When there is a high demand for blockspace it becomes very expensive to make transactions. A large volume payment processor may aggregate all their payments into a single O(1) transaction commitment for purposes of confirmation using CHECKTEMPLATEVERIFY. Then, some time later, the payments can be expanded out of that UTXO when the demand for blockspace is decreased. These payments can be structured in a tree-like fashion to reduce individual costs of redemption.
The below chart showcases the structure of these transactions in comparison to normal transactions and batched transactions.
<img src="bip-0119/states.svg" align="middle"></img>
A simulation is shown below of what impact this could have on mempool backlog given 5% network adoption, and 50% network adoption. The code for the simulation is provided in this BIP's subdirectory.
<img src="bip-0119/five.png" align="middle"></img> <img src="bip-0119/fifty.png" align="middle"></img>
Payment Channels
There are numerous payment channel related uses.
Channel Factories
Using CHECKTEMPLATEVERIFY for Channel Factories is similar to the use for Congestion Control, except the leaf node transactions are channels instead of plain payments. The channel can be between the sender and recipient or a target of recipient's choice. Using an CHECKTEMPLATEVERIFY, the recipient may give the sender an address which makes a tree of channels unbeknownst to them. These channels are time insensitive for setup, as all punishments are relative timelocked to the penultimate transaction node. Thus, coins sent using a congestion controlled transaction can still enjoy instant liquidity.
Non-Interactive Channels
When opening a traditional payment channel, both parties to the channel must participate. This is because the channel uses pre-signed multi-sig transactions to ensure that a channel can always be exited by either party, before entering. With CHECKTEMPLATEVERIFY, it’s possible for a single party to construct a channel which either party can exit from without requiring signatures from both parties. These payment channels can operate in one direction, paying to the channel "listener" without need for their private key to be online. <img src="bip-0119/nic.svg" align="middle"></img>
Increased Channel Routes
In the Lightning Network protocol, Hashed Time Locked Contracts (HTLCS) are used in the construction of channels. A new HTLC is required per route that the channel is serving in. In BOLT #2, this maximum number of HTLCs in a channel is hard limited to 483 as the maximum safe size to prevent the transaction from being too large to be valid. In common software implementations such as LND, this limit is set much lower to 12 HTLCS. This is because accepting a larger number of HTLCS makes it more difficult for transactions to confirm during congested periods as they must pay higher fees. Therefore, similarly to how congestion control is handled for normal transaction, lightning channel updates can be done across an CHECKTEMPLATEVERIFY tree, allowing nodes to safely use many more HTLCS. Because each HTLC can have its own relative time lock in the tree, this also improves the latency sensitivity of the lightning protocol on contested channel close.
Wallet Vaults
When greater security is required for cold storage solutions, there can be default script paths that move funds from one target to another target. For example, a cold wallet can be set up where one customer support desk can, without further authorization, move a portion of the funds (using multiple pre-set amounts) into a lukewarm wallet operated by an isolated support desk. The support desk can then issue some funds to a hot wallet, and send the remainder back to cold storage with a similar withdrawal mechanism in place. This is all possible without CHECKTEMPLATEVERIFY, but CHECKTEMPLATEVERIFY eliminates the need for coordination and online signers, as well as reducing the ability for a support desk to improperly move funds. Furthermore, all such designs can be combined with relative time locks to give time for compliance and risk desks to intervene.
<img src="bip-0119/vaults.svg" align="middle"></img>
CoinJoin
CHECKTEMPLATEVERIFY makes it much easier to set up trustless CoinJoins than previously because participants agree on a single output which pays all participants, which will be lower fee than before. Further Each participant doesn't need to know the totality of the outputs committed to by that output, they only have to verify their own sub-tree will pay them.
Detailed Specification
The below code is the main logic for verifying CHECKTEMPLATEVERIFY, and is the canonical specification for the semantics of OP_CHECKTEMPLATEVERIFY.
case OP_CHECKTEMPLATEVERIFY: { // if flags not enabled; treat as a NOP4 if (!(flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH)) { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); 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: if (!checker.CheckDefaultCheckTemplateVerifyHash(stack.back())) { 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_NOPS) { return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); } } } break;
The hash is computed as follows:
uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, uint32_t input_index) { return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequenceSHA256(tx), input_index); } uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& 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) : GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index); } uint256 GetDefaultCheckTemplateVerifyHashWithScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash, const uint256& scriptSig_hash, const uint32_t input_index) { auto h = CHashWriter(SER_GETHASH, 0) << tx.nVersion << tx.nLockTime << scriptSig_hash << uint32_t(tx.vin.size()) << sequences_hash << uint32_t(tx.vout.size()) << outputs_hash << input_index; return h.GetSHA256(); } uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash, const uint32_t input_index) { auto h = CHashWriter(SER_GETHASH, 0) << tx.nVersion << tx.nLockTime << uint32_t(tx.vin.size()) << sequences_hash << uint32_t(tx.vout.size()) << outputs_hash << input_index; return h.GetSHA256(); }
A PayToBareDefaultCheckTemplateVerifyHash output matches the following template:
bool CScript::IsPayToBareDefaultCheckTemplateVerifyHash() const { // Extra-fast test for pay-to-basic-standard-template CScripts: return (this->size() == 34 && (*this)[0] == 0x20 && (*this)[33] == OP_CHECKTEMPLATEVERIFY); }
Deployment
Deployment should be done via BIP 9 VersionBits deployed through Speedy Trial.
The start time and bit in the implementation are currently set to bit 5 and NEVER_ACTIVE/NO_TIMEOUT, but this is subject to change while the BIP is a draft.
For the avoidance of unclarity, the parameters to be determined are:
// Deployment of CTV (BIP 119) consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].bit = 5; consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY].min_activation_height = 0;
Until BIP-119 reaches ACTIVE state and the SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH flag is set, the network should execute a NOP4 as SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS for policy and a NOP for consensus.
In order to facilitate using CHECKTEMPLATEVERIFY, the common case of a PayToBareDefaultCheckTemplateVerifyHash with no scriptSig data shall be made standard to permit relaying. Future template types may be standardized later as policy changes.
Reference Implementation
A reference implementation and tests are available here: https://github.com/JeremyRubin/bitcoin/tree/checktemplateverify.
Rationale
The goal of CHECKTEMPLATEVERIFY is to be minimal impact on the existing codebase -- in the future, as we become aware of more complex but shown to be safe use cases new template types can be added.
Below we'll discuss the rules one-by-one:
The DefaultCheckTemplateVerifyHash of the transaction at the current input index matches the top of the stack
The set of data committed to is a superset of data which can impact the TXID of the transaction, other than the inputs. This ensures that for a given known input, the TXIDs can also be known ahead of time. Otherwise, CHECKTEMPLATEVERIFY would not be usable for Channel Factory type constructions as the redemption TXID could be malleated and pre-signed transactions invalidated.
Committing to the version and locktime
Were these values not committed, it would be possible to delay the spending of an output arbitrarily as well as possible to change the TXID.
Committing these values, rather than restricting them to specific values, is more flexible as it permits users of CHECKTEMPLATEVERIFY the set the version and locktime as they please.
Committing to the ScriptSigs Hash
The scriptsig in a segwit transaction must be exactly empty, unless it is a P2SH segwit transaction in which case it must be only the exact redeemscript. P2SH is incompatible (unless the P2SH hash is broken) with CHECKTEMPLATEVERIFY because the template hash must commit to the ScriptSig, which must contain the redeemscript, which is a hash cycle.
To prevent malleability when not using a segwit input, we also commit to the scriptsig. This makes it possible to use a 2 input CHECKTEMPLATEVERIFY with a legacy pre-signed spend, as long as the exact scriptsig for the legacy output is committed. This is more robust than simply disallowing any scriptSig to be set with CHECKTEMPLATEVERIFY.
If no scriptSigs are set in the transaction, there is no purpose in hashing the data or including it in the DefaultCheckTemplateVerifyHash, so we elide it. It is expected to be common that no scriptSigs will be set as segwit mandates that the scriptSig must be empty (to avoid malleability).
We commit to the hash rather than the values themselves as this is already precomputed for each transaction to optimize SIGHASH_ALL signatures.
Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from script.
Committing to the number of inputs
If we allow more than one input to be spent in the transaction then it would be possible for two outputs to request payment to the same set of outputs, resulting in half the intended payments being discarded, the "half-spend" problem.
Furthermore, the restriction on which inputs can be co-spent is critical for payments-channel constructs where a stable TXID is a requirement (updates would need to be signed on all combinations of inputs).
However, there are legitimate use cases for allowing multiple inputs. For example:
Script paths:
Path A: <+24 hours> OP_CHECKSEQUENCEVERIFY OP_CHECKTEMPLATEVERIFY <Pay Alice 1 Bitcoin (1 input) nLockTime for +24 hours> Path B: OP_CHECKTEMPLATEVERIFY <Pay Bob 2 Bitcoin (2 inputs)>
In this case, there are 24 hours for the output to, with the addition of a second output, pay Bob 2 BTC. If 24 hours lapses, then Alice may redeem her 1 BTC from the contract. Both input UTXOs may have the exact same Path B, or only one.
The issue with these constructs is that there are N! orders that the inputs can be ordered in and it's not generally possible to restrict the ordering.
CHECKTEMPLATEVERIFY allows for users to guarantee the exact number of inputs being spent. In general, using CHECKTEMPLATEVERIFY with more than one input is difficult and exposes subtle issues, so multiple inputs should not be used except in specific applications.
In principal, committing to the Sequences Hash (below) implicitly commits to the number of inputs, making this field strictly redundant. However, separately committing to this number makes it easier to construct DefaultCheckTemplateVerifyHash from script.
We treat the number of inputs as a `uint32_t` because signature checking code expects nIn to be an `unsigned int`, even though in principal a transaction can encode more than a `uint32_t`'s worth of inputs.
Committing to the Sequences Hash
If we don't commit to the sequences, then the TXID can be malleated. This also allows us to enforce a relative sequence lock without an OP_CSV. It is insufficient to just pair CHECKTEMPLATEVERIFY with OP_CSV because OP_CSV enforces a minimum nSequence value, not a literal value.
We commit to the hash rather than the values themselves as this is already precomputed for each transaction to optimize SIGHASH_ALL signatures.
Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from script.
Committing to the Number of Outputs
In principal, committing to the Outputs Hash (below) implicitly commits to the number of outputs, making this field strictly redundant. However, separately committing to this number makes it easier to construct DefaultCheckTemplateVerifyHash from script.
We treat the number of outputs as a `uint32_t` because a `COutpoint` index is a `uint32_t`, even though in principal a transaction could encode more outputs.
Committing to the outputs hash
This ensures that spending the UTXO is guaranteed to create the exact outputs requested.
We commit to the hash rather than the values themselves as this is already precomputed for each transaction to optimize SIGHASH_ALL signatures.
Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from script.
Committing to the current input's index
Committing to the currently executing input's index is not strictly needed for anti-malleability, however it does restrict the input orderings eliminating a source of malleability for protocol designers.
However, committing to the index eliminates key-reuse vulnerability to the half-spend problem. As CHECKTEMPLATEVERIFY scripts commit to being spent at particular index, reused instances of these scripts cannot be spent at the same index, which implies that they cannot be spent in the same transaction. This makes it safer to design wallet vault contracts without half-spend vulnerabilities.
Committing to the current index doesn't prevent one from expressing a CHECKTEMPLATEVERIFY which can be spent at multiple indicies. In current script, the CHECKTEMPLATEVERIFY operation can be wrapped in an OP_IF for each index (or Tapscript branches in the future). If OP_CAT or OP_SHA256STREAM are added to Bitcoin, the index may simply be passed in by the witness before hashing.
Committing to Values by Hash
Committing to values by hash makes it easier and more efficient to construct a DefaultCheckTemplateVerifyHash from script. Fields which are not intended to be set may be committed to by hash without incurring O(n) overhead to re-hash.
Furthermore, if OP_SHA256STREAM is added in the future, it may be possible to write a script which allows adding a single output to a list of outputs without incurring O(n) overhead by committing to a hash midstate in the script.
Using SHA256
SHA256 is a 32 byte hash which meets Bitcoin's security standards and is available already inside of Bitcoin Script for programmatic creation of template programs.
RIPEMD160, a 20 byte hash, might also be a viable hash in some contexts and has some benefits. For fee efficiency, RIPEMD160 saves 12 bytes. However, RIPEMD160 was not chosen for BIP-119 because it introduces risks around the verification of programs created by third parties to be subject to a [birthday-attack https://bitcoin.stackexchange.com/questions/54841/birthday-attack-on-p2sh] on transaction preimages.
Using Non-Tagged Hashes
The Taproot/Schnorr BIPs use Tagged Hashes (`SHA256(SHA256(tag)||SHA256(tag)||msg)`) to prevent taproot leafs, branches, tweaks, and signatures from overlapping in a way that might introduce a security [vulnerability https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-June/016091.html].
OP_CHECKTEMPLATEVERIFY is not subject to this sort of vulnerability as the hashes are effectively tagged externally, that is, by OP_CHECKTEMPLATEVERIFY itself and therefore cannot be confused for another hash.
It would be a conservative design decisison to make it a tagged hash even if there was no obvious benefit and no cost. However, in the future, if OP_CAT were to be introduced to Bitcoin, it would make programs which dynamically build OP_CHECKTEMPLATEVERIFY hashes less space-efficient. Therefore, bare untagged hashes are used in BIP-119.
The Ordering of Fields
Strictly speaking, the ordering of fields is insignificant. However, with a carefully selected order, the efficiency of future scripts (e.g., those using a OP_CAT or OP_SHA256STREAM) may be improved (as described in the Future Upgrades section).
In particular, the order is selected in order of least likely to change to most.
- nVersion
- nLockTime
- scriptSig hash (maybe!)
- input count
- sequences hash
- output count
- outputs hash
- input index
Several fields are infrequently modified. nVersion should change infrequently. nLockTime should generally be fixed to 0 (in the case of a payment tree, only the *first* lock time is needed to prevent fee-sniping the root). scriptSig hash should generally not be set at all.
Since there are many possible sequences hash for a given input count, the input count comes before the sequences hash.
Since there are many possible outputs hashes for a given out count, the output count comes before the outputs hash.
Since we're generally using a single input to many output design, we're more likely to modify the outputs hash than the inputs hash.
We usually have just a single input on a CHECKTEMPLATEVERIFY script, which would suggest that it does not make sense for input index to be the last field. However, given the desirability of being able to express a "don't care" index easily (e.g., for decentralized kickstarter-type transactions), this value is placed last.
Design Tradeoffs and Risks
Covenants have historically been controversial given their potential for fungibility risks -- coins could be minted which have a permanent restriction on how they may or may not be spent or required to propagate metadata.
In the CHECKTEMPLATEVERIFY approach, the covenants are severely restricted to simple templates. The structure of CHECKTEMPLATEVERIFY template is such that the outputs must be known exactly at the time of construction. Based on a destructuring argument, it is only possible to create templates which expand in a finite number of steps. Thus templated transactions are in theory as safe as transactions which create all the inputs directly in this regard.
Furthermore, templates are restricted to be spendable as a known number of inputs only, preventing unintentional introduction of the 'half spend' problem.
Templates, as restricted as they are, bear some risks.
Permanently Unspendable Outputs
The preimage argument passed to CHECKTEMPLATEVERIFY may be unknown or otherwise unsatisfiable. However, requiring knowledge that an address is spendable from is incompatible with sender's ability to spend to any address (especially, OP_RETURN). If a sender needs to know the template can be spent from before sending, they may request a signature of an provably non-transaction challenge string from the leafs of the CHECKTEMPLATEVERIFY tree.
Forwarding Addresses
Key-reuse with CHECKTEMPLATEVERIFY may be used as a form of "forwarding address contract". A forwarding address is an address which can automatically execute in a predefined way. For example, a exchange's hot wallet might use an address which can automatically be moved to a cold storage address after a relative timeout.
The issue is that reusing addresses in this way can lead to loss of funds. Suppose one creates an template address which forwards 1 BTC to cold storage. Creating an output to this address with less than 1 BTC will be frozen permanently. Paying more than 1 BTC will lead to the funds in excess of 1BTC to be paid as a large miner fee. CHECKTEMPLATEVERIFY could commit to the exact amount of bitcoin provided by the inputs/amount of fee paid, but as this is a user error and not a malleability issue this is not done. Future soft-forks could introduce opcodes which allow conditionalizing which template or script branches may be used based on inspecting the amount of funds available in a transaction
As a general best practice, it is incumbent on Bitcoin users to not reuse any address unless you are certain that the address is acceptable for the payment attempted. This limitation and risk is not unique to CHECKTEMPLATEVERIFY. For example, atomic swap scripts are single use once the hash is revealed. Future Taproot scripts may contain many logical branches that would be unsafe for being spent to multiple times (e.g., a Hash Time Lock branch should be instantiated with unique hashes each time it is used). Keys which have signed a SIGHASH_ANYPREVOUT transaction can similarly become reuse-unsafe.
Because CHECKTEMPLATEVERIFY commits to the input index currently being spent, reused-keys are guaranteed to execute in separate transactions which reduces the risk of "half-spend" type issues.
NOP-Default and Standardness Rules
If the argument length is not exactly 32, CHECKTEMPLATEVERIFY treats it as a NOP. Many OP_NOP upgrades prefer to fail in such circumstances. In particular, for CHECKTEMPLATEVERIFY, making an invalid argument a NOP permits future soft-forks to upgrade the semantics or loosed restrictions around the value being previously pushed only.
The standardness rules may lead an unscrupulous script developer to accidentally rely on the stricter standardness rules to be enforced during consensus. Should that developer submit a transaction directly to the network relying on standardness rejection, an standardness-invalid but consensus-valid transaction may be caused, leading to a potential loss of funds.
Feature Redundancy
CHECKTEMPLATEVERIFY templates are substantially less risky than other covenant systems. If implemented, other covenant systems could make the CHECKTEMPLATEVERIFY's functionality redundant. However, given CHECKTEMPLATEVERIFY's simple semantics and low on chain cost it's likely that it would continue to be favored even if redundant with other capabilities.
More powerful covenants like those proposed by MES16, would also bring some benefits in terms of improving the ability to adjust for things like fees rather than relying on child-pays-for-parent or other mechanisms. However, these features come at substantially increased complexity and room for unintended behavior.
Alternatively, SIGHASH_ANYPREVOUTANYSCRIPT based covenant designs can implement something similar to templates, via a scriptPubKey like:
<sig of desired TX with PK and fixed nonce R || SIGHASH_ANYPREVOUTANYSCRIPT <PK with public SK> OP_CHECKSIG
SIGHASH_ANYPREVOUTANYSCRIPT bears additional technical and implementation risks that may preclude its viability for inclusion in Bitcoin, but the capabilities above are similar to what CHECKTEMPLATEVERIFY offers. The key functional difference between SIGHASH_ANYPREVOUTANYSCRIPT and OP_CHECKTEMPLATEVERIFY is that OP_CHECKTEMPLATEVERIFY restricts the number of additional inputs and precludes dynamically determined change outputs while SIGHASH_ANYPREVOUTANYSCRIPT can be combined with SIGHASH_SINGLE or SIGHASH_ANYONECANPAY. For the additional inputs, OP_CHECKTEMPLATEVERIFY also commits to the scriptsig and sequence, which allows for specifying specific P2SH scripts (or segwit v0 P2SH) which have some use cases. Furthermore, CHECKTEMPLATEVERIFY has benefits in terms of script size (depending on choice of PK, SIGHASH_ANYPREVOUTANYSCRIPT may use about 2x-3x the bytes) and verification speed, as OP_CHECKTEMPLATEVERIFY requires only hash computation rather than signature operations. This can be significant when constructing large payment trees or programmatic compilations. CHECKTEMPLATEVERIFY also has a feature-wise benefit in that it provides a robust pathway for future template upgrades.
OP_CHECKSIGFROMSTACKVERIFY along with OP_CAT may also be used to emulate CHECKTEMPLATEVERIFY. However such constructions are more complicated to use than CHECKTEMPLATEVERIFY, and encumbers additional verification overhead absent from CHECKTEMPLATEVERIFY. These types of covenants also bear similar potential recursion issues to OP_COV which make it unlikely for inclusion in Bitcoin.
Given the simplicity of this approach to implement and analyze, and the benefits realizable by user applications, CHECKTEMPLATEVERIFY's template based approach is proposed in lieu of more complete covenants system.
Future Upgrades
This section describes updates to OP_CHECKTEMPLATEVERIFY that are possible in the future as well as synergies with other possible upgrades.
CHECKTEMPLATEVERIFY Versions
OP_CHECKTEMPLATEVERIFY currently only verifies properties of 32 byte arguments. In the future, meaning could be ascribed to other length arguments. For example, a 33-byte argument could just the last byte as a control program. In that case, DefaultCheckTemplateVerifyHash could be computed when the flag byte is set to CTVHASH_ALL. Other programs could be added similar to SIGHASH_TYPEs. For example, CTVHASH_GROUP could read data from the Taproot Annex for compatibility with SIGHASH_GROUP type proposals and allow dynamic malleability of which indexes get hashed for bundling.
Eltoo with OP_CHECKSIGFROMSTACKVERIFY
Were both OP_CHECKTEMPLATEVERIFY and OP_CHECKSIGFROMSTACKVERIFY to be added to Bitcoin, it would be possible to implement a variant of Eltoo's floating transactions using the following script:
witness(S+n): <sig> <H(tx with nLockTime S+n paying to program(S+n))> program(S): OP_CHECKTEMPLATEVERIFY <musig_key(pk_update_a, pk_update_b)> OP_CHECKSIGFROMSTACKVERIFY <S+1> OP_CHECKLOCKTIMEVERIFY
Compared to SIGHASH_ANYPREVOUTANYSCRIPT, because OP_CHECKTEMPLATEVERIFY does not allow something similar to SIGHASH_ANYONECANPAY or SIGHASH_SINGLE, protocol implementers might elect to sign multiple versions of transactions with CPFP Anchor Outputs or Inputs for paying fees or an alternative such as transaction sponsors might be considered.
OP_AMOUNTVERIFY
An opcode which verifies the exact amount that is being spent in the transaction, the amount paid as fees, or made available in a given output could be used to make safer OP_CHECKTEMPLATEVERIFY addressses. For instance, if the OP_CHECKTEMPLATEVERIFY program P expects exactly S satoshis, sending S-1 satoshis would result in a frozen UTXO and sending S+n satoshis would result in n satoshis being paid to fee. A range check could restrict the program to only apply for expected values and default to a keypath otherwise, e.g.:
IF OP_AMOUNTVERIFY <N> OP_GREATER <PK> CHECKSIG ELSE <H> OP_CHECKTEMPLATEVERIFY
OP_CAT/OP_SHA256STREAM
OP_CHECKTEMPLATEVERIFY is (as described in the Ordering of Fields section) efficient for building covenants dynamically should Bitcoin get enhanced string manipulation opcodes.
As an example, the following code checks an input index argument and concatenates it to the template and checks the template matches the transaction.
OP_SIZE 4 OP_EQUALVERIF <nVersion || nLockTime || input count || sequences hash || output count || outputs hash> OP_SWAP OP_CAT OP_SHA256 OP_CHECKTEMPLATEVERIFY
Backwards Compatibility
OP_CHECKTEMPLATEVERIFY replaces a OP_NOP4 with stricter verification semantics. Therefore, scripts which previously were valid will cease to be valid with this change. Stricter verification semantics for an OP_NOP are a soft fork, so existing software will be fully functional without upgrade except for mining and block validation. Similar soft forks for OP_CHECKSEQUENCEVERIFY and OP_CHECKLOCKTIMEVERIFY (see BIP-0065 and BIP-0112) have similarly changed OP_NOP semantics without introducing compatibility issues.
In contrast to previous forks, OP_CHECKTEMPLATEVERIFY will not make scripts valid for policy until the new rule is active.
Older wallet software will be able to accept spends from OP_CHECKTEMPLATEVERIFY outputs, but will require an upgrade in order to treat PayToBareDefaultCheckTemplateVerifyHash chains with a confirmed ancestor as being "trusted" (i.e., eligible for spending before the transaction is confirmed).
Backports of OP_CHECKTEMPLATEVERIFY can be trivially prepared (see the reference implementation) for older node versions that can be patched but not upgraded to a newer major release.
References
- utxos.org informational site
- Scaling Bitcoin Presentation
- Optech Newsletter Covering OP_CHECKOUTPUTSHASHVERIFY
- Structuring Multi Transaction Contracts in Bitcoin
- Lazuli Notes (ECDSA based N-of-N Signatures for Certified Post-Dated UTXOs)
- Bitcoin Covenants
- CoinCovenants using SCIP signatures, an amusingly bad idea.
- Enhancing Bitcoin Transactions with Covenants
Note on Similar Alternatives
An earlier version of CHECKTEMPLATEVERIFY, CHECKOUTPUTSHASHVERIFY, is withdrawn in favor of CHECKTEMPLATEVERIFY. CHECKOUTPUTSHASHVERIFY did not commit to the version or lock time and was thus insecure.
CHECKTEMPLATEVERIFY could also be implemented as an extension to Taproot, and was proposed this way earlier. However, given that CHECKTEMPLATEVERIFY has no dependency on Taproot, it is preferable to deploy it independently.
CHECKTEMPLATEVERIFY has also been previously referred to as OP_SECURETHEBAG, which is mentioned here to aid in searching and referencing discussion on this BIP.
Copyright
This document is licensed under the 3-clause BSD license.