diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ef17c4f2..5d42fd958e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## v0.16.0 (TBD) ### Changes +- [BREAKING] Moved the initial-state account getters (`get_initial_*`) from `miden::protocol::active_account` to `miden::protocol::native_account`. They now always operate on the native account and panic with `ERR_ACCOUNT_IS_NOT_NATIVE` when invoked from a foreign procedure invocation (FPI) context ([#2034](https://github.com/0xMiden/protocol/issues/2034)). - Cleaned up `signature.masm` by removing redundant scheme-id validation and duplication, dropping the `neq.0` double-negation in `assert_supported_scheme_word`, and eliminating the unused `NUM_OF_APPROVERS_LOC` slot; also optimized `verify_signatures` to reuse the signer index and approver public key from the operand stack instead of round-tripping them through local memory ([#3230](https://github.com/0xMiden/protocol/pull/3230)). - Fixed the transaction executor host honoring `AuthRequest` events emitted outside the registered auth procedure, which let untrusted note or transaction scripts force the host to sign; signature production is now restricted to the authentication procedure ([#3233](https://github.com/0xMiden/protocol/pull/3233)). - Added the `miden::protocol::tx::compute_fee` procedure, which lets account and note code compute the transaction fee during execution ([#3211](https://github.com/0xMiden/protocol/issues/3211)). diff --git a/crates/miden-protocol/asm/kernels/transaction-core/src/account.masm b/crates/miden-protocol/asm/kernels/transaction-core/src/account.masm index 7d03447145..b907be7d3c 100644 --- a/crates/miden-protocol/asm/kernels/transaction-core/src/account.masm +++ b/crates/miden-protocol/asm/kernels/transaction-core/src/account.masm @@ -217,26 +217,7 @@ end ### ACCOUNT COMMITMENT ################################################### -#! Returns the commitment of the active account at the beginning of the transaction. -#! -#! Inputs: [] -#! Outputs: [INIT_COMMITMENT] -#! -#! Where: -#! - INIT_COMMITMENT is the initial account commitment. -pub proc get_initial_commitment - # determine whether the active account is native - exec.memory::is_native_account - # => [is_native_account] - - if.true - exec.memory::get_init_account_commitment - else - # for the foreign account current commitment equals to initial - exec.compute_commitment - end - # => [INIT_COMMITMENT] -end +pub use {get_init_account_commitment as get_initial_commitment} from miden::tx_kernel_core::memory #! Computes commitment to the state of the active account. #! @@ -282,32 +263,7 @@ pub use {get_account_code_commitment as get_code_commitment} from miden::tx_kern ### STORAGE COMMITMENT ################################################### -#! Returns the storage commitment of the active account at the beginning of the transaction. -#! -#! Inputs: [] -#! Outputs: [INIT_ACCOUNT_STORAGE_COMMITMENT] -#! -#! Where: -#! - INIT_ACCOUNT_STORAGE_COMMITMENT is the initial account storage commitment. -pub proc get_initial_storage_commitment - # Get the storage commitment of the active account. For the foreign account this commitment will - # be initial. - exec.memory::get_account_storage_commitment - # => [ACTIVE_ACCOUNT_STORAGE_COMMITMENT] - - # get the initial storage commitment of the native account - exec.memory::get_init_account_storage_commitment - # => [INIT_NATIVE_ACCOUNT_STORAGE_COMMITMENT, ACTIVE_ACCOUNT_STORAGE_COMMITMENT] - - # check whether the active account is native - exec.memory::is_native_account - # => [is_native_account, INIT_NATIVE_ACCOUNT_STORAGE_COMMITMENT, ACTIVE_ACCOUNT_STORAGE_COMMITMENT] - - # if the active account is native, keep the INIT_NATIVE_ACCOUNT_STORAGE_COMMITMENT, or - # ACTIVE_ACCOUNT_STORAGE_COMMITMENT otherwise - cdropw - # => [INIT_ACCOUNT_STORAGE_COMMITMENT] -end +pub use {get_init_account_storage_commitment as get_initial_storage_commitment} from miden::tx_kernel_core::memory #! Computes the storage commitment of the active account. #! @@ -327,32 +283,7 @@ end ### VAULT ROOT ########################################################### -#! Returns the vault root of the active account at the beginning of the transaction. -#! -#! Inputs: [] -#! Outputs: [INIT_ACCOUNT_VAULT_ROOT] -#! -#! Where: -#! - INIT_ACCOUNT_VAULT_ROOT is the initial account vault root. -pub proc get_initial_vault_root - # Get the vault root of the active account. For the foreign account this root will be equal to - # the initial one. - exec.memory::get_account_vault_root - # => [ACTIVE_ACCOUNT_VAULT_ROOT] - - # get the initial vault root of the native account - exec.memory::get_init_native_account_vault_root - # => [INIT_NATIVE_ACCOUNT_VAULT_ROOT, ACTIVE_ACCOUNT_VAULT_ROOT] - - # check whether the active account is native - exec.memory::is_native_account - # => [is_native_account, INIT_NATIVE_ACCOUNT_VAULT_ROOT, ACTIVE_ACCOUNT_VAULT_ROOT] - - # if the active account is native, keep the INIT_NATIVE_ACCOUNT_VAULT_ROOT, or - # ACTIVE_ACCOUNT_VAULT_ROOT otherwise - cdropw - # => [INIT_ACCOUNT_VAULT_ROOT] -end +pub use {get_init_native_account_vault_root as get_initial_vault_root} from miden::tx_kernel_core::memory # STORAGE # ------------------------------------------------------------------------------------------------- @@ -471,7 +402,7 @@ pub proc get_typed_item # => [VALUE, slot_type] end -#! Gets an item from the account storage at its initial state (beginning of transaction). +#! Gets an item from the native account storage at its initial state (beginning of transaction). #! #! Inputs: [slot_id_suffix, slot_id_prefix] #! Outputs: [INIT_VALUE] @@ -484,9 +415,9 @@ end #! Panics if: #! - a slot with the provided slot ID does not exist in account storage. pub proc get_initial_item - # get account initial storage slots section offset - exec.memory::get_account_initial_storage_slots_ptr - # => [account_initial_storage_slots_ptr, slot_id_suffix, slot_id_prefix] + # get native account initial storage slots section offset + exec.memory::get_native_account_initial_storage_slots_ptr + # => [native_account_initial_storage_slots_ptr, slot_id_suffix, slot_id_prefix] exec.get_storage_slot_ptr # => [slot_ptr] @@ -569,7 +500,7 @@ pub proc get_map_item end #! Returns the VALUE located under the specified KEY within the map contained in the given -#! account storage slot at its initial state (beginning of transaction). +#! native account storage slot at its initial state (beginning of transaction). #! #! Inputs: [slot_id_suffix, slot_id_prefix, KEY] #! Outputs: [INIT_VALUE] @@ -583,8 +514,8 @@ end #! - a slot with the provided slot ID does not exist in account storage. #! - the requested storage slot type is not map. pub proc get_initial_map_item - exec.memory::get_account_initial_storage_slots_ptr - # => [initial_storage_slots_ptr, slot_id_suffix, slot_id_prefix, KEY] + exec.memory::get_native_account_initial_storage_slots_ptr + # => [native_initial_storage_slots_ptr, slot_id_suffix, slot_id_prefix, KEY] exec.get_map_item_raw end @@ -773,7 +704,7 @@ pub proc get_asset # => [ASSET_VALUE] end -#! Returns the ASSET_VALUE associated with the provided asset ID in the active account's vault at +#! Returns the ASSET_VALUE associated with the provided asset ID in the native account's vault at #! the beginning of the transaction. #! #! Inputs: [ASSET_ID] @@ -783,8 +714,8 @@ end #! - ASSET_ID is the asset ID of the asset to fetch. #! - ASSET_VALUE is the value of the asset from the vault, which can be the EMPTY_WORD if it isn't present. pub proc get_initial_asset - # get the vault root associated with the initial vault root of the native account - exec.memory::get_account_initial_vault_root_ptr movdn.4 + # get the initial vault root ptr of the native account + exec.memory::get_init_native_account_vault_root_ptr movdn.4 # => [ASSET_ID, init_native_vault_root_ptr] # emit event to signal that an asset is requested @@ -1444,8 +1375,8 @@ pub proc get_item_patch movup.2 exec.get_item_raw # => [CURRENT_VALUE, slot_id_suffix, slot_id_prefix, offset] - # get account initial storage slots section offset - exec.memory::get_account_initial_storage_slots_ptr + # get native account initial storage slots section offset + exec.memory::get_native_account_initial_storage_slots_ptr # => [init_storage_slots_ptr, CURRENT_VALUE, slot_id_suffix, slot_id_prefix, offset] movup.7 add diff --git a/crates/miden-protocol/asm/kernels/transaction-core/src/memory.masm b/crates/miden-protocol/asm/kernels/transaction-core/src/memory.masm index 6bc40076c6..ca25344b59 100644 --- a/crates/miden-protocol/asm/kernels/transaction-core/src/memory.masm +++ b/crates/miden-protocol/asm/kernels/transaction-core/src/memory.masm @@ -1109,36 +1109,6 @@ pub proc set_account_vault_root mem_storew_le end -#! Returns the memory pointer to the initial vault root of the active account. -#! -#! For the native account, this returns the pointer to the initial vault root. -#! For foreign accounts, this returns the regular vault root pointer since foreign accounts -#! are read-only and their initial and current vault state always matches. -#! -#! Inputs: [] -#! Outputs: [account_initial_vault_root_ptr] -#! -#! Where: -#! - account_initial_vault_root_ptr is the memory pointer to the initial vault root. -pub proc get_account_initial_vault_root_ptr - # for foreign account, use the regular vault root pointer since foreign accounts are read-only - # and initial == current - exec.get_account_vault_root_ptr - # => [account_vault_root_ptr] - - # for native account, use the initial vault root pointer - exec.get_init_native_account_vault_root_ptr - # => [native_account_initial_vault_root_ptr, account_vault_root_ptr] - - # get the flag indicating whether the active account is native - exec.is_native_account - # => [is_native_account, native_account_initial_vault_root_ptr, account_vault_root_ptr] - - # according to the is_native_account flag, return the corresponding pointer - cdrop - # => [account_initial_vault_root_ptr] -end - ### ACCOUNT CODE ################################################# #! Returns the code commitment of the account. @@ -1380,36 +1350,6 @@ pub proc get_native_account_initial_storage_slots_ptr push.NATIVE_ACCOUNT_DATA_PTR add.ACCT_INITIAL_STORAGE_SLOTS_SECTION_OFFSET end -#! Returns the memory pointer to the initial storage slots of the active account. -#! -#! For the native account, this returns the pointer to the initial storage slots section. -#! For foreign accounts, this returns the regular storage slots pointer since foreign accounts -#! are read-only and their initial and current storage state always matches. -#! -#! Inputs: [] -#! Outputs: [account_initial_storage_slots_ptr] -#! -#! Where: -#! - account_initial_storage_slots_ptr is the memory pointer to the initial storage slot values. -pub proc get_account_initial_storage_slots_ptr - # for foreign account, use the regular storage slots pointer since foreign accounts are - # read-only and initial == current - exec.get_account_active_storage_slots_section_ptr - # => [account_storage_slots_ptr] - - # for native account, use the initial storage slots pointer - exec.get_native_account_initial_storage_slots_ptr - # => [native_account_initial_storage_slots_ptr, account_storage_slots_ptr] - - # get the flag indicating whether the active account is native - exec.is_native_account - # => [is_native_account, native_account_initial_storage_slots_ptr, account_storage_slots_ptr] - - # according to the is_native_account flag, return the corresponding pointer - cdrop - # => [account_initial_storage_slots_ptr] -end - ### ACCOUNT DELTA ################################################# #! Returns the link map pointer to the storage map patch of the storage map in the given slot index. diff --git a/crates/miden-protocol/asm/kernels/transaction/lib/api.masm b/crates/miden-protocol/asm/kernels/transaction/lib/api.masm index e8d6f8f96d..a0cba3d87a 100644 --- a/crates/miden-protocol/asm/kernels/transaction/lib/api.masm +++ b/crates/miden-protocol/asm/kernels/transaction/lib/api.masm @@ -98,7 +98,7 @@ end # ACCOUNT # ------------------------------------------------------------------------------------------------- -#! Returns the active account commitment at the beginning of the transaction. +#! Returns the native account commitment at the beginning of the transaction. #! #! Inputs: [pad(16)] #! Outputs: [INIT_COMMITMENT, pad(12)] @@ -106,8 +106,15 @@ end #! Where: #! - INIT_COMMITMENT is the initial account commitment. #! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! #! Invocation: dynexec pub proc account_get_initial_commitment + # check that this procedure was executed against the native account + exec.memory::assert_native_account + # => [pad(16)] + # get the initial account commitment exec.account::get_initial_commitment # => [INIT_COMMITMENT, pad(16)] @@ -292,7 +299,7 @@ pub proc account_get_code_commitment # => [CODE_COMMITMENT, pad(12)] end -#! Returns the storage commitment of the active account at the beginning of the transaction. +#! Returns the storage commitment of the native account at the beginning of the transaction. #! #! Inputs: [pad(16)] #! Outputs: [INIT_STORAGE_COMMITMENT, pad(12)] @@ -300,8 +307,15 @@ end #! Where: #! - INIT_STORAGE_COMMITMENT is the initial account storage commitment. #! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! #! Invocation: dynexec pub proc account_get_initial_storage_commitment + # check that this procedure was executed against the native account + exec.memory::assert_native_account + # => [pad(16)] + # get the initial account storage commitment exec.account::get_initial_storage_commitment # => [INIT_STORAGE_COMMITMENT, pad(16)] @@ -418,7 +432,7 @@ pub proc account_get_map_item # => [VALUE, pad(12)] end -#! Gets an item from the account storage at its initial state (beginning of transaction). +#! Gets an item from the native account storage at its initial state (beginning of transaction). #! #! Inputs: [slot_id_suffix, slot_id_prefix, pad(14)] #! Outputs: [INIT_VALUE, pad(12)] @@ -430,9 +444,14 @@ end #! #! Panics if: #! - a slot with the provided slot ID does not exist in account storage. +#! - the invocation of this procedure does not originate from the native account. #! #! Invocation: dynexec pub proc account_get_initial_item + # check that this procedure was executed against the native account + exec.memory::assert_native_account + # => [slot_id_suffix, slot_id_prefix, pad(14)] + # authenticate that the procedure invocation originates from the account context exec.authenticate_account_origin # => [slot_id_suffix, slot_id_prefix, pad(14)] @@ -447,7 +466,7 @@ pub proc account_get_initial_item end #! Returns the initial VALUE located under the specified KEY within the map contained in the -#! account storage slot identified by the slot ID at the beginning of the transaction. +#! native account storage slot identified by the slot ID at the beginning of the transaction. #! #! Inputs: [slot_id_suffix, slot_id_prefix, KEY, pad(10)] #! Outputs: [INIT_VALUE, pad(12)] @@ -461,9 +480,14 @@ end #! Panics if: #! - a slot with the provided slot ID does not exist in account storage. #! - the requested storage slot type is not map. +#! - the invocation of this procedure does not originate from the native account. #! #! Invocation: dynexec pub proc account_get_initial_map_item + # check that this procedure was executed against the native account + exec.memory::assert_native_account + # => [slot_id_suffix, slot_id_prefix, KEY, pad(10)] + # authenticate that the procedure invocation originates from the account context exec.authenticate_account_origin # => [slot_id_suffix, slot_id_prefix, KEY, pad(10)] @@ -512,7 +536,7 @@ pub proc account_set_map_item # => [OLD_VALUE, pad(12)] end -#! Returns the vault root of the active account at the beginning of the transaction. +#! Returns the vault root of the native account at the beginning of the transaction. #! #! Inputs: [pad(16)] #! Outputs: [INIT_VAULT_ROOT, pad(12)] @@ -520,8 +544,15 @@ end #! Where: #! - INIT_VAULT_ROOT is the initial account vault root. #! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! #! Invocation: dynexec pub proc account_get_initial_vault_root + # check that this procedure was executed against the native account + exec.memory::assert_native_account + # => [pad(16)] + # get the initial account vault root exec.account::get_initial_vault_root # => [INIT_VAULT_ROOT, pad(16)] @@ -635,7 +666,7 @@ pub proc account_get_asset # => [ASSET_VALUE, pad(12)] end -#! Returns the asset associated with the provided asset ID in the active account's vault at +#! Returns the asset associated with the provided asset ID in the native account's vault at #! the beginning of the transaction. #! #! Inputs: [ASSET_ID, pad(12)] @@ -645,8 +676,15 @@ end #! - ASSET_ID is the asset ID of the asset to fetch. #! - ASSET_VALUE is the value of the asset from the vault, which can be the EMPTY_WORD if it isn't present. #! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! #! Invocation: dynexec pub proc account_get_initial_asset + # check that this procedure was executed against the native account + exec.memory::assert_native_account + # => [ASSET_ID, pad(12)] + exec.asset::validate_id # => [ASSET_ID, pad(12)] @@ -665,6 +703,7 @@ end #! #! Panics if: #! - the procedure root is not part of the account code. +#! - the invocation of this procedure does not originate from the native account. #! #! Invocation: dynexec pub proc account_was_procedure_called diff --git a/crates/miden-protocol/asm/protocol/src/active_account.masm b/crates/miden-protocol/asm/protocol/src/active_account.masm index 549aa2fca5..d923667c88 100644 --- a/crates/miden-protocol/asm/protocol/src/active_account.masm +++ b/crates/miden-protocol/asm/protocol/src/active_account.masm @@ -3,20 +3,14 @@ use {COMPOSITION_FUNGIBLE, COMPOSITION_NONE} from miden::protocol::asset use { ACCOUNT_GET_ID_OFFSET, ACCOUNT_GET_NONCE_OFFSET, - ACCOUNT_GET_INITIAL_COMMITMENT_OFFSET, ACCOUNT_COMPUTE_COMMITMENT_OFFSET, ACCOUNT_GET_CODE_COMMITMENT_OFFSET, - ACCOUNT_GET_INITIAL_STORAGE_COMMITMENT_OFFSET, ACCOUNT_COMPUTE_STORAGE_COMMITMENT_OFFSET, - ACCOUNT_GET_INITIAL_VAULT_ROOT_OFFSET, ACCOUNT_GET_VAULT_ROOT_OFFSET, ACCOUNT_GET_ITEM_OFFSET, ACCOUNT_HAS_STORAGE_SLOT_OFFSET, - ACCOUNT_GET_INITIAL_ITEM_OFFSET, ACCOUNT_GET_MAP_ITEM_OFFSET, - ACCOUNT_GET_INITIAL_MAP_ITEM_OFFSET, ACCOUNT_GET_ASSET_OFFSET, - ACCOUNT_GET_INITIAL_ASSET_OFFSET, ACCOUNT_GET_NUM_PROCEDURES_OFFSET, ACCOUNT_GET_PROCEDURE_ROOT_OFFSET, ACCOUNT_HAS_PROCEDURE_OFFSET, @@ -97,31 +91,6 @@ end # COMMITMENTS # ------------------------------------------------------------------------------------------------- -#! Returns the commitment of the active account at the beginning of the transaction. -#! -#! Inputs: [] -#! Outputs: [INIT_COMMITMENT] -#! -#! Where: -#! - INIT_COMMITMENT is the initial account commitment. -#! -#! Invocation: exec -pub proc get_initial_commitment - # pad the stack - padw padw padw push.0.0.0 - # => [pad(15)] - - push.ACCOUNT_GET_INITIAL_COMMITMENT_OFFSET - # => [offset, pad(15)] - - syscall.exec_kernel_proc - # => [INIT_COMMITMENT, pad(12)] - - # clean the stack - swapdw dropw dropw swapw dropw - # => [INIT_COMMITMENT] -end - #! Computes and returns commitment to the state of the active account. #! #! Inputs: [] @@ -185,36 +154,6 @@ pub proc get_code_commitment # => [CODE_COMMITMENT] end -#! Returns the storage commitment of the active account at the beginning of the transaction. -#! -#! During an account-creating transaction (when the initial nonce is 0), this procedure and -#! compute_storage_commitment will return the same value at the beginning of the transaction -#! (before any note or transaction scripts were executed). Despite that, the account delta may -#! not be empty. See account::compute_delta_commitment for more. -#! -#! Inputs: [] -#! Outputs: [INIT_STORAGE_COMMITMENT] -#! -#! Where: -#! - INIT_STORAGE_COMMITMENT is the initial account storage commitment. -#! -#! Invocation: exec -pub proc get_initial_storage_commitment - # pad the stack - padw padw padw push.0.0.0 - # => [pad(15)] - - push.ACCOUNT_GET_INITIAL_STORAGE_COMMITMENT_OFFSET - # => [offset, pad(15)] - - syscall.exec_kernel_proc - # => [INIT_STORAGE_COMMITMENT, pad(12)] - - # clean the stack - swapdw dropw dropw swapw dropw - # => [INIT_STORAGE_COMMITMENT] -end - #! Computes the latest storage commitment of the active account. #! #! Notice that this procedure always returns the latest commitment, but it doesn't actually always @@ -249,31 +188,6 @@ pub proc compute_storage_commitment # => [STORAGE_COMMITMENT] end -#! Returns the vault root of the active account at the beginning of the transaction. -#! -#! Inputs: [] -#! Outputs: [INIT_VAULT_ROOT] -#! -#! Where: -#! - INIT_VAULT_ROOT is the initial account vault root. -#! -#! Invocation: exec -pub proc get_initial_vault_root - # pad the stack - padw padw padw push.0.0.0 - # => [pad(15)] - - push.ACCOUNT_GET_INITIAL_VAULT_ROOT_OFFSET - # => [offset, pad(15)] - - syscall.exec_kernel_proc - # => [INIT_VAULT_ROOT, pad(12)] - - # clean the stack - swapdw dropw dropw swapw dropw - # => [INIT_VAULT_ROOT] -end - #! Returns the vault root of the active account. #! #! Inputs: [] @@ -368,40 +282,6 @@ pub proc has_storage_slot # => [has_slot] end -#! Gets the initial item from the active account storage slot as it was at the beginning of the -#! transaction. -#! -#! Inputs: [slot_id_suffix, slot_id_prefix] -#! Outputs: [INIT_VALUE] -#! -#! Where: -#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are -#! the first two felts of the hashed slot name. -#! - INIT_VALUE is the initial value of the item at the beginning of the transaction. -#! -#! Panics if: -#! - a slot with the provided slot ID does not exist in account storage. -#! -#! Invocation: exec -pub proc get_initial_item - push.0 movdn.2 - # => [slot_id_suffix, slot_id_prefix, 0] - - push.ACCOUNT_GET_INITIAL_ITEM_OFFSET - # => [offset, slot_id_suffix, slot_id_prefix, 0] - - # pad the stack - padw swapw padw padw swapdw - # => [offset, slot_id_suffix, slot_id_prefix, pad(13)] - - syscall.exec_kernel_proc - # => [INIT_VALUE, pad(12)] - - # clean the stack - swapdw dropw dropw swapw dropw - # => [INIT_VALUE] -end - #! Gets a map item from the active account storage. #! #! Inputs: [slot_id_suffix, slot_id_prefix, KEY] @@ -435,38 +315,6 @@ pub proc get_map_item # => [VALUE] end -#! Gets the initial VALUE from the active account storage map as it was at the beginning of the -#! transaction. -#! -#! Inputs: [slot_id_suffix, slot_id_prefix, KEY] -#! Outputs: [INIT_VALUE] -#! -#! Where: -#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are -#! the first two felts of the hashed slot name. -#! - KEY is the key of the item to get. -#! - INIT_VALUE is the initial value of the item at the beginning of the transaction. -#! -#! Panics if: -#! - a slot with the provided slot ID does not exist in account storage. -#! - the slot item at index is not a map. -#! -#! Invocation: exec -pub proc get_initial_map_item - push.ACCOUNT_GET_INITIAL_MAP_ITEM_OFFSET - # => [offset, slot_id_suffix, slot_id_prefix, KEY] - - push.0 movdn.7 padw padw swapdw - # => [offset, slot_id_suffix, slot_id_prefix, KEY, pad(9)] - - syscall.exec_kernel_proc - # => [INIT_VALUE, pad(12)] - - # clean the stack - swapdw dropw dropw swapw dropw - # => [INIT_VALUE] -end - # VAULT # ------------------------------------------------------------------------------------------------- @@ -498,35 +346,6 @@ pub proc get_asset # => [ASSET_VALUE] end -#! Returns the asset associated with the provided asset ID in the active account's vault at -#! the beginning of the transaction. -#! -#! Inputs: [ASSET_ID] -#! Outputs: [ASSET_VALUE] -#! -#! Where: -#! - ASSET_ID is the asset ID of the asset to fetch. -#! - ASSET_VALUE is the value of the asset from the vault, which can be the EMPTY_WORD if it isn't -#! present. -#! -#! Invocation: exec -pub proc get_initial_asset - push.ACCOUNT_GET_INITIAL_ASSET_OFFSET - # => [offset, ASSET_ID] - - # pad the stack - push.0 movdn.5 push.0 movdn.5 push.0 movdn.5 - padw padw swapdw - # => [offset, ASSET_ID, pad(11)] - - syscall.exec_kernel_proc - # => [ASSET_VALUE, pad(12)] - - # clean the stack - swapdw dropw dropw swapw dropw - # => [ASSET_VALUE] -end - #! Returns the balance of the fungible asset associated with the provided asset ID in the #! active account's vault. #! @@ -556,35 +375,6 @@ pub proc get_balance # => [balance] end -#! Returns the balance of the fungible asset associated with the provided asset ID in the -#! active account's vault at the beginning of the transaction. -#! -#! Inputs: [ASSET_ID] -#! Outputs: [init_balance] -#! -#! Where: -#! - ASSET_ID is the asset ID of the fungible asset of interest. -#! - init_balance is the vault balance of the fungible asset at the beginning of the transaction. -#! -#! Panics if: -#! - the asset composition encoded in ASSET_ID is not fungible. -#! -#! Invocation: exec -pub proc get_initial_balance - # assert that the asset composition is fungible - exec.asset::id_to_composition - push.COMPOSITION_FUNGIBLE - assert_eq.err=ERR_VAULT_GET_BALANCE_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_ASSET - # => [ASSET_ID] - - exec.get_initial_asset - # => [ASSET_VALUE] - - # extract the asset's balance - exec.asset::fungible_value_into_amount - # => [balance] -end - #! Returns a boolean indicating whether the active account stores an asset with the provided #! non-fungible asset ID in its vault. #! diff --git a/crates/miden-protocol/asm/protocol/src/native_account.masm b/crates/miden-protocol/asm/protocol/src/native_account.masm index 5d23f8f8d6..aaf340289e 100644 --- a/crates/miden-protocol/asm/protocol/src/native_account.masm +++ b/crates/miden-protocol/asm/protocol/src/native_account.masm @@ -1,7 +1,15 @@ +use miden::protocol::asset +use {COMPOSITION_FUNGIBLE} from miden::protocol::asset use { ACCOUNT_ADD_ASSET_OFFSET, ACCOUNT_COMPUTE_DELTA_COMMITMENT_OFFSET, ACCOUNT_GET_ID_OFFSET, + ACCOUNT_GET_INITIAL_ASSET_OFFSET, + ACCOUNT_GET_INITIAL_COMMITMENT_OFFSET, + ACCOUNT_GET_INITIAL_ITEM_OFFSET, + ACCOUNT_GET_INITIAL_MAP_ITEM_OFFSET, + ACCOUNT_GET_INITIAL_STORAGE_COMMITMENT_OFFSET, + ACCOUNT_GET_INITIAL_VAULT_ROOT_OFFSET, ACCOUNT_INCR_NONCE_OFFSET, ACCOUNT_REMOVE_ASSET_OFFSET, ACCOUNT_SET_ITEM_OFFSET, @@ -12,6 +20,11 @@ use { # NATIVE ACCOUNT PROCEDURES # ================================================================================================= +# ERRORS +# ------------------------------------------------------------------------------------------------- + +const ERR_VAULT_GET_BALANCE_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_ASSET="get_balance can only be called on a fungible asset" + # ID AND NONCE # ------------------------------------------------------------------------------------------------- @@ -118,6 +131,95 @@ pub proc compute_delta_commitment # => [DELTA_COMMITMENT] end +#! Returns the commitment of the native account at the beginning of the transaction. +#! +#! Inputs: [] +#! Outputs: [INIT_COMMITMENT] +#! +#! Where: +#! - INIT_COMMITMENT is the initial account commitment. +#! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! +#! Invocation: exec +pub proc get_initial_commitment + # pad the stack + padw padw padw push.0.0.0 + # => [pad(15)] + + push.ACCOUNT_GET_INITIAL_COMMITMENT_OFFSET + # => [offset, pad(15)] + + syscall.exec_kernel_proc + # => [INIT_COMMITMENT, pad(12)] + + # clean the stack + swapdw dropw dropw swapw dropw + # => [INIT_COMMITMENT] +end + +#! Returns the storage commitment of the native account at the beginning of the transaction. +#! +#! During an account-creating transaction (when the initial nonce is 0), this procedure and +#! active_account::compute_storage_commitment will return the same value at the beginning of the +#! transaction (before any note or transaction scripts were executed). Despite that, the account +#! delta may not be empty. See compute_delta_commitment for more. +#! +#! Inputs: [] +#! Outputs: [INIT_STORAGE_COMMITMENT] +#! +#! Where: +#! - INIT_STORAGE_COMMITMENT is the initial account storage commitment. +#! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! +#! Invocation: exec +pub proc get_initial_storage_commitment + # pad the stack + padw padw padw push.0.0.0 + # => [pad(15)] + + push.ACCOUNT_GET_INITIAL_STORAGE_COMMITMENT_OFFSET + # => [offset, pad(15)] + + syscall.exec_kernel_proc + # => [INIT_STORAGE_COMMITMENT, pad(12)] + + # clean the stack + swapdw dropw dropw swapw dropw + # => [INIT_STORAGE_COMMITMENT] +end + +#! Returns the vault root of the native account at the beginning of the transaction. +#! +#! Inputs: [] +#! Outputs: [INIT_VAULT_ROOT] +#! +#! Where: +#! - INIT_VAULT_ROOT is the initial account vault root. +#! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! +#! Invocation: exec +pub proc get_initial_vault_root + # pad the stack + padw padw padw push.0.0.0 + # => [pad(15)] + + push.ACCOUNT_GET_INITIAL_VAULT_ROOT_OFFSET + # => [offset, pad(15)] + + syscall.exec_kernel_proc + # => [INIT_VAULT_ROOT, pad(12)] + + # clean the stack + swapdw dropw dropw swapw dropw + # => [INIT_VAULT_ROOT] +end + # STORAGE # ------------------------------------------------------------------------------------------------- @@ -195,6 +297,74 @@ pub proc set_map_item # => [OLD_VALUE] end +#! Gets the initial item from the native account storage slot as it was at the beginning of the +#! transaction. +#! +#! Inputs: [slot_id_suffix, slot_id_prefix] +#! Outputs: [INIT_VALUE] +#! +#! Where: +#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are +#! the first two felts of the hashed slot name. +#! - INIT_VALUE is the initial value of the item at the beginning of the transaction. +#! +#! Panics if: +#! - a slot with the provided slot ID does not exist in account storage. +#! - the invocation of this procedure does not originate from the native account. +#! +#! Invocation: exec +pub proc get_initial_item + push.0 movdn.2 + # => [slot_id_suffix, slot_id_prefix, 0] + + push.ACCOUNT_GET_INITIAL_ITEM_OFFSET + # => [offset, slot_id_suffix, slot_id_prefix, 0] + + # pad the stack + padw swapw padw padw swapdw + # => [offset, slot_id_suffix, slot_id_prefix, pad(13)] + + syscall.exec_kernel_proc + # => [INIT_VALUE, pad(12)] + + # clean the stack + swapdw dropw dropw swapw dropw + # => [INIT_VALUE] +end + +#! Gets the initial VALUE from the native account storage map as it was at the beginning of the +#! transaction. +#! +#! Inputs: [slot_id_suffix, slot_id_prefix, KEY] +#! Outputs: [INIT_VALUE] +#! +#! Where: +#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are +#! the first two felts of the hashed slot name. +#! - KEY is the key of the item to get. +#! - INIT_VALUE is the initial value of the item at the beginning of the transaction. +#! +#! Panics if: +#! - a slot with the provided slot ID does not exist in account storage. +#! - the slot item at index is not a map. +#! - the invocation of this procedure does not originate from the native account. +#! +#! Invocation: exec +pub proc get_initial_map_item + push.ACCOUNT_GET_INITIAL_MAP_ITEM_OFFSET + # => [offset, slot_id_suffix, slot_id_prefix, KEY] + + push.0 movdn.7 padw padw swapdw + # => [offset, slot_id_suffix, slot_id_prefix, KEY, pad(9)] + + syscall.exec_kernel_proc + # => [INIT_VALUE, pad(12)] + + # clean the stack + swapdw dropw dropw swapw dropw + # => [INIT_VALUE] +end + # VAULT # ------------------------------------------------------------------------------------------------- @@ -266,6 +436,68 @@ pub proc remove_asset # => [FINAL_ASSET_VALUE] end +#! Returns the asset associated with the provided asset ID in the native account's vault at +#! the beginning of the transaction. +#! +#! Inputs: [ASSET_ID] +#! Outputs: [ASSET_VALUE] +#! +#! Where: +#! - ASSET_ID is the asset ID of the asset to fetch. +#! - ASSET_VALUE is the value of the asset from the vault, which can be the EMPTY_WORD if it isn't +#! present. +#! +#! Panics if: +#! - the invocation of this procedure does not originate from the native account. +#! +#! Invocation: exec +pub proc get_initial_asset + push.ACCOUNT_GET_INITIAL_ASSET_OFFSET + # => [offset, ASSET_ID] + + # pad the stack + push.0 movdn.5 push.0 movdn.5 push.0 movdn.5 + padw padw swapdw + # => [offset, ASSET_ID, pad(11)] + + syscall.exec_kernel_proc + # => [ASSET_VALUE, pad(12)] + + # clean the stack + swapdw dropw dropw swapw dropw + # => [ASSET_VALUE] +end + +#! Returns the balance of the fungible asset associated with the provided asset ID in the +#! native account's vault at the beginning of the transaction. +#! +#! Inputs: [ASSET_ID] +#! Outputs: [init_balance] +#! +#! Where: +#! - ASSET_ID is the asset ID of the fungible asset of interest. +#! - init_balance is the vault balance of the fungible asset at the beginning of the transaction. +#! +#! Panics if: +#! - the asset composition encoded in ASSET_ID is not fungible. +#! - the invocation of this procedure does not originate from the native account. +#! +#! Invocation: exec +pub proc get_initial_balance + # assert that the asset composition is fungible + exec.asset::id_to_composition + push.COMPOSITION_FUNGIBLE + assert_eq.err=ERR_VAULT_GET_BALANCE_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_ASSET + # => [ASSET_ID] + + exec.get_initial_asset + # => [ASSET_VALUE] + + # extract the asset's balance + exec.asset::fungible_value_into_amount + # => [balance] +end + # CODE # ------------------------------------------------------------------------------------------------- diff --git a/crates/miden-standards/asm/components/auth/network_account/network_account.masm b/crates/miden-standards/asm/components/auth/network_account/network_account.masm index 4bdcdae78b..25ce172e9c 100644 --- a/crates/miden-standards/asm/components/auth/network_account/network_account.masm +++ b/crates/miden-standards/asm/components/auth/network_account/network_account.masm @@ -57,7 +57,7 @@ pub proc auth_network_transaction(auth_args: word) # => [pad(16)] # ---- Increment nonce iff the account state changed or the account is new ---- - exec.active_account::get_initial_commitment + exec.native_account::get_initial_commitment # => [INITIAL_COMMITMENT, pad(16)] exec.active_account::compute_commitment diff --git a/crates/miden-standards/asm/components/auth/no_auth/no_auth.masm b/crates/miden-standards/asm/components/auth/no_auth/no_auth.masm index f5c6bd6681..c1bf3ae372 100644 --- a/crates/miden-standards/asm/components/auth/no_auth/no_auth.masm +++ b/crates/miden-standards/asm/components/auth/no_auth/no_auth.masm @@ -18,7 +18,7 @@ use miden::core::word pub proc auth_no_auth # check if the account state has changed by comparing initial and final commitments - exec.active_account::get_initial_commitment + exec.native_account::get_initial_commitment # => [INITIAL_COMMITMENT, pad(16)] exec.active_account::compute_commitment diff --git a/crates/miden-standards/asm/components/auth/singlesig/singlesig.masm b/crates/miden-standards/asm/components/auth/singlesig/singlesig.masm index 774ab6accc..f9f0cdbffb 100644 --- a/crates/miden-standards/asm/components/auth/singlesig/singlesig.masm +++ b/crates/miden-standards/asm/components/auth/singlesig/singlesig.masm @@ -3,7 +3,7 @@ # See the `AuthBasicSignature` Rust type's documentation for more details. use miden::standards::auth::signature -use miden::protocol::active_account +use miden::protocol::native_account # CONSTANTS # ================================================================================================= @@ -41,10 +41,10 @@ pub proc auth_tx(auth_args: word) # Fetch public key from storage. # --------------------------------------------------------------------------------------------- - push.PUBLIC_KEY_SLOT[0..2] exec.active_account::get_initial_item + push.PUBLIC_KEY_SLOT[0..2] exec.native_account::get_initial_item # => [PK_COMM, pad(16)] - push.SCHEME_ID_SLOT[0..2] exec.active_account::get_initial_item + push.SCHEME_ID_SLOT[0..2] exec.native_account::get_initial_item # => [scheme_id, 0, 0, 0, PK_COMM, pad(16)] movdn.7 drop drop drop diff --git a/crates/miden-standards/asm/components/auth/singlesig_acl/singlesig_acl.masm b/crates/miden-standards/asm/components/auth/singlesig_acl/singlesig_acl.masm index 87e97fb033..787f8c9c7e 100644 --- a/crates/miden-standards/asm/components/auth/singlesig_acl/singlesig_acl.masm +++ b/crates/miden-standards/asm/components/auth/singlesig_acl/singlesig_acl.masm @@ -75,7 +75,7 @@ pub proc auth_tx_acl(auth_args: word) push.EXEMPT_PROCEDURE_ROOTS_SLOT[0..2] # => [slot_suffix, slot_prefix, PROC_ROOT, i, auth_required, pad(16)] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [[is_exempt, 0, 0, 0], i, auth_required, pad(16)] movdn.3 drop drop drop @@ -107,11 +107,11 @@ pub proc auth_tx_acl(auth_args: word) # If authentication is required, perform signature verification if.true # Fetch public key from storage. - push.PUBLIC_KEY_SLOT[0..2] exec.active_account::get_initial_item + push.PUBLIC_KEY_SLOT[0..2] exec.native_account::get_initial_item # => [PK_COMM, pad(16)] # Fetch scheme_id from storage - push.SCHEME_ID_SLOT[0..2] exec.active_account::get_initial_item + push.SCHEME_ID_SLOT[0..2] exec.native_account::get_initial_item # => [[scheme_id, 0, 0, 0], PK_COMM, pad(16)] movdn.7 drop drop drop @@ -121,7 +121,7 @@ pub proc auth_tx_acl(auth_args: word) else # ------ Check if initial account commitment differs from current commitment ------ - exec.active_account::get_initial_commitment + exec.native_account::get_initial_commitment # => [INITIAL_COMMITMENT, pad(16)] exec.active_account::compute_commitment diff --git a/crates/miden-standards/asm/standards/auth/multisig.masm b/crates/miden-standards/asm/standards/auth/multisig.masm index 705f7754dc..d8fc49b371 100644 --- a/crates/miden-standards/asm/standards/auth/multisig.masm +++ b/crates/miden-standards/asm/standards/auth/multisig.masm @@ -449,7 +449,7 @@ proc compute_transaction_threshold(default_threshold: u32) -> u32 # 2b. get the override proc_threshold of that procedure # if the procedure has no override threshold, the returned map item will be [0, 0, 0, 0] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [[proc_threshold, 0, 0, 0], num_procedures-1, transaction_threshold] movdn.3 drop drop drop @@ -505,7 +505,7 @@ end #! Invocation: exec pub proc get_initial_threshold_and_num_approvers push.THRESHOLD_CONFIG_SLOT[0..2] - exec.active_account::get_initial_item + exec.native_account::get_initial_item # => [default_threshold, num_approvers, 0, 0] movup.2 drop movup.2 drop @@ -628,7 +628,7 @@ pub proc get_signer_at push.APPROVER_PUBLIC_KEYS_SLOT[0..2] # => [pub_key_slot_suffix, pub_key_slot_prefix, APPROVER_MAP_KEY, index] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [PUB_KEY, index] movup.4 @@ -640,7 +640,7 @@ pub proc get_signer_at push.APPROVER_SCHEME_ID_SLOT[0..2] # => [scheme_id_slot_suffix, scheme_id_slot_prefix, APPROVER_MAP_KEY, PUB_KEY] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [[scheme_id, 0, 0, 0], PUB_KEY] movdn.7 drop drop drop @@ -693,7 +693,7 @@ pub proc is_signer(pub_key: word) -> felt push.APPROVER_PUBLIC_KEYS_SLOT[0..2] # => [pub_key_slot_suffix, pub_key_slot_prefix, APPROVER_MAP_KEY, PUB_KEY] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [CURRENT_PUB_KEY, PUB_KEY] dupw.1 exec.word::eq diff --git a/crates/miden-standards/asm/standards/auth/multisig_smart/mod.masm b/crates/miden-standards/asm/standards/auth/multisig_smart/mod.masm index 6bd03b70b2..f0fd85fd7f 100644 --- a/crates/miden-standards/asm/standards/auth/multisig_smart/mod.masm +++ b/crates/miden-standards/asm/standards/auth/multisig_smart/mod.masm @@ -84,7 +84,7 @@ const DEFAULT_THRESHOLD_LOC = 1 #! Invocation: exec pub proc get_procedure_policy push.PROCEDURE_POLICIES_SLOT[0..2] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [immediate_threshold, delayed_threshold, note_restrictions, 0] movup.3 drop diff --git a/crates/miden-standards/asm/standards/auth/note_script_allowlist.masm b/crates/miden-standards/asm/standards/auth/note_script_allowlist.masm index b1ab7f6144..214031be6b 100644 --- a/crates/miden-standards/asm/standards/auth/note_script_allowlist.masm +++ b/crates/miden-standards/asm/standards/auth/note_script_allowlist.masm @@ -8,7 +8,7 @@ # passes the slot id (suffix, prefix) so the same logic can back multiple components, each with # their own allowlist. -use miden::protocol::active_account +use miden::protocol::native_account use miden::protocol::tx use miden::protocol::input_note use miden::core::word @@ -27,7 +27,7 @@ const ERR_NOTE_SCRIPT_ALLOWLIST_NOTE_NOT_ALLOWED="input note script root is not #! Map convention: keys are note script roots (defined as Word), and any non-empty value marks a #! root as allowed. Empty values (the default for absent keys) cause this procedure to fail. #! -#! Note: Reads the allowlist via `active_account::get_initial_map_item`, i.e. the transaction's +#! Note: Reads the allowlist via `native_account::get_initial_map_item`, i.e. the transaction's #! initial storage state rather than the live state. #! #! Inputs: [allowlist_slot_id_suffix, allowlist_slot_id_prefix] @@ -60,7 +60,7 @@ pub proc assert_all_input_notes_allowed dup.6 dup.6 # => [slot_id_suffix, slot_id_prefix, NOTE_SCRIPT_ROOT, note_idx, slot_id_suffix, slot_id_prefix] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [VALUE, note_idx, slot_id_suffix, slot_id_prefix] exec.word::eqz not diff --git a/crates/miden-standards/asm/standards/auth/signature.masm b/crates/miden-standards/asm/standards/auth/signature.masm index d0f09e413d..1c56a7ecf3 100644 --- a/crates/miden-standards/asm/standards/auth/signature.masm +++ b/crates/miden-standards/asm/standards/auth/signature.masm @@ -1,7 +1,6 @@ use miden::core::crypto::dsa::falcon512_poseidon2 use miden::core::crypto::hashes::poseidon2 use miden::core::crypto::dsa::ecdsa_k256_keccak -use miden::protocol::active_account use {AUTH_REQUEST_EVENT} from miden::protocol::auth use miden::protocol::native_account use miden::protocol::tx @@ -168,7 +167,7 @@ end #! the provided account storage map slot, verifies their signatures against the transaction message, #! and returns the number of successfully verified signatures. #! -#! Note: Calls `active_account::get_initial_map_item` to access the transaction's initial storage +#! Note: Calls `native_account::get_initial_map_item` to access the transaction's initial storage #! state rather than the current state. This is crucial when validating transactions that update #! the owner public key mapping - the previous signers must authorize the change to the new signers, #! not the new signers authorizing themselves. @@ -213,7 +212,7 @@ pub proc verify_signatures # Get public key from initial storage state loc_load.APPROVER_PUB_KEY_SLOT_ID_PREFIX_LOC loc_load.APPROVER_PUB_KEY_SLOT_ID_SUFFIX_LOC - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [PK_COMM, signer_idx, MSG] # Check if signature exists for this signer. @@ -261,7 +260,7 @@ pub proc verify_signatures # => [scheme_slot_id_suffix, scheme_slot_id_prefix, APPROVER_MAP_KEY, PK_COMM, MSG, MSG, signer_idx] # Get scheme_id for the signer index from initial storage state. - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [[scheme_id, 0, 0, 0], PK_COMM, MSG, MSG, signer_idx] movdn.3 drop drop drop diff --git a/crates/miden-standards/asm/standards/auth/tx_script_allowlist.masm b/crates/miden-standards/asm/standards/auth/tx_script_allowlist.masm index c7607e348a..c0fe19f866 100644 --- a/crates/miden-standards/asm/standards/auth/tx_script_allowlist.masm +++ b/crates/miden-standards/asm/standards/auth/tx_script_allowlist.masm @@ -8,7 +8,7 @@ # the slot id (suffix, prefix) so the same logic can back multiple components, each with their own # allowlist. -use miden::protocol::active_account +use miden::protocol::native_account use miden::protocol::tx use miden::core::word @@ -28,7 +28,7 @@ const ERR_TX_SCRIPT_ALLOWLIST_TX_SCRIPT_NOT_ALLOWED="transaction script root is #! Map convention: keys are tx script roots (defined as Word), and any non-empty value marks a root #! as allowed. Empty values (the default for absent keys) cause this procedure to fail. #! -#! Note: Reads the allowlist via `active_account::get_initial_map_item`, i.e. the transaction's +#! Note: Reads the allowlist via `native_account::get_initial_map_item`, i.e. the transaction's #! initial storage state rather than the live state. #! #! Inputs: [allowlist_slot_id_suffix, allowlist_slot_id_prefix] @@ -56,7 +56,7 @@ pub proc assert_tx_script_allowed movup.5 movup.5 # => [slot_id_suffix, slot_id_prefix, TX_SCRIPT_ROOT] - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [VALUE] exec.word::eqz not diff --git a/crates/miden-standards/src/testing/mock_account_code.rs b/crates/miden-standards/src/testing/mock_account_code.rs index 74bfa80127..7fdbf8a582 100644 --- a/crates/miden-standards/src/testing/mock_account_code.rs +++ b/crates/miden-standards/src/testing/mock_account_code.rs @@ -68,7 +68,7 @@ const MOCK_ACCOUNT_CODE: &str = " #! Outputs: [VALUE, pad(12)] @account_procedure pub proc get_initial_item - exec.active_account::get_initial_item + exec.native_account::get_initial_item # => [VALUE, pad(14)] # truncate the stack @@ -96,7 +96,7 @@ const MOCK_ACCOUNT_CODE: &str = " #! Outputs: [INIT_VALUE, pad(12)] @account_procedure pub proc get_initial_map_item - exec.active_account::get_initial_map_item + exec.native_account::get_initial_map_item # => [INIT_VALUE, pad(12)] end diff --git a/crates/miden-testing/src/kernel_tests/tx/test_account.rs b/crates/miden-testing/src/kernel_tests/tx/test_account.rs index 73527890e3..c8339d7a6a 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_account.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_account.rs @@ -97,13 +97,14 @@ pub async fn compute_commitment() -> anyhow::Result<()> { use miden::core::word use miden::protocol::active_account + use miden::protocol::native_account use mock::account as mock_account const MOCK_MAP_SLOT = word("{mock_map_slot}") @transaction_script pub proc main - exec.active_account::get_initial_commitment + exec.native_account::get_initial_commitment # => [INITIAL_COMMITMENT] exec.active_account::compute_commitment @@ -771,14 +772,14 @@ async fn test_get_initial_storage_commitment() -> anyhow::Result<()> { let code = format!( r#" - use miden::protocol::active_account + use miden::protocol::native_account use miden::tx_kernel_core::prologue begin exec.prologue::prepare_transaction # get the initial storage commitment - exec.active_account::get_initial_storage_commitment + exec.native_account::get_initial_storage_commitment push.{expected_storage_commitment} assert_eqw.err="actual storage commitment is not equal to the expected one" end @@ -968,14 +969,14 @@ async fn test_get_vault_root() -> anyhow::Result<()> { // get the initial vault root let code = format!( r#" - use miden::protocol::active_account + use miden::protocol::native_account use miden::tx_kernel_core::prologue begin exec.prologue::prepare_transaction # get the initial vault root - exec.active_account::get_initial_vault_root + exec.native_account::get_initial_vault_root push.{expected_vault_root} assert_eqw.err="initial vault root mismatch" end @@ -1018,7 +1019,7 @@ async fn test_get_vault_root() -> anyhow::Result<()> { Ok(()) } -/// This test checks the correctness of the `miden::protocol::active_account::get_initial_balance` +/// This test checks the correctness of the `miden::protocol::native_account::get_initial_balance` /// procedure in two cases: /// - when a note adds the asset which already exists in the account vault. /// - when a note adds the asset which doesn't exist in the account vault. @@ -1079,6 +1080,7 @@ async fn test_get_init_balance_addition() -> anyhow::Result<()> { let add_existing_source = format!( r#" use miden::protocol::active_account + use miden::protocol::native_account @transaction_script pub proc main @@ -1094,7 +1096,7 @@ async fn test_get_init_balance_addition() -> anyhow::Result<()> { # get the initial asset balance push.{ASSET_ID} - exec.active_account::get_initial_balance + exec.native_account::get_initial_balance # => [init_balance] # assert initial balance is correct @@ -1129,6 +1131,7 @@ async fn test_get_init_balance_addition() -> anyhow::Result<()> { let add_new_source = format!( r#" use miden::protocol::active_account + use miden::protocol::native_account @transaction_script pub proc main @@ -1144,7 +1147,7 @@ async fn test_get_init_balance_addition() -> anyhow::Result<()> { # get the initial asset balance push.{ASSET_ID} - exec.active_account::get_initial_balance + exec.native_account::get_initial_balance # => [init_balance] # assert initial balance is correct @@ -1169,7 +1172,7 @@ async fn test_get_init_balance_addition() -> anyhow::Result<()> { Ok(()) } -/// This test checks the correctness of the `miden::protocol::active_account::get_initial_balance` +/// This test checks the correctness of the `miden::protocol::native_account::get_initial_balance` /// procedure in case when we create a note which removes an asset from the account vault. /// /// As part of the test pipeline it also checks the correctness of the @@ -1207,6 +1210,7 @@ async fn test_get_init_balance_subtraction() -> anyhow::Result<()> { let remove_existing_source = format!( r#" use miden::protocol::active_account + use miden::protocol::native_account use miden::standards::wallets::basic as wallet use mock::util @@ -1233,7 +1237,7 @@ async fn test_get_init_balance_subtraction() -> anyhow::Result<()> { # get the initial asset balance push.{ASSET_ID} - exec.active_account::get_initial_balance + exec.native_account::get_initial_balance # => [init_balance] # assert initial balance is correct @@ -1261,7 +1265,7 @@ async fn test_get_init_balance_subtraction() -> anyhow::Result<()> { Ok(()) } -/// This test checks the correctness of the `miden::protocol::active_account::get_initial_asset` +/// This test checks the correctness of the `miden::protocol::native_account::get_initial_asset` /// procedure creating a note which removes an asset from the account vault. /// /// As part of the test pipeline it also checks the correctness of the @@ -1300,6 +1304,7 @@ async fn test_get_init_asset() -> anyhow::Result<()> { let remove_existing_source = format!( r#" use miden::protocol::active_account + use miden::protocol::native_account use miden::standards::wallets::basic as wallet use mock::util @@ -1323,7 +1328,7 @@ async fn test_get_init_asset() -> anyhow::Result<()> { # => [] # get the initial asset - push.{ASSET_ID} exec.active_account::get_initial_asset + push.{ASSET_ID} exec.native_account::get_initial_asset # => [INITIAL_ASSET] push.{INITIAL_ASSET_VALUE} diff --git a/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs b/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs index 808024baf4..574648a3d8 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs @@ -25,6 +25,7 @@ use miden_protocol::asset::{ NonFungibleAssetDetails, }; use miden_protocol::errors::tx_kernel::{ + ERR_ACCOUNT_IS_NOT_NATIVE, ERR_FOREIGN_ACCOUNT_CONTEXT_AGAINST_NATIVE_ACCOUNT, ERR_FOREIGN_ACCOUNT_INVALID_COMMITMENT, ERR_FOREIGN_ACCOUNT_MAX_NUMBER_EXCEEDED, @@ -864,114 +865,6 @@ async fn foreign_account_can_get_balance_and_presence_of_asset() -> anyhow::Resu Ok(()) } -/// Test that the `miden::get_initial_balance` procedure works correctly being called from a foreign -/// account. -#[tokio::test] -async fn foreign_account_get_initial_balance() -> anyhow::Result<()> { - let fungible_faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_1)?; - let fungible_asset = Asset::Fungible(FungibleAsset::new(fungible_faucet_id, 10)?); - let fungible_asset_id = AssetId::new_fungible(fungible_faucet_id); - - let foreign_account_code_source = format!( - " - use miden::protocol::active_account - - @account_procedure - pub proc get_initial_balance - # push the asset ID on the stack - push.{FUNGIBLE_ASSET_ID} - - # get the initial balance of the asset associated with the provided asset ID - exec.active_account::get_balance - # => [initial_balance] - - # truncate the stack - swap drop - # => [initial_balance] - end - ", - FUNGIBLE_ASSET_ID = fungible_asset_id.to_word(), - ); - - let source_manager = Arc::new(DefaultSourceManager::default()); - let foreign_account_component = AccountComponent::new( - CodeBuilder::with_source_manager(source_manager.clone()) - .compile_component_code("foreign_account_code", foreign_account_code_source)?, - vec![], - AccountComponentMetadata::mock("foreign_account_code"), - )?; - - let foreign_account = AccountBuilder::new(rand::random()) - .with_auth_component(Auth::IncrNonce) - .with_component(foreign_account_component.clone()) - .with_assets(vec![fungible_asset]) - .build_existing()?; - - let native_account = AccountBuilder::new(rand::random()) - .with_auth_component(Auth::IncrNonce) - .with_component(MockAccountComponent::with_empty_slots()) - .account_type(AccountType::Public) - .build_existing()?; - - let mut mock_chain = - MockChainBuilder::with_accounts([native_account.clone(), foreign_account.clone()])? - .build()?; - mock_chain.prove_next_block()?; - - let code = format!( - " - use miden::core::sys - - use miden::protocol::tx - - @transaction_script - pub proc main - # Get the initial balance of the fungible asset from the foreign account - - # pad the stack for the `execute_foreign_procedure` execution - padw padw padw push.0.0.0 - # => [pad(15)] - - # get the hash of the `get_initial_balance` procedure - procref.::foreign_account_code::get_initial_balance - - # push the foreign account ID - push.{foreign_prefix} push.{foreign_suffix} - # => [foreign_account_id_suffix, foreign_account_id_prefix, FOREIGN_PROC_ROOT, pad(15)] - - exec.tx::execute_foreign_procedure - # => [init_foreign_balance] - - # assert that the initial balance of the asset in the foreign account equals 10 - push.10 assert_eq.err=\"Initial balance should be 10\" - # => [] - - # truncate the stack - exec.sys::truncate_stack - end - ", - foreign_prefix = foreign_account.id().prefix().as_felt(), - foreign_suffix = foreign_account.id().suffix(), - ); - - let tx_script = CodeBuilder::with_source_manager(source_manager.clone()) - .with_dynamically_linked_library(foreign_account_component.component_code())? - .compile_tx_script(code)?; - - let foreign_account_inputs = mock_chain.get_foreign_account_inputs(foreign_account.id())?; - - mock_chain - .build_tx_context(native_account.id(), &[], &[])? - .foreign_accounts([foreign_account_inputs]) - .tx_script(tx_script) - .with_source_manager(source_manager) - .build()? - .execute() - .await?; - - Ok(()) -} - // NESTED FPI TESTS // ================================================================================================ @@ -1884,11 +1777,11 @@ async fn test_fpi_get_account_id() -> anyhow::Result<()> { Ok(()) } -/// Test that get_initial_item and get_initial_map_item work correctly with foreign accounts. +/// Test that `native_account::get_initial_item` cannot be called against a foreign account: it is a +/// native-account-only procedure, so invoking it from an FPI context must fail via +/// `memory::assert_native_account` with `ERR_ACCOUNT_IS_NOT_NATIVE`. #[tokio::test] -async fn test_get_initial_item_and_get_initial_map_item_with_foreign_account() -> anyhow::Result<()> -{ - // Create a native account +async fn get_initial_item_fails_for_foreign_account() -> anyhow::Result<()> { let native_account = AccountBuilder::new(rand::random()) .with_auth_component(Auth::IncrNonce) .with_component(MockAccountComponent::with_empty_slots()) @@ -1896,13 +1789,11 @@ async fn test_get_initial_item_and_get_initial_map_item_with_foreign_account() - .build_existing()?; let mock_value_slot0 = AccountStorage::mock_value_slot0(); - let mock_map_slot = AccountStorage::mock_map_slot(); - let (map_key, map_value) = STORAGE_LEAVES_2[0]; - // Create foreign procedures that test get_initial_item and get_initial_map_item + // Foreign procedure that attempts to call the native-only get_initial_item. let foreign_account_code_source = format!( r#" - use miden::protocol::active_account + use miden::protocol::native_account use miden::core::sys const MOCK_VALUE_SLOT0 = word("{mock_value_slot0}") @@ -1910,13 +1801,7 @@ async fn test_get_initial_item_and_get_initial_map_item_with_foreign_account() - @account_procedure pub proc test_get_initial_item push.MOCK_VALUE_SLOT0[0..2] - exec.active_account::get_initial_item - exec.sys::truncate_stack - end - - @account_procedure - pub proc test_get_initial_map_item - exec.active_account::get_initial_map_item + exec.native_account::get_initial_item exec.sys::truncate_stack end "#, @@ -1926,7 +1811,7 @@ async fn test_get_initial_item_and_get_initial_map_item_with_foreign_account() - let foreign_account_component = AccountComponent::new( CodeBuilder::default() .compile_component_code("foreign_account", foreign_account_code_source)?, - vec![mock_value_slot0.clone(), mock_map_slot.clone()], + vec![mock_value_slot0.clone()], AccountComponentMetadata::mock("foreign_account"), )?; @@ -1935,7 +1820,6 @@ async fn test_get_initial_item_and_get_initial_map_item_with_foreign_account() - .with_component(foreign_account_component.clone()) .build_existing()?; - // Create the mock chain with both accounts let mut mock_chain = MockChainBuilder::with_accounts([native_account.clone(), foreign_account.clone()])? .build()?; @@ -1948,51 +1832,34 @@ async fn test_get_initial_item_and_get_initial_map_item_with_foreign_account() - use miden::core::sys use miden::protocol::tx - const MOCK_MAP_SLOT = word("{mock_map_slot}") - @transaction_script pub proc main - # Test get_initial_item on foreign account + # attempt to call the native-only get_initial_item on a foreign account padw padw padw push.0.0.0 - # => [pad(15)] procref.::foreign_account::test_get_initial_item push.{foreign_account_id_prefix} push.{foreign_account_id_suffix} exec.tx::execute_foreign_procedure - push.{expected_value_slot_0} - assert_eqw.err="foreign account get_initial_item should work" - - # Test get_initial_map_item on foreign account - padw padw push.0.0 - push.{map_key} - push.MOCK_MAP_SLOT[0..2] - procref.::foreign_account::test_get_initial_map_item - push.{foreign_account_id_prefix} push.{foreign_account_id_suffix} - exec.tx::execute_foreign_procedure - push.{map_value} - assert_eqw.err="foreign account get_initial_map_item should work" exec.sys::truncate_stack end "#, - mock_map_slot = mock_map_slot.name(), foreign_account_id_prefix = foreign_account.id().prefix().as_felt(), foreign_account_id_suffix = foreign_account.id().suffix(), - expected_value_slot_0 = mock_value_slot0.content().value(), - map_key = &map_key, - map_value = &map_value, ); let tx_script = CodeBuilder::with_mock_libraries() .with_dynamically_linked_library(foreign_account_component.component_code())? .compile_tx_script(code)?; - mock_chain + let result = mock_chain .build_tx_context(native_account.id(), &[], &[])? .foreign_accounts(vec![foreign_account_inputs]) .tx_script(tx_script) .build()? .execute() - .await?; + .await; + + assert_transaction_executor_error!(result, ERR_ACCOUNT_IS_NOT_NATIVE); Ok(()) } diff --git a/docs/src/protocol_library.md b/docs/src/protocol_library.md index 012562e18d..d12bff81f8 100644 --- a/docs/src/protocol_library.md +++ b/docs/src/protocol_library.md @@ -45,21 +45,14 @@ Active account procedures can be used to read from storage, fetch or compute com | -------------------------------- | ----------------------------- | ----------------------------- | | `get_id` | Returns the ID of the active account.

**Inputs:** `[]`
**Outputs:** `[account_id_suffix, account_id_prefix]` | Any | | `get_nonce` | Returns the nonce of the active account. Always returns the initial nonce as it can only be incremented in auth procedures.

**Inputs:** `[]`
**Outputs:** `[nonce]` | Any | -| `get_initial_commitment` | Returns the active account commitment at the beginning of the transaction.

**Inputs:** `[]`
**Outputs:** `[INIT_COMMITMENT]` | Any | | `compute_commitment` | Computes and returns the account commitment from account data stored in memory.

**Inputs:** `[]`
**Outputs:** `[ACCOUNT_COMMITMENT]` | Any | | `get_code_commitment` | Gets the account code commitment of the active account.

**Inputs:** `[]`
**Outputs:** `[CODE_COMMITMENT]` | Account | -| `get_initial_storage_commitment` | Returns the storage commitment of the active account at the beginning of the transaction.

**Inputs:** `[]`
**Outputs:** `[INIT_STORAGE_COMMITMENT]` | Any | | `compute_storage_commitment` | Computes the latest account storage commitment of the active account.

**Inputs:** `[]`
**Outputs:** `[STORAGE_COMMITMENT]` | Account | | `get_item` | Gets an item from the account storage.

**Inputs:** `[slot_id_suffix, slot_id_prefix]`
**Outputs:** `[VALUE]` | Account | -| `get_initial_item` | Gets the initial item from the account storage slot as it was at the beginning of the transaction.

**Inputs:** `[slot_id_suffix, slot_id_prefix]`
**Outputs:** `[VALUE]` | Account | | `get_map_item` | Returns the VALUE located under the specified KEY within the map contained in the given account storage slot.

**Inputs:** `[slot_id_suffix, slot_id_prefix, KEY]`
**Outputs:** `[VALUE]` | Account | -| `get_initial_map_item` | Gets the initial VALUE from the account storage map as it was at the beginning of the transaction.

**Inputs:** `[slot_id_suffix, slot_id_prefix, KEY]`
**Outputs:** `[VALUE]` | Account | | `get_asset` | Returns the asset associated with the provided asset ID in the active account's vault.

**Inputs:** `[ASSET_ID]`
**Outputs:** `[ASSET_VALUE]` | Any | -| `get_initial_asset` | Returns the asset associated with the provided asset ID in the active account's vault at the beginning of the transaction.

**Inputs:** `[ASSET_ID]`
**Outputs:** `[ASSET_VALUE]` | Any | | `get_balance` | Returns the balance of the fungible asset associated with the provided faucet_id in the active account's vault.

**Inputs:** `[faucet_id_suffix, faucet_id_prefix]`
**Outputs:** `[balance]` | Any | -| `get_initial_balance` | Returns the balance of the fungible asset associated with the provided faucet_id in the active account's vault at the beginning of the transaction.

**Inputs:** `[faucet_id_suffix, faucet_id_prefix]`
**Outputs:** `[init_balance]` | Any | | `has_non_fungible_asset` | Returns a boolean indicating whether the non-fungible asset is present in the active account's vault.

**Inputs:** `[ASSET_VALUE]`
**Outputs:** `[has_asset]` | Any | -| `get_initial_vault_root` | Returns the vault root of the active account at the beginning of the transaction.

**Inputs:** `[]`
**Outputs:** `[INIT_VAULT_ROOT]` | Any | | `get_vault_root` | Returns the vault root of the active account.

**Inputs:** `[]`
**Outputs:** `[VAULT_ROOT]` | Any | | `get_num_procedures` | Returns the number of procedures in the active account.

**Inputs:** `[]`
**Outputs:** `[num_procedures]` | Any | | `get_procedure_root` | Returns the procedure root for the procedure at the specified index.

**Inputs:** `[index]`
**Outputs:** `[PROC_ROOT]` | Any | @@ -67,7 +60,9 @@ Active account procedures can be used to read from storage, fetch or compute com ## Native account Procedures (`miden::protocol::native_account`) -Native account procedures can be used to write to storage, add or remove assets from the vault and compute delta commitment of the native account. +Native account procedures can be used to write to storage, add or remove assets from the vault and compute delta commitment of the native account. They also expose the initial (beginning-of-transaction) state of the native account. + +Notice that the initial-state getters can only be executed against the native account: invoking them against the foreign account (during FPI) panics. Foreign accounts are immutable, so in order to read their (initial) values, the corresponding getters from the `active_account` module should be used. | Procedure | Description | Context | | ------------------------------ | ------------------------------ | ------------------------------ | @@ -78,7 +73,14 @@ Native account procedures can be used to write to storage, add or remove assets | `set_map_item` | Sets VALUE under the specified KEY within the map contained in the given native account storage slot.

**Inputs:** `[slot_id_suffix, slot_id_prefix, KEY, VALUE]`
**Outputs:** `[OLD_VALUE]` | Native & Account | | `add_asset` | Adds the specified asset to the vault. For fungible assets, returns the total after addition.

**Inputs:** `[ASSET_ID, ASSET_VALUE]`
**Outputs:** `[ASSET_VALUE']` | Native & Account | | `remove_asset` | Removes the specified asset from the vault and returns the remaining asset value.

**Inputs:** `[ASSET_ID, ASSET_VALUE]`
**Outputs:** `[REMAINING_ASSET_VALUE]` | Native & Account | -| `was_procedure_called` | Returns 1 if a native account procedure was called during transaction execution, and 0 otherwise.

**Inputs:** `[PROC_ROOT]`
**Outputs:** `[was_called]` | Any | +| `get_initial_commitment` | Returns the native account commitment at the beginning of the transaction.

**Inputs:** `[]`
**Outputs:** `[INIT_COMMITMENT]` | Native | +| `get_initial_storage_commitment` | Returns the storage commitment of the native account at the beginning of the transaction.

**Inputs:** `[]`
**Outputs:** `[INIT_STORAGE_COMMITMENT]` | Native | +| `get_initial_item` | Gets the initial item from the native account storage slot as it was at the beginning of the transaction.

**Inputs:** `[slot_id_suffix, slot_id_prefix]`
**Outputs:** `[VALUE]` | Native | +| `get_initial_map_item` | Gets the initial VALUE from the native account storage map as it was at the beginning of the transaction.

**Inputs:** `[slot_id_suffix, slot_id_prefix, KEY]`
**Outputs:** `[VALUE]` | Native | +| `get_initial_asset` | Returns the asset associated with the provided asset ID in the native account's vault at the beginning of the transaction.

**Inputs:** `[ASSET_ID]`
**Outputs:** `[ASSET_VALUE]` | Native | +| `get_initial_balance` | Returns the balance of the fungible asset associated with the provided faucet_id in the native account's vault at the beginning of the transaction.

**Inputs:** `[faucet_id_suffix, faucet_id_prefix]`
**Outputs:** `[init_balance]` | Native | +| `get_initial_vault_root` | Returns the vault root of the native account at the beginning of the transaction.

**Inputs:** `[]`
**Outputs:** `[INIT_VAULT_ROOT]` | Native | +| `was_procedure_called` | Returns 1 if a native account procedure was called during transaction execution, and 0 otherwise.

**Inputs:** `[PROC_ROOT]`
**Outputs:** `[was_called]` | Native | ## Active Note Procedures (`miden::protocol::active_note`)