- Feature name: signed_transaction_payload
- Start date: 2020-07-10
- RFC PR: iotaledger/protocol-rfcs#0000
This RFC defines a new transaction structure for Chrysalis Phase 2, which replaces the current notion of bundles. Specifically, this RFC describes the transaction payload to be embedded into a message.
The current IOTA protocol uses so called transactions (which are vertices in the Tangle), where each transaction defines either an input or output. A grouping of those input/output transaction vertices make up a so called bundle which transfers the given values as an atomic unit (the entire bundle is applied or none of it). The input transactions define the funds to consume to create the deposits onto the output transactions target addresses. Additionally, to accommodate the rather big WOTS signatures, additional transaction vertices might be part of the bundle in order to carry parts of the signature which don't fit into one transaction vertex.
The bundle concept has proven to be tedious, spawning a plethora of problems:
- Since the data making up the bundle is split across multiple vertices, it complicates the validation of the entire transfer. Instead of being able to immediately tell whether a bundle is valid or not, a node implementation must first collect all parts of the bundle before any actual validation can happen. This increases the complexity of the node implementation immensely.
- Reattaching the tail transaction of a bundle causes the entire transfer to be reapplied.
- TODO write more problems
To fix the problems mentioned above and creating a more flexible transaction structure, we want to achieve a self-contained transaction structure defining the data of the entire transfer as a payload to be embedded into a message.
The new transaction structure should fulfill following criteria:
- Support for Ed25519 (and thus reusable addresses) and WOTS signatures.
- Support for adding new types of signature schemes, addresses, inputs and outputs as part of protocol upgrades.
- Self-contained as in being able to validate the transaction immediately after receiving it.
- Enable unspent transaction outputs (UTXO) as inputs instead of an account based model. (UTXO enables easier double-spend detection)
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 specify the outputs of previous transactions as inputs, which are consumed in order to create new outputs. A transaction must consume the entirety of the specified inputs.
Using an 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 especially important when having reusable addresses. Replaying the same transaction would manifest itself as already being applied or existent and thus not have any impact.
- Technically seen, balances are no longer associated to addresses which raises the level of abstraction and thus enables other types of outputs. Consider for example a type of output which specifies the balance to be unlocked by a transaction using this output which must fulfill a very hard Proof-of-Work difficulty or supply some other unlock criteria etc.
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 unlock block. An unlock block 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:
The way UTXOs are referenced is further described in the Structure section of this RFC.
A Signed Transaction payload is made up of two parts:
- The Unsigned Transaction part which contains the inputs, outputs and an optional embedded payload.
- The Unlock Blocks which unlock the Unsigned Transaction's inputs. In case the unlock block contains a signature, it signs the entire Unsigned Transaction part.
Following table structure describes the entirety of a Signed Transaction payload's serialized form:
Data Types
Notation | Size | Description |
---|---|---|
byte |
1 byte | An unsigned 8-bit integer. |
varint |
variable | A numerical value using N amount of bytes needed to represent its value. See docs on the Protocol Buffers site. |
ByteArray |
1 varint (length) + L * bytes | A variable sized array of bytes where the leading varint L denotes the size of the array. |
ByteArray[N] |
N * bytes | A fixed sized array of bytes (without a leading varint N denoting the size of the array). i.e. ByteArray[32] : A byte array with 32 bytes. |
Subschema Notation
Name | Description |
---|---|
oneOf |
One of the listed subschemas. |
optOneOf |
Optionally one of the listed subschemas. |
anyOf |
Any (one or more) of the listed subschemas. |
Name | Type | Description | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Payload Type | varint | Set to value 0 to denote a Signed Transaction payload. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Transaction oneOf |
Unsigned TransactionDescribes the essence data making up a transaction by defining its inputs and outputs and an optional payload.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Unlock Blocks Count | byte/varint | The count of unlock blocks proceeding. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Unlock Blocks anyOf |
Ed25519 Signature Unlock Block
WOTS Signature Unlock Block
|
In general, all parts of a Signed Transaction begin with a byte describing the type of the given part in order to keep the flexibility to introduce new types/versions of the given part in the future.
As described, the Unsigned Transaction of a Signed Transaction carries the inputs, outputs and an optional payload. The Unsigned Transaction is an explicit type of transaction and therefore starts with its own Transaction Type byte which is of value 0.
An Unsigned Transaction must contain at least one input and output.
The Inputs part holds the inputs to consume, respectively to fund the outputs of the Unsigned Transaction. There is only one type of input as of now, the UTXO Input.
Format
Name | Type | Description | ||||||
Input Type | byte/varint | Set to value 0 to denote a UTXO Input. | ||||||
Transaction ID | ByteArray[64] | The transaction reference from which the UTXO comes from. | ||||||
Transaction Output Index | byte/varint | The index of the output on the referenced transaction to consume. | ||||||
Unlock Index | byte/varint | The index of the unlock block unlocking the funds used in this input. Multiple inputs can reference the same unlock block, for example, inputs consuming multiple UTXOs residing on a specific Ed25519 address may reference the same signature unlock block with the corresponding signature unlocking the funds. | ||||||
Unlock Mode | byte/varint |
Defines the unlock block's type which unlocks this input.
|
An UTXO Input is an input which directly references an output of a previous transaction by using the given transaction's BLAKE2b-256 (TODO: are we going to use this?) hash + the index of the output on that transaction. It defines which unlock block in the unlock blocks part of the Signed Transaction unlocks this input with the type the unlock block must have.
Example: If the output the input references outputs to an Ed25519 address, then the corresponding unlock block must be of type Signature Unlock Block.
Multiple inputs may reference the same unlock block, for example, if an Unsigned Transaction consumes UTXOs which output to the same Ed25519 address, then one unlock block with the corresponding signature can be used to unlock those inputs.
The Outputs part holds the outputs to create with this Unsigned Transaction. There is only one type of output as of now, the SigLockedSingleDeposit.
Format
Name | Type | Description | ||||||||||||||||||
Output Type | byte/varint | Set to value 0 to denote a SigLockedSingleDeposit. | ||||||||||||||||||
Address (oneOf) |
Ed25519 Address
WOTS Address
|
|||||||||||||||||||
Amount | uint64 | The amount of tokens to deposit with this SigLockedSingleDeposit output. |
The SigLockedSingleDeposit defines an output (with a certain amount) to a single target address which is unlocked via a signature proving ownership over the given address. Such output can hold addresses of different types.
The payload part of an Unsigned Transaction can hold an optional payload. This payload must not affect the validity of the Unsigned Transaction. Only the Indexation Payload (TODO: LINK TO RFC) is supported as of now. An Unsigned Transaction holding a payload of a non-supported type is invalid.
The Unlock Blocks part holds the unlock blocks unlocking inputs within an Unsigned Transaction. As of now, only unlock blocks of type Signature Unlock Block exist.
Inputs must specify what type their corresponding Unlock Block is:
Name | Value | Description |
SIGNATURE | 0 | A signature unlock block. |
A Signature Unlock Block defines an Unlock Block which holds a signature of some type unlocking one or more inputs. Such block signs the entire Unsigned Transaction part of an Signed Transaction including the optional payload.
A Signature Unlock Block first defines its type (this is a type "within" the Signature Unlock Block. It is not the type of the Unlock Block) and then the corresponding data needed to parse and validate the signature. There are two types of Signature Unlock Blocks, one for Ed25519 addresses and one for WOTS addresses.
Ed25519 Signature Unlock Block
Name | Type | Description |
---|---|---|
Signature Type | byte/varint | Set to value 0 to denote an Ed25519 Signature Unlock Block. |
Public key | ByteArray[32] | The public key of the Ed25519 keypair which is used to verify the signature. |
Signature | ByteArray[64] | The signature signing the serialized Unsigned Transaction. |
WOTS Signature Unlock Block
Name | Type | Description |
---|---|---|
Signature Type | byte/varint | Set to value 1 to denote a WOTS Signature Unlock Block. |
Signature | ByteArray | The signature signing the serialized Unsigned Transaction. |
A Signed Transaction payload has different validation stages, since some validation steps can only be executed if certain information becomes present, respectively should have become present. We therefore distinguish between syntactical- and semantic validation.
This validation can commence as soon as the transaction data has been received in its entirety. It validates the structure but not the signatures of the transaction. If the transaction does not pass this stage, it must not be further broadcasted and can be discarded.
Following criteria defines whether the transaction passes the syntactical validation:
Transaction Type
value must be 0, denoting anUnsigned Transaction
.- Inputs:
Inputs Count
must be 0 < x ≤ 127.- At least one input must be present in the transaction.
Input Type
value must be 0, denoting anUTXO Input
.UTXO Input
:Transaction Output Index
must be 0 ≤ x ≤ 127.Unlock Index
must be ≤ highest seen index + 1. The first defined input must start at index 0. Sequence examples of inputsUnlock Indices
:- Valid sequence:
0, 0, 1, 2, 1, 3
. - Invalid sequence:
0, 1, 2, 4
or0, 1, 2, 3, 6, 4
- Valid sequence:
Unlock Mode
must be 0 (denoting aSignature Unlock Block
).- Inputs must be in lexicographical order by their specified
Transaction ID
.
- Outputs:
Outputs Count
must be 0 < x ≤ 127.Output Type
must be 0, denoting aSigLockedSingleDeposit
.SigLockedSingleDeposit
:Address Type
must either be 0 or 1, denoting anEd25519
- orWOTS address
.- If
Address
is of typeWOTS address
, its bytes must be validT5B1
bytes. Amount
must be > 0.
- Accumulated output balance must not exceed the total supply of tokens
2'779'530'283'277'761
.
Payload Length
must be 0 (to indicate that there's no payload) or be valid for the specified payload type.Payload Type
must be 0 ifPayload Length
is not 0, denoting anIndexation Payload
.Unlock Blocks Count
must match the amount of mentioned uniqueUnlock Indices
specified in the inputs. Must be 0 < x ≤ 127.Signature Unlock Block Type
must either be 0 or 1, denoting anEd25519
- orWOTS Signature Unlock block
.- Given the type and length information, the Signed Transaction must consume the entire byte array the
Payload Length
field in the Message defines.
Semantic validation starts when a message which is part of a confirmation cone of a milestone, is processed in the White-Flag ordering. Semantics are only validated during White-Flag confirmations to enforce an ordering which can be understood by all the nodes (i.e. milestone cones), no matter in which order transactions are received. Otherwise, if semantic validation would occur as soon as a transaction would be received, it could potentially lead to nodes having different views of the UTXOs available to spend.
Processing transactions in the White-Flag ordering enables users to spend UTXOs which are in the same milestone confirmation cone, if their transaction comes after the funding transaction in the mentioned White-Flag ordering. It is recommended that users spending unconfirmed UTXOs attach their message directly onto the message containing the source transaction.
Following criteria defines whether the transaction passes the semantic validation:
- The UTXOs the transaction references must be known (booked) and unspent.
- The transaction is spending the entirety of the funds of the referenced UTXOs to the ouputs.
- The address type of the referenced UTXO must match the type of Signature Unlock Block type.
- The Signature Unlock Blocks are valid, i.e. the signatures prove ownership over the addresses of the referenced UTXOs.
If a transaction passes the semantic validation, its referenced UTXOs must be marked as spent and the corresponding new outputs must be booked/specified in the ledger. The booked transaction then also becomes part of the White-Flag Merkle tree inclusion set.
Transactions which do not pass semantic validation are ignored. Their UTXOs are not marked as spent and neither are their outputs booked into the ledger.
Why should we not do this?
- Why is this design the best in the space of possible designs?
- What other designs have been considered and what is the rationale for not choosing them?
- What is the impact of not doing this?
- What parts of the design do you expect to resolve through the RFC process before this gets merged?
- What parts of the design do you expect to resolve through the implementation of this feature before stabilization?
- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC?