miden-protocol 0.16.0-beta.1

Core components of the Miden protocol
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
use {TX_EXEC_FOREIGN_PROC_OFFSET, TX_GET_BLOCK_COMMITMENT_OFFSET, TX_GET_BLOCK_NUMBER_OFFSET, TX_GET_BLOCK_TIMESTAMP_OFFSET, TX_GET_EXPIRATION_DELTA_OFFSET, TX_GET_FEE_FAUCET_ID_OFFSET, TX_GET_INPUT_NOTES_COMMITMENT_OFFSET, TX_GET_NUM_INPUT_NOTES_OFFSET, TX_GET_NUM_OUTPUT_NOTES_OFFSET, TX_GET_OUTPUT_NOTES_COMMITMENT_OFFSET, TX_GET_TX_SCRIPT_ROOT_OFFSET, TX_PREPARE_FPI_OFFSET, TX_UPDATE_EXPIRATION_BLOCK_DELTA_OFFSET, TX_COMPUTE_FEE_OFFSET}
    from miden::protocol::kernel_proc_offsets
use {AccountId, AccountProcedureRoot, BlockNumber, TransactionScriptRoot}
    from miden::protocol::types

#! Returns the block number of the transaction reference block.
#!
#! Inputs:  []
#! Outputs: [num]
#!
#! Where:
#! - num is the transaction reference block number.
#!
#! Invocation: exec
pub proc get_block_number() -> BlockNumber
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_BLOCK_NUMBER_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [num, pad(15)]

    # clean the stack
    swapw.3 dropw dropw dropw movdn.3 drop drop drop
    # => [num]
end

#! Returns the block commitment of the transaction reference block.
#!
#! Inputs:  []
#! Outputs: [BLOCK_COMMITMENT]
#!
#! Where:
#! - BLOCK_COMMITMENT is the commitment to the reference block of the transaction.
#!
#! Invocation: exec
pub proc get_block_commitment() -> word
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_BLOCK_COMMITMENT_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [BLOCK_COMMITMENT, pad(12)]

    # clean the stack
    swapdw dropw dropw swapw dropw
    # => [BLOCK_COMMITMENT]
end

#! Returns the timestamp of the reference block for this transaction.
#!
#! WARNING: the returned timestamp is not guaranteed to be precise (i.e., could be several seconds
#! off) or recent, unless recency is separately enforced by setting transaction expiration delta.
#!
#! Specifically, the reference blocks (and therefore the corresponding block timestamp) can be
#! chosen somewhat arbitrarily by the transaction executor. While this does not allow executors to
#! choose future timestamps, they can choose older timestamps for their benefit.
#!
#! For example, consider a script that includes a "time boundary", where before time 10 account X
#! can consume the note and after time 10 another account Y can consume the note. Even if the latest
#! block in the chain is at time 11, the owner of account X can choose to create a transaction
#! referencing the block at time 5 and still consume the note, while account Y would also be able
#! to consume the note when referencing the latest block. This is not necessarily a problem in all
#! cases, but must be taken into consideration by script developers.
#!
#! If the above is undesired, then one possible countermeasure is to set a transaction expiration
#! delta. For example, with a delta of 3, the oldest block account X could reference is the one at
#! time 8. This still allows for consumption by both accounts during a period of time, but shortens
#! that window.
#!
#! Inputs:  []
#! Outputs: [timestamp]
#!
#! Where:
#! - timestamp is the timestamp of the reference block for this transaction. The underlying value is
#!   of type u32, so u32 operations can be safely used on it.
pub proc get_block_timestamp() -> u32
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_BLOCK_TIMESTAMP_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [timestamp, pad(15)]

    # clean the stack
    swapw.3 dropw dropw dropw movdn.3 drop drop drop
    # => [timestamp]
end

#! Returns the input notes commitment hash.
#!
#! See `transaction::api::get_input_notes_commitment` for details.
#!
#! Inputs:  []
#! Outputs: [INPUT_NOTES_COMMITMENT]
#!
#! Where:
#! - INPUT_NOTES_COMMITMENT is the input notes commitment hash.
#!
#! Invocation: exec
pub proc get_input_notes_commitment() -> word
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_INPUT_NOTES_COMMITMENT_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [INPUT_NOTES_COMMITMENT, pad(12)]

    # clean the stack
    swapdw dropw dropw swapw dropw
    # => [INPUT_NOTES_COMMITMENT]
end

#! Returns the output notes commitment. This is computed as a sequential hash of
#! (note_details_commitment, note_metadata_commitment) tuples over all output notes.
#!
#! Inputs:  []
#! Outputs: [OUTPUT_NOTES_COMMITMENT]
#!
#! Where:
#! - OUTPUT_NOTES_COMMITMENT is the output notes commitment.
#!
#! Invocation: exec
pub proc get_output_notes_commitment() -> word
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_OUTPUT_NOTES_COMMITMENT_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [OUTPUT_NOTES_COMMITMENT, pad(12)]

    # clean the stack
    swapdw dropw dropw swapw dropw
    # => [OUTPUT_NOTES_COMMITMENT]
end

#! Returns the total number of input notes consumed by this transaction.
#!
#! Inputs:  []
#! Outputs: [num_input_notes]
#!
#! Where:
#! - num_input_notes is the total number of input notes consumed by this transaction.
#!
#! Invocation: exec
pub proc get_num_input_notes() -> u16
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_NUM_INPUT_NOTES_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [num_input_notes, pad(15)]

    # clean the stack
    swapw.3 dropw dropw dropw movdn.3 drop drop drop
    # => [num_input_notes]
end

#! Returns the current number of output notes created in this transaction.
#!
#! The number of output notes can changes during transaction execution. This will happen any time
#! as new output notes is created.
#!
#! Inputs:  []
#! Outputs: [num_output_notes]
#!
#! Where:
#! - num_output_notes is the number of output notes created in this transaction so far.
#!
#! Invocation: exec
pub proc get_num_output_notes() -> u16
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_NUM_OUTPUT_NOTES_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [num_output_notes, pad(15)]

    # clean the stack
    swapw.3 dropw dropw dropw movdn.3 drop drop drop
    # => [num_output_notes]
end

#! Executes the provided procedure against the foreign account.
#!
#! WARNING: the foreign account state read here reflects the transaction reference block, which is
#! chosen by the executor. The foreign account commitment is not a transaction public input
#! and is not revalidated against the foreign account's current on-chain state at inclusion, so the
#! returned values may be outdated.
#!
#! If a foreign account holds time-sensitive data, it is the responsibility of that account to set a
#! transaction expiration delta according to how time-sensitive the data is. The delta bounds how old
#! the reference block can be relative to the block the transaction is included in. For example, if an
#! oracle price is updated every 5 blocks, the oracle account should set an expiration delta of 5 (or
#! smaller): if the current block is 40 and the delta is 5, the reference block must be block 35 or
#! newer, so a value from block 20 could not be read.
#!
#! Inputs:  [foreign_account_id_suffix, foreign_account_id_prefix, FOREIGN_PROC_ROOT, foreign_procedure_inputs(16)]
#! Outputs: [foreign_procedure_outputs(16)]
#!
#! Where:
#! - foreign_account_id_{suffix,prefix} are the suffix and prefix felts of the account ID of the
#!   foreign account to execute the procedure on.
#! - foreign_procedure_inputs are the inputs to the foreign procedure padded to 16 felts.
#! - foreign_procedure_outputs are the outputs of the foreign procedure padded to 16 felts.
#!
#! Panics if:
#! - the provided foreign account ID is invalid.
#!
#! Invocation: exec
@locals(6) # foreign proc root (4) + foreign account ID (2)
pub proc execute_foreign_procedure(
    foreign_account_id: AccountId,
    foreign_proc_root: AccountProcedureRoot,
    foreign_procedure_inputs : [
        felt ; 16
    ]
) -> [felt ; 16]
    # store the foreign account ID and foreign procedure root to the local memory
    # this will allow us to get the 16th element of the foreign procedure inputs to pass it to the
    # `tx_prepare_fpi` kernel procedure
    loc_store.4 loc_store.5 loc_storew_le.0 dropw
    # OS => [foreign_procedure_inputs(16)]
    # LM => [FOREIGN_PROC_ROOT, foreign_account_id_suffix, foreign_account_id_prefix]

    # move up the last element of the foreign procedure inputs
    movup.15
    # => [foreign_proc_input_value_15, foreign_procedure_inputs(15)]

    # load the foreign account ID and foreign procedure root back to the operand stack
    padw loc_loadw_le.0 loc_load.5 loc_load.4
    # => [foreign_account_id_suffix, foreign_account_id_prefix, FOREIGN_PROC_ROOT, foreign_proc_input_value_15, foreign_procedure_inputs(15)]

    # get the tx_prepare_fpi procedure offset
    push.TX_PREPARE_FPI_OFFSET
    # => [offset, foreign_account_id_suffix, foreign_account_id_prefix, FOREIGN_PROC_ROOT, foreign_proc_input_value_15, foreign_procedure_inputs(15)]

    # pad the stack before the syscall
    padw padw swapdw
    # => [offset, foreign_account_id_suffix, foreign_account_id_prefix, FOREIGN_PROC_ROOT,
    #     foreign_proc_input_value_15, pad(8), foreign_procedure_inputs(15)]

    # store the foreign account ID, foreign procedure root, and the 16th (last) element of the
    # foreign procedure inputs to the memory
    syscall.exec_kernel_proc
    # => [pad(16), foreign_procedure_inputs(15)]

    # clean the stack
    dropw dropw dropw dropw
    # => [foreign_procedure_inputs(15)]

    # perform the FPI call
    push.TX_EXEC_FOREIGN_PROC_OFFSET syscall.exec_kernel_proc
    # => [foreign_procedure_outputs(16)]
end

#! Updates the transaction expiration delta.
#!
#! The transaction expiration delta specifies how close to the transaction's reference block the
#! transaction must be included into the chain. For example, if the transaction's reference block is
#! 100 and transaction expiration delta is 10, the transaction can be included into the chain by
#! block 110. If this does not happen, the transaction is considered expired and cannot be included
#! into the chain.
#!
#! Once set, transaction expiration delta can be decreased, but not increased.
#!
#! Inputs: [block_height_delta, ...]
#! Output: [...]
#!
#! Where:
#! - block_height_delta is the desired expiration time delta (1 to 0xFFFF).
#!
#! Annotation hint: is not used anywhere
pub proc update_expiration_block_delta(block_height_delta: u16)
    push.TX_UPDATE_EXPIRATION_BLOCK_DELTA_OFFSET
    # => [offset, expiration_delta, ...]

    # pad the stack
    push.0 movdn.2 push.0 movdn.2 padw swapw padw padw swapdw
    # => [offset, expiration_delta, pad(14)]

    syscall.exec_kernel_proc

    # clear the stack
    dropw dropw dropw dropw
end

#! Returns the transaction expiration delta, or 0 if the delta has not been set.
#!
#! Inputs: [...]
#! Output: [block_height_delta, ...]
#!
#! Where:
#! - block_height_delta is the stored expiration time delta (1 to 0xFFFF).
#!
#! Annotation hint: is not used anywhere
pub proc get_expiration_block_delta() -> u16
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_EXPIRATION_DELTA_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [expiration_delta, pad(15)]

    # clear the stack
    swapw.3 dropw dropw dropw movdn.3 drop drop drop
    # => [expiration_delta]
end

#! Returns the transaction script root, or the empty word if no transaction script was executed.
#!
#! Inputs:  []
#! Outputs: [TX_SCRIPT_ROOT]
#!
#! Where:
#! - TX_SCRIPT_ROOT is the root of the transaction script executed in this transaction, or the
#!   empty word if no transaction script was executed.
#!
#! Invocation: exec
pub proc get_tx_script_root() -> TransactionScriptRoot
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_TX_SCRIPT_ROOT_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [TX_SCRIPT_ROOT, pad(12)]

    # clean the stack
    swapdw dropw dropw swapw dropw
    # => [TX_SCRIPT_ROOT]
end

#! Computes the fee required for the current transaction.
#!
#! Inputs:  [num_extra_cycles, EXCLUDE_NOTES_COMMITMENT]
#! Outputs: [fee_amount]
#!
#! Where:
#! - num_extra_cycles is the number of cycles that should be added to the current number of cycles
#!   before computing the fee. This allows accounting for cycles that are spent after this call, e.g.
#!   for signature verification or the epilogue.
#! - EXCLUDE_NOTES_COMMITMENT is a commitment to a list of output note indices that should be
#!   excluded from the fee computation, or the empty word if no notes are excluded.
#! - fee_amount is the computed fee amount of the transaction in the fee asset.
#!
#! Invocation: exec
pub proc compute_fee(num_extra_cycles: u32, exclude_notes_commitment: word) -> felt
    push.TX_COMPUTE_FEE_OFFSET
    # => [offset, num_extra_cycles, EXCLUDE_NOTES_COMMITMENT]

    # pad the stack to 16 elements
    push.0.0 movdn.7 movdn.7 padw padw swapdw
    # => [offset, num_extra_cycles, EXCLUDE_NOTES_COMMITMENT, pad(10)]

    syscall.exec_kernel_proc
    # => [fee_amount, pad(15)]

    # truncate the stack
    movdn.15 dropw dropw dropw drop drop drop
    # => [fee_amount]
end

#! Returns the fee faucet ID of the transaction's reference block.
#!
#! Inputs:  []
#! Outputs: [fee_faucet_id_suffix, fee_faucet_id_prefix]
#!
#! Where:
#! - fee_faucet_id_{suffix,prefix} are the suffix and prefix felts of the ID of the faucet issuing
#!   the native fee asset.
#!
#! Invocation: exec
pub proc get_fee_faucet_id() -> AccountId
    # pad the stack
    padw padw padw push.0.0.0
    # => [pad(15)]

    push.TX_GET_FEE_FAUCET_ID_OFFSET
    # => [offset, pad(15)]

    syscall.exec_kernel_proc
    # => [fee_faucet_id_suffix, fee_faucet_id_prefix, pad(14)]

    # clean the stack
    swapdw dropw dropw swapw dropw movdn.3 movdn.3 drop drop
    # => [fee_faucet_id_suffix, fee_faucet_id_prefix]
end