This was an early demo of the ideas behind the CashTokens CHIP.
For an introduction to the latest iteration of CashTokens, see:
Read the blog post: CashTokens: Contract-Validated Tokens for Bitcoin Cash.
Review the authentication template in Bitauth IDE:
https://ide.bitauth.com/import-gist/a440232cebba8f0b2b6b9aa5db1fdb37
If you have questions, feedback, or you're interested in contributing to future CashTokens or TxInt Opcodes specifications, please join CashToken Devs on Telegram or message me on Twitter.
Below are some notes which may make it into a future CashTokens and/or TxInt specification.
Current draft implementation of the TxInt upgrade ➔
The current target date for a TxInt opcode upgrade is May 2022. Some TxInt opcodes could be enabled earlier, but many should only be enabled with larger integer support (see below).
While CashToken can work within the 520-byte stack item size limit, because CashToken inductive proofs require inspecting the parent and grandparent transactions' contents, stack items can easily reach 520 bytes. Flexibility in signing schemes also increases the amount of bytecode required to validate each allowed configuration, contributing to overhead which must fit within the 520 bytes for P2SH outputs. For these reasons, the token covenant in this implementation is limited to multisig security schemes with a maximum of 3 signers (m-of-n where m <= 3, n <= 3). Increasing the stack item size limit to 1000 bytes would provide space for token covenants which use additional locktime-based security features or the largest allowed multisig schemes (up to 20 keys). A stack item size limit of 2,000 to 5,000 bytes would likely provide space for validation of transactions with multiple complex covenant inputs.
The OP_OUTPOINTTXHASH
operation pushes the outpoint transaction hash in big-endian byte order. While the serialized transaction format itself specifies this value in each input in little-endian order (reversing the double-sha256 hash of the parent transaction serializations), most VM bytecode use-cases will require the value in big-endian byte order (non-reversed). As an added benefit, big-endian byte order is also used by most external systems (explorers, indexers, etc.).
The OP_UTXOBYTECODE
operation pushes the bytecode currently being evaluated to the stack. For standard scripts, this is the locking bytecode of the Unspent Transaction Output (UTXO) spent by the input. For P2SH scripts, the UTXO's redeem script is pushed (rather than OP_HASH160 <redeem_script_hash> OP_EQUAL
). This behavior matches the existing behavior of the current VM during P2SH evaluation – once the P2SH pattern is matched, the remaining stack is copied, and the VM begins evaluation again with the new array of instructions. OP_UTXOBYTECODE
provides access to the serialization of this instruction list (in derivatives of the Satoshi implementation, the script
parameter provided to EvalScript
).
With CashTokens, it's possible to create covenants for which multiple entities compete to create the next covenant transaction. These entities may be willing to pay higher-than-normal fees to have their version of the covenants next state mined. A non-negligible volume of these transactions may incentivize miners to develop backchannel Replace-By-Fee (RBF) infrastructure and weakening zero-confirmation reliability.
For example, when a second user attempts to outbid a previously broadcast covenant transaction, nodes which heard the first transaction may refuse to broadcast the second. If those nodes broadcast some form of Double-Spend Proof (DSP) for the new transaction, miners may be incentivized to request the "warned-against" double spend (over other channels) to maximize fees.
To avoid incentivizing the creation of double-spend backchannels, DSP strategies should account for the possibility of significant markets for fee-replacement. (Even without CashTokens, this is already true for other types of anyone-can-spend locking scripts.) Well-designed CashToken covenants should also avoid creating such scenarios, since "bidding wars" may also degrade the user experience of covenants.
It's possible to differentiate token types within a single CashToken corporation contract by using the tokens' satoshi values. For example, a corporation covenant can be designed to issue tokens with a base value above the current dust limit (546 satoshis) where each additional satoshi represents another unit of the token. E.g. for a base of 1000 satoshis, a 1001 satoshi CashToken is worth 1 UNIT (1001-1000), but a 2000 satoshi CashToken is worth 1000 UNITs (2000-1000).
Because the CashToken covenant places strict limitations on transfers, higher-level covenants can rely on CashTokens to only change their satoshi values in allowed ways from transfer-to-transfer. This same strategy can be used to differentiate other types of tokens like classes of stock (preferred, common, class B, etc.) or various privilege levels in a CashToken sidechain.
Because Script Numbers are currently limited to 4 bytes for mathematical operations, numbers pushed to the stack by OP_UTXOVALUE
, and OP_OUTPUTVALUE
are practically limited to positive int32 numbers. This limits the total operational value to 2,147,483,647 satoshis, or about 21 BCH. While this proposal doesn't yet recommend a solution for working with larger numbers in the VM, it would be valuable to adopt a big integer solution before or at the same time as the TxInt opcodes.
It should also be noted that future upgrades which enable fractional satoshi will complicate OP_UTXOVALUE
and OP_OUTPUTVALUE
. It may be valuable to plan upgrade strategies which allow these opcodes to be used with the higher specificity values. OP_OUTPUTVALUE
could be modified to accept the index -1
as an indicator that a higher specificity operation should be used (future subdivisions could be specified with -2
,-3
, etc). To allow for future upgrades, it may be valuable to require that OP_UTXOVALUE
consumes the value 0
from the stack to indicate the unit "satoshis".
(Update 2020-12-16: I'm also considering a design where each OP_UTXO*
opcode consumes a number to select a particular input such that OP_INPUTINDEX OP_UTXOVALUE
would do what OP_UTXOVALUE
does in the initial draft implementation.)
Contracts inspecting transactions are made simpler and safer with operations to convert between Script Numbers and Bitcoin VarInts. Without safe means of reading/writing VarInts, contracts must be carefully specified to either manually convert between formats or limit allowable input/output counts in proofs. Additionally, ease of use of VarInts in contracts might help to minimize wasted space caused by fixed-width contract values (e.g. nonces, indexes, payment amounts, rates, etc.).
Currently, only an implementation for OP_NUM2VARINT is proposed. This is sufficient for many types of covenants, but other covenants may be made possible or more efficient with an implementation of the reverse operation.
Many covenant contracts utilizing transaction introspection will need to convert between Script Numbers (a.k.a. CScriptNum
, usually inclusive range from -2^31 + 1 to 2^31 - 1), transaction output satoshi values (little-endian, unsigned 64-bit integers), and variable-length integers (positive integers from 0 to 2^64−1, used in transaction and signing serializations). Beyond these existing formats, some strategy is needed to perform mathematical operations on output satoshi values (and on fractional satoshi values, which may no longer fit inside a uint64).
It may be valuable to solve all these number encoding problems at one time (perhaps in a v3 transaction format). Some goals and requirements for a variable-length integer solution:
- A single, variable-length, unsigned integer format for transaction serializations – to be used by the version, input/output count, input indexes, bytecode length, and satoshi value fields. (Version 1 and 2 transactions tend to waste bytes in fixed-width version and satoshi value integer fields, while also preventing these fields from interoperating with the VM's Script Number format in contracts. A unified integer type could solve both issues.)
- Math support for variable-length integers – all math operations currently operate on Script Numbers, a 32-bit signed integer format used by the VM. It must be possible for math operations to either operate on the variable-length integer type or convert between Script Numbers and the variable-length integer type. This is particularly important for math operations involving satoshi values larger than the current limit of 2,147,483,647 satoshis (about 21 BCH).
- A clear upgrade path to "fractional satoshis" – increasing the precision of value fields should be possible without breaking changes to VM operations.
Note, if a new variable-length integer format were phased in with v3 transactions, OP_NUM2VARINT could be modified to use this format when used in a v3 transaction. However, because this difference would need to be tracked along with every UTXO for proper enforcement, it would be advantageous to deploy this "upgraded OP_NUM2VARINT" such that it is only valid in v3 transactions. If OP_NUM2VARINT were to also be deployed for v1 and v2 transactions, it may be valuable to define a separate opcode for a v3-only OP_NUM2BIGINT.
One or more serialized transaction introspection operations could simplify CashToken inductive proofs and other types of looping contracts. Rather than operating on the current transaction (as is the case for this proposal's set of operations), serialized transaction introspection opcodes would instead operate on the top stack item, interpreting the stack item as a serialized transaction and extracting requested data. This strategy would result in shorter contracts when validation of parent transactions is required, though it would likely require an expansion of the 520 byte stack item size limit. Notably, while the transaction serialization format is already consensus-critical for transaction identification in outpoints, "serialized TxInt" operations would further ossify the serialization format. It may be wise to only enable these types of transactions after widespread use is demonstrated, and only for the latest transaction version deployed at that time.
(Just uploading a screenshot)
https://ide.bitauth.com/import-gist/a440232cebba8f0b2b6b9aa5db1fdb37