diff --git a/miden-lib/asm/kernels/transaction/api.masm b/miden-lib/asm/kernels/transaction/api.masm index c0e293d76..7babac391 100644 --- a/miden-lib/asm/kernels/transaction/api.masm +++ b/miden-lib/asm/kernels/transaction/api.masm @@ -14,7 +14,6 @@ const.ADD_ASSET_TO_ACCOUNT_VAULT_EVENT=131072 # Event emitted to signal that an asset is being removed from the account vault. const.REMOVE_ASSET_FROM_ACCOUNT_VAULT_EVENT=131073 - # AUTHENTICATION # ================================================================================================= diff --git a/miden-lib/asm/miden/kernels/tx/account.masm b/miden-lib/asm/miden/kernels/tx/account.masm index 4137cc9bd..cd76a88d3 100644 --- a/miden-lib/asm/miden/kernels/tx/account.masm +++ b/miden-lib/asm/miden/kernels/tx/account.masm @@ -36,6 +36,13 @@ const.SLOT_TYPES_COMMITMENT_STORAGE_SLOT=255 # The maximum value a slot type can take (An array of depth 64). const.MAX_SLOT_TYPE=64 +# EVENTS +# ================================================================================================= + +# Event emitted to push the index of the account procedure at the top of the operand stack onto +# the advice stack. +const.PUSH_ACCOUNT_PROCEDURE_INDEX_EVENT=131074 + # CONSTANT ACCESSORS # ================================================================================================= @@ -343,7 +350,7 @@ export.set_item # => [V] end -#! Authenticates the proedcure root is part of the account code Merkle treee. Panics if the +#! Verifies that the procedure root is part of the account code Merkle tree. Panics if the #! procedure root is not part of the account code Merkle tree. #! #! Stack: [PROC_ROOT] @@ -355,8 +362,8 @@ export.authenticate_procedure.1 exec.memory::get_acct_code_root swapw # => [PROC_ROOT, CODE_ROOT] - # load the index of the procedure root onto the advice stack - adv.push_mapval adv_push.1 movdn.4 + # load the index of the procedure root onto the advice stack, and move it to the operand stack + emit.PUSH_ACCOUNT_PROCEDURE_INDEX_EVENT adv_push.1 movdn.4 # => [PROC_ROOT, index, CODE_ROOT] # push the depth of the code Merkle tree onto the stack diff --git a/miden-lib/src/tests/mod.rs b/miden-lib/src/tests/mod.rs index 293caae1e..1d4f738e1 100644 --- a/miden-lib/src/tests/mod.rs +++ b/miden-lib/src/tests/mod.rs @@ -1,15 +1,9 @@ use std::path::PathBuf; -use miden_objects::{ - transaction::PreparedTransaction, - vm::{Program, StackInputs}, - Felt, Hasher, Word, ONE, ZERO, -}; -use vm_processor::{ - AdviceProvider, ContextId, DefaultHost, MemAdviceProvider, Process, ProcessState, -}; +use miden_objects::{vm::StackInputs, Felt, Hasher, Word, ONE, ZERO}; +use vm_processor::{ContextId, MemAdviceProvider, Process, ProcessState}; -use super::{transaction::ToTransactionKernelInputs, Library}; +use super::Library; mod test_account; mod test_asset; @@ -46,12 +40,6 @@ fn test_compile() { // HELPER FUNCTIONS // ================================================================================================ -fn build_tx_inputs(tx: &PreparedTransaction) -> (Program, StackInputs, MemAdviceProvider) { - let (stack_inputs, advice_inputs) = tx.get_kernel_inputs(); - let advice_provider = MemAdviceProvider::from(advice_inputs); - (tx.program().clone(), stack_inputs, advice_provider) -} - fn build_module_path(dir: &str, file: &str) -> PathBuf { [env!("CARGO_MANIFEST_DIR"), "asm", dir, file].iter().collect() } diff --git a/miden-lib/src/tests/test_account.rs b/miden-lib/src/tests/test_account.rs index c26d2d466..a732cade1 100644 --- a/miden-lib/src/tests/test_account.rs +++ b/miden-lib/src/tests/test_account.rs @@ -10,17 +10,18 @@ use mock::{ }, mock::{ account::MockAccountType, + host::MockHost, notes::AssetPreservationStatus, transaction::{mock_executed_tx, mock_inputs}, }, prepare_transaction, procedures::{output_notes_data_procedure, prepare_word}, - run_tx, run_within_tx_kernel, + run_tx, run_within_host, run_within_tx_kernel, }; use super::{ - super::transaction::ToTransactionKernelInputs, build_tx_inputs, ContextId, Felt, - MemAdviceProvider, ProcessState, StackInputs, Word, ONE, ZERO, + super::transaction::ToTransactionKernelInputs, ContextId, Felt, MemAdviceProvider, + ProcessState, StackInputs, Word, ONE, ZERO, }; use crate::transaction::memory::{ACCT_CODE_ROOT_PTR, ACCT_NEW_CODE_ROOT_PTR}; @@ -29,7 +30,7 @@ use crate::transaction::memory::{ACCT_CODE_ROOT_PTR, ACCT_NEW_CODE_ROOT_PTR}; #[test] pub fn test_set_code_is_not_immediate() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = " @@ -42,10 +43,8 @@ pub fn test_set_code_is_not_immediate() { end "; - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction).unwrap(); // assert the code root is not changed assert_eq!( @@ -91,9 +90,8 @@ pub fn test_set_code_succeeds() { ); let (stack_inputs, advice_inputs) = executed_transaction.get_kernel_inputs(); - let process = - run_within_tx_kernel("", &code, stack_inputs, MemAdviceProvider::from(advice_inputs), None) - .unwrap(); + let host = MockHost::new(executed_transaction.initial_account().into(), advice_inputs); + let process = run_within_host("", &code, stack_inputs, host, None).unwrap(); // assert the code root is changed after the epilogue assert_eq!( @@ -224,7 +222,7 @@ fn test_is_faucet_procedure() { #[test] fn test_get_item() { for storage_item in [storage_item_0(), storage_item_1()] { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = format!( @@ -251,20 +249,18 @@ fn test_get_item() { item_value = prepare_word(&storage_item.1 .1) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } } #[test] fn test_set_item() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); // copy the initial account slots (SMT) - let mut account_smt = account.storage().slots().clone(); + let mut account_smt = tx_inputs.account().storage().slots().clone(); let init_root = account_smt.root(); // insert a new leaf value @@ -306,17 +302,15 @@ fn test_set_item() { new_root = prepare_word(&account_smt.root()), ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } // TODO: reenable once storage map support is implemented #[ignore] #[test] fn test_get_map_item() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = format!( @@ -347,19 +341,8 @@ fn test_get_map_item() { child_value = prepare_word(&CHILD_STORAGE_VALUE_0) ); - let transaction = prepare_transaction( - account, - None, - block_header, - chain, - notes, - None, - code.as_str(), - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, code.as_str(), None); + let _process = run_tx(&transaction).unwrap(); } // ACCOUNT VAULT TESTS @@ -367,9 +350,10 @@ fn test_get_map_item() { #[test] fn test_get_vault_commitment() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); + let account = tx_inputs.account(); let code = format!( " use.miden::account @@ -388,10 +372,8 @@ fn test_get_vault_commitment() { expected_vault_commitment = prepare_word(&account.vault().commitment()), ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } // PROCEDURE AUTHENTICATION TESTS @@ -399,8 +381,9 @@ fn test_get_vault_commitment() { #[test] fn test_authenticate_procedure() { - let (account, ..) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); + let account = tx_inputs.account(); let test_cases = vec![ (account.code().procedure_tree().get_leaf(0).unwrap(), true), @@ -409,7 +392,7 @@ fn test_authenticate_procedure() { ]; for (root, valid) in test_cases.into_iter() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = format!( @@ -431,10 +414,8 @@ fn test_authenticate_procedure() { root = prepare_word(&root) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); match valid { true => assert!(process.is_ok()), diff --git a/miden-lib/src/tests/test_asset.rs b/miden-lib/src/tests/test_asset.rs index 03bc2655e..e548a5c12 100644 --- a/miden-lib/src/tests/test_asset.rs +++ b/miden-lib/src/tests/test_asset.rs @@ -9,11 +9,11 @@ use mock::{ run_tx, }; -use super::{build_tx_inputs, Hasher, Word, ONE}; +use super::{Hasher, Word, ONE}; #[test] fn test_create_fungible_asset_succeeds() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -44,15 +44,13 @@ fn test_create_fungible_asset_succeeds() { " ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction); } #[test] fn test_create_non_fungible_asset_succeeds() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::NonFungibleFaucet { acct_id: ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -84,8 +82,6 @@ fn test_create_non_fungible_asset_succeeds() { expected_non_fungible_asset = prepare_word(&Word::from(non_fungible_asset)) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } diff --git a/miden-lib/src/tests/test_asset_vault.rs b/miden-lib/src/tests/test_asset_vault.rs index 52b6ecdf2..99a9403ff 100644 --- a/miden-lib/src/tests/test_asset_vault.rs +++ b/miden-lib/src/tests/test_asset_vault.rs @@ -14,12 +14,12 @@ use mock::{ run_tx, }; -use super::{build_tx_inputs, ContextId, Felt, ProcessState, Word, ONE, ZERO}; +use super::{ContextId, Felt, ProcessState, Word, ONE, ZERO}; use crate::transaction::memory; #[test] fn test_get_balance() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let faucet_id: AccountId = ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); @@ -36,10 +36,8 @@ fn test_get_balance() { " ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); assert_eq!( process.stack.get(0).as_int(), @@ -49,7 +47,7 @@ fn test_get_balance() { #[test] fn test_get_balance_non_fungible_fails() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = format!( @@ -65,19 +63,17 @@ fn test_get_balance_non_fungible_fails() { " ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_has_non_fungible_asset() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); - let non_fungible_asset = account.vault().assets().next().unwrap(); + let non_fungible_asset = tx_inputs.account().vault().assets().next().unwrap(); let code = format!( " @@ -93,19 +89,17 @@ fn test_has_non_fungible_asset() { non_fungible_asset_key = prepare_word(&non_fungible_asset.vault_key()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); assert_eq!(process.stack.get(0), ONE); } #[test] fn test_add_fungible_asset_success() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let faucet_id: AccountId = ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); let amount = FungibleAsset::MAX_AMOUNT - FUNGIBLE_ASSET_AMOUNT; @@ -126,10 +120,8 @@ fn test_add_fungible_asset_success() { FUNGIBLE_ASSET = prepare_word(&add_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); assert_eq!( process.stack.get_word(0), @@ -144,9 +136,9 @@ fn test_add_fungible_asset_success() { #[test] fn test_add_non_fungible_asset_fail_overflow() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let faucet_id: AccountId = ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); let amount = FungibleAsset::MAX_AMOUNT - FUNGIBLE_ASSET_AMOUNT + 1; @@ -167,10 +159,8 @@ fn test_add_non_fungible_asset_fail_overflow() { FUNGIBLE_ASSET = prepare_word(&add_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); assert!(account_vault.add_asset(add_fungible_asset).is_err()); @@ -178,11 +168,11 @@ fn test_add_non_fungible_asset_fail_overflow() { #[test] fn test_add_non_fungible_asset_success() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let faucet_id: AccountId = ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let add_non_fungible_asset = Asset::NonFungible( NonFungibleAsset::new( &NonFungibleAssetDetails::new(faucet_id, vec![1, 2, 3, 4, 5, 6, 7, 8]).unwrap(), @@ -204,10 +194,8 @@ fn test_add_non_fungible_asset_success() { FUNGIBLE_ASSET = prepare_word(&add_non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); assert_eq!( process.stack.get_word(0), @@ -222,11 +210,11 @@ fn test_add_non_fungible_asset_success() { #[test] fn test_add_non_fungible_asset_fail_duplicate() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let faucet_id: AccountId = ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let non_fungible_asset_details = NonFungibleAssetDetails::new(faucet_id, NON_FUNGIBLE_ASSET_DATA.to_vec()).unwrap(); let non_fungible_asset = @@ -246,10 +234,8 @@ fn test_add_non_fungible_asset_fail_duplicate() { NON_FUNGIBLE_ASSET = prepare_word(&non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); assert!(account_vault.add_asset(non_fungible_asset).is_err()); @@ -257,9 +243,9 @@ fn test_add_non_fungible_asset_fail_duplicate() { #[test] fn test_remove_fungible_asset_success_no_balance_remaining() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let faucet_id: AccountId = ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); let amount = FUNGIBLE_ASSET_AMOUNT; @@ -280,10 +266,8 @@ fn test_remove_fungible_asset_success_no_balance_remaining() { FUNGIBLE_ASSET = prepare_word(&remove_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); assert_eq!( process.stack.get_word(0), @@ -298,7 +282,7 @@ fn test_remove_fungible_asset_success_no_balance_remaining() { #[test] fn test_remove_fungible_asset_fail_remove_too_much() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let faucet_id: AccountId = ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); @@ -320,19 +304,17 @@ fn test_remove_fungible_asset_fail_remove_too_much() { FUNGIBLE_ASSET = prepare_word(&remove_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_remove_fungible_asset_success_balance_remaining() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let faucet_id: AccountId = ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); let amount = FUNGIBLE_ASSET_AMOUNT - 1; @@ -353,10 +335,8 @@ fn test_remove_fungible_asset_success_balance_remaining() { FUNGIBLE_ASSET = prepare_word(&remove_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); assert_eq!( process.stack.get_word(0), @@ -371,11 +351,11 @@ fn test_remove_fungible_asset_success_balance_remaining() { #[test] fn test_remove_non_fungible_asset_fail_doesnt_exist() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let faucet_id: AccountId = (ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN + 1).try_into().unwrap(); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let non_fungible_asset_details = NonFungibleAssetDetails::new(faucet_id, NON_FUNGIBLE_ASSET_DATA.to_vec()).unwrap(); let non_existent_non_fungible_asset = @@ -395,10 +375,8 @@ fn test_remove_non_fungible_asset_fail_doesnt_exist() { FUNGIBLE_ASSET = prepare_word(&non_existent_non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); assert!(account_vault.remove_asset(non_existent_non_fungible_asset).is_err()); @@ -406,11 +384,11 @@ fn test_remove_non_fungible_asset_fail_doesnt_exist() { #[test] fn test_remove_non_fungible_asset_success() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let faucet_id: AccountId = ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(); - let mut account_vault = account.vault().clone(); + let mut account_vault = tx_inputs.account().vault().clone(); let non_fungible_asset_details = NonFungibleAssetDetails::new(faucet_id, NON_FUNGIBLE_ASSET_DATA.to_vec()).unwrap(); let non_fungible_asset = @@ -430,10 +408,8 @@ fn test_remove_non_fungible_asset_success() { FUNGIBLE_ASSET = prepare_word(&non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); assert_eq!( process.stack.get_word(0), diff --git a/miden-lib/src/tests/test_faucet.rs b/miden-lib/src/tests/test_faucet.rs index cee089ef2..6eaffe522 100644 --- a/miden-lib/src/tests/test_faucet.rs +++ b/miden-lib/src/tests/test_faucet.rs @@ -12,7 +12,7 @@ use mock::{ run_tx, }; -use super::{build_tx_inputs, ONE}; +use super::ONE; use crate::transaction::memory::FAUCET_STORAGE_DATA_SLOT; // FUNGIBLE FAUCET MINT TESTS @@ -20,7 +20,7 @@ use crate::transaction::memory::FAUCET_STORAGE_DATA_SLOT; #[test] fn test_mint_fungible_asset_succeeds() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -43,7 +43,7 @@ fn test_mint_fungible_asset_succeeds() { push.{FUNGIBLE_ASSET_AMOUNT}.0.0.{ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN} exec.faucet::mint - # assert the correct asset is returned + # assert the correct asset is returned push.{FUNGIBLE_ASSET_AMOUNT}.0.0.{ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN} assert_eqw @@ -63,15 +63,13 @@ fn test_mint_fungible_asset_succeeds() { expected_final_storage_amount = FUNGIBLE_FAUCET_INITIAL_BALANCE + FUNGIBLE_ASSET_AMOUNT ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } #[test] fn test_mint_fungible_asset_fails_not_faucet_account() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = format!( @@ -88,16 +86,14 @@ fn test_mint_fungible_asset_fails_not_faucet_account() { " ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_mint_fungible_asset_inconsistent_faucet_id() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -120,17 +116,15 @@ fn test_mint_fungible_asset_inconsistent_faucet_id() { ", ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_mint_fungible_asset_fails_saturate_max_amount() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -154,10 +148,8 @@ fn test_mint_fungible_asset_fails_saturate_max_amount() { saturating_amount = FungibleAsset::MAX_AMOUNT - FUNGIBLE_FAUCET_INITIAL_BALANCE + 1 ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } @@ -169,7 +161,7 @@ fn test_mint_fungible_asset_fails_saturate_max_amount() { #[ignore] #[test] fn test_mint_non_fungible_asset_succeeds() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::NonFungibleFaucet { acct_id: ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -217,15 +209,13 @@ fn test_mint_non_fungible_asset_succeeds() { non_fungible_asset = prepare_word(&non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } #[test] fn test_mint_non_fungible_asset_fails_not_faucet_account() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let non_fungible_asset = non_fungible_asset(ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN); @@ -244,17 +234,15 @@ fn test_mint_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = prepare_word(&non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_mint_non_fungible_asset_fails_inconsistent_faucet_id() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let non_fungible_asset = non_fungible_asset(ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN_1); @@ -273,17 +261,15 @@ fn test_mint_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = prepare_word(&non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_mint_non_fungible_asset_fails_asset_already_exists() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::NonFungibleFaucet { acct_id: ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -308,10 +294,8 @@ fn test_mint_non_fungible_asset_fails_asset_already_exists() { non_fungible_asset = prepare_word(&non_fungible_asset.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } @@ -321,7 +305,7 @@ fn test_mint_non_fungible_asset_fails_asset_already_exists() { #[test] fn test_burn_fungible_asset_succeeds() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN_1, nonce: ONE, @@ -365,15 +349,13 @@ fn test_burn_fungible_asset_succeeds() { expected_final_storage_amount = FUNGIBLE_FAUCET_INITIAL_BALANCE - FUNGIBLE_ASSET_AMOUNT ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } #[test] fn test_burn_fungible_asset_fails_not_faucet_account() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = format!( @@ -390,17 +372,15 @@ fn test_burn_fungible_asset_fails_not_faucet_account() { " ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_burn_fungible_asset_inconsistent_faucet_id() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -423,16 +403,14 @@ fn test_burn_fungible_asset_inconsistent_faucet_id() { ", ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_burn_fungible_asset_insufficient_input_amount() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN_1, nonce: ONE, @@ -456,10 +434,8 @@ fn test_burn_fungible_asset_insufficient_input_amount() { saturating_amount = CONSUMED_ASSET_1_AMOUNT + 1 ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } @@ -471,7 +447,7 @@ fn test_burn_fungible_asset_insufficient_input_amount() { #[ignore] #[test] fn test_burn_non_fungible_asset_succeeds() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::NonFungibleFaucet { acct_id: ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -519,15 +495,13 @@ fn test_burn_non_fungible_asset_succeeds() { non_fungible_asset = prepare_word(&non_fungible_asset_burnt.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } #[test] fn test_burn_non_fungible_asset_fails_does_not_exist() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::NonFungibleFaucet { acct_id: ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -557,17 +531,15 @@ fn test_burn_non_fungible_asset_fails_does_not_exist() { non_fungible_asset = prepare_word(&non_fungible_asset_burnt.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_burn_non_fungible_asset_fails_not_faucet_account() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::StandardExisting, AssetPreservationStatus::TooManyNonFungibleInput, ); @@ -593,17 +565,15 @@ fn test_burn_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = prepare_word(&non_fungible_asset_burnt.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_burn_non_fungible_asset_fails_inconsistent_faucet_id() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::NonFungibleFaucet { acct_id: ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -633,10 +603,8 @@ fn test_burn_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = prepare_word(&non_fungible_asset_burnt.into()) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } @@ -646,7 +614,7 @@ fn test_burn_non_fungible_asset_fails_inconsistent_faucet_id() { #[test] fn test_get_total_issuance_succeeds() { - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs( MockAccountType::FungibleFaucet { acct_id: ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, nonce: ONE, @@ -675,8 +643,6 @@ fn test_get_total_issuance_succeeds() { ", ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } diff --git a/miden-lib/src/tests/test_note.rs b/miden-lib/src/tests/test_note.rs index f11a1feb0..880f16eb6 100644 --- a/miden-lib/src/tests/test_note.rs +++ b/miden-lib/src/tests/test_note.rs @@ -1,20 +1,21 @@ use miden_objects::{notes::Note, transaction::PreparedTransaction, WORD_SIZE}; use mock::{ consumed_note_data_ptr, - mock::{account::MockAccountType, notes::AssetPreservationStatus, transaction::mock_inputs}, + mock::{ + account::MockAccountType, host::MockHost, notes::AssetPreservationStatus, + transaction::mock_inputs, + }, prepare_transaction, procedures::prepare_word, run_tx, }; -use super::{ - build_tx_inputs, AdviceProvider, ContextId, DefaultHost, Felt, Process, ProcessState, ZERO, -}; +use super::{ContextId, Felt, Process, ProcessState, ZERO}; use crate::transaction::memory::CURRENT_CONSUMED_NOTE_PTR; #[test] fn test_get_sender_no_sender() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); // calling get_sender should return sender @@ -34,17 +35,15 @@ fn test_get_sender_no_sender() { end "; - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } #[test] fn test_get_sender() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); // calling get_sender should return sender @@ -61,10 +60,8 @@ fn test_get_sender() { end "; - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction).unwrap(); let sender = transaction.input_notes().get_note(0).note().metadata().sender().into(); assert_eq!(process.stack.get(0), sender); @@ -72,9 +69,11 @@ fn test_get_sender() { #[test] fn test_get_vault_data() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); + let notes = tx_inputs.input_notes(); + // calling get_vault_info should return vault info let code = format!( " @@ -108,22 +107,21 @@ fn test_get_vault_data() { push.{note_1_num_assets} assert_eq end ", - note_0_asset_hash = prepare_word(¬es[0].note().assets().commitment()), - note_0_num_assets = notes[0].note().assets().num_assets(), - note_1_asset_hash = prepare_word(¬es[1].note().assets().commitment()), - note_1_num_assets = notes[1].note().assets().num_assets(), + note_0_asset_hash = prepare_word(¬es.get_note(0).note().assets().commitment()), + note_0_num_assets = notes.get_note(0).note().assets().num_assets(), + note_1_asset_hash = prepare_word(¬es.get_note(1).note().assets().commitment()), + note_1_num_assets = notes.get_note(1).note().assets().num_assets(), ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } #[test] fn test_get_assets() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); + let notes = tx_inputs.input_notes(); const DEST_POINTER_NOTE_0: u32 = 100000000; const DEST_POINTER_NOTE_1: u32 = 200000000; @@ -215,31 +213,21 @@ fn test_get_assets() { call.process_note_1 end ", - note_0_num_assets = notes[0].note().assets().num_assets(), - note_1_num_assets = notes[1].note().assets().num_assets(), - NOTE_0_ASSET_ASSERTIONS = construct_asset_assertions(notes[0].note()), - NOTE_1_ASSET_ASSERTIONS = construct_asset_assertions(notes[1].note()), + note_0_num_assets = notes.get_note(0).note().assets().num_assets(), + note_1_num_assets = notes.get_note(1).note().assets().num_assets(), + NOTE_0_ASSET_ASSERTIONS = construct_asset_assertions(notes.get_note(0).note()), + NOTE_1_ASSET_ASSERTIONS = construct_asset_assertions(notes.get_note(1).note()), ); - let transaction = prepare_transaction( - account, - None, - block_header, - chain, - notes.clone(), - None, - &code, - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } #[test] fn test_get_inputs() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); + let notes = tx_inputs.input_notes(); const DEST_POINTER_NOTE_0: u32 = 100000000; @@ -295,27 +283,16 @@ fn test_get_inputs() { call.process_note_0 end ", - NOTE_1_INPUT_ASSERTIONS = construct_input_assertions(notes[0].note()), + NOTE_1_INPUT_ASSERTIONS = construct_input_assertions(notes.get_note(0).note()), ); - let transaction = prepare_transaction( - account, - None, - block_header, - chain, - notes.clone(), - None, - &code, - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } #[test] fn test_note_setup() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = " @@ -328,19 +305,14 @@ fn test_note_setup() { end "; - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction).unwrap(); note_setup_stack_assertions(&process, &transaction); note_setup_memory_assertions(&process); } -fn note_setup_stack_assertions( - process: &Process>, - inputs: &PreparedTransaction, -) { +fn note_setup_stack_assertions(process: &Process, inputs: &PreparedTransaction) { let mut expected_stack = [ZERO; 16]; // replace the top four elements with the tx script root @@ -352,7 +324,7 @@ fn note_setup_stack_assertions( assert_eq!(process.stack.trace_state(), expected_stack) } -fn note_setup_memory_assertions(process: &Process>) { +fn note_setup_memory_assertions(process: &Process) { // assert that the correct pointer is stored in bookkeeping memory assert_eq!( process.get_mem_value(ContextId::root(), CURRENT_CONSUMED_NOTE_PTR).unwrap()[0], diff --git a/miden-lib/src/tests/test_prologue.rs b/miden-lib/src/tests/test_prologue.rs index 40b5dd63d..484dc65d0 100644 --- a/miden-lib/src/tests/test_prologue.rs +++ b/miden-lib/src/tests/test_prologue.rs @@ -1,16 +1,22 @@ -use assembly::ast::ProgramAst; -use miden_objects::transaction::{PreparedTransaction, TransactionScript}; +use miden_objects::{ + assembly::ProgramAst, + transaction::{PreparedTransaction, TransactionScript}, + Digest, +}; use mock::{ constants::{generate_account_seed, AccountSeedType}, consumed_note_data_ptr, - mock::{account::MockAccountType, notes::AssetPreservationStatus, transaction::mock_inputs}, - prepare_transaction, run_tx, + mock::{ + account::MockAccountType, + host::MockHost, + notes::AssetPreservationStatus, + transaction::{mock_inputs, mock_inputs_with_account_seed}, + }, + prepare_transaction, run_tx, run_tx_with_inputs, }; +use vm_processor::AdviceInputs; -use super::{ - build_module_path, build_tx_inputs, AdviceProvider, ContextId, DefaultHost, Felt, Process, - ProcessState, Word, TX_KERNEL_DIR, ZERO, -}; +use super::{build_module_path, ContextId, Felt, Process, ProcessState, Word, TX_KERNEL_DIR, ZERO}; use crate::transaction::{ memory::{ ACCT_CODE_ROOT_PTR, ACCT_DB_ROOT_PTR, ACCT_ID_AND_NONCE_PTR, ACCT_ID_PTR, @@ -28,7 +34,7 @@ const PROLOGUE_FILE: &str = "prologue.masm"; #[test] fn test_transaction_prologue() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = " @@ -50,19 +56,8 @@ fn test_transaction_prologue() { .unwrap(); let assembly_file = build_module_path(TX_KERNEL_DIR, PROLOGUE_FILE); - let transaction = prepare_transaction( - account, - None, - block_header, - chain, - notes, - Some(tx_script), - code, - "", - Some(assembly_file), - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, Some(tx_script), code, Some(assembly_file)); + let process = run_tx(&transaction).unwrap(); global_input_memory_assertions(&process, &transaction); block_data_memory_assertions(&process, &transaction); @@ -71,10 +66,7 @@ fn test_transaction_prologue() { consumed_notes_memory_assertions(&process, &transaction); } -fn global_input_memory_assertions( - process: &Process>, - inputs: &PreparedTransaction, -) { +fn global_input_memory_assertions(process: &Process, inputs: &PreparedTransaction) { // The block hash should be stored at the BLK_HASH_PTR assert_eq!( process.get_mem_value(ContextId::root(), BLK_HASH_PTR).unwrap(), @@ -112,10 +104,7 @@ fn global_input_memory_assertions( ); } -fn block_data_memory_assertions( - process: &Process>, - inputs: &PreparedTransaction, -) { +fn block_data_memory_assertions(process: &Process, inputs: &PreparedTransaction) { // The block hash should be stored at the BLK_HASH_PTR assert_eq!( process.get_mem_value(ContextId::root(), BLK_HASH_PTR).unwrap(), @@ -183,10 +172,7 @@ fn block_data_memory_assertions( ); } -fn chain_mmr_memory_assertions( - process: &Process>, - inputs: &PreparedTransaction, -) { +fn chain_mmr_memory_assertions(process: &Process, inputs: &PreparedTransaction) { // The number of leaves should be stored at the CHAIN_MMR_NUM_LEAVES_PTR assert_eq!( process.get_mem_value(ContextId::root(), CHAIN_MMR_NUM_LEAVES_PTR).unwrap()[0], @@ -205,10 +191,7 @@ fn chain_mmr_memory_assertions( } } -fn account_data_memory_assertions( - process: &Process>, - inputs: &PreparedTransaction, -) { +fn account_data_memory_assertions(process: &Process, inputs: &PreparedTransaction) { // The account id should be stored at ACCT_ID_AND_NONCE_PTR[0] assert_eq!( process.get_mem_value(ContextId::root(), ACCT_ID_AND_NONCE_PTR).unwrap(), @@ -249,10 +232,7 @@ fn account_data_memory_assertions( } } -fn consumed_notes_memory_assertions( - process: &Process>, - inputs: &PreparedTransaction, -) { +fn consumed_notes_memory_assertions(process: &Process, inputs: &PreparedTransaction) { // The number of consumed notes should be stored at the CONSUMED_NOTES_OFFSET assert_eq!( process.get_mem_value(ContextId::root(), CONSUMED_NOTE_SECTION_OFFSET).unwrap()[0], @@ -337,8 +317,11 @@ fn consumed_notes_memory_assertions( pub fn test_prologue_create_account() { let (_acct_id, account_seed) = generate_account_seed(AccountSeedType::RegularAccountUpdatableCodeOnChain); - let (account, block_header, chain, notes) = - mock_inputs(MockAccountType::StandardNew, AssetPreservationStatus::Preserved); + let tx_inputs = mock_inputs_with_account_seed( + MockAccountType::StandardNew, + AssetPreservationStatus::Preserved, + Some(account_seed), + ); let code = " use.miden::kernels::tx::prologue @@ -347,19 +330,8 @@ pub fn test_prologue_create_account() { end "; - let transaction = prepare_transaction( - account, - Some(account_seed), - block_header, - chain, - notes, - None, - code, - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let _process = run_tx(&transaction).unwrap(); } #[cfg_attr(not(feature = "testing"), ignore)] @@ -367,13 +339,14 @@ pub fn test_prologue_create_account() { pub fn test_prologue_create_account_valid_fungible_faucet_reserved_slot() { let (acct_id, account_seed) = generate_account_seed(AccountSeedType::FungibleFaucetValidInitialBalance); - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs_with_account_seed( MockAccountType::FungibleFaucet { acct_id: acct_id.into(), nonce: ZERO, empty_reserved_slot: true, }, AssetPreservationStatus::Preserved, + Some(account_seed), ); let code = " use.miden::kernels::tx::prologue @@ -383,19 +356,8 @@ pub fn test_prologue_create_account_valid_fungible_faucet_reserved_slot() { end "; - let transaction = prepare_transaction( - account, - Some(account_seed), - block_header, - chain, - notes, - None, - code, - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction); assert!(process.is_ok()); } @@ -405,13 +367,14 @@ pub fn test_prologue_create_account_valid_fungible_faucet_reserved_slot() { pub fn test_prologue_create_account_invalid_fungible_faucet_reserved_slot() { let (acct_id, account_seed) = generate_account_seed(AccountSeedType::FungibleFaucetInvalidInitialBalance); - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs_with_account_seed( MockAccountType::FungibleFaucet { acct_id: acct_id.into(), nonce: ZERO, empty_reserved_slot: false, }, AssetPreservationStatus::Preserved, + Some(account_seed), ); let code = " use.miden::kernels::tx::prologue @@ -421,19 +384,8 @@ pub fn test_prologue_create_account_invalid_fungible_faucet_reserved_slot() { end "; - let transaction = prepare_transaction( - account, - Some(account_seed), - block_header, - chain, - notes, - None, - code, - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } @@ -443,13 +395,14 @@ pub fn test_prologue_create_account_invalid_fungible_faucet_reserved_slot() { pub fn test_prologue_create_account_valid_non_fungible_faucet_reserved_slot() { let (acct_id, account_seed) = generate_account_seed(AccountSeedType::NonFungibleFaucetValidReservedSlot); - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs_with_account_seed( MockAccountType::NonFungibleFaucet { acct_id: acct_id.into(), nonce: ZERO, empty_reserved_slot: true, }, AssetPreservationStatus::Preserved, + Some(account_seed), ); let code = " use.miden::kernels::tx::prologue @@ -459,19 +412,8 @@ pub fn test_prologue_create_account_valid_non_fungible_faucet_reserved_slot() { end "; - let transaction = prepare_transaction( - account, - Some(account_seed), - block_header, - chain, - notes, - None, - code, - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction); assert!(process.is_ok()) } @@ -481,13 +423,14 @@ pub fn test_prologue_create_account_valid_non_fungible_faucet_reserved_slot() { pub fn test_prologue_create_account_invalid_non_fungible_faucet_reserved_slot() { let (acct_id, account_seed) = generate_account_seed(AccountSeedType::NonFungibleFaucetInvalidReservedSlot); - let (account, block_header, chain, notes) = mock_inputs( + let tx_inputs = mock_inputs_with_account_seed( MockAccountType::NonFungibleFaucet { acct_id: acct_id.into(), nonce: ZERO, empty_reserved_slot: false, }, AssetPreservationStatus::Preserved, + Some(account_seed), ); let code = " use.miden::kernels::tx::prologue @@ -497,20 +440,8 @@ pub fn test_prologue_create_account_invalid_non_fungible_faucet_reserved_slot() end "; - let transaction = prepare_transaction( - account, - Some(account_seed), - block_header, - chain, - notes, - None, - code, - "", - None, - ); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - - let process = run_tx(program, stack_inputs, advice_provider); + let transaction = prepare_transaction(tx_inputs, None, code, None); + let process = run_tx(&transaction); assert!(process.is_err()); } @@ -519,9 +450,12 @@ pub fn test_prologue_create_account_invalid_non_fungible_faucet_reserved_slot() pub fn test_prologue_create_account_invalid_seed() { let (_acct_id, account_seed) = generate_account_seed(AccountSeedType::RegularAccountUpdatableCodeOnChain); - let (account, block_header, chain, notes) = - mock_inputs(MockAccountType::StandardNew, AssetPreservationStatus::Preserved); - let account_seed_key = [account.id().into(), ZERO, ZERO, ZERO]; + let tx_inputs = mock_inputs_with_account_seed( + MockAccountType::StandardNew, + AssetPreservationStatus::Preserved, + Some(account_seed), + ); + let account_seed_key = [tx_inputs.account().id().into(), ZERO, ZERO, ZERO]; let code = " use.miden::kernels::tx::prologue @@ -531,31 +465,20 @@ pub fn test_prologue_create_account_invalid_seed() { end "; - let transaction = prepare_transaction( - account, - Some(account_seed), - block_header, - chain, - notes, - None, - code, - "", - None, - ); - let (program, stack_inputs, mut advice_provider) = build_tx_inputs(&transaction); + let transaction = prepare_transaction(tx_inputs, None, code, None); + //let (program, stack_inputs, mut advice_provider) = build_tx_inputs(&transaction); // lets override the seed with an invalid seed to ensure the kernel fails - advice_provider - .insert_into_map(account_seed_key, vec![ZERO, ZERO, ZERO, ZERO]) - .unwrap(); + let adv_inputs = AdviceInputs::default() + .with_map([(Digest::from(account_seed_key).as_bytes(), vec![ZERO; 4])]); - let process = run_tx(program, stack_inputs, &mut advice_provider); + let process = run_tx_with_inputs(&transaction, adv_inputs); assert!(process.is_err()); } #[test] fn test_get_blk_version() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = " use.miden::kernels::tx::memory @@ -567,17 +490,15 @@ fn test_get_blk_version() { end "; - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs.clone(), None, code, None); + let process = run_tx(&transaction).unwrap(); - assert_eq!(process.stack.get(0), block_header.version()); + assert_eq!(process.stack.get(0), tx_inputs.block_header().version()); } #[test] fn test_get_blk_timestamp() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let code = " use.miden::kernels::tx::memory @@ -589,10 +510,8 @@ fn test_get_blk_timestamp() { end "; - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs.clone(), None, code, None); + let process = run_tx(&transaction).unwrap(); - assert_eq!(process.stack.get(0), block_header.timestamp()); + assert_eq!(process.stack.get(0), tx_inputs.block_header().timestamp()); } diff --git a/miden-lib/src/tests/test_tx.rs b/miden-lib/src/tests/test_tx.rs index 68db28b3d..5db64f079 100644 --- a/miden-lib/src/tests/test_tx.rs +++ b/miden-lib/src/tests/test_tx.rs @@ -10,9 +10,7 @@ use mock::{ run_tx, run_within_tx_kernel, }; -use super::{ - build_tx_inputs, ContextId, Felt, MemAdviceProvider, ProcessState, StackInputs, Word, ONE, ZERO, -}; +use super::{ContextId, Felt, MemAdviceProvider, ProcessState, StackInputs, Word, ONE, ZERO}; use crate::transaction::memory::{ CREATED_NOTE_ASSETS_OFFSET, CREATED_NOTE_METADATA_OFFSET, CREATED_NOTE_RECIPIENT_OFFSET, CREATED_NOTE_SECTION_OFFSET, NUM_CREATED_NOTES_PTR, @@ -20,9 +18,9 @@ use crate::transaction::memory::{ #[test] fn test_create_note() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); - let account_id = account.id(); + let account_id = tx_inputs.account().id(); let recipient = [ZERO, ONE, Felt::new(2), Felt::new(3)]; let tag = Felt::new(4); @@ -48,10 +46,8 @@ fn test_create_note() { asset = prepare_word(&asset) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let process = run_tx(&transaction).unwrap(); // assert the number of created notes has been incremented to 1. assert_eq!( @@ -133,13 +129,13 @@ fn test_create_note_too_many_notes() { #[test] fn test_get_output_notes_hash() { - let (account, block_header, chain, notes) = + let tx_inputs = mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); // extract input note data - let input_note_1 = notes.first().unwrap().note(); + let input_note_1 = tx_inputs.input_notes().get_note(0).note(); let input_asset_1 = **input_note_1.assets().iter().take(1).collect::>().first().unwrap(); - let input_note_2 = notes.last().unwrap().note(); + let input_note_2 = tx_inputs.input_notes().get_note(1).note(); let input_asset_2 = **input_note_2.assets().iter().take(1).collect::>().first().unwrap(); // create output note 1 @@ -150,7 +146,7 @@ fn test_get_output_notes_hash() { &[], &[input_asset_1], output_serial_no_1, - account.id(), + tx_inputs.account().id(), output_tag_1, ) .unwrap(); @@ -163,7 +159,7 @@ fn test_get_output_notes_hash() { &[], &[input_asset_2], output_serial_no_2, - account.id(), + tx_inputs.account().id(), output_tag_2, ) .unwrap(); @@ -216,8 +212,6 @@ fn test_get_output_notes_hash() { expected = prepare_word(&expected_output_notes_hash) ); - let transaction = - prepare_transaction(account, None, block_header, chain, notes, None, &code, "", None); - let (program, stack_inputs, advice_provider) = build_tx_inputs(&transaction); - let _process = run_tx(program, stack_inputs, advice_provider).unwrap(); + let transaction = prepare_transaction(tx_inputs, None, &code, None); + let _process = run_tx(&transaction).unwrap(); } diff --git a/miden-lib/src/transaction/errors.rs b/miden-lib/src/transaction/errors.rs index 92c4754f6..51d4401ce 100644 --- a/miden-lib/src/transaction/errors.rs +++ b/miden-lib/src/transaction/errors.rs @@ -1,5 +1,28 @@ use core::fmt; +use super::Digest; + +// TRANSACTION KERNEL ERROR +// ================================================================================================ + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum TransactionKernelError { + UnknownAccountProcedure(Digest), +} + +impl fmt::Display for TransactionKernelError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::UnknownAccountProcedure(proc_root) => { + write!(f, "account procedure with root {proc_root} is not in the advice provider") + }, + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for TransactionKernelError {} + // TRANSACTION EVENT PARSING ERROR // ================================================================================================ diff --git a/miden-lib/src/transaction/events.rs b/miden-lib/src/transaction/events.rs index ccc4572bc..e2ef2d194 100644 --- a/miden-lib/src/transaction/events.rs +++ b/miden-lib/src/transaction/events.rs @@ -17,6 +17,7 @@ use super::TransactionEventParsingError; pub enum TransactionEvent { AddAssetToAccountVault = 0x2_0000, // 131072 RemoveAssetFromAccountVault = 0x2_0001, // 131073 + PushAccountProcedureIndex = 0x2_0002, // 131074 } impl TransactionEvent { @@ -41,6 +42,7 @@ impl TryFrom for TransactionEvent { match value { 0x2_0000 => Ok(TransactionEvent::AddAssetToAccountVault), 0x2_0001 => Ok(TransactionEvent::RemoveAssetFromAccountVault), + 0x2_0002 => Ok(TransactionEvent::PushAccountProcedureIndex), _ => Err(TransactionEventParsingError::InvalidTransactionEvent(value)), } } diff --git a/miden-lib/src/transaction/inputs.rs b/miden-lib/src/transaction/inputs.rs index 456c7c066..606fdc530 100644 --- a/miden-lib/src/transaction/inputs.rs +++ b/miden-lib/src/transaction/inputs.rs @@ -229,13 +229,6 @@ fn add_account_to_advice_inputs( // extend the merkle store with account code tree inputs.extend_merkle_store(code.procedure_tree().inner_nodes()); - // extend advice map with account proc root |-> proc index - inputs.extend_map( - code.procedure_tree() - .leaves() - .map(|(idx, leaf)| (leaf.into_bytes(), vec![idx.into()])), - ); - // --- account seed ------------------------------------------------------- if let Some(account_seed) = account_seed { inputs.extend_map(vec![( diff --git a/miden-lib/src/transaction/mod.rs b/miden-lib/src/transaction/mod.rs index 6ec842a8a..36e419719 100644 --- a/miden-lib/src/transaction/mod.rs +++ b/miden-lib/src/transaction/mod.rs @@ -28,7 +28,7 @@ pub use outputs::{ }; mod errors; -pub use errors::TransactionEventParsingError; +pub use errors::{TransactionEventParsingError, TransactionKernelError}; // TRANSACTION KERNEL // ================================================================================================ diff --git a/miden-tx/src/executor/mod.rs b/miden-tx/src/executor/mod.rs index b59bf6ab8..8cca1268d 100644 --- a/miden-tx/src/executor/mod.rs +++ b/miden-tx/src/executor/mod.rs @@ -144,7 +144,7 @@ impl TransactionExecutor { let (stack_inputs, advice_inputs) = transaction.get_kernel_inputs(); let advice_recorder: RecAdviceProvider = advice_inputs.into(); - let mut host = TransactionHost::new(advice_recorder); + let mut host = TransactionHost::new(transaction.account().into(), advice_recorder); let result = vm_processor::execute( transaction.program(), diff --git a/miden-tx/src/host/account_delta.rs b/miden-tx/src/host/account_delta.rs index 1e1fb6728..207d2f875 100644 --- a/miden-tx/src/host/account_delta.rs +++ b/miden-tx/src/host/account_delta.rs @@ -4,7 +4,7 @@ use miden_objects::{ utils::collections::{btree_map::Entry, BTreeMap}, Digest, }; -use vm_processor::{ExecutionError, HostResponse, ProcessState}; +use vm_processor::{ExecutionError, ProcessState}; // ACCOUNT VAULT DELTA TRACKER // ================================================================================================ @@ -31,10 +31,7 @@ impl AccountVaultDeltaTracker { /// Extracts the asset that is being added to the account's vault from the process state and /// updates the appropriate fungible or non-fungible asset map. - pub fn add_asset( - &mut self, - process: &S, - ) -> Result { + pub fn add_asset(&mut self, process: &S) -> Result<(), ExecutionError> { let asset: Asset = process.get_stack_word(0).try_into().map_err(|err| { ExecutionError::EventError(format!( "Failed to apply account vault delta - asset is malformed - {err}" @@ -54,16 +51,13 @@ impl AccountVaultDeltaTracker { }, }; - Ok(HostResponse::None) + Ok(()) } /// Extracts the asset that is being removed from the account's vault from the process state /// and updates the appropriate [AccountVaultDeltaHandler::fungible_assets] or /// [AccountVaultDeltaHandler::non_fungible_assets] map. - pub fn remove_asset( - &mut self, - process: &S, - ) -> Result { + pub fn remove_asset(&mut self, process: &S) -> Result<(), ExecutionError> { let asset: Asset = process.get_stack_word(0).try_into().map_err(|err| { ExecutionError::EventError(format!( "Failed to apply account vault delta - asset is malformed - {err}" @@ -83,7 +77,7 @@ impl AccountVaultDeltaTracker { }, }; - Ok(HostResponse::None) + Ok(()) } // CONVERSIONS diff --git a/miden-tx/src/host/account_procs.rs b/miden-tx/src/host/account_procs.rs new file mode 100644 index 000000000..21d72c73d --- /dev/null +++ b/miden-tx/src/host/account_procs.rs @@ -0,0 +1,56 @@ +use miden_lib::transaction::TransactionKernelError; +use miden_objects::accounts::AccountCode; + +use super::{AdviceProvider, BTreeMap, Digest, NodeIndex, ProcessState}; + +// ACCOUNT PROCEDURE INDEX MAP +// ================================================================================================ + +/// A map of proc_root |-> proc_index for all known procedures of an account interface. +pub struct AccountProcedureIndexMap(BTreeMap); + +impl AccountProcedureIndexMap { + /// Returns a new [AccountProcedureIndexMap] instantiated with account procedures present in + /// the provided advice provider. + /// + /// This function assumes that the account procedure tree (or a part thereof) is loaded into the + /// Merkle store of the provided advice provider. + pub fn new(account_code_root: Digest, adv_provider: &A) -> Self { + // get the Merkle store with the procedure tree from the advice provider + let proc_store = adv_provider.get_store_subset([account_code_root].iter()); + + // iterate over all possible procedure indexes + let mut result = BTreeMap::new(); + for i in 0..AccountCode::MAX_NUM_PROCEDURES { + let index = NodeIndex::new(AccountCode::PROCEDURE_TREE_DEPTH, i as u64) + .expect("procedure tree index is valid"); + // if the node at the current index does not exist, skip it and try the next node;this + // situation is valid if not all account procedures are loaded into the advice provider + if let Ok(proc_root) = proc_store.get_node(account_code_root, index) { + // if we got an empty digest, this means we got to the end of the procedure list + if proc_root == Digest::default() { + break; + } + result.insert(proc_root, i as u8); + } + } + Self(result) + } + + /// Returns index of the procedure whose root is currently at the top of the operand stack in + /// the provided process. + /// + /// # Errors + /// Returns an error if the procedure at the top of the operand stack is not present in this + /// map. + pub fn get_proc_index( + &self, + process: &S, + ) -> Result { + let proc_root = process.get_stack_word(0).into(); + self.0 + .get(&proc_root) + .cloned() + .ok_or(TransactionKernelError::UnknownAccountProcedure(proc_root)) + } +} diff --git a/miden-tx/src/host/mod.rs b/miden-tx/src/host/mod.rs index 7328fd2ce..5d0a3b0ab 100644 --- a/miden-tx/src/host/mod.rs +++ b/miden-tx/src/host/mod.rs @@ -1,13 +1,20 @@ use miden_lib::transaction::TransactionEvent; -use miden_objects::{accounts::delta::AccountVaultDelta, utils::string::ToString}; +use miden_objects::{ + accounts::{delta::AccountVaultDelta, AccountStub}, + utils::{collections::BTreeMap, string::ToString}, + Digest, +}; use vm_processor::{ - AdviceExtractor, AdviceInjector, AdviceProvider, ContextId, ExecutionError, Host, HostResponse, - ProcessState, + crypto::NodeIndex, AdviceExtractor, AdviceInjector, AdviceProvider, AdviceSource, ContextId, + ExecutionError, Host, HostResponse, ProcessState, }; mod account_delta; use account_delta::AccountVaultDeltaTracker; +mod account_procs; +use account_procs::AccountProcedureIndexMap; + // TRANSACTION HOST // ================================================================================================ @@ -21,14 +28,17 @@ use account_delta::AccountVaultDeltaTracker; pub struct TransactionHost { adv_provider: A, acct_vault_delta_tracker: AccountVaultDeltaTracker, + acct_procedure_index_map: AccountProcedureIndexMap, } impl TransactionHost { /// Returns a new [TransactionHost] instance with the provided [AdviceProvider]. - pub fn new(adv_provider: A) -> Self { + pub fn new(account: AccountStub, adv_provider: A) -> Self { + let proc_index_map = AccountProcedureIndexMap::new(account.code_root(), &adv_provider); Self { adv_provider, acct_vault_delta_tracker: AccountVaultDeltaTracker::default(), + acct_procedure_index_map: proc_index_map, } } @@ -36,6 +46,21 @@ impl TransactionHost { pub fn into_parts(self) -> (A, AccountVaultDelta) { (self.adv_provider, self.acct_vault_delta_tracker.into_vault_delta()) } + + // EVENT HANDLERS + // -------------------------------------------------------------------------------------------- + + fn on_push_account_procedure_index( + &mut self, + process: &S, + ) -> Result<(), ExecutionError> { + let proc_idx = self + .acct_procedure_index_map + .get_proc_index(process) + .map_err(|err| ExecutionError::EventError(err.to_string()))?; + self.adv_provider.push_stack(AdviceSource::Value(proc_idx.into()))?; + Ok(()) + } } impl Host for TransactionHost { @@ -73,6 +98,9 @@ impl Host for TransactionHost { match event { AddAssetToAccountVault => self.acct_vault_delta_tracker.add_asset(process), RemoveAssetFromAccountVault => self.acct_vault_delta_tracker.remove_asset(process), - } + PushAccountProcedureIndex => self.on_push_account_procedure_index(process), + }?; + + Ok(HostResponse::None) } } diff --git a/miden-tx/src/prover/mod.rs b/miden-tx/src/prover/mod.rs index 6967d05a7..96d0711ae 100644 --- a/miden-tx/src/prover/mod.rs +++ b/miden-tx/src/prover/mod.rs @@ -51,7 +51,7 @@ impl TransactionProver { let tx_script_root = tx_witness.tx_script().map(|script| *script.hash()); let advice_provider: MemAdviceProvider = advice_inputs.into(); - let mut host = TransactionHost::new(advice_provider); + let mut host = TransactionHost::new(tx_witness.account().into(), advice_provider); let (stack_outputs, proof) = prove(tx_witness.program(), stack_inputs, &mut host, self.proof_options.clone()) .map_err(TransactionProverError::ProveTransactionProgramFailed)?; diff --git a/miden-tx/src/tests.rs b/miden-tx/src/tests.rs index 46198efc0..2f974ce85 100644 --- a/miden-tx/src/tests.rs +++ b/miden-tx/src/tests.rs @@ -49,7 +49,7 @@ fn test_transaction_executor_witness() { // use the witness to execute the transaction again let (stack_inputs, advice_inputs) = tx_witness.get_kernel_inputs(); let mem_advice_provider: MemAdviceProvider = advice_inputs.into(); - let mut host = TransactionHost::new(mem_advice_provider); + let mut host = TransactionHost::new(tx_witness.account().into(), mem_advice_provider); let result = vm_processor::execute(tx_witness.program(), stack_inputs, &mut host, Default::default()) .unwrap(); @@ -346,13 +346,14 @@ struct MockDataStore { impl MockDataStore { pub fn new(asset_preservation: AssetPreservationStatus) -> Self { - let (account, block_header, block_chain, input_notes) = - mock_inputs(MockAccountType::StandardExisting, asset_preservation); + let (account, _, block_header, block_chain, notes) = + mock_inputs(MockAccountType::StandardExisting, asset_preservation).into_parts(); + Self { account, block_header, block_chain, - notes: input_notes, + notes: notes.into_vec(), } } } diff --git a/miden-tx/tests/common/mod.rs b/miden-tx/tests/common/mod.rs index c54b26ce2..5b54bb287 100644 --- a/miden-tx/tests/common/mod.rs +++ b/miden-tx/tests/common/mod.rs @@ -32,13 +32,14 @@ pub struct MockDataStore { impl MockDataStore { pub fn new() -> Self { - let (account, block_header, block_chain, consumed_notes) = - mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); + let (account, _, block_header, block_chain, notes) = + mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved) + .into_parts(); Self { account, block_header, block_chain, - notes: consumed_notes, + notes: notes.into_vec(), } } diff --git a/mock/src/lib.rs b/mock/src/lib.rs index fa8dbf2c4..912442aaf 100644 --- a/mock/src/lib.rs +++ b/mock/src/lib.rs @@ -1,18 +1,15 @@ use std::{fs::File, io::Read, path::PathBuf}; -use miden_lib::transaction::{memory, TransactionKernel}; +use miden_lib::transaction::{memory, ToTransactionKernelInputs, TransactionKernel}; use miden_objects::{ - accounts::Account, notes::NoteAssets, - transaction::{ - ChainMmr, InputNote, InputNotes, OutputNotes, PreparedTransaction, TransactionInputs, - TransactionScript, - }, - BlockHeader, Felt, StarkField, + transaction::{OutputNotes, PreparedTransaction, TransactionInputs, TransactionScript}, + Felt, StarkField, }; +use mock::host::MockHost; use vm_processor::{ - AdviceProvider, DefaultHost, ExecutionError, ExecutionOptions, Process, Program, StackInputs, - Word, + AdviceInputs, AdviceProvider, DefaultHost, ExecutionError, ExecutionOptions, Host, Process, + StackInputs, Word, }; pub mod builders; @@ -35,18 +32,18 @@ fn load_file_with_code(imports: &str, code: &str, assembly_file: PathBuf) -> Str } /// Inject `code` along side the specified file and run it -pub fn run_tx( - program: Program, - stack_inputs: StackInputs, - mut adv: A, -) -> Result>, ExecutionError> -where - A: AdviceProvider, -{ - // mock account method for testing from root context - adv.insert_into_map(Word::default(), vec![Felt::new(255)]).unwrap(); +pub fn run_tx(tx: &PreparedTransaction) -> Result, ExecutionError> { + run_tx_with_inputs(tx, AdviceInputs::default()) +} - let host = DefaultHost::new(adv); +pub fn run_tx_with_inputs( + tx: &PreparedTransaction, + inputs: AdviceInputs, +) -> Result, ExecutionError> { + let program = tx.program().clone(); + let (stack_inputs, mut advice_inputs) = tx.get_kernel_inputs(); + advice_inputs.extend(inputs); + let host = MockHost::new(tx.account().into(), advice_inputs); let mut process = Process::new(program.kernel().clone(), stack_inputs, host, ExecutionOptions::default()); process.execute(&program)?; @@ -83,41 +80,46 @@ where Ok(process) } +/// Inject `code` along side the specified file and run it +pub fn run_within_host( + imports: &str, + code: &str, + stack_inputs: StackInputs, + host: H, + file_path: Option, +) -> Result, ExecutionError> { + let assembler = TransactionKernel::assembler(); + let code = match file_path { + Some(file_path) => load_file_with_code(imports, code, file_path), + None => format!("{imports}{code}"), + }; + + let program = assembler.compile(code).unwrap(); + let mut process = + Process::new(program.kernel().clone(), stack_inputs, host, ExecutionOptions::default()); + process.execute(&program)?; + Ok(process) +} + // TEST HELPERS // ================================================================================================ pub fn consumed_note_data_ptr(note_idx: u32) -> memory::MemoryAddress { memory::CONSUMED_NOTE_SECTION_OFFSET + (1 + note_idx) * 1024 } -#[allow(clippy::too_many_arguments)] pub fn prepare_transaction( - account: Account, - account_seed: Option, - block_header: BlockHeader, - chain: ChainMmr, - notes: Vec, + tx_inputs: TransactionInputs, tx_script: Option, code: &str, - imports: &str, file_path: Option, ) -> PreparedTransaction { let assembler = TransactionKernel::assembler(); let code = match file_path { - Some(file_path) => load_file_with_code(imports, code, file_path), - None => format!("{imports}{code}"), + Some(file_path) => load_file_with_code("", code, file_path), + None => code.to_string(), }; let program = assembler.compile(code).unwrap(); - - let tx_inputs = TransactionInputs::new( - account, - account_seed, - block_header, - chain, - InputNotes::new(notes).unwrap(), - ) - .unwrap(); - PreparedTransaction::new(program, tx_script, tx_inputs) } diff --git a/mock/src/mock/host/account_procs.rs b/mock/src/mock/host/account_procs.rs new file mode 100644 index 000000000..f5d74e2fa --- /dev/null +++ b/mock/src/mock/host/account_procs.rs @@ -0,0 +1,61 @@ +use miden_lib::transaction::TransactionKernelError; +use miden_objects::accounts::AccountCode; + +use super::{AdviceProvider, BTreeMap, Digest, NodeIndex, ProcessState}; + +// ACCOUNT PROCEDURE INDEX MAP +// ================================================================================================ + +/// A map of proc_root |-> proc_index for all known procedures of an account interface. +pub struct AccountProcedureIndexMap(BTreeMap); + +impl AccountProcedureIndexMap { + /// Returns a new [AccountProcedureIndexMap] instantiated with account procedures present in + /// the provided advice provider. + /// + /// This function assumes that the account procedure tree (or a part thereof) is loaded into the + /// Merkle store of the provided advice provider. + pub fn new(account_code_root: Digest, adv_provider: &A) -> Self { + // get the Merkle store with the procedure tree from the advice provider + let proc_store = adv_provider.get_store_subset([account_code_root].iter()); + + // iterate over all possible procedure indexes + let mut result = BTreeMap::new(); + for i in 0..AccountCode::MAX_NUM_PROCEDURES { + let index = NodeIndex::new(AccountCode::PROCEDURE_TREE_DEPTH, i as u64) + .expect("procedure tree index is valid"); + // if the node at the current index does not exist, skip it and try the next node;this + // situation is valid if not all account procedures are loaded into the advice provider + if let Ok(proc_root) = proc_store.get_node(account_code_root, index) { + // if we got an empty digest, this means we got to the end of the procedure list + if proc_root == Digest::default() { + break; + } + result.insert(proc_root, i as u8); + } + } + Self(result) + } + + /// Returns index of the procedure whose root is currently at the top of the operand stack in + /// the provided process. + /// + /// # Errors + /// Returns an error if the procedure at the top of the operand stack is not present in this + /// map. + pub fn get_proc_index( + &self, + process: &S, + ) -> Result { + let proc_root = process.get_stack_word(0).into(); + // mock account method for testing from root context + // TODO: figure out if we can get rid of this + if proc_root == Digest::default() { + return Ok(255); + } + self.0 + .get(&proc_root) + .cloned() + .ok_or(TransactionKernelError::UnknownAccountProcedure(proc_root)) + } +} diff --git a/mock/src/mock/host/mod.rs b/mock/src/mock/host/mod.rs new file mode 100644 index 000000000..e86d3ce5c --- /dev/null +++ b/mock/src/mock/host/mod.rs @@ -0,0 +1,99 @@ +use miden_lib::transaction::TransactionEvent; +use miden_objects::{ + accounts::{delta::AccountVaultDelta, AccountStub}, + utils::{collections::BTreeMap, string::ToString}, + Digest, +}; +use vm_processor::{ + crypto::NodeIndex, AdviceExtractor, AdviceInjector, AdviceInputs, AdviceProvider, AdviceSource, + ContextId, ExecutionError, Host, HostResponse, MemAdviceProvider, ProcessState, +}; + +mod account_procs; +use account_procs::AccountProcedureIndexMap; + +// MOCK HOST +// ================================================================================================ + +/// This is very similar to the TransactionHost in miden-tx. The differences include: +/// - We do not track account delta here. +/// - There is special handling of EMPTY_DIGEST in account procedure index map. +/// - This host uses `MemAdviceProvider` which is instantiated from the passed in advice inputs. +pub struct MockHost { + adv_provider: MemAdviceProvider, + acct_procedure_index_map: AccountProcedureIndexMap, +} + +impl MockHost { + /// Returns a new [MockHost] instance with the provided [AdviceInputs]. + pub fn new(account: AccountStub, advice_inputs: AdviceInputs) -> Self { + let adv_provider: MemAdviceProvider = advice_inputs.into(); + let proc_index_map = AccountProcedureIndexMap::new(account.code_root(), &adv_provider); + Self { + adv_provider, + acct_procedure_index_map: proc_index_map, + } + } + + /// Consumes this transaction host and returns the advice provider and account vault delta. + pub fn into_parts(self) -> (MemAdviceProvider, AccountVaultDelta) { + (self.adv_provider, AccountVaultDelta::default()) + } + + // EVENT HANDLERS + // -------------------------------------------------------------------------------------------- + + fn on_push_account_procedure_index( + &mut self, + process: &S, + ) -> Result<(), ExecutionError> { + let proc_idx = self + .acct_procedure_index_map + .get_proc_index(process) + .map_err(|err| ExecutionError::EventError(err.to_string()))?; + self.adv_provider.push_stack(AdviceSource::Value(proc_idx.into()))?; + Ok(()) + } +} + +impl Host for MockHost { + fn get_advice( + &mut self, + process: &S, + extractor: AdviceExtractor, + ) -> Result { + self.adv_provider.get_advice(process, &extractor) + } + + fn set_advice( + &mut self, + process: &S, + injector: AdviceInjector, + ) -> Result { + self.adv_provider.set_advice(process, &injector) + } + + fn on_event( + &mut self, + process: &S, + event_id: u32, + ) -> Result { + let event = TransactionEvent::try_from(event_id) + .map_err(|err| ExecutionError::EventError(err.to_string()))?; + + if process.ctx() != ContextId::root() { + return Err(ExecutionError::EventError(format!( + "{event} event can only be emitted from the root context" + ))); + } + + use TransactionEvent::*; + match event { + AddAssetToAccountVault => Ok(()), + RemoveAssetFromAccountVault => Ok(()), + PushAccountProcedureIndex => self.on_push_account_procedure_index(process), + }?; + + Ok(HostResponse::None) + } +} diff --git a/mock/src/mock/mod.rs b/mock/src/mock/mod.rs index 4814faee6..5899f2218 100644 --- a/mock/src/mock/mod.rs +++ b/mock/src/mock/mod.rs @@ -1,6 +1,7 @@ pub mod account; pub mod block; pub mod chain; +pub mod host; pub mod mmr_peaks; pub mod notes; pub mod transaction; diff --git a/mock/src/mock/transaction.rs b/mock/src/mock/transaction.rs index 856c98797..b3b82782f 100644 --- a/mock/src/mock/transaction.rs +++ b/mock/src/mock/transaction.rs @@ -8,7 +8,7 @@ use miden_objects::{ utils::collections::Vec, BlockHeader, Felt, FieldElement, }; -use vm_processor::{AdviceInputs, Operation, Program}; +use vm_processor::{AdviceInputs, Operation, Program, Word}; use super::{ super::TransactionKernel, @@ -24,7 +24,15 @@ use super::{ pub fn mock_inputs( account_type: MockAccountType, asset_preservation: AssetPreservationStatus, -) -> (Account, BlockHeader, ChainMmr, Vec) { +) -> TransactionInputs { + mock_inputs_with_account_seed(account_type, asset_preservation, None) +} + +pub fn mock_inputs_with_account_seed( + account_type: MockAccountType, + asset_preservation: AssetPreservationStatus, + account_seed: Option, +) -> TransactionInputs { // Create assembler and assembler context let assembler = TransactionKernel::assembler(); @@ -51,7 +59,8 @@ pub fn mock_inputs( mock_block_header(4, Some(chain_mmr.peaks().hash_peaks()), None, &[account.clone()]); // Transaction inputs - (account, block_header, chain_mmr, recorded_notes) + let input_notes = InputNotes::new(recorded_notes).unwrap(); + TransactionInputs::new(account, account_seed, block_header, chain_mmr, input_notes).unwrap() } pub fn mock_inputs_with_existing( diff --git a/objects/src/accounts/code.rs b/objects/src/accounts/code.rs index 092be2d20..9e1914547 100644 --- a/objects/src/accounts/code.rs +++ b/objects/src/accounts/code.rs @@ -11,12 +11,6 @@ use crate::crypto::merkle::SimpleSmt; // CONSTANTS // ================================================================================================ -/// The depth of the Merkle tree that is used to commit to the account's public interface. -const ACCOUNT_CODE_TREE_DEPTH: u8 = 8; - -/// The maximum number of account interface procedures. -const MAX_ACCOUNT_PROCEDURES: usize = 2_usize.pow(ACCOUNT_CODE_TREE_DEPTH as u32); - /// Default serialization options for account code AST. const MODULE_SERDE_OPTIONS: AstSerdeOptions = AstSerdeOptions::new(true); @@ -36,6 +30,15 @@ pub struct AccountCode { } impl AccountCode { + // CONSTANTS + // -------------------------------------------------------------------------------------------- + + /// The depth of the Merkle tree that is used to commit to the account's public interface. + pub const PROCEDURE_TREE_DEPTH: u8 = 8; + + /// The maximum number of account interface procedures. + pub const MAX_NUM_PROCEDURES: usize = 2_usize.pow(Self::PROCEDURE_TREE_DEPTH as u32); + // CONSTRUCTOR // -------------------------------------------------------------------------------------------- /// Returns a new definition of an account's interface compiled from the specified source code. @@ -54,9 +57,9 @@ impl AccountCode { // make sure the number of procedures is between 1 and 256 (both inclusive) if procedures.is_empty() { return Err(AccountError::AccountCodeNoProcedures); - } else if procedures.len() > MAX_ACCOUNT_PROCEDURES { + } else if procedures.len() > Self::MAX_NUM_PROCEDURES { return Err(AccountError::AccountCodeTooManyProcedures { - max: MAX_ACCOUNT_PROCEDURES, + max: Self::MAX_NUM_PROCEDURES, actual: procedures.len(), }); } @@ -78,7 +81,7 @@ impl AccountCode { /// Panics if the number of procedures is smaller than 1 or greater than 256. pub fn from_parts(module: ModuleAst, procedures: Vec) -> Self { assert!(!procedures.is_empty(), "no account procedures"); - assert!(procedures.len() <= MAX_ACCOUNT_PROCEDURES, "too many account procedures"); + assert!(procedures.len() <= Self::MAX_NUM_PROCEDURES, "too many account procedures"); Self { procedure_tree: OnceCell::new(), module, @@ -184,7 +187,7 @@ fn build_procedure_tree(procedures: &[Digest]) -> SimpleSmt { }; SimpleSmt::with_leaves( - ACCOUNT_CODE_TREE_DEPTH, + AccountCode::PROCEDURE_TREE_DEPTH, procedures .iter() .enumerate() diff --git a/objects/src/accounts/stub.rs b/objects/src/accounts/stub.rs index 41768c841..d7a156d7e 100644 --- a/objects/src/accounts/stub.rs +++ b/objects/src/accounts/stub.rs @@ -79,13 +79,19 @@ impl AccountStub { } impl From for AccountStub { - fn from(value: Account) -> Self { + fn from(account: Account) -> Self { + (&account).into() + } +} + +impl From<&Account> for AccountStub { + fn from(account: &Account) -> Self { Self { - id: value.id(), - nonce: value.nonce(), - vault_root: value.vault().commitment(), - storage_root: value.storage().root(), - code_root: value.code().root(), + id: account.id(), + nonce: account.nonce(), + vault_root: account.vault().commitment(), + storage_root: account.storage().root(), + code_root: account.code().root(), } } } diff --git a/objects/src/transaction/inputs.rs b/objects/src/transaction/inputs.rs index 62c8e8743..9d7c849c7 100644 --- a/objects/src/transaction/inputs.rs +++ b/objects/src/transaction/inputs.rs @@ -88,6 +88,20 @@ impl TransactionInputs { pub fn input_notes(&self) -> &InputNotes { &self.input_notes } + + // CONVERSIONS + // -------------------------------------------------------------------------------------------- + + /// Consumes these transaction inputs and returns their underlying components. + pub fn into_parts(self) -> (Account, Option, BlockHeader, ChainMmr, InputNotes) { + ( + self.account, + self.account_seed, + self.block_header, + self.block_chain, + self.input_notes, + ) + } } // TO NULLIFIER TRAIT @@ -207,6 +221,14 @@ impl InputNotes { pub fn iter(&self) -> impl Iterator { self.notes.iter() } + + // CONVERSIONS + // -------------------------------------------------------------------------------------------- + + /// Converts self into a vector of input notes. + pub fn into_vec(self) -> Vec { + self.notes + } } impl IntoIterator for InputNotes {