CHIP-2021-02: Native Introspection Opcodes
OWNERS: Jason Dreyzehner, Jonathan Silverblood
DISCUSSION: Bitcoin Cash Research, Telegram
VERSION: 1.1.4
MILESTONES: Published, Specification, Testnet, Accepted (BU - BCHN - Knuth - Verde - Bitauth), Deployed (May 15th, 2022).
Summary
This proposal adds a set of new virtual machine (VM) operations which enable BCH contracts to efficiently access details about the current transaction like output values, recipients, and more – without increasing transaction validation costs.
Deployment
Deployment of this specification is proposed for the May 2022 upgrade.
This proposal does not depend on CHIP: Bigger Script Integers
, but support for larger script numbers is required for all possible results of OP_UTXOVALUE
and OP_OUTPUTVALUE
to be used in arithmetic operations. It is therefore recommended that both CHIPs be deployed together.
This proposal does not depend on CHIP: Version 3 Transaction Format (PMv3)
, but it includes an integration specification to add introspection support for the v3 transaction format. See also: Interaction with PMv3.
Motivation
Since the introduction of OP_CHECKDATASIG (2018-11-15), it has been possible to implement practical Bitcoin Cash covenants – contracts which validate properties of the transaction in which the contract funds are spent.
Covenants enable a wide range of new innovation, but the strategy by which they are currently implemented is extremely inefficient: most of a transactions contents must be duplicated for each input which utilizes a covenant. In practice, this doubles or triples the size of even the simplest covenant transactions1, and advanced covenant applications quickly exceed VM limits such as the maximum standard unlocking bytecode length (A.K.A. MAX_TX_IN_SCRIPT_SIG_SIZE
) of 1,650 bytes. This severely limits the extent of current BCH covenant development and usage.
Covenants are currently implemented using a workaround in which the same signature is checked by both
OP_CHECKSIG
andOP_CHECKDATASIG
. TheOP_CHECKSIG
confirms the signature is valid for the current transaction, and theOP_CHECKDATASIG
allows the contract to validate that the signature covers a particular preimage provided in the unlocking bytecode. If both checks are successful, the contract can trust that the preimage provided toOP_CHECKDATASIG
is the genuine signing serialization of the current transaction. By further inspecting this preimage, the contract can validate other properties of the transaction.
Because nodes are already required to have full access to a transaction's contents and UTXO information during transaction validation, native introspection opcodes can be introduced without impacting existing transaction validation costs.
Calculations
- An optimized implementation of the
OP_CHECKSIG
+OP_CHECKDATASIG
workaround (<public_key> <signature> <preimage> OP_3DUP OP_SHA256 OP_ROT OP_CHECKDATASIGVERIFY OP_DROP <sighash_flags> OP_CAT OP_SWAP OP_CHECKSIGVERIFY
) requires at least 12 bytes of operations, a 33-byte public key, a 65 to 73-byte signature, and a signing serialization preimage which is typically at least 188 bytes. In total, this construction is expected to require at least 298 bytes per covenant input. For some contracts, the preimage can be partially generated usingSIGHASH_ANYONECANPAY
andOP_NUM2BIN
, theoretically reducing the preimage size to ~90 bytes and bringing the minimum possible overhead to ~200 bytes.
Benefits
Adding native support for introspection operations would make covenants simpler, safer, and more efficient, enabling innovative new use cases.
Simpler, Safer Contracts
While contracts using the current covenant workaround must carefully validate all provided transaction information, contracts using native introspection operations could safely rely on information returned by the VM without further validation. This significantly reduces contract size and complexity, making contract development and security review easier.
Reduced Transaction Sizes
By eliminating the need for a wasteful double-signature checking workaround, covenant transaction sizes can be reduced by hundreds of bytes, making them as efficient as other common transaction types. This would reduce wasted network bandwidth and lower transaction fees for all covenant applications.
Because covenant applications cover a large variety of common transaction types – including scheduled and recurring payments – improved efficiency in covenant transactions would significantly improve overall throughput of the BCH network.
Enable Innovation
By eliminating waste in covenant contracts, native introspection operations can extend the scope of possible applications which can be developed within current VM limits. This would enable far more innovation on Bitcoin Cash, without increasing node validation costs.
Costs & Risk Mitigation
The following costs and risks have been assessed.
Node Upgrade Costs
This proposal affects consensus – all fully-validating node software must implement these VM changes to remain in consensus.
These VM changes are backwards-compatible: all past and currently-possible transactions remain valid under these new rules.
Other Software Upgrade Costs
While most wallets, indexers, and other software will not require updates to support this proposal (beyond upgrades to any supporting node infrastructure), updates will be required to some libraries, transaction compilers, and other software which implements the BCH VM (e.g. Bitauth IDE).
Assignment of Opcodes
The specified operations would occupy 15 codepoints within the BCH VM instruction set. This represents a notable portion of the remaining 81 unused codepoints (80, 98, 101, 102, 137, 138, 176, 179-185, 189-255). However, we consider this to be a prudent use of these codepoints.
Technical Specification
A range of Bitcoin Cash VM codepoints is reserved for transaction introspection operations – 0xc0
(192) through 0xcf
(207) – and a new set of 15 operations allows contracts to introspect all available transaction and evaluation state.
Nullary Operations
The following 6 operations consume no items and push a single result to the stack. If the item to be pushed to the stack is longer than the stack item length limit (A.K.A. MAX_SCRIPT_ELEMENT_SIZE
), immediately fail evaluation. If the additional stack item would cause the stack to exceed the maximum stack size (A.K.A. MAX_STACK_SIZE
), immediately fail evaluation.
Operation | Codepoint | Description |
---|---|---|
OP_INPUTINDEX | 0xc0 (192) |
Push the index of the input being evaluated to the stack as a Script Number. |
OP_ACTIVEBYTECODE | 0xc1 (193) |
Push the bytecode currently being evaluated, beginning after the last executed OP_CODESEPARATOR , to the stack1. For Pay-to-Script-Hash (P2SH) evaluations, this is the redeem bytecode of the Unspent Transaction Output (UTXO) being spent; for all other evaluations, this is the locking bytecode of the UTXO being spent.2 |
OP_TXVERSION | 0xc2 (194) |
Push the version of the current transaction to the stack as a Script Number. |
OP_TXINPUTCOUNT | 0xc3 (195) |
Push the count of inputs in the current transaction to the stack as a Script Number. |
OP_TXOUTPUTCOUNT | 0xc4 (196) |
Push the count of outputs in the current transaction to the stack as a Script Number. |
OP_TXLOCKTIME | 0xc5 (197) |
Push the locktime of the current transaction to the stack as a Script Number. |
OP_ACTIVEBYTECODE
pushes the serialized bytecode for the instructions currently under evaluation beginning after the most recently executedOP_CODESEPARATOR
and continuing through the final instruction. If noOP_CODESEPARATOR
has been executed,OP_ACTIVEBYTECODE
pushes the full, serialized bytecode for the instructions currently under evaluation. (In the Satoshi implementation, this is simply theCScript
contents passed to the currentEvalScript
.)- This behavior matches the existing behavior of the BCH VM during P2SH evaluation – once the P2SH pattern is matched, the remaining stack is copied, and the VM begins evaluation again with the P2SH redeem bytecode set as the new
active bytecode
. (In the Satoshi implementation, this P2SH redeem bytecode is passed as aCScript
to a new execution ofEvalScript
.)
Unary Operations
The following 9 operations pop the top item from the stack as an index (Script Number) and push a single result to the stack. If the consumed value is not a valid, minimally-encoded index for the operation, an error is produced. If the item to be pushed to the stack is longer than the stack item length limit (A.K.A. MAX_SCRIPT_ELEMENT_SIZE
), immediately fail evaluation.
Operation | Codepoint | Description |
---|---|---|
OP_UTXOVALUE | 0xc6 (198) |
Pop the top item from the stack as an input index (Script Number). Push the value (in satoshis) of the Unspent Transaction Output (UTXO) spent by that input to the stack as a Script Number. |
OP_UTXOBYTECODE | 0xc7 (199) |
Pop the top item from the stack as an input index (Script Number). Push the full locking bytecode of the Unspent Transaction Output (UTXO) spent by that input to the stack. |
OP_OUTPOINTTXHASH | 0xc8 (200) |
Pop the top item from the stack as an input index (Script Number). From that input, push the outpoint transaction hash – the hash of the transaction which created the Unspent Transaction Output (UTXO) which is being spent – to the stack in OP_HASH256 byte order1. |
OP_OUTPOINTINDEX | 0xc9 (201) |
Pop the top item from the stack as an input index (Script Number). From that input, push the outpoint index – the index of the output in the transaction which created the Unspent Transaction Output (UTXO) which is being spent – to the stack as a Script Number. |
OP_INPUTBYTECODE | 0xca (202) |
Pop the top item from the stack as an input index (Script Number). Push the unlocking bytecode of the input at that index to the stack. |
OP_INPUTSEQUENCENUMBER | 0xcb (203) |
Pop the top item from the stack as an input index (Script Number). Push the sequence number of the input at that index to the stack as a Script Number. |
OP_OUTPUTVALUE | 0xcc (204) |
Pop the top item from the stack as an output index (Script Number). Push the value (in satoshis) of the output at that index to the stack as a Script Number. |
OP_OUTPUTBYTECODE | 0xcd (205) |
Pop the top item from the stack as an output index (Script Number). Push the locking bytecode of the output at that index to the stack. |
- This is the byte order produced/required by all BCH VM operations which employ SHA-256 (including
OP_SHA256
andOP_HASH256
), the byte order used for outpoint transaction hashes in the P2P transaction format, and the byte order produced by most SHA-256 libraries. For reference, the genesis block header in this byte order is little-endian –6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000
– and can be produced by this script:<0x0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c> OP_HASH256
. (Note, this is the opposite byte order as is commonly used in user interfaces like block explorers.)
CHIP Integration: Bigger Script Integers
Because VM arithmetic operations currently limit Script Number
inputs to signed 32-bit integers, the maximum results of OP_UTXOVALUE
and OP_OUTPUTVALUE
which can be used in practical contracts is 2147483647
satoshis (~21.47
BCH). For this reason, it is recommended that CHIP: Bigger Script Integers
be deployed before or with this CHIP.
This CHIP can be deployed without CHIP: Bigger Script Integers
, and no direct integration is required between the two CHIPs. If CHIP: Bigger Script Integers
is not deployed with or before this proposal, the above specified operations must still behave as specified. (OP_UTXOVALUE
and OP_OUTPUTVALUE
may push Script Numbers to the stack which are up to 8 bytes in length and therefore could not be used as inputs to arithmetic operations. Until some arithmetic range upgrade, these operations would likely only be used in practice for values which can be encoded in 4 bytes or less.)
CHIP Integration: Version 3 Transaction Format (PMv3)
If this proposal is adopted with or after CHIP: Version 3 Transaction Format (PMv3)
, the OP_INPUTDETACHED
unary introspection operation must also be activated:
Operation | Codepoint | Description |
---|---|---|
OP_INPUTDETACHED3 | 0xce (206) |
Pop the top item from the stack as an input index (Script Number). If the input at that index uses a detached proof, push 1 (0x01 ), otherwise push 0 (0x , the empty item). |
See Interaction with PMv3 for rationale.
Additionally, the description of OP_INPUTBYTECODE
can be clarified to confirm that its result is always the input's unlocking bytecode (regardless of whether or not the proof is detached):
Operation | Codepoint | Description |
---|---|---|
OP_INPUTBYTECODE | 0xca (202) |
Pop the top item from the stack as an input index (Script Number). Push the unlocking bytecode of the input at that index to the stack. (If the selected input uses a detached proof, the pushed value is the unlocking bytecode content of the detached proof.) |
Rationale
This section documents design decisions made in this specification.
Ordering Operations by Arity
This proposal groups new introspection operations by arity: all operations which consume no stack values precede all operations which consume an index value from the stack.
This simplifies some implementations, allowing operations of like arities to more easily reuse logic. For example, in the Satoshi implementation, all unary numeric operations are handled in the same fallthrough switch case, allowing each operation to reuse the same stack pop and error handling logic.
Beyond arity, operations are arranged within the instruction set to match the order in which their results appear within the P2P transaction format.
Operation Set Completeness
The operations specified in this proposal expose the most raw form of every static property of transaction and evaluation state within the current VM model.
This strategy necessarily incorporates operations which may initially seem to duplicate existing functionality, notably OP_TXLOCKTIME
and OP_INPUTSEQUENCENUMBER
(many use cases for these operations can also be accomplished using the existing OP_CHECKLOCKTIMEVERIFY
and OP_CHECKSEQUENCEVERIFY
, respectively). However, contract authors are not always able to reverse the order of a construction to make use of these operations. This limitation is particularly acute in covenant use cases: where other limitations prevent a contract from inverting a construction (or even providing the expected result of that operation via unlocking bytecode), some use cases are likely impossible without these functionally-similar introspection operations.
Notably, the existing instruction set includes
OP_SUB
even thoughOP_ADD
can be indirectly used (backwards) to accomplish many of the same validations. The existence of inverse and functionally-similar operations is important for both accommodating new use cases and optimizing contracts.
By implementing introspection in a single deployment as a complete, logical set of operations – rather than by piecemeal activation as contract authors lobby for operations which are important for their use cases – we allow new innovation to take place primarily in "userspace" and limit future technical debt.
Note: introspection of dynamic VM state – e.g. current instruction pointer index, the current state of various cumulative limits, etc. – is intentionally excluded from this specification.
This approach avoids consensus standardization of various implementation details which could complicate some implementations and requires further research and justification. Instead, this proposal incorporates only introspection operations for previously consensus-standardized, static properties of transaction and evaluation state which are already available to contracts via the
OP_CHECKSIG
+OP_CHECKDATASIG
hack.
Differences Between OP_ACTIVEBYTECODE
and OP_INPUTINDEX OP_UTXOBYTECODE
The operations specified in this proposal include partially-overlapping functionality in one rare case: the results of OP_ACTIVEBYTECODE
and OP_INPUTINDEX OP_UTXOBYTECODE
are equal in non-P2SH contracts (i.e. spending the output of a non-standard transaction). However, in the more common (standard) P2SH case, OP_ACTIVEBYTECODE
produces the raw redeem bytecode, while OP_INPUTINDEX OP_UTXOBYTECODE
will produce only the already-hashed result in the P2SH-template locking bytecode (OP_HASH160 OP_PUSHBYTES_20 <redeem_bytecode_hash> OP_EQUAL
). This distinction is very important in covenant applications: even in simple cases, it can save many hundreds of bytes by avoiding the need to push a duplicate copy of the covenant's redeem bytecode (to construct the covenant's next output). While OP_ACTIVEBYTECODE
is very cheap for the VM (typically a simple buffer copy), this single optimization reduces many covenant sizes by 50% or more.
To demonstrate, the following script produces a
1
for P2SH contracts, but a0
for non-P2SH contracts (spending a non-standard transaction):<OP_HASH160 OP_PUSHBYTES_20> OP_ACTIVEBYTECODE OP_HASH160 <OP_EQUAL> OP_CAT OP_CAT OP_INPUTINDEX OP_UTXOBYTECODE OP_EQUAL
.
Alternatively, this same functionality could be provided by modifying OP_UTXOBYTECODE
to only return the "active" bytecode of each UTXO (i.e. for P2SH contracts, only the raw redeem bytecode), but this would require a significantly more complex implementation: a transaction's inputs would need to be evaluated in two phases, caching each P2SH input's redeem bytecode for access by other inputs where needed. Additionally, information would still be lost unless another introspection operation were made available for contracts to judge which inputs spend a P2SH UTXO (e.g. a unary OP_ISP2SH
).
An advantage of that more complex solution over the proposed OP_ACTIVEBYTECODE
solution could be more efficient access to the raw redeem bytecode of sibling inputs (other than the "active" one). While this might be useful in optimizing some highly-advanced covenants, the proposed solution offers a far simpler consensus implementation and slightly more efficient contracts in the common case (1-byte OP_ACTIVEBYTECODE
vs. 2-byte OP_INPUTINDEX OP_UTXOBYTECODE
).
The complexity of this issue ultimately stems from the implementation chosen for BIP16/P2SH, which bifurcated VM evaluation into two modes: standard and P2SH. This complicated the operational model of the VM and is particularly disruptive to the logical consistency of introspection operations between the two modes. The chosen solution focuses on simplicity and optimizing the most common cases, rather than a more complex solution which might optimize more cases. If usage of sibling redeem bytecode becomes common in real world applications, future upgrades could offer more targeted optimizations for those cases.
Introspection Operation Range
This proposal leaves a 3 codepoint gap between the last defined operation in the current BCH instruction set (OP_REVERSEBYTES
, 0xbc
/188
) and the beginning of the proposed introspection operation range (OP_INPUTINDEX
, 0xc0
/192
).
This breaks from the recent precedent (since Nov. 2018) of adding each new opcode at the next-available codepoint. (After OP_NOP10
/0xb9
, OP_CHECKDATASIG
/0xba
, OP_CHECKDATASIGVERIFY
/0xbb
, and OP_REVERSEBYTES
/0xbc
were appended to the ISA in activation order, rather than being grouped logically with similar operations). While this may appear to complicate logic for detecting invalid codepoints (from op > FIRST_UNDEFINED_OP_VALUE
to isUndefined(op)
), it is equivalent in practice, as validators are optimized for evaluating valid bytecode (the common case). For example, in the Satoshi implementation, a switch statement is used to switch between valid operations – invalid opcodes only return their error after the VM iterates through the full list of possible valid opcodes.
By leaving gaps in the ISA, future upgrades may group similar operations nearer to each other. In the long term, this may produce a more coherent ISA than one ordered only by opcode activation time.
In the context of this proposal, the proposed gap offers up to 3 codepoints for use either by formatting operations (logically grouped with OP_REVERSEBYTES
) or for use by additional nullary introspection operations (if the VM model is extended to incorporate new transaction-level primitives or metadata). Likewise, the 2 remaining codepoints within the introspection range (0xce
and 0xcf
) provide space for additional unary introspection operations.
Exclusion of Aggregation Operations
With the partial exception of OP_ACTIVEBYTECODE
, this proposal includes only operations which expose raw state – derived state must be computed using other VM operations. While this simplifies the proposal to a clearly defined set of "primitive" operations, certain useful, derived state elements are not yet possible to compute in all cases. For example, since the VM does not include any construction for looping or iteration, aggregate values like "total input value" and "total output value" are not always possible for contracts to compute.
While it would be possible to define aggregate operations like OP_TXINPUTVALUE
and OP_TXOUTPUTVALUE
to make this derived state accessible to all contracts, this proposal considers standardization of any derived state to be premature. Even with piecemeal implementation of some derived state operations, some important types of aggregated/derived state cannot be reasonably standardized, e.g. "public keys referenced by all P2PKH outputs". For contracts to support extracting this information, it's necessary to add support for generalized loops/iteration to the VM.
For this reason, this proposal does not include any aggregate operations; contract authors should instead look to proposals like CHIP: Bounded Looping Operations
for this support.
With
CHIP: Bounded Looping Operations
, aOP_TXINPUTVALUE
equivalent would require only 14 bytes:<0> <0> OP_BEGIN // loop (re)starts with index, value OP_OVER OP_UTXOVALUE OP_ADD // Add UTXO value to total OP_SWAP OP_1ADD OP_SWAP // increment index OP_OVER OP_TXINPUTCOUNT OP_EQUAL OP_UNTIL // loop until next index would exceed final index OP_NIP // drop index, leaving sum of UTXO values
While not included in this proposal, future proposals may introduce aggregate operations either as a partial alternative to looping operations or as an optimization strategy for common aggregations.
Interaction with PMv3
The PMv3 version 3 transaction format proposal would add two fields which don't yet exist in the v1/v2 transaction formats: detached signatures
and detached proofs
. If adopted with PMv3, this proposal recommends only one additional introspection operation (OP_INPUTDETACHED
).
Detached signatures are themselves inherently reusable across multiple inputs – rather than a specialized introspection operation, many use cases can reference a particular detached signature directly. Also, because all detached signature-covered transaction elements are themselves natively introspectable, there's little value in an operation which makes the OP_CHECKSIG
+ OP_CHECKDATASIG
workaround more efficient for detached signatures. As such, this proposal does not recommend any new introspection operation(s) for detached signatures.
Detached proofs add only one new bit of information: whether or not each input is detached (true
or false
). Access to this information is valuable to many public covenants; if a covenant requires proofs to be detached for transaction sizes to be kept in check, the covenant needs to prevent malicious users from interacting with the covenant using transactions with non-detached proofs (leading to increased covenant transaction costs and even disabling of poorly-designed public covenants).
To allow inspection of this information, the OP_INPUTDETACHED
unary operation is proposed, and the OP_INPUTBYTECODE
operation is clarified: (If the selected input uses a detached proof, the pushed value is the unlocking bytecode content of the detached proof.)
.
This strategy makes validation of transaction shapes trivial: OP_INPUTINDEX OP_INPUTDETACHED OP_VERIFY
would ensure that the current contract is using a detached proof. It also maintains a consistent behavior for OP_INPUTBYTECODE
(for both detached and standard proofs) – the pushed results of OP_INPUTBYTECODE
would always be the unlocking bytecode regardless of whether or not the proof is detached.
Note, the un-hashed result of
OP_INPUTBYTECODE
is most useful to practical contracts, but it's also trivial to reproduce anydetached proof hash
under this scheme:<N> OP_INPUTBYTECODE OP_HASH256
.
No-operation alternative
Alternatively, it could be possible to avoid introducing a new OP_INPUTDETACHED
operation at the cost of significantly increased contract complexity. Under this scheme, the OP_INPUTBYTECODE
operation could instead be modified to push the detached proof hash
for inputs which use detached proofs.
While this configuration would technically expose all transaction information, verifying the detached-ness of any particular input would not be trivial, and reviewing contracts for security would become more difficult.
In some cases, the size of the unlocking bytecode could simply be validated: OP_INPUTBYTECODE OP_SIZE <32> OP_EQUAL
. If it can be guaranteed that no raw unlocking bytecode values of exactly 32-bytes exist for a particular input, this may be sufficient to guarantee that said input is detached. Otherwise, the contract will also be required to validate that a double SHA-256 preimage exists which equals the value returned by OP_INPUTBYTECODE
. This comprehensively-secure solution would require duplicating the contents of the unlocking bytecode for each validated input, significantly increasing transaction sizes.
Finally, this solution would break the logical consistency of OP_INPUTBYTECODE
– contracts which depend on the ability to introspect unlocking bytecode would require careful logic to identify whether or not the value returned by OP_INPUTBYTECODE
is actually unlocking bytecode rather than the hash of that input's unlocking bytecode. In some cases, this may open contracts to vulnerabilities in which carefully "mined" detached proof hashes could deceive the contract into believing a poorly-validated detached proof hash is raw unlocking bytecode.
While this alternative strategy would save a codepoint in the BCH instruction set, it would significantly increase contract complexity, security review costs, and transaction costs. Therefore, this proposal recommends implementation of the simpler OP_INPUTDETACHED
operation.
Use of Single-Byte Opcodes
Earlier proposals attempted to use fewer opcodes by either introducing all introspection operations as a single opcode or by introducing multi-byte opcodes. However, deeper analysis indicates that the BCH instruction set might never reach 255 operations within the current VM model (future VM models are likely to have their own independent set of operations, rather than naively extending the current instruction set).
While it is likely wise to reserve both the remaining OP_NOP4
-OP_NOP10
range and the range from 0xf0
to 0xff
for future multi-byte opcodes (leaving room for ~6000 2-byte opcodes), jumping to multi-byte opcodes would be a premature optimization, with uncertain future benefit and immediate negative consequences.
As such – and because introspection operations are critical to all covenant use cases – this proposal specifies the proposed operations as standard, single-byte opcodes.
Push-Only Limitation of Unlocking Bytecode
For clarity, this proposal does not modify the existing limitation (present since BCH_2018-11-15) preventing transactions from including "non-push" operations – all operations at codepoints greater than 96 (0x60
) – in unlocking bytecode. This limitation also prevents all operations specified in this proposal from appearing in unlocking bytecode.
This limitation is maintained to prevent a third-party malleability vector: any non-push operation can be replaced in a malleated transaction with an equivalent push operation pushing the computed result of the non-push operation. While all third-party malleability vectors would be eliminated by PMv3's detached signatures, this CHIP leaves any loosening of the non-push limitation to future proposals.
OP_ACTIVEBYTECODE
Support for OP_CODESEPARATOR
In earlier versions of this proposal, the result of OP_ACTIVEBYTECODE
did not account for the last executed OP_CODESEPARATOR
. However, the current behavior is considered more conservative (OP_ACTIVEBYTECODE
returns the active bytecode beginning after the last evaluated OP_CODESEPARATOR
). Contracts which don't utilize OP_CODESEPARATOR
are unaffected by this change, contracts which utilize OP_CODESEPARATOR
can access either behavior (an earlier result of OP_ACTIVEBYTECODE
can always be saved for use after OP_CODESEPARATOR
is called), and some unusual contracts may be able to utilize the new behavior to optimize their bytecode size or runtime requirements.
Notably, the index of the last executed OP_CODESEPARATOR
is available using the OP_CHECKSIG
+ OP_CHECKDATASIG
workaround, so providing access to this state via OP_ACTIVEBYTECODE
is also valuable for operation set completeness.
Implementations
Test Cases
Evaluation of Alternatives
No alternative native introspection proposals are currently public, but alternative designs for several components of this proposal have been documented in the Rationale section.
Several past proposals have informed the design of this proposal:
- The initial
OP_PUSHSTATE
proposal used a single opcode and templated approach. (The proposal was withdrawn in favor of this CHIP.) - An implementation of a closely-related
OP_PUSH_TX_STATE
exists for the Bitcoin Unlimited node software in the NextChain project. - A multi-byte fork of the
OP_PUSHSTATE
proposal introduced the idea of unary operations which select information by input/output index.
Delay or rejection of this proposal may incur the following costs:
- Continued use of the inefficient workaround increases the size of the blockchain could negatively impact initial block download times and storage requirements.
- The complexity of the current workaround increases development costs and raises the barrier to entry for new developers.
- Because the current workaround is difficult to implement securely, implementation problems could result in loss of profits and reputational damage, both for the implementing company and the Bitcoin Cash ecosystem.
- Some applications and use cases will be impossible without native introspection, and competitors may outcompete BCH for these users.
Primary Stakeholders
At least three primary stakeholder groups exist:
Companies and Organizations
Companies and organizations currently building products utilizing introspection include:
General Protocols made AnyHedge, a volatility risk-trading contract. They plan to build additional, non-custodial services and can support additional functionality with native introspection.
Tobias Ruck created be.cash, a refillable, offline wallet in the form of a credit card.
Casues Cash built a modified Mecenas to support recurring payments in USD.
Mistcoin has produced minable SLP tokens.
Flipstarter funding contracts utilizing native introspection might improve usability.
SmartBCH is building an EVM compatible Bitcoin Cash sidechain, and might use introspection as part of a bridge between the main and side chain.
Independent Developers
A number of independent developers are developing tools and services that rely on introspection:
bitjson created CashChannels, reccuring payments for Bitcoin Cash.
haryu703 created Hamingja, a loyalty points system using non-tradable SLP token and is working on an SLP swap/trading contract.
Licho created the Last Will contract to manage inheritance, the Mecenas contract for recurring payments, and is interested in implementing traditional games, like NIM.
p0oker created an SLP Vending contract that mints tokens on-demand and is building 1) a BCH staking contract that mints tokens over time and 2) an SLP exchange contract to sell NFTs.
Tobias Ruck is investigating a non-custodial on-chain gambling product.
James Cramer is experimenting with SLP Mint Guard to protect minting batons, SLP Vault to help reclaim unclaimed tokens, making tokens with minting schedules, and building SLP Dollars which are freezable by the issuer.
Investors
These individuals and organizations have invested in the BCH currency and ecosystem on the premise that it can become peer to peer electronic cash for the world. These stakeholders expect the token to serve effectively as money, including in the innovative financial services which could be enabled by native introspection.
Statements
...
General Protocols
The CHIP requires further analysis and specification before it is possible to take a strong position. GP commits to supporting this CHIP with reasonable resources. GP predicts that the benefits to BCH value and network effect will greatly outweigh the costs. Regarding the multiple implementation options available, GP sees multiple good options and encourages the active CHIP participants to choose one with reasonable logic and zero polarization.
p0oker
I believe removing the current work arounds with the addition of native introspection OP Codes can improve the reliability of the smart contracts on Bitcoin Cash. Covenants are important and useful in many business use cases and it’s important to make them bulletproof!
Licho
The covenant technology have proven to be a vibrant area of BCH development. It allows us to replicate more and more of traditional banking services in a non-custodial way. The native introspection seems to be the key ingredient of the future of permissionless money.
Tom Zander — founder Flowee
This CHIP is super valuable and I fully support the direction this is going in and the ideas behind this chip. I will continue to monitor the progress with enthusiasm.
Jimtendo - recurr.app
Introspection is a useful and welcome addition to Bitcoin Cash's Smart Contract capabilities. This CHIP describes a well thought-out and efficient way of achieving it and therefore has my full support and endorsement.
Rosco Kalis - cashscript
If this CHIP is implemented, I will commit to supporting the entire range of implemented introspection opcodes in CashScript. This greatly simplifies the compiler code that deals with introspection and will result in smaller and more efficient covenant contracts.
Changelog
This section summarizes the evolution of this document.
- v1.1.4 - 2021-12-1 (current)
- Link to BCHN test cases
- v1.1.3 - 2021-8-25 (
29054bb8
)- Add support for
OP_CODESEPARATOR
inOP_ACTIVEBYTECODE
(#27)
- Add support for
- v1.1.2 - 2021-6-22 (
e9e8a67d
)- Clarify minimal-encoding requirement for unary operation indexes
- Clarify interaction with
CHIP: Bigger Script Integers
- Clarify (lack of) effect on transaction validation costs
- v1.1.1 - 2021-6-10 (
f501154f
)- Added statement from stakeholder
- v1.1 – 2021-6-8 (
d67eb98b
)- Added version and
Changelog
- Extracted integration specifications into independent
CHIP Integration
sections - Correct and clarify resulting byte order of
OP_OUTPOINTTXHASH
- Clarify failure of introspection operations which attempt to exceed stack limits
- Added version and
- v1.0 – 2021-6-3 (
163f74be
)- Revised technical specification:
- Convert
OP_OUTPOINTTXHASH
,OP_OUTPOINTINDEX
,OP_UTXOBYTECODE
, andOP_UTXOVALUE
to unary operations - Group operations by arity (nullary, unary), then by P2P transaction format order
- Distinguish
OP_ACTIVEBYTECODE
from unaryOP_UTXOBYTECODE
(rationale) - Removed formatting operations (
OP_NUM2VARINT
andOP_VARINT2NUM
) and aggregated/hashed/templated operation placeholders - Specified integration strategy for
CHIP: Version 3 Transaction Format (PMv3)
andCHIP: Bigger Script Integers
- Convert
- Added
Rationale
section, revised supporting material (Summary
,Deployment
,Motivation
,Benefits
, etc.)
- Revised technical specification:
- v0.1 – 2021-3-22 (
95a99e22
)- Expanded
Motivation and Benefits
,Costs and Risks
, andList of major stakeholders
- Initial technical specification
- Expanded
- v0 – 2021-2-21 (
53989f7d
)- Initial draft
Copyright Notice
Copyright (c) 2021 GeneralProtocols / Research
Permission is granted to copy, distribute and/or modify this document under the terms of the MIT license.