diff --git a/kip-0017.md b/kip-0017.md new file mode 100644 index 0000000..5d3219b --- /dev/null +++ b/kip-0017.md @@ -0,0 +1,142 @@ +``` +  KIP: 17 +  Layer: Consensus, Script Engine +  Title: Covenants and Improved Scripting Capabilities +  Authors: Ori Newman +  Status: Draft +``` + +## Abstract + +This proposal is a continuation of KIP 10 [1], introducing full covenant support to Kaspa by extending the scripting language with introspection opcodes to all transaction fields, along with byte-string manipulation primitives. These additions enable scripts to inspect and constrain properties of the spending transaction, allowing validation of stateful transitions encoded implicitly or explicitly in UTXOs. + +## Specification + +### 1. New Opcodes + +The following new opcodes are introduced to enhance script functionality: + +#### Transaction Level Introspection Opcodes: + +1. `OpTxVersion` (0xb2): Returns the version of the transaction. +2. `OpTxLockTime` (0xb5): Returns the locktime field of the transaction. +3. `OpTxSubnetId` (0xb6): Returns the subnetwork ID of the transaction. +4. `OpTxGas` (0xb7): Returns the gas field of the transaction. +5. `OpTxPayloadLen` (0xc4): Returns the payload length of the transaction. +6. `OpTxPayloadSubstr` (0xb8): Returns the payload substring of the transaction from `start` to `end`. Returns error for invalid ranges, or when `end-start > MAX_SCRIPT_ELEMENT_SIZE = 520`. + +#### Input/Output Introspection Opcodes: + +1. `OpTxInputSpkLen(idx)`: (0xc5) Returns the script public key length of the specified input. +2. `OpTxInputSpkSubstr(idx, start, end)` (0xc6): Returns the script public key substring of the specified input from `start` to `end`. Returns error for invalid ranges, or when `end-start > MAX_SCRIPT_ELEMENT_SIZE = 520`. +3. `OpTxOutputSpkLen(idx)`: (0xc7) Returns the script public key length of the specified output. +4. `OpTxOutputSpkSubstr(idx, start, end)`: (0xc8) Returns the script public key substring of the specified output from `start` to `end`. Returns error for invalid ranges, or when `end-start > MAX_SCRIPT_ELEMENT_SIZE = 520`. +5. `OpTxInputScriptSigLen(idx)` (0xc9): Returns the script signature length of the input. +6. `OpTxInputScriptSigSubstr(idx, start, end)`: (0xca) Returns the script signature substring of the input from `start` to `end`. Returns error for invalid ranges, or when `end-start > MAX_SCRIPT_ELEMENT_SIZE = 520`. +7. `OpOutpointTxId(idx)` (0xba): Returns the transaction ID of the outpoint. +8. `OpOutpointIndex` (0xbb): Returns the index of the outpoint. +9. `OpTxInputSeq(idx)` (0xbd): Returns the sequence number of the input. +10. `OpTxInputIsCoinbase(idx)` (0xc1): Returns whether the input is a coinbase. + +##### Note on Substring Opcodes + +On all substring related opcodes, we consider the first byte to be at position 0, the start position is inclusive, and the end position is exclusive. + +#### Other Opcodes: + +1. `OpCat(str1, str2)`: (0x7e) Concatenates two byte strings. Returns error if the resulting string exceeds `MAX_SCRIPT_ELEMENT_SIZE = 520` [2]. +2. `OpSubstr(str, start, end)`: (0x7f) Returns the substring of a byte string (from start (inclusive) until end (exclusive)). Returns error for invalid ranges, or when `end-start > MAX_SCRIPT_ELEMENT_SIZE = 520`. +3. `OpBlake2bWithKey(data, key)`: (0xa7) Returns the Blake2b hash of the data with the key used for domain separation. +4. `OpInvert(str)` (0x83): Returns the bitwise NOT of a byte string. +5. `OpAnd(str1, str2)` (0x84): Returns the bitwise AND of two byte strings. Returns error if the two strings are of different lengths. +6. `OpOr(str1, str2)` (0x85): Returns the bitwise OR of two byte strings. Returns error if the two strings are of different lengths. +7. `OpXor(str1, str2)` (0x86): Returns the bitwise XOR of two byte strings. Returns error if the two strings are of different lengths. +8. `OpMul` (0x95): Returns the product of two numbers. Returns error on overflow. +9. `OpDiv` (0x96): Returns the quotient of two numbers. Returns error on division by zero. +10. `OpMod` (0x97): Returns the remainder of two numbers. Returns error on modulo by zero. + +### 2. Activation + +The features introduced in this KIP are activated based on DAA score: + +1. Prior to activation: + - New opcodes are treated as invalid +2. After activation: + - All new opcodes become available + +## Motivation + +The combination of introspection opcodes and OP_CAT/OP_SUBSTR can be used to implictly attach state to UTXOs and enforce correct state transitions. + +For example, we can implement a simple covenant that requires us to increase a counter stored in the transaction payload every time the UTXO is spent, and forces us to send the new transaction to the same scriptPubKey: + +Given siganture script of the form: ` `, the scriptPubKey will be: + +``` +OpDup OpRot OpRot OpCat +"TransactionID" OpBlake2bWithDomain +OpTxInputIndex OpOutpointTxId OpEqualVerify +Op1Add +0 OpTxPayloadLen OpTxPayloadSubstr +OpEqualVerify +OpTxInputIndex OpTxInputSpk 0 OpOutputSpk +OpEqualVerify +OpTxOutputCount 1 OpEqual +``` + +This script can be written in pseudocode as: + +``` +validate(prev_tx,tx){ + return hash(prev_tx) == tx.inputs[curr_idx].prev_tx_id + AND tx.outputs[0].script_pub_key == prev_tx.inputs[curr_idx].script_pub_key + AND len(tx.outputs) == 1 + AND tx.payload == prev_tx.payload + 1; +} +``` + +In general, once we can encode some state transition function δ in script, we can validate that `δ(prev_payload,tx) = new_payload`, where δ can also introduce some constraints on `tx` using introspection opcodes (checking its signautre, enforcing a locktime, etc). + +### Note on Transaction Encoding + +Many covenant constructions require the spender to provide a full copy of the previous transaction as witness data in order to validate that +`tx.inputs[idx].prev_tx_id = hash(prev_tx)`. + +As a result, the transaction ID hashing algorithm implicitly defines a canonical transaction encoding that scripts can rely on. Covenant scripts may reconstruct or inspect this encoding to verify that a provided previous transaction matches the referenced outpoint. + +A reference implementation of the transaction ID hashing and encoding logic is provided in [3]. + +## Use Cases + +Covenants enable a variety of use cases, including but not limited to: + +1. Fungible and non-fungible tokens [4]. +2. Smart Vaults for enhanced security [5]. +3. Congestion control mechanisms [6]. +4. With the help of ZK opcodes, implement L1-L2 trustless bridges. + +See [7] for more use cases. + +## Backwards Compatibility + +This proposal requires a hard fork, as it introduces new opcodes to the scripting language. Older software will require an update to support these new features. Existing scripts and addresses remain valid, but cannot use the new functionality without being updated. + +## Reference Implementation + +https://github.com/kaspanet/rusty-kaspa/pull/797 + +## References + +1. KIP 10: [kip-0010.md](kip-0010.md) + +2. `OP_CAT` BIP: https://github.com/bip420/bip420 + +3. Reference implemenation of transaction ID hashing: https://github.com/kaspanet/rusty-kaspa/blob/2ccc9e4ca9aa184c62c4fb14dbb463834264e01d/consensus/core/src/hashing/tx.rs#L40 + +4. Cat Protocol for covenants based tokens: https://catprotocol.org/ + +5. Vaults: https://utxos.org/uses/vaults/ + +6. Congestion Control: https://utxos.org/uses/scaling/ + +7. More covenants use cases: https://utxos.org/uses/, https://github.com/sCrypt-Inc/awesome-op-cat#op_cat-use-cases, https://covenants.info/use-cases/