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_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