You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This document defines how to compute the unique identifiers used for transactions and state elements.
7
+
8
+
## Transaction ID
9
+
10
+
The _transaction ID_ (also called _transaction hash_) of a transaction is computed as the [hash](./cryptographic_primitives.md#hashing) of the [serialized transaction](./tx_format.md#transaction) with [fields zeroed out for signing](./tx_format.md) (see different inputs and outputs for which fields are set to zero).
11
+
12
+
## UTXO ID
13
+
14
+
The UTXO ID of a transaction's output is computed as the [hash](./cryptographic_primitives.md#hashing) of the concatenation of the [transaction ID](#transaction-id) and the output index as a `uint8`.
15
+
16
+
The UTXO ID of a deposit is computed as the [hash](./cryptographic_primitives.md#hashing) of TODO.
|`data`| One of [TransactionScript](#transactionscript) or [TransactionCreate](#transactioncreate)| Transaction data. |
44
45
46
+
Transaction is invalid if:
47
+
*`type > TransactionType.Create`
48
+
*`gasLimit > MAX_GAS_PER_TX`
49
+
*`blockheight() < maturity`
50
+
*`inputsCount > MAX_INPUTS`
51
+
*`outputsCount > MAX_OUTPUTS`
52
+
*`witnessesCount > MAX_WITNESSES`
53
+
45
54
When serializing a transaction, fields are serialized as follows (with inner structs serialized recursively):
46
55
1.`uint8`, `uint16`, `uint32`, `uint64`: big-endian right-aligned to 8 bytes.
47
56
1.`byte[32]`: as-is.
48
57
1.`byte[]`: as-is, with padding zeroes aligned to 8 bytes.
49
58
59
+
When deserializing a transaction, the reverse is done. If there are insufficient bytes or too many bytes, the transaction is invalid.
60
+
50
61
### TransactionScript
51
62
52
63
| name | type | description |
@@ -66,8 +77,9 @@ When serializing a transaction, fields are serialized as follows (with inner str
66
77
|`witnesses`|[Witness](#witness)`[]`| List of witnesses. |
67
78
68
79
Transaction is invalid if:
69
-
*`blockheight() < maturity`
70
80
* Any output is of type `OutputType.ContractCreated`
81
+
*`scriptLength > MAX_SCRIPT_LENGTH`
82
+
*`scriptDataLength > MAX_SCRIPT_DATA_LENGTH`
71
83
72
84
### TransactionCreate
73
85
@@ -87,13 +99,12 @@ Transaction is invalid if:
87
99
|`witnesses`|[Witness](#witness)`[]`| List of witnesses. |
88
100
89
101
Transaction is invalid if:
90
-
*`blockheight() < maturity`
91
102
* Any input is of type `InputType.Contract`
92
103
* Any output is of type `OutputType.Contract` or `OutputType.Variable`
93
104
* More than one output is of type `OutputType.ContractCreated`
94
105
*`bytecodeLength * 4 > CONTRACT_MAX_SIZE`
95
106
96
-
Creates a contract with contract ID `sha256(0x4655454C ++ tx.data.salt ++ root(tx.data.bytecode))`, where `root` is the Merkle root of [the binary Merkle tree](./cryptographic_primitives.md) with each leaf being an 8-byte word of bytecode. If the bytecode is not a multiple of 8 bytes (i.e. if there are an odd number of instructions), the last opcode is padding with 4-byte zero.
107
+
Creates a contract with contract ID `sha256(0x4655454C ++ tx.data.salt ++ root(tx.data.bytecode))`, where `root` is the Merkle root of [the binary Merkle tree](./cryptographic_primitives.md) with each leaf being an 8-byte word of bytecode. If the bytecode is not a multiple of 8 bytes (i.e. if there are an odd number of instructions), the last opcode is padded with 4-byte zero.
97
108
98
109
## Input
99
110
@@ -121,6 +132,11 @@ enum InputType : uint8 {
121
132
|`predicate`|`byte[]`| Predicate bytecode. |
122
133
|`predicateData`|`byte[]`| Predicate input data (parameters). |
Note: when signing a transaction, `amount` and `stateRoot` are set to zero.
168
193
169
-
Note: when executing a transaction, `amount` and `stateRoot` are initialized to the balance and state root of the contract with ID `tx.inputs[inputIndex].contractID`.
194
+
Note: when verifying a predicate or executing a script, `amount` and `stateRoot` are initialized to the balance and state root of the contract with ID `tx.inputs[inputIndex].contractID`.
170
195
171
196
### OutputChange
172
197
@@ -177,7 +202,7 @@ Note: when executing a transaction, `amount` and `stateRoot` are initialized to
177
202
178
203
Note: when signing a transaction, `amount` is set to zero.
179
204
180
-
Note: when executing a transaction, `amount` is initialized to zero.
205
+
Note: when verifying a predicate or executing a script, `amount` is initialized to zero.
181
206
182
207
This output type indicates that the output's amount may vary based on transaction execution, but is otherwise identical to a [Coin](#outputcoin) output. An `amount` of zero after transaction execution indicates that the output is unspendable and can be pruned from the UTXO set.
183
208
@@ -190,7 +215,7 @@ This output type indicates that the output's amount may vary based on transactio
190
215
191
216
Note: when signing a transaction, `to` and `amount` are set to zero.
192
217
193
-
Note: when executing a transaction, `to` and `amount` are initialized to zero.
218
+
Note: when verifying a predicate or executing a script, `to` and `amount` are initialized to zero.
194
219
195
220
This output type indicates that the output's amount and owner may vary based on transaction execution, but is otherwise identical to a [Coin](#outputcoin) output. An `amount` of zero after transaction execution indicates that the output is unspendable and can be pruned from the UTXO set.
This section defines _standardness rules_ for transactions: the bare minimum required to accept an unconfirmed transaction into a mempool. Chains of unconfirmed transactions are omitted.
17
+
Once a transaction is seen, it goes through several stages of validation, in this order:
For a transaction `tx`, state `state`, and contract set `contracts`, the following checks must pass.
22
-
23
-
### Version
23
+
## VM Precondition Validity Rules
24
24
25
-
```py
26
-
return tx.version ==0
27
-
```
25
+
This section defines _vm precondition validity rules_ for transactions: the bare minimum required to accept an unconfirmed transaction into a mempool, and preconditions that the VM assumes to hold prior to execution. Chains of unconfirmed transactions are omitted.
28
26
29
-
### Spending UTXOs or Created Contracts
27
+
The validity rules assuming sequential transaction validation for side effects (i.e. state changes). However, by construction, transactions with different access lists can be validated in parallel. Transactions with overlapping access lists must be validated and placed in blocks in topological order.
30
28
31
-
```py
32
-
forinputin tx.inputs:
33
-
ifinput.type == InputType.Coin:
34
-
ifnotinput.utxoID in state:
35
-
returnFalse
36
-
ifinput.type == InputType.Contract:
37
-
ifnotinput.contractID in contracts:
38
-
returnTrue
39
-
```
29
+
For a transaction `tx`, state `state`, and contract set `contracts`, the following checks must pass.
40
30
41
-
### Transaction Maturity
31
+
### Base Sanity Checks
42
32
43
-
```py
44
-
return blockheight() >= tx.maturity
45
-
```
33
+
Base sanity checks are defined in the [transaction format](./tx_format.md).
46
34
47
-
### Input Maturity
35
+
### Spending UTXOs and Created Contracts
48
36
49
37
```py
50
38
forinputin tx.inputs:
51
-
ifinput.type == InputType.Coin:
52
-
if blockheight() < state[input.utxoID].created +input.maturity:
The transaction hash is computed as defined [here](./identifiers.md#transaction-id).
137
98
138
-
For each input of type `InputType.Coin` and `predicateLength > 0`, [verify its predicate](./main.md#predicate-verification).
99
+
## Predicate Verification
139
100
140
-
## Validity Rules
101
+
For each input of type `InputType.Coin` and `predicateLength > 0`, [verify its predicate](../vm/main.md#predicate-verification).
141
102
142
-
This section defines _validity rules_ for transactions: the requirements for a confirmed transaction to be valid.
103
+
## Script Execution
143
104
144
-
Given transaction `tx`, state `state`, and contract set `contracts`:
105
+
Given transaction `tx`, the following checks must pass:
145
106
146
-
If `tx.scriptLength == 0`, there is no script and the transaction defines a simple balance transfer, and no further checks are required. Transaction processing is completed by removing spent UTXOs from the state and adding created UTXOs to the state.
107
+
If `tx.scriptLength == 0`, there is no script and the transaction defines a simple balance transfer, so no further checks are required.
147
108
148
109
If `tx.scriptLength > 0`, the script must be executed. The free balance available to be moved around by the script and called contracts is `freeBalance`:
Once the free balance is computed, the [script is executed](../vm/main.md#script-execution) and the transaction in memory on VM termination is used as the final transaction which is included in the block, i.e.:
116
+
117
+
```
118
+
tx = MEM[40, MEM[32, 8]]
119
+
```
120
+
121
+
If the transaction as included in a block does not match the final transaction, the block is invalid.
122
+
123
+
## VM Postcondition Validity Rules
124
+
125
+
This section defines _VM postcondition validity rules_ for transactions: the requirements for a transaction to be valid after it has been executed.
126
+
127
+
Given transaction `tx`, state `state`, and contract set `contracts`, the following checks must pass.
155
128
156
129
### No Inflation
157
130
158
131
```py
159
132
defsum_all_inputs(tx) -> int:
160
133
total: int=0
161
134
forinputin tx.inputs:
162
-
ifinput.type == InputType.Coin:
163
-
total += state[input.utxoID].amount
164
-
elseifinput.type == InputType.Contract:
165
-
total += state[tx.witnesses[input.witnessIndex]].amount
135
+
total += state[input.utxoID].amount
166
136
return total
167
137
168
138
defsum_all_outputs(tx) -> int:
169
139
total: int=0
170
140
for output in tx.outputs:
171
-
if output.type == OutputType.Coin:
141
+
if output.type != OutputType.ContractCreated:
172
142
total += output.amount
173
-
elseif output.type == OutputType.Contract:
174
-
total += tx.witnesses[output.amountWitnessIndex]
175
143
return total
176
144
177
145
return sum_all_inputs(tx) >= sum_all_outputs(tx)
178
146
```
147
+
148
+
### State Changes
149
+
150
+
Transaction processing is completed by removing spent UTXOs from the state and adding created UTXOs to the state.
Copy file name to clipboardExpand all lines: specs/vm/main.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -73,7 +73,8 @@ A complete list of opcodes in the Fuel VM is documented [here](./opcodes.md).
73
73
Every time the VM runs, a single monolithic memory of size `VM_MAX_RAM` bytes is allocated, indexed by individual byte. A stack and heap memory model is used, allowing for dynamic memory allocation in higher-level languages. The stack begins at `0` and grows upward. The heap begins at `VM_MAX_RAM - 1` and grows downward.
74
74
75
75
To initialize the VM, the following is pushed on the stack sequentially:
76
-
1. Transaction hash (`byte[32]`, word-aligned).
76
+
1. Transaction hash (`byte[32]`, word-aligned), computed as defined [here](../protocol/identifiers.md#transaction-id).
77
+
1. Transaction length, in bytes (`uint64`, word-aligned).
77
78
1. The [transaction, serialized](../protocol/tx_format.md).
78
79
79
80
Then the following registers are initialized (without explicit initialization, all registers are initialized to zero):
0 commit comments