diff --git a/tips/TIP-0045/tip-0045.md b/tips/TIP-0045/tip-0045.md new file mode 100644 index 000000000..0502cc5cd --- /dev/null +++ b/tips/TIP-0045/tip-0045.md @@ -0,0 +1,1760 @@ +--- +tip: 45 +title: IOTA 2.0 Transaction Payload +description: Defines the Transaction with the corresponding IOTA 2.0 output types +author: + Philipp Gackstatter (@PhilippGackstatter) , Daria Dziubałtowska (@daria305) + +discussions-to: TODO +status: Draft +type: Standards +layer: Core +created: 2023-05-08 +requires: TIP-39, TIP-41, TIP-42, TIP-43 and TIP-44 +replaces: TIP-20 +--- + +# Summary + +This TIP proposes a new UTXO-based transaction structure consisting of all the inputs and outputs of a transfer. +Specifically, this TIP defines a transaction payload for _blocks_ described in [TIP-46](../TIP-0046/tip-0046.md) and +extends the transaction payload described in [TIP-20](../TIP-0007/tip-0020.md). + +# Motivation + +[TIP-20](../TIP-0020/tip-0020.md) introduced a new extended transaction model for the Stardust update. This TIP extends +this model to be aligned with all new Mana and account features: + +- accommodate for the new output types introduced in [TIP-41](../TIP-0041/tip-0041.md), + [TIP-42](../TIP-0042/tip-0042.md), [TIP-43](../TIP-0043/tip-0043.md), [TIP-44](../TIP-0044/tip-0044.md); +- add the _Allotments_ field in the transaction for adding Mana to an Account's Block Issuance Credits; +- add the _Context Inputs_ field in the transaction for non-UTXO inputs that provide contextual information for the + transaction; +- add the _Creation Slot_ field that is the index of the slot in which the transaction was created; +- updates the syntactic validation rules to ensure the correctness of input and output Mana balances according to IOTA + 2.0 Mana requirements, defined in [TIP-39](../TIP-0039/tip-0039.md). + +The motivation of these changes is to adjust the transaction and its validation rules with the protocol upgrade to IOTA +2.0. Validation rules must now consider the Mana decay factor and the possibility of Mana allotment in the transaction +to a Block Issuance Credits account. + +# Building Blocks + +## Merkle Tree + +A [merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) is a tree data structure that allows for efficient proofs of +inclusion. The serialization schemes defined here are only for a merkle proof of a value in the tree or for the tree's +merkle root. As the tree itself can be represented as the array of its leaves, it does not have its own serialization +scheme. + +### Merkle Proof + +A merkle tree proof is serialized as one of two possible schemas: A tree node or the hash of the value for which the +proof is computed. A `Leaf Hash` schema is additionally used in tree nodes, but cannot be at the top-level of a proof. + +#### Node + +
+ Node +
A merkle tree node that contains two child components.
+
+ + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Merkle Tree Component Typeuint8Set to value 0 to denote a Node.
Left oneOf +
+ Node +
A merkle tree node that contains two child components. Defined in TIP-45 (Node).
+
+
+ Leaf Hash +
Contains the hash of a leaf in the tree. Defined in TIP-45 (Leaf Hash).
+
+
+ Value Hash +
Contains the hash of the value for which the proof is being computed. Defined in TIP-45 (Value Hash).
+
+
Right oneOf +
+ Node +
A merkle tree node that contains two child components. Defined in TIP-45 (Node).
+
+
+ Leaf Hash +
Contains the hash of a leaf in the tree. Defined in TIP-45 (Leaf Hash).
+
+
+ Value Hash +
Contains the hash of the value for which the proof is being computed. Defined in TIP-45 (Value Hash).
+
+
+ +#### Leaf Hash + +
+ Leaf Hash +
Contains the hash of a leaf in the tree.
+
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Merkle Tree Component Typeuint8Set to value 1 to denote a Leaf Hash.
Hash(uint8)ByteArrayThe hash of the leaf.
+ +#### Value Hash + +
+ Value Hash +
Contains the hash of the value for which the proof is being computed.
+
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Merkle Tree Component Typeuint8Set to value 2 to denote a Value Hash.
Hash(uint8)ByteArrayThe hash of the value.
+ +#### Proof Computation + +A **merkle proof** is computed as follows: + +- Preliminary Definitions: + - Let `Leaves` be an array of serialized values, representing the leaves of the tree and `Leaves Len` the length of + that array. + - Let `Leaves[i]` denote the `i`-th element in the `Leaves` array. + - Let `Leaves[Start:End]` denote the subslice of `Leaves` from `Start` (inclusive) to `End` (exclusive). + - Let `Largest Power Of Two(n)` be a procedure that returns the largest power of two less than `n`. + - BLAKE2b-256 is used as the hash function. +- Let `Hash Leaf(Bytes)` be a procedure that produces the hash of the given byte array consisting of these values in + their displayed order: + - the leaf domain-separation prefix with value `0` of type `uint8`, + - and `Bytes`. +- Let `Hash Node(Left Bytes, Right Bytes)` be a procedure that produces the hash of the given byte arrays consisting of + these values in their displayed order: + - the node domain-separation prefix with value `1` of type `uint8`, + - and `Left Bytes`, + - and `Right Bytes`. +- Let `Hash Subtree(Leaves)` be a procedure that produces the hash of a sub-tree in the following way: + - If `Leaves Len == 0` return the hash of the empty string. + - If `Leaves Len == 1` return a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`. + - Otherwise, compute `Split` as `Largest Power Of Two(Leaves Len)`: + - Let `Left` be the result of `Hash Subtree(Leaves[0:Split])`. + - Let `Right` be the result of `Hash Subtree(Leaves[Split:Leaves Len])`. + - Return `Hash Node(Left, Right)` +- Let `Compute Proof(Leaves, Index)` be the procedure that computes the proof for the leaf at index `Index`, defined as + follows: + - If `Leaves Len == 0` return an error, since at least one item is required to compute a proof. + - If `Leaves Len == 1` return a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`. + - If `Leaves Len == 2`: + - If `Index == 0` return a `Node` with: + - `Left` set to a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`. + - `Right` set to a `Leaf Hash` with its `Hash` field set to `Hash Leaf(Leaves[1])`. + - If `Index == 1` return a `Node` with: + - `Left` set to a `Leaf Hash` with its `Hash` field set to `Hash Leaf(Leaves[0])`. + - `Right` set to a `Value Hash` with its `Hash` field set to `Hash Leaf(Leaves[1])`. + - Otherwise, compute `Split` as `Largest Power Of Two(Leaves Len)`: + - If `Index < Split` return a `Node` with: + - `Left` set to the result of `Compute Proof(Leaves[0:Split], Index)`. + - `Right` set to a `Leaf Hash` with its `Hash` field set to `Hash Subtree(Leaves[Split:Leaves Len])`. + - Otherwise return a `Node` with: + - `Left` set to a `Leaf Hash` with its `Hash` field set to `Hash Subtree(Leaves[0:Split])`. + - `Right` set to the result of `Compute Proof(Leaves[Split:Leaves Len], Index)`. + +### Merkle Root + +The **merkle root** is a `ByteArray[32]` and can be computed from two different inputs: + +- From a merkle tree with its array of `Leaves` by executing `Hash Subtree(Leaves)`. +- From a merkle proof by executing `Hash Component` on the top-level component of the proof, where + `Hash Component(Merkle Tree Component)` is a procedure defined as: + - If the component is a `Leaf Hash`, return its field `Hash`. + - If the component is a `Value Hash`, return its field `Hash`. + - If the component is a `Node` return `Hash Node(Hash Component(Left), Hash Component(Right))`. + +# Detailed design + +## UTXO + +The _unspent transaction output_ (UTXO) model defines a ledger state where balances are not directly associated to +addresses but to the outputs of transactions. In this model, transactions reference outputs of previous transactions as +inputs, which are consumed (removed) to create new outputs. A transaction must consume all the funds of the referenced +inputs. + +Using a UTXO-based model provides several benefits: + +- Parallel validation of transactions. +- Easier double-spend detection since conflicting transactions would reference the same UTXO. +- Replay-protection, which is important when having reusable addresses. Replaying the same transaction would manifest + itself as already being applied or existent, and thus, not have any impact. +- Balances are no longer strictly associated to addresses. This allows a higher level of abstraction, and thus, enables + other types of outputs with particular unlock criteria. + +Within a transaction using UTXOs, inputs and outputs make up the to-be-signed data of the transaction. The section +unlocking the inputs is called the _unlock_. An unlock may contain a signature proving ownership of a given input's +address and/or other unlock criteria. + +The following image depicts the flow of funds using UTXO: + +![UTXO flow](utxo.png) + +## Signed Transaction + +### Serialized Layout + +A _Signed Transaction_ Payload is made up of two parts: + +1. The _Transaction_ part which contains the inputs, outputs, and an optional embedded payload. +2. The _Unlocks_ which unlock, or _sign_, the inputs of the _Transaction_. + +The serialized form of the transaction is deterministic, meaning the same logical transaction always results in the same +serialized byte sequence. The inputs and outputs are considered as lists. They can contain duplicates and their +serialization order matches the order of the list; they do not need to be sorted. + +The following table describes the entirety of a _Signed Transaction_ in its serialized form following the notation from +[TIP-21](../TIP-0021/tip-0021.md): + +
+ Signed Transaction +
A transaction with its unlocks.
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Payload Typeuint8Set to value 1 to denote a Signed Transaction.
Transaction +
+ Transaction +
A transaction without its unlocks.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Network IDuint64The ID of the network for which this essence is valid for. It consists of the first 8 bytes of the BLAKE2b-256 hash of the Network Name.
Creation Slotuint32The slot index in which the transaction was created.
Context Inputs Countuint16The number of Context Inputs following.
Context Inputs optAnyOf +
+ Commitment Input +
A Commitment Input allows referencing a commitment to a certain slot and is used to provide a notion of time for transaction execution that is linked to the containing Block's Issuing Time. Defined in TIP-45 (Commitment Input).
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Context Input Typeuint8Set to value 0 to denote a Commitment Input.
Commitment IDByteArray[36]The commitment identifier to reference to.
+
+
+ Block Issuance Credit Input +
A Block Issuance Credit Input provides the BIC balance of a specific account as context to transaction execution. Defined in TIP-45 (Block Issuance Credit Input).
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Context Input Typeuint8Set to value 1 to denote a Block Issuance Credit Input.
Account IDByteArray[32]The ID of the Account for which this input provides the BIC.
+
+
+ Reward Input +
A Reward Input indicates which transaction Input is claiming Mana rewards. Defined in TIP-45 (Reward Input).
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Context Input Typeuint8Set to value 2 to denote a Reward Input.
Indexuint16The index of the transaction input for which to claim rewards.
+
+
Inputs Countuint16The number of Inputs following.
Inputs anyOf +
+ UTXO Input +
Describes an input which references an unspent transaction output to consume. Defined in TIP-45 (UTXO Input).
+ + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Input Typeuint8Set to value 0 to denote a UTXO Input.
Transaction IDByteArray[36]The identifier of the transaction that created the referenced output.
Transaction Output Indexuint16The output index of the referenced output.
+
+
Allotments Countuint16The number of Allotments following.
Allotments optAnyOf +
+ Allotment +
Allots Mana to the account identified by the contained Account ID.
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Account IDByteArray[32]The ID of the Account to which the Mana is allotted.
Manauint64The amount of Mana to allot.
+
+
Capabilities(uint8)ByteArrayThe capabilities of the transaction.
Payload Lengthuint32The length in bytes of the optional payload.
Payload optOneOf +
+ Tagged Data +
Optional Data with an optional Tag. Defined in TIP-53 (Tagged Data).
+
+
Outputs Countuint16The number of Outputs following,
Outputs anyOf +
+ Basic Output +
Describes a basic output with optional features. Defined in TIP-41 (Basic Output).
+
+
+ Foundry Output +
Describes a foundry output that is controlled by an account. Defined in TIP-44 (Foundry Output).
+
+
+ Account Output +
Describes an account in the ledger which can be used to issue blocks or stake for validation. Defined in TIP-42 (Account Output).
+
+
+ NFT Output +
Describes an NFT output, a globally unique token with metadata attached. Defined in TIP-43 (NFT Output).
+
+
+ Delegation Output +
Describes a Delegation Output, which delegates its contained IOTA coins to a validator. Defined in TIP-40 (Delegation Output).
+
+
+
+
Unlocks Countuint16The number of unlocks following.
Unlocks anyOf +
+ Signature Unlock +
Unlocks the address derived from the contained Public Key in the transaction in which it is contained in. Defined in TIP-45 (Signature Unlock).
+
+
+ Reference Unlock +
References a previous unlock to support unlocking multiple inputs owned by the same address. Defined in TIP-45 (Reference Unlock).
+
+
+ Account Unlock +
Points to the unlock of a consumed Account Output. Defined in TIP-42 (Account Unlock).
+
+
+ Anchor Unlock +
Points to the unlock of a consumed Anchor Output. Defined in TIP-54 (Anchor Unlock).
+
+
+ NFT Unlock +
Points to the unlock of a consumed NFT Output. Defined in TIP-43 (NFT Unlock).
+
+
+ Multi Unlock +
Unlocks a Multi Address with a list of other unlocks. Defined in TIP-52 (Multi Unlock).
+
+
+ +### Output ID Proof + +TIP-20 introduced an Inputs Commitment in the transaction to prevent +[an attack vector](https://github.com/iotaledger/tips/discussions/51) on the client. Consider a client requesting Output +IDs from a node which it wants to use as inputs to a transaction. The client has no way to check whether the received +Outputs correspond to the Output IDs it requested. While the Output ID technically depends on the content of the actual +output, a client has no way of validating this without access to the original transaction. A client will only include +the Output ID in a transaction as an input, not the entire output. Hence, if a client receives fake outputs from a +malicious node, it might end up producing a transaction that consumes an output it did not intend to consume. For that +reason the Inputs Commitment was introduced, which provides a cryptographic commitment to the _content_ of all used +inputs. This enables the protocol to detect such attacks, since the transaction would be invalid if the client used a +(e.g. fake) output for their transaction that does not match the one stored by the nodes in the ledger. + +This TIP removes the Inputs Commitment and introduces an Output Commitment through which the Transaction ID becomes +dependent on the outputs it creates. This is used to create proofs which a client can use to verify that an Output ID +indeed belongs to a certain Output. This means that instead of the protocol checking the Inputs Commitment to prevent +the above-mentioned attack, this responsibility now falls to the client, which, when fetching an Output for a certain +Output ID, receives the output as well as the corresponding proof for its Output ID. The client can trustlessly verify +that the output and its ID match which in turn renders the Inputs Commitment unnecessary. + +More generally, this setup is also useful to prove that a given transaction produced an output with a certain state. + +Such an Output ID Proof is a [merkle proof](#merkle-proof), with the array of the serialized `Outputs` as the `Leaves` +of the tree. + +A proof is serialized as follows: + +
+ Output ID Proof +
A merkle proof that allows for cryptographic verification that an Output ID belongs to a given Output.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Slotuint32The slot in which the Output was created.
Output Indexuint16The index of the output in the transaction.
Transaction CommitmentByteArray[32]The commitment to the transaction.
Output Commitment Proof oneOf +
+ Node +
A merkle tree node that contains two child components. Defined in TIP-45 (Node).
+ + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Merkle Tree Component Typeuint8Set to value 0 to denote a Node.
Left oneOf +
+ Node +
A merkle tree node that contains two child components. Defined in TIP-45 (Node).
+
+
+ Leaf Hash +
Contains the hash of a leaf in the tree. Defined in TIP-45 (Leaf Hash).
+
+
+ Value Hash +
Contains the hash of the value for which the proof is being computed. Defined in TIP-45 (Value Hash).
+
+
Right oneOf +
+ Node +
A merkle tree node that contains two child components. Defined in TIP-45 (Node).
+
+
+ Leaf Hash +
Contains the hash of a leaf in the tree. Defined in TIP-45 (Leaf Hash).
+
+
+ Value Hash +
Contains the hash of the value for which the proof is being computed. Defined in TIP-45 (Value Hash).
+
+
+
+
+ Value Hash +
Contains the hash of the value for which the proof is being computed. Defined in TIP-45 (Value Hash).
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Merkle Tree Component Typeuint8Set to value 2 to denote a Value Hash.
Hash(uint8)ByteArrayThe hash of the value.
+
+
+ +By computing the [merkle root](#merkle-root) from the `Output Commitment Proof` the [Transaction ID](#transaction-id) +and Output ID can be reconstructed, using the other fields of the proof. The `Output ID Proof` can thus be used to prove +that a given Output ID was derived from a given Output. + +### Transaction ID + +A Transaction ID consists of two commitments, the _Transaction Commitment_ and the _Output Commitment_. It is a +`ByteArray[36]` which is computed as follows: + +- Let `Transaction Bytes` be the concatenated serialization of the fields from `Network ID` to `Payload`. +- Let `Transaction Commitment` be the BLAKE2b-256 hash of `Transaction Bytes`. +- Let `Output Commitment` be the [merkle root](#merkle-root) over the merkle tree with the serialized `Outputs` as its + `Leaves`. +- Let `ID` be the BLAKE2b-256 of the concatenation of `Transaction Commitment` and `Output Commitment`. +- Construct the `Transaction ID` as the concatenation of the `ID` and the little-endian encoded `Creation Slot`. + +### Network ID + +The `Network ID` field of the transaction serves as a +[replay protection mechanism](https://github.com/iotaledger/tips/discussions/56). It is a unique value denoting whether +the transaction was meant for the IOTA mainnet, shimmer, testnet-1, or a private network. It consists of the first 8 +bytes of the BLAKE2b-256 hash of the `Network Name` protocol parameter, interpreted as a `uint64` in little endian +encoding. + +| Network Name | Resulting `Network ID` | Network Name defined in | +| ------------------- | ---------------------- | --------------------------------------------------- | +| `iota-mainnet` | `9374574019616453254` | [TIP-22](../TIP-0022/tip-0022.md#detailed-design) | +| `shimmer` | `14364762045254553490` | [TIP-32](../TIP-0032/tip-0032.md#global-parameters) | +| `testnet-1` | `1856588631910923207` | - | +| `example-mynetwork` | `1967754805504104511` | - | + +### Creation Slot + +The transaction timestamp is expressed as a `Slot Index`, as there is no need for finer granularity. The validity of the +transaction timestamp is checked in comparison with the `Block` timestamp. Therefore, it is performed at the level of +semantic validation of a block, described in [TIP-0046](../TIP-0046/tip-0046.md). + +### Inputs + +The `Inputs` field holds the inputs to consume in order to fund the outputs of the Transaction Payload. +Currently, there is one type of input: + +- _UTXO Input_. + +Each input must be accompanied by a corresponding Unlock at the same index in the Unlocks part of the +Transaction Payload. + +#### UTXO Input + +A UTXO Input is an input which references an unspent output of a previous transaction. This UTXO is uniquely +identified by its _Output ID_, defined by the _Transaction ID_ of the creating transaction together with corresponding +output index. Each UTXO Input must be accompanied by an Unlock that is allowed to unlock the referenced +output. + +
+ UTXO Input +
Describes an input which references an unspent transaction output to consume.
+
+ + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Input Typeuint8Set to value 0 to denote a UTXO Input.
Transaction IDByteArray[36]The identifier of the transaction that created the referenced output.
Transaction Output Indexuint16The output index of the referenced output.
+ +### Context Inputs + +The `Context Inputs` field holds inputs that provide additional contextual information for the execution of a +transaction, such as for different functionality related to accounts, commitments, or Mana rewards. Context inputs do +not need to be unlocked. This TIP defines 3 types of context inputs: + +- _Commitment Input_. +- _Block Issuance Credit Input_. +- _Reward Input_. + +#### Commitment Input + +A _Commitment Input_ allows referencing a commitment to a certain slot. It is used to provide a notion of time for +transaction execution that is linked to the containing _Block_'s _Issuing Time_. It proves that the time at the +transaction execution is past a certain slot in the past, as the slot has already been committed. The slot reference is +expressed as the _Commitment ID_ and can be resolved to the _Commitment_ value before executing the transaction. The +_Commitment_ itself provides the `Slot Index` which serves as the time reference. A Block that contains a transaction +with a Commitment input has additional validation rules as defined in [TIP-0046](../TIP-0046/tip-0046.md). Only one +_Commitment Input_ may be present in a transaction. + +It is serialized as follows: + +
+ Commitment Input +
A Commitment Input allows referencing a commitment to a certain slot and is used to provide a notion of time for transaction execution that is linked to the containing Block's Issuing Time.
+
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Context Input Typeuint8Set to value 0 to denote a Commitment Input.
Commitment IDByteArray[36]The commitment identifier to reference to.
+ +#### Block Issuance Credit Input + +A _Block Issuance Credit Input_ provides the BIC balance of a specific account as context to transaction execution of a +specific slot. It is required for any _Account_ transition and destruction if the account contains a _Block Issuer +Feature_, as any operation on the _Account_ can only be allowed if the BIC balance is non-negative at a specific point +in time. A _Block Issuance Credit Input_ always requires a _Commitment Input_. The input will be resolved to the BIC +value of the account identified by `Account ID` at the `Slot Index` given by the _Commitment Input_. Multiple _Block +Issuance Credit Inputs_ can be present in a single transaction to provide the BIC for different accounts; however, no +two _Block Issuance Credits Inputs_ can reference the same account. + +It is serialized as follows: + +
+ Block Issuance Credit Input +
A Block Issuance Credit Input provides the BIC balance of a specific account as context to transaction execution.
+
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Context Input Typeuint8Set to value 1 to denote a Block Issuance Credit Input.
Account IDByteArray[32]The ID of the Account for which this input provides the BIC.
+ +#### Reward Input + +A _Reward Input_ indicates which transaction `Input` is claiming Mana rewards. It can reference an _Account Output_ with +a _Staking Feature_ or a _Delegation Output_. The input is resolved by calculating the total amount of rewards the +respective output can claim which is provided as context for transaction execution. The amount of rewards that can be +claimed is added to the total sum of Mana on the input side of the transaction. Multiple such inputs can be present in a +single transaction to claim rewards for different outputs; however, no two _Reward Inputs_ can reference the same index. + +It is serialized as follows: + +
+ Reward Input +
A Reward Input indicates which transaction Input is claiming Mana rewards.
+
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Context Input Typeuint8Set to value 2 to denote a Reward Input.
Indexuint16The index of the transaction input for which to claim rewards.
+ +### Outputs + +The `Outputs` field holds the outputs that are created by the Transaction Payload. There are different output +types, but they must all have an `Amount` field denoting the number of IOTA coins to deposit. + +### Allotments + +The `Allotments` field contains the list of all Mana allotments, the `Account ID`, and corresponding values that +converts Mana provided by the inputs in the form of stored Mana in inputs or potential Mana derived from the inputs' +IOTA coins. Mana listed in this field will be added upon commitment of the slot in which the transaction was issued, in +form of _Block Issuance Credits_ to the account's BIC value. + +Note that _Block Issuance Credits_ are used to pay for the block issuance, they are burned on the slot commitment of the +issuance slot. The good practice would be to always allot enough Mana to cover for the block issuance. + +### Payload + +The _Transaction_ itself can contain another payload as described in general in [TIP-46](../TIP-0046/tip-0046.md). The +[semantic validity](#semantic-validation) of the encapsulating _Transaction Payload_ is unaffected by the possibly +contained payload. + +### Transaction Capabilities + +Transaction Capabilities are represented as a `ByteArray` with a length prefix. For the transaction that contains them +to be valid, the following conditions must hold: + +- The length prefix must be `0` or `1`. + - This condition may be relaxed in the future and implementations should already allow for greater lengths. +- Bit indices start at `0`. For each byte, they are counted starting from the least-significant bit. If there was a + previous byte, the indices continue where the previous byte's indices left off. + - For example: In a list of two bytes with the bit patterns `0001 0000` and `0000 0100`, bits with indices `4` and + `10` are set. +- There must be no trailing zero bytes in the byte array. + - This rule ensures that two transactions whose content is identical, and in particular, that have the same + capabilities will have the same binary representation. + +#### Capability Flags + +The following table shows the mapping from the bit pattern to the capability flags, where the `Flag Index` is the index +of the bit. + +This list is an Allowlist: If the bit is `1` (**set**) the transaction has the capability, if the bit is `0` (**unset**) +it does not have it. + +| Flag Index | Capability (if flag is set) | +| ---------- | ---------------------------- | +| 0 | Can burn Native Tokens. | +| 1 | Can burn Mana. | +| 2 | Can destroy Account Outputs. | +| 3 | Can destroy Anchor Outputs. | +| 4 | Can destroy Foundry Outputs. | +| 5 | Can destroy NFT Outputs. | + +The transaction validation rules for each flag are defined where the respective asset to which it applies is defined. + +### Unlocks + +The `Unlocks` field holds the unlocks which unlock the inputs in a _Transaction_. + +#### Signer UID + +A _Signer UID_ uniquely identifies a signer and is used to check whether different addresses are backed by the same +keypair, i.e. the same signer. One common way to identify a signer is by hashing the public key of the signature. This +concept is introduced as an abstraction over all kinds of signatures, some of which may not have a public key. The +_Signer UID_ is defined by Signatures as well as Addresses that are backed by a cryptographic key pair. + +#### Signature Unlock + +The Signature Unlock holds a signature signing the BLAKE2b-256 hash of the serialized `Transaction` field. It is +serialized as follows: + +
+ Signature Unlock +
Unlocks the address derived from the contained Public Key in the transaction in which it is contained in.
+
+ + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Unlock Typeuint8Set to value 0 to denote a Signature Unlock.
Signature oneOf +
+ Ed25519 Signature +
An Ed25519 Signature with the public key that verifies it. Defined in TIP-38 (Ed25519 Signature).
+ + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Signature Typeuint8Set to value 0 to denote an Ed25519 Signature.
Public KeyByteArray[32]The Ed25519 public key that verifies the signature.
SignatureByteArray[64]The Ed25519 signature that must be verified according to TIP-14.
+
+
+ +##### Signature Unlock Syntactic Validation + +- `Signature` must contain an _Ed25519 Signature_. +- The _Signature Unlock_ must be unique within the subset of _Signature Unlocks_ in the `Unlocks` field of the + transaction based on the contained signature's _Signer UID_. + +##### Signature Unlock Semantic Validation + +- The _Signer UID_ of the signature must match the _Signer UID_ of the to-be-unlocked `Address`. +- The `Signature` field must contain a signature, signing the BLAKE2b-256 hash of the serialized `Transaction` field + which is validated by the `Public Key`. + +#### Reference Unlock + +The Reference Unlock references a previous Unlock (which must not be another Reference Unlock). It +**must** be used if multiple inputs can be unlocked via the same Unlock. It is serialized as follows: + +
+ Reference Unlock +
References a previous unlock to support unlocking multiple inputs owned by the same address.
+
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Unlock Typeuint8Set to value 1 to denote a Reference Unlock.
Referenceuint16Represents the index of a previous unlock.
+ +Example: Consider a Transaction containing the UTXO Inputs 0, 1 and 2, where 0 and 2 are both spending +outputs belonging to the same Ed25519 address `A` and 1 is spending from a different address `B`. This results in the +following structure of the Unlocks part: + +| Index | Unlock | +| ----- | ------------------------------------------------------------------------------------ | +| 0 | A _Signature Unlock_ holding the Ed25519 signature for address `A`. | +| 1 | A _Signature Unlock_ holding the Ed25519 signature for address `B`. | +| 2 | A _Reference Unlock_ which references 0, as both require the same signature for `A`. | + +##### Reference Unlock Syntactic Validation + +- The _Reference Unlock_ at index `i` must have `Reference < i` and the unlock at index `Reference` must be a _Signature + Unlock_ or _Multi Unlock_. + +##### Reference Unlock Semantic Validation + +- It must hold for the `Unlock` at index `Reference`, to which the _Reference Unlock_ at index `i` points and the + corresponding address `Address` of the input at index `i`: + - The `Unlock` must be a semantically valid unlock for `Address`. + +### Work Score + +Let the work score of a transaction be defined as follows. + +- Let `Size Score` be `Work Score Parameters::DataByte * Transaction Size` where `Transaction Size` is the size of the + serialized _Transaction_. +- Let `Input Score` be `Inputs Count * Work Score Parameters::Input`. +- Let `Context Input Score` be `Context Inputs Count * Work Score Parameters::Context Input`. +- Let `Outputs Score` be the sum of work scores of each output `Output` in `Outputs`, where the work score of `Output` + is defined as: + - Let `Native Token Score` be `Work Score Parameters::Native Token` if `Output` contains a `Native Token Feature`, `0` + otherwise. + - Let `Token Scheme Score` be `Work Score Parameters::Native Token` if `Output` contains a _Simple Token Scheme_, `0` + otherwise. + - Let `Staking Score` be `Work Score Parameters::Staking` if `Output` contains a _Staking Feature_, `0` otherwise. + - Let `Block Issuer Score` be `Work Score Parameters::Block Issuer` if `Output` contains a _Block Issuer Feature_, `0` + otherwise. + - Return + `Work Score Parameters::Output + Native Token Score + Token Scheme Score + Staking Score + Block Issuer Score`. +- Let `Allotment Score` be `Work Score Parameters::Allotment * Allotments Count`. +- Let `Signature Score` be the sum of work scores of the signatures contained in _Signature Unlocks_ (directly or within + _Multi Unlocks_) within `Unlocks`. + - Signature work scores are defined with the respective schema definition. +- Return `Size Score + Input Score + Context Input Score + Outputs Score + Allotment Score + Signature Score`. + +## Validation + +A Transaction Payload has different validation stages since some validation steps can only be executed when +certain information has (or has not) been received. We therefore distinguish between syntactic and semantic validation. + +The different output types and optional output features introduced by [TIP-38](../TIP-0038/tip-0038.md), +[TIP-1](../TIP-0042/tip-0041.md),[TIP-42](../TIP-0042/tip-0042.md), [TIP-43](../TIP-0043/tip-0043.md) and +[TIP-44](../TIP-0044/tip-0044.md) add additional constraints to the transaction validation rules, but since these are +specific to the given outputs and features, they are discussed for each +[output type](../TIP-0038/tip-0038.md#output-design) and [feature type](../TIP-0038/tip-0038.md#features) separately. + +### Syntactic validation + +Syntactic validation is checked as soon as the transaction has been received. It validates the structure but not the +signatures of the transaction. If the transaction does not pass this stage, it must not be broadcast further and can be +discarded right away. + +The following criteria defines whether a payload passes the syntactical validation: + +- Transaction: + - `Network ID` must match the value of the current network. + - Inputs: + - `Inputs Count` must be `0 < x ≤ Max Inputs Count`. + - For each input the following must be true: + - `Input Type` must denote an allowed input type, listed in section [Inputs](#inputs). + - `Transaction Output Index` must be `0 ≤ x < Max Outputs Count`. + - Each pair of `Transaction ID` and `Transaction Output Index` must be unique in the list of inputs. + - Context Inputs: + - `Context Inputs Count` must be `0 ≤ x ≤ Max Inputs Count`. + - `Context Input Type` must denote an allowed input type, listed in section [Context Inputs](#context-inputs). + - The Context Inputs must be lexically ordered and unique, both based on the following comparison criteria: + - `Context Input Type` as the first criteria for all Context Inputs. + - `Index` as the second criteria for _Reward Inputs_. + - `Account ID` as the second criteria for _Block Issuance Credit Inputs_. + - There must be zero or one _Commitment Input_. + - A _Commitment Input_ must be present if one or more _Block Issuance Credit Inputs_ or _Reward Inputs_ are present. + - For each `Index` in the _Reward Inputs_ it must hold that: `Index < Inputs Count`. + - Outputs: + - `Outputs Count` must be `0 < x ≤ Max Outputs Count`. + - For each output the following must be true: + - `Output Type` must match one of the values described under [Outputs](#outputs). + - The `Amount` field must not be `0`. + - The `Amount` field must be at least the minimum storage deposit according to [TIP-47](../TIP-0047/tip-0047.md). + - The output itself must pass syntactic validation. + - The sum of all `Amount` fields must not exceed `Token Supply`. + - The sum of all `Mana` fields must not exceed 2Mana Bits Count - 1. + - Allotments: + - `Allotments Count` must be `0 ≤ x ≤ 128`. + - The sum of all `Mana` fields must not exceed 2Mana Bits Count - 1. + - Every `Mana` field in an Allotment must be `> 0`. + - There must be no duplicated `AccountID`s in the list of allotments. + - Each entry in `Allotments` must be lexicographically ordered based on its `Account ID`. + - Payload (if present): + - `Payload Type` must match one of the values described under [Payload](#payload). + - Payload fields must be correctly parsable in the context of the `Payload Type`. + - The payload itself must pass syntactic validation. +- Unlocks: + - `Unlocks Count` must match `Inputs Count` of the _Transaction_. + - For each unlock the following must be true: + - The unlock itself must pass syntactic validation. +- Given the type and length information, the _Transaction Payload_ must consume the entire byte array of the `Payload` + field of the encapsulating object. + +### Semantic validation + +The Semantic validation of a _Transaction Payload_ is performed when its encapsulating block is confirmed. The semantic +validity of transactions depends on the partial order in which they are processed. The solidification mechanism of the +protocol ensures that all inputs will be processed only when all inputs are known valid, and not conflicting. + +Processing transactions according to its partial-ordering enables users to spend UTXOs which are created at similar +point in time, but the input transaction has not yet been confirmed by the network, as they will be processed by +preserving their input-output order relations. In this case, it is recommended that users include the _Block ID_ of the +funding transaction as a parent of the block containing the spending transaction. + +#### Transaction Semantic Validation + +- Each input must reference a valid UTXO, i.e., the output referenced by the input's `Transaction ID` and + `Transaction Output Index` is known (booked) and unspent. +- All _Reward Inputs_ must reference a Delegation Output or an Account Output which contains a Staking Feature. +- The transaction must spend the entire coin balance, i.e., the sum of the `Amount` fields of all the UTXOs referenced + by inputs must match the sum of the `Amount` fields of all outputs. +- Each unlock must be valid with respect to the UTXO referenced by the input of the same index, according to their + respective semantic unlock validation rules. +- If a _Transaction Payload_ passes the semantic validation, its referenced UTXOs must be marked as spent and its new + outputs must be created/booked in the ledger. +- Transactions that do not pass semantic validation are ignored. Their UTXOs are not marked as spent and their outputs + are not booked in the ledger. +- The [semantic rules of Mana](../TIP-0039/tip-0039.md#mana-transaction-validation-rules) pass. + +## Miscellaneous + +### Address reuse + +While, in contrast to Winternitz one-time signatures (W-OTS), producing multiple Ed25519 signatures for the same private +key and address does not decrease its security, it still drastically reduces the privacy of users. It is thus considered +best practice that applications and services create a new address per deposit to circumvent these privacy issues. + +In essence, Ed25519 support allows for smaller transaction sizes and to safely spend funds which were sent to an already +used deposit address. Ed25519 addresses are not meant to be used like email addresses. See this +[Bitcoin wiki article](https://en.bitcoin.it/wiki/Address_reuse) for further information. + +# Drawbacks + +- The new transaction format is the core data type within the IOTA ecosystem. Changing it means that all projects need + to accommodate it, including wallets, web services, client libraries, and applications using IOTA in general. It is + not possible to keep these changes backwards compatible, meaning that all nodes must upgrade to further participate in + the network. +- It is not possible to produce a valid transaction without having access to the content of the consumed outputs. + +# Rationale and Alternatives + +- _Network ID_ is an explicit field in the transaction while it could be made a configuration parameter for the + signature generating process. In this scenario, the signature would be invalid if the parameter on client and network + side mismatch. While this would reduce the size of a transaction, it would make it impossible to debug the reason for + having an invalid signature and transaction. With the current solution we intend to optimize for ease of development. +- Uniqueness of all inputs is kept as it prevents introducing double spends in the same transaction. +- The sorting criteria for _Commitment Inputs_ is only based on their _Context Input Type_ and does not take into + account the _Commitment ID_, which allows for an optimization when determining whether there are zero or one + _Commitment Inputs_. An algorithm checking lexical order and uniqueness will detect the violation of the desired "at + most one" semantic as soon as two or more _Commitment Inputs_ are present, since those would be considered duplicates. +- Requiring lexical order in various places (such as for _Context Inputs_) is mostly an optimization in order to allow + for efficient duplicate detection. + +# Test Vectors + +## Transaction ID + +The following shows a transaction and its computed Transaction ID. + +Transaction (json-encoded): + +```json +{ + "type": 1, + "transaction": { + "networkId": "8342982141227064571", + "creationSlot": 11, + "contextInputs": [ + { + "type": 0, + "commitmentId": "0x3a1e3b617060146e0362361a4b752833186108395f3b2b3d3e6c655e287d707601000000" + }, + { + "type": 1, + "accountId": "0x17432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a" + }, + { + "type": 2, + "index": 0 + } + ], + "inputs": [ + { + "type": 0, + "transactionId": "0xf09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed7195200000000", + "transactionOutputIndex": 0 + }, + { + "type": 0, + "transactionId": "0xd2c5ccba12b6fad51652131289867492799c9fc5710244418aa6e955f8fa826100000000", + "transactionOutputIndex": 0 + } + ], + "allotments": [ + { + "accountId": "0x476820096e7038107d071a4e473f1e295f346e2d0824263e5e3e7d004f6b6915", + "mana": "2189" + }, + { + "accountId": "0x7e0d0a5848362b23120f55115b096774036d7610137a631413221f5573344507", + "mana": "2285" + } + ], + "capabilities": "0x01", + "outputs": [ + { + "type": 0, + "amount": "100000", + "mana": "0", + "unlockConditions": [ + { + "type": 0, + "address": { + "type": 0, + "pubKeyHash": "0xed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a" + } + } + ], + "features": [ + { + "type": 5, + "id": "0x086372557616532f714f104e5f44297b7a286d077956291a6d4f59081f484463712a64300c00", + "amount": "0x14be8149371263f4" + } + ] + }, + { + "type": 1, + "amount": "100000", + "mana": "5000", + "accountId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "foundryCounter": 0, + "unlockConditions": [ + { + "type": 0, + "address": { + "type": 0, + "pubKeyHash": "0xed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a" + } + } + ], + "features": [ + { + "type": 2, + "entries": { + "hello": "0x776f726c64" + } + }, + { + "type": 6, + "expirySlot": 4294967295, + "blockIssuerKeys": [ + { + "type": 0, + "pubKeyHash": "0x295409de79016133647d4078cb01618a4ba018eb74ff613138d8ff8dc05de73c" + }, + { + "type": 0, + "pubKeyHash": "0x868f4c6ef7b5b1d55838cbfb8ae4f3a9776c53cdd3e3d33000094d72acab5a2f" + } + ] + }, + { + "type": 7, + "stakedAmount": "10000", + "fixedCost": "400", + "startEpoch": 0, + "endEpoch": 4294967295 + } + ] + } + ] + }, + "unlocks": [ + { + "type": 0, + "signature": { + "type": 0, + "publicKey": "0x2daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257ac", + "signature": "0x5bb409d59e01d2ea9f1a1fb67feb681d0d3ecb05787cadad2f89fdf13ef7ff03ad5cebf28df5dddd8510992596d98b133f86e14f76824e6ccc369a8f5df44806" + } + }, + { + "type": 1, + "reference": 0 + } + ] +} +``` + +Transaction (hex-encoded binary serialization): + +``` +0x01fb5c44ef0d3ac8730b0000000300003a1e3b617060146e0362361a4b752833186108395f3b2b3d3e6c655e287d7076010000000117432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a020000020000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed7195200000000000000d2c5ccba12b6fad51652131289867492799c9fc5710244418aa6e955f8fa82610000000000000200476820096e7038107d071a4e473f1e295f346e2d0824263e5e3e7d004f6b69158d080000000000007e0d0a5848362b23120f55115b096774036d7610137a631413221f5573344507ed08000000000000010100000000020000a0860100000000000000000000000000010000ed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a0105086372557616532f714f104e5f44297b7a286d077956291a6d4f59081f484463712a64300c00f46312374981be1400000000000000000000000000000000000000000000000001a0860100000000008813000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000ed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a0302010568656c6c6f0500776f726c6406ffffffff0200295409de79016133647d4078cb01618a4ba018eb74ff613138d8ff8dc05de73c00868f4c6ef7b5b1d55838cbfb8ae4f3a9776c53cdd3e3d33000094d72acab5a2f071027000000000000900100000000000000000000ffffffff00020000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257ac5bb409d59e01d2ea9f1a1fb67feb681d0d3ecb05787cadad2f89fdf13ef7ff03ad5cebf28df5dddd8510992596d98b133f86e14f76824e6ccc369a8f5df44806010000 +``` + +Transaction ID: + +``` +0xb16af73e9f3aa82e90e11908886d61661f0a34b5f6cb939daac8086e7b2093120b000000 +``` + +## Output ID Proof + +### Single Output + +An Output ID Proof for a transaction with a single output. + +Signed Transaction (1 Output) (hex-encoded binary serialization): + +``` +0x01fb5c44ef0d3ac8730b0000000000010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719520000000000000000013f0000000002000040420f0000000000000000000000000001000041b5fc0f730776b9d25dc9ffba236ce34bd9433f8a4bc8e286612e42654e0138000040420f00000000000000000000000000010000c5797137d27ceeb1d7a7f712b2dbbd2cb6b9e3fa39fe98a7751ea5913f00495d00010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257acea95793c5a8aef7eeb0daa2a1632f0abf6eeb4c7ca19808f20f6101a6d22ea8f8b4d85dbbbd21d0ac521991a57536fbd37bccd85ab29254a3b5d2e534fda5506 +``` + +Output ID Proof (Output Index 0) (json-encoded): + +```json +{ + "slot": 11, + "outputIndex": 0, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 2, + "hash": "0xb750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b" + }, + "r": { + "type": 1, + "hash": "0x6b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab72" + } + } +} +``` + +Output ID Proof (Output Index 0) (hex-encoded binary serialization): + +``` +0x0b0000000000e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470000220b750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b01206b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab72 +``` + +### Five Outputs + +An Output ID Proof for a transaction with five outputs (not a power of two number of outputs). + +Signed Transaction (5 Outputs) (hex-encoded binary serialization): + +``` +0x01fb5c44ef0d3ac8730b0000000000010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719520000000000000000013f0000000006000040420f0000000000000000000000000001000041b5fc0f730776b9d25dc9ffba236ce34bd9433f8a4bc8e286612e42654e0138000040420f00000000000000000000000000010000c5797137d27ceeb1d7a7f712b2dbbd2cb6b9e3fa39fe98a7751ea5913f00495d000040420f00000000000000000000000000010000c3d789866209202d21895e9a5a69ceb4b1fba08f53237c697e32cf6780a89a71000040420f000000000000000000000000000100008b1697f39c48f841e78e9e3fb2eae08d6af3463fc26fdfbf8ae23ad86ef5353d000040420f00000000000000000000000000010000145a6400ae4ce60e2192b6e538bb790a774db03070afaff1f0c83beedd15fa65000040420f00000000000000000000000000010000f25fbe26abe7ddc7b1ba9fc94a8f6c5a1ac025b0f8027fb7c5ec6047b771527100010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257ac75b951fbf7c55b41b6323cd9b00fe5c444f3145d7bc75da7ae366756f01ee8a18a8e15c6321eb0972084d05422b6eb257869f6f5333ae17b763c0f111d65510e +``` + +Output ID Proof (Output Index 2) (json-encoded): + +```json +{ + "slot": 11, + "outputIndex": 2, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 1, + "hash": "0xdb9fc09b2bdea181fd4f9775116a2ec3c27c93a7ce0ce8f5835fda73bfd09b49" + }, + "r": { + "type": 0, + "l": { + "type": 2, + "hash": "0xe6fc3cdc50433760d43adfe52426648597c092d8973a30529ad0058d6a03b55d" + }, + "r": { + "type": 1, + "hash": "0x7392fe9c9e518a0bc1b0f032e003dbf73096fb95a8bfdbfe05e05f67e0894038" + } + } + }, + "r": { + "type": 1, + "hash": "0xc00b8503cb3aa5473f1a4b4d68cdad468c52e628fdf8dc175caae2d8bec75297" + } + } +} +``` + +Output ID Proof (Output Index 2) (hex-encoded binary serialization): + +``` +0x0b0000000200e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f47000000120db9fc09b2bdea181fd4f9775116a2ec3c27c93a7ce0ce8f5835fda73bfd09b49000220e6fc3cdc50433760d43adfe52426648597c092d8973a30529ad0058d6a03b55d01207392fe9c9e518a0bc1b0f032e003dbf73096fb95a8bfdbfe05e05f67e08940380120c00b8503cb3aa5473f1a4b4d68cdad468c52e628fdf8dc175caae2d8bec75297 +``` + +### 32 Outputs + +An Output ID Proof for a transaction with 32 outputs. + +Signed Transaction (32 Outputs) (hex-encoded binary serialization): + +``` +0x01fb5c44ef0d3ac8730b0000000000010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719520000000000000000013f0000000021000040420f0000000000000000000000000001000041b5fc0f730776b9d25dc9ffba236ce34bd9433f8a4bc8e286612e42654e0138000040420f00000000000000000000000000010000c5797137d27ceeb1d7a7f712b2dbbd2cb6b9e3fa39fe98a7751ea5913f00495d000040420f00000000000000000000000000010000c3d789866209202d21895e9a5a69ceb4b1fba08f53237c697e32cf6780a89a71000040420f000000000000000000000000000100008b1697f39c48f841e78e9e3fb2eae08d6af3463fc26fdfbf8ae23ad86ef5353d000040420f00000000000000000000000000010000145a6400ae4ce60e2192b6e538bb790a774db03070afaff1f0c83beedd15fa65000040420f00000000000000000000000000010000f25fbe26abe7ddc7b1ba9fc94a8f6c5a1ac025b0f8027fb7c5ec6047b7715271000040420f00000000000000000000000000010000ea2e3aa40282125d37373a7a51b94e806156f3d4d5a3e4a7679e9dac36ae5daa000040420f000000000000000000000000000100003475a41594b179a940fe311fddb2b8f0f68ff86fc88d50b085ed0af6dc916879000040420f00000000000000000000000000010000e7f9581f4105471c428dcba08f274986fbc084cbebbe77e0121f6486d7543dab000040420f00000000000000000000000000010000b2313d9e1e500c0105496d43459c33692af0d72c5412a6aa896c2d968aa09d0b000040420f0000000000000000000000000001000056db5b539ddeda7e1c81602669e26506d1a5b3119713d30090ba674cd837e567000040420f000000000000000000000000000100000f29bab850895afefbc2fcc2db1d60f1d86e275ef406b8d98c4e7ed6112c74e5000040420f00000000000000000000000000010000bda720e6d8bf203933dbf1dc4bd00e87e39e93fe514f6e64c9288ae8ce0ca84a000040420f000000000000000000000000000100009d3fd662ba96b4df02d578526090c1f9a580e1d93376380b302bc153b08c9bca000040420f00000000000000000000000000010000613fc72ee7c78035e0cc469a1f49629a98e5ad9c87ce441b9605baa249c42744000040420f000000000000000000000000000100004400a5ed5664a913bb87cb0af6b81bbe01b6a34824f92822cacf6d28f24c235e000040420f000000000000000000000000000100000b4cca1c8d620d650c8bf0f6b3575278732bb79b0156080557a72ffca84e4049000040420f00000000000000000000000000010000f8d2c1579c46b28987a0ed69f1d751b166c4dfd8c1701066aa9d3ad16761785a000040420f00000000000000000000000000010000cd682775e623f1b3f4a99f4d10509aae49a9e4fb2bb959c604d95b7f053fbd38000040420f000000000000000000000000000100006de2cd6d6b75cdf3ecdddcab903e6df6ca288d8ae3ea66c4281b7f86cf063e36000040420f000000000000000000000000000100002a207ba664da0a73f7722868af1396e35e94c96ceb32ddba28dfe862258ac8cb000040420f000000000000000000000000000100004e9807d3cfd5b26ad015b3a8c746d602234a8aeeb09a4f0b814ccf092170086c000040420f000000000000000000000000000100008c2150b4207ba52c8b75ebf13bcb9db776ca103c3ccd6fd25c065a4c91878751000040420f000000000000000000000000000100003293f372d83017fb62eddadf4dfe963c92b5aaa9a4b955da9e8c165318fe8e05000040420f00000000000000000000000000010000c439c102d9b01aab0c7dd33763fb9d376defb5b0d3238122835b9b0eb2def7c6000040420f00000000000000000000000000010000757a899de49f0b2a00dc90ef5bd901c3e24e4998d939cff0f0cf55e8e208e41d000040420f0000000000000000000000000001000032a40408819bfce14fc7101a42d4fc6cf02780c385fc2c3c07e38ddab307f57e000040420f000000000000000000000000000100003f010f28a30d3a5caf57b682ee1b29a89fe13847d761f751a2efef3079d20047000040420f00000000000000000000000000010000c1c3d93b0a50cae27cbfc53cf0195430cda86ce34a63471a59120a61cbc3f5ea000040420f0000000000000000000000000001000009ee1ed9707cec374bdc4977ed77fa237e9f788f6bd47ecbe65d5e3788ccc9b1000040420f00000000000000000000000000010000df40b4f6fe643a1ab1a4ecc7f2f1d2feb24aea9b8cfedb09d21d4dd1870f784e000040420f00000000000000000000000000010000f77ec745cf5fe977cd02905d866cb2ecce4631d02910f96ac49945db418966cb000040420f000000000000000000000000000100009d1879ca302277d00c6a00aa70a23caae1aadbc1232cd3026875ba9291cce11600010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257accae4a03e1357e6ce71deb6f0de8ec9cf2c0f62cbcc0a54a7ea8db5c05257f2c538139739cc41aebd32ffee5f45d8b2c5004079d4d675189d3aa092cc673de704 +``` + +Output ID Proof (Output Index 0) (json-encoded): + +```json +{ + "slot": 11, + "outputIndex": 0, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 2, + "hash": "0xb750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b" + }, + "r": { + "type": 1, + "hash": "0x6b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab72" + } + }, + "r": { + "type": 1, + "hash": "0xb125aad50138d88d8c43459345cbab04523c7e8fc4ea00a2c63bf9c792734775" + } + }, + "r": { + "type": 1, + "hash": "0x91ce0e100a30fed59e0ef34bc4fae37aa46811d48cc18f95b2cc02371fb7e7b8" + } + }, + "r": { + "type": 1, + "hash": "0x8211ee89080681552986e3321b231ff1cfdc114a952c1e3d3fc934283603df1f" + } + }, + "r": { + "type": 1, + "hash": "0x84fc02511dfc0326c9c82aa7081430cbfac7dc9d4e9144527374f66399e5c790" + } + }, + "r": { + "type": 1, + "hash": "0x4ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39" + } + } +} +``` + +Output ID Proof (Output Index 0) (hex-encoded binary serialization): + +``` +0x0b0000000000e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f4700000000000000220b750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b01206b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab720120b125aad50138d88d8c43459345cbab04523c7e8fc4ea00a2c63bf9c792734775012091ce0e100a30fed59e0ef34bc4fae37aa46811d48cc18f95b2cc02371fb7e7b801208211ee89080681552986e3321b231ff1cfdc114a952c1e3d3fc934283603df1f012084fc02511dfc0326c9c82aa7081430cbfac7dc9d4e9144527374f66399e5c79001204ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39 +``` + +Output ID Proof (Output Index 28) (json-encoded): + +```json +{ + "slot": 11, + "outputIndex": 28, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 1, + "hash": "0x7f564883c631d43a902ef144a674e6ac11ed7db1c9e88ecf7a664c19885de497" + }, + "r": { + "type": 0, + "l": { + "type": 1, + "hash": "0xaa70d7aab4560bcafda057bcffca504f4d6ca89bc5652d4cf60a33e85a39bc5f" + }, + "r": { + "type": 0, + "l": { + "type": 1, + "hash": "0xc6e9e11d1ae2b9479e778fed77d273ced27cfee60b8d9c2cb0fce4efe5b1d179" + }, + "r": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 2, + "hash": "0x56cf9617298303d80e0b0bc7a38e9807db5e6b5c1dbe32338ec54efa830f1d93" + }, + "r": { + "type": 1, + "hash": "0x45d50fb24eecc01fed1254b75e0ddc97c3d8825f02e68b75da3f16f14573cc53" + } + }, + "r": { + "type": 1, + "hash": "0x2e88c7335dcc28ef7cf618d77336b62f49c1d0c05d956e516eb9a37f556373e2" + } + } + } + } + }, + "r": { + "type": 1, + "hash": "0x4ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39" + } + } +} +``` + +Output ID Proof (Output Index 28) (hex-encoded binary serialization): + +``` +0x0b0000001c00e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470000001207f564883c631d43a902ef144a674e6ac11ed7db1c9e88ecf7a664c19885de497000120aa70d7aab4560bcafda057bcffca504f4d6ca89bc5652d4cf60a33e85a39bc5f000120c6e9e11d1ae2b9479e778fed77d273ced27cfee60b8d9c2cb0fce4efe5b1d1790000022056cf9617298303d80e0b0bc7a38e9807db5e6b5c1dbe32338ec54efa830f1d93012045d50fb24eecc01fed1254b75e0ddc97c3d8825f02e68b75da3f16f14573cc5301202e88c7335dcc28ef7cf618d77336b62f49c1d0c05d956e516eb9a37f556373e201204ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39 +``` + +## Potential and Stored Mana + +The following test vector shows a transaction where one output is being consumed and one is created. The potential mana +generated by the consumed output is stored in the created output while the decayed stored mana of the consumed output is +allotted to an account. + +Transaction (json-encoded): + +```json +{ + "type": 1, + "transaction": { + "networkId": "8342982141227064571", + "creationSlot": 5000000, + "contextInputs": [ + { + "type": 0, + "commitmentId": "0x3a1e3b617060146e0362361a4b752833186108395f3b2b3d3e6c655e287d7076364b4c00" + } + ], + "inputs": [ + { + "type": 0, + "transactionId": "0xf09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed7195005000000", + "transactionOutputIndex": 0 + } + ], + "allotments": [ + { + "accountId": "0x476820096e7038107d071a4e473f1e295f346e2d0824263e5e3e7d004f6b6915", + "mana": "2272" + } + ], + "outputs": [ + { + "type": 0, + "amount": "100000", + "mana": "2502459", + "unlockConditions": [ + { + "type": 0, + "address": { + "type": 0, + "pubKeyHash": "0xed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a" + } + } + ] + } + ] + }, + "unlocks": [ + { + "type": 0, + "signature": { + "type": 0, + "publicKey": "0x2daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257ac", + "signature": "0x7a3da62e0c314918170a2dc476588dd6e27032b7817a08be7482643b434604a5ecec55616bd77730e86bfd223bd3a2d09b0d5366058d5470d192a9adef77a007" + } + } + ] +} +``` + +Transaction (hex-encoded binary serialization): + +``` +0x01fb5c44ef0d3ac873404b4c000100003a1e3b617060146e0362361a4b752833186108395f3b2b3d3e6c655e287d7076364b4c00010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719500500000000000100476820096e7038107d071a4e473f1e295f346e2d0824263e5e3e7d004f6b6915e0080000000000000000000000010000a0860100000000003b2f260000000000010000ed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a00010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257ac7a3da62e0c314918170a2dc476588dd6e27032b7817a08be7482643b434604a5ecec55616bd77730e86bfd223bd3a2d09b0d5366058d5470d192a9adef77a007 +``` + +Input with Output ID: `0xf09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed71950050000000000` (= creation +slot 5) (json-encoded): + +```json +{ + "type": 0, + "amount": "100000", + "mana": "4000", + "unlockConditions": [ + { + "type": 0, + "address": { + "type": 0, + "pubKeyHash": "0xed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a" + } + } + ] +} +``` + +Input with Output ID: `0xf09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed71950050000000000` (= creation +slot 5) (hex-encoded binary serialization): + +``` +0x00a086010000000000a00f000000000000010000ed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a00 +``` + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/tips/TIP-0045/utxo.png b/tips/TIP-0045/utxo.png new file mode 100644 index 000000000..b29177df2 Binary files /dev/null and b/tips/TIP-0045/utxo.png differ