From 8c59e661d3ab190f317132dccb2416f50fd2e56a Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Wed, 19 Mar 2025 01:10:43 -0300 Subject: [PATCH 01/29] refactor: Change way of providing code and inputs to executor --- CHANGELOG.md | 1 + bin/bench-tx/src/main.rs | 34 ++-- crates/miden-objects/src/note/note_tag.rs | 5 +- .../miden-objects/src/testing/account_id.rs | 2 +- crates/miden-tx/src/errors/mod.rs | 4 +- crates/miden-tx/src/executor/data_store.rs | 40 +++-- crates/miden-tx/src/executor/mod.rs | 79 ++++---- crates/miden-tx/src/host/mod.rs | 8 +- .../src/testing/tx_context/builder.rs | 3 +- crates/miden-tx/src/testing/tx_context/mod.rs | 78 ++++---- crates/miden-tx/src/tests/kernel_tests/mod.rs | 13 +- .../src/tests/kernel_tests/test_account.rs | 3 +- .../src/tests/kernel_tests/test_asset.rs | 3 +- .../tests/kernel_tests/test_asset_vault.rs | 3 +- .../src/tests/kernel_tests/test_faucet.rs | 3 +- .../src/tests/kernel_tests/test_note.rs | 35 ++-- .../src/tests/kernel_tests/test_tx.rs | 29 +-- crates/miden-tx/src/tests/mod.rs | 169 ++++++------------ .../tests/integration/scripts/faucet.rs | 6 +- .../tests/integration/scripts/p2id.rs | 6 +- .../tests/integration/scripts/swap.rs | 6 +- 21 files changed, 243 insertions(+), 287 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 552fb8bdb0..1f164a8b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - [BREAKING] Enable timestamp customization on `MockChain::seal_block` (#1208). - [BREAKING] Renamed constants and comments: `OnChain` -> `Public` and `OffChain` -> `Private` (#1218). - [BREAKING] Replace "hash" with "commitment" in `BlockHeader::{prev_hash, chain_root, kernel_root, tx_hash, proof_hash, sub_hash, hash}` (#1209, #1221, #1226). +- [BREAKING] Split `DataStore` API and refactored `TransactionExecutor` API (#1229). ## 0.7.2 (2025-01-28) - `miden-objects` crate only diff --git a/bin/bench-tx/src/main.rs b/bin/bench-tx/src/main.rs index 3b5814b63b..91636f0dd8 100644 --- a/bin/bench-tx/src/main.rs +++ b/bin/bench-tx/src/main.rs @@ -3,6 +3,7 @@ use std::{ fs::{read_to_string, write, File}, io::Write, path::Path, + sync::Arc, }; use miden_lib::{note::create_p2id_note, transaction::TransactionKernel}; @@ -59,6 +60,7 @@ fn main() -> Result<(), String> { // ================================================================================================ /// Runs the default transaction with empty transaction script and two default notes. +#[allow(clippy::arc_with_non_send_sync)] pub fn benchmark_default_tx() -> Result { let tx_context = TransactionContextBuilder::with_standard_account(ONE) .with_mock_notes_preserved() @@ -67,23 +69,20 @@ pub fn benchmark_default_tx() -> Result { let account_id = tx_context.account().id(); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); - + let tx_args = tx_context.tx_args().clone(); + let notes = tx_context.tx_inputs().input_notes().clone(); + let mast_store = tx_context.get_mast_store(); let executor: TransactionExecutor = - TransactionExecutor::new(tx_context.get_data_store(), None).with_tracing(); + TransactionExecutor::new(Arc::new(tx_context), mast_store, None).with_tracing(); let executed_transaction = executor - .execute_transaction(account_id, block_ref, ¬e_ids, tx_context.tx_args().clone()) + .execute_transaction(account_id, block_ref, notes, tx_args) .map_err(|e| e.to_string())?; Ok(executed_transaction.into()) } /// Runs the transaction which consumes a P2ID note into a basic wallet. +#[allow(clippy::arc_with_non_send_sync)] pub fn benchmark_p2id() -> Result { // Create assets let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(); @@ -116,17 +115,14 @@ pub fn benchmark_p2id() -> Result { let tx_context = TransactionContextBuilder::new(target_account.clone()) .input_notes(vec![note.clone()]) .build(); + let block_ref = tx_context.tx_inputs().block_header().block_num(); - let executor = TransactionExecutor::new(tx_context.get_data_store(), Some(falcon_auth.clone())) - .with_tracing(); + let notes = tx_context.tx_inputs().input_notes().clone(); + let mast_store = tx_context.get_mast_store(); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); + let executor = + TransactionExecutor::new(Arc::new(tx_context), mast_store, Some(falcon_auth.clone())) + .with_tracing(); let tx_script_target = TransactionScript::compile(DEFAULT_AUTH_SCRIPT, [], TransactionKernel::assembler()) @@ -135,7 +131,7 @@ pub fn benchmark_p2id() -> Result { // execute transaction let executed_transaction = executor - .execute_transaction(target_account.id(), block_ref, ¬e_ids, tx_args_target) + .execute_transaction(target_account.id(), block_ref, notes, tx_args_target) .unwrap(); Ok(executed_transaction.into()) diff --git a/crates/miden-objects/src/note/note_tag.rs b/crates/miden-objects/src/note/note_tag.rs index 69add07c16..e790e381d5 100644 --- a/crates/miden-objects/src/note/note_tag.rs +++ b/crates/miden-objects/src/note/note_tag.rs @@ -324,7 +324,7 @@ mod tests { ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE_2, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE_ON_2, ACCOUNT_ID_SENDER, + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE_ON_CHAIN_2, ACCOUNT_ID_SENDER, }, NoteError, }; @@ -342,7 +342,8 @@ mod tests { AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap(), AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE_2).unwrap(), AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE).unwrap(), - AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE_ON_2).unwrap(), + AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE_ON_CHAIN_2) + .unwrap(), AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(), AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_1).unwrap(), AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2).unwrap(), diff --git a/crates/miden-objects/src/testing/account_id.rs b/crates/miden-objects/src/testing/account_id.rs index 196f2470c4..74ffdd4ba1 100644 --- a/crates/miden-objects/src/testing/account_id.rs +++ b/crates/miden-objects/src/testing/account_id.rs @@ -37,7 +37,7 @@ pub const ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE: u128 = account_id( AccountStorageMode::Public, 0xacdd_eefc, ); -pub const ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE_ON_2: u128 = account_id( +pub const ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE_ON_CHAIN_2: u128 = account_id( AccountType::RegularAccountUpdatableCode, AccountStorageMode::Public, 0xeeff_ccdd, diff --git a/crates/miden-tx/src/errors/mod.rs b/crates/miden-tx/src/errors/mod.rs index a667fd589e..57d2f6df3a 100644 --- a/crates/miden-tx/src/errors/mod.rs +++ b/crates/miden-tx/src/errors/mod.rs @@ -18,6 +18,8 @@ pub enum TransactionExecutorError { TransactionProgramExecutionFailed(#[source] ExecutionError), #[error("failed to fetch transaction inputs from the data store")] FetchTransactionInputsFailed(#[source] DataStoreError), + #[error("failed to create transaction inputs")] + InvalidTransactionInputs(#[source] TransactionInputError), #[error("input account ID {input_id} does not match output account ID {output_id}")] InconsistentAccountId { input_id: AccountId, @@ -113,8 +115,6 @@ pub enum DataStoreError { AccountNotFound(AccountId), #[error("block with number {0} not found in data store")] BlockNotFound(BlockNumber), - #[error("failed to create transaction inputs")] - InvalidTransactionInput(#[source] TransactionInputError), #[error("note with id {0} is already consumed")] NoteAlreadyConsumed(NoteId), #[error("not with id {0} not found in data store")] diff --git a/crates/miden-tx/src/executor/data_store.rs b/crates/miden-tx/src/executor/data_store.rs index 6d520aaa4b..2e9331a8b4 100644 --- a/crates/miden-tx/src/executor/data_store.rs +++ b/crates/miden-tx/src/executor/data_store.rs @@ -1,9 +1,13 @@ #[cfg(feature = "async")] use alloc::boxed::Box; +use alloc::collections::BTreeSet; use miden_objects::{ - account::AccountId, block::BlockNumber, note::NoteId, transaction::TransactionInputs, + account::{Account, AccountId}, + block::{BlockHeader, BlockNumber}, + transaction::ChainMmr, }; +use vm_processor::Word; use winter_maybe_async::*; use crate::DataStoreError; @@ -15,26 +19,36 @@ use crate::DataStoreError; /// required for transaction execution. #[maybe_async_trait] pub trait DataStore { - /// Returns account, chain, and input note data required to execute a transaction against - /// the account with the specified ID and consuming the set of specified input notes. + /// Returns blockchain-related data required to execute a transaction against a specific + /// account, that consumes specific notes. /// - /// block_ref must be the block number of the block by which all of the input notes have been - /// recorded in the chain. In general, it is recommended that bock_ref corresponds to the - /// latest block available in the data store. + /// The returned [`ChainMmr`] is expected to contain the complete set of requested + /// block numbers (`ref_blocks`). /// /// # Errors /// Returns an error if: - /// - The account with the specified ID could not be found in the data store. /// - The block with the specified number could not be found in the data store. - /// - Any of the notes with the specified IDs could not be found in the data store. - /// - Any of the notes with the specified IDs were already consumed. /// - The combination of specified inputs resulted in a transaction input error. /// - The data store encountered some internal error #[maybe_async] - fn get_transaction_inputs( + fn get_chain_inputs( + &self, + ref_blocks: BTreeSet, + block_header: BlockNumber, + ) -> Result<(ChainMmr, BlockHeader), DataStoreError>; + + /// Returns account data required to execute a transaction. + /// + /// For a new [`Account`], the corresponding seed should be returned as the second element + /// of the return tuple. + /// + /// # Errors + /// Returns an error if: + /// - The account with the specified ID could not be found in the data store. + /// - The data store encountered some internal error. + #[maybe_async] + fn get_account_inputs( &self, account_id: AccountId, - block_ref: BlockNumber, - notes: &[NoteId], - ) -> Result; + ) -> Result<(Account, Option), DataStoreError>; } diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index 357233e656..ddb1fadc36 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -3,14 +3,16 @@ use alloc::{collections::BTreeSet, sync::Arc, vec::Vec}; use miden_lib::transaction::TransactionKernel; use miden_objects::{ account::{AccountCode, AccountId}, - assembly::Library, block::BlockNumber, - note::NoteId, - transaction::{ExecutedTransaction, TransactionArgs, TransactionInputs, TransactionScript}, + note::NoteLocation, + transaction::{ + ExecutedTransaction, InputNote, InputNotes, TransactionArgs, TransactionInputs, + TransactionScript, + }, vm::StackOutputs, Felt, MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES, ZERO, }; -use vm_processor::{AdviceInputs, ExecutionOptions, Process, RecAdviceProvider}; +use vm_processor::{AdviceInputs, ExecutionOptions, MastForestStore, Process, RecAdviceProvider}; use winter_maybe_async::{maybe_async, maybe_await}; use super::{TransactionExecutorError, TransactionHost}; @@ -36,7 +38,7 @@ pub use mast_store::TransactionMastStore; /// [TransactionAuthenticator], allowing it to be used with different backend implementations. pub struct TransactionExecutor { data_store: Arc, - mast_store: Arc, + mast_forest_store: Arc, authenticator: Option>, /// Holds the code of all accounts loaded into this transaction executor via the /// [Self::load_account_code()] method. @@ -52,13 +54,14 @@ impl TransactionExecutor { /// [TransactionAuthenticator]. pub fn new( data_store: Arc, + mast_forest_store: Arc, authenticator: Option>, ) -> Self { const _: () = assert!(MIN_TX_EXECUTION_CYCLES <= MAX_TX_EXECUTION_CYCLES); Self { data_store, - mast_store: Arc::new(TransactionMastStore::new()), + mast_forest_store, authenticator, exec_options: ExecutionOptions::new( Some(MAX_TX_EXECUTION_CYCLES), @@ -91,27 +94,6 @@ impl TransactionExecutor { self } - // STATE MUTATORS - // -------------------------------------------------------------------------------------------- - - /// Loads the provided account code into the internal MAST forest store and adds the commitment - /// of the provided code to the commitments set. - pub fn load_account_code(&mut self, code: &AccountCode) { - // load the code mast forest to the mast store - self.mast_store.load_account_code(code); - - // store the commitment of the foreign account code in the set - self.account_codes.insert(code.clone()); - } - - /// Loads the provided library code into the internal MAST forest store. - /// - /// TODO: this is a work-around to support accounts which were complied with user-defined - /// libraries. Once Miden Assembler supports library vendoring, this should go away. - pub fn load_library(&mut self, library: &Library) { - self.mast_store.insert(library.mast_forest().clone()); - } - // TRANSACTION EXECUTION // -------------------------------------------------------------------------------------------- @@ -130,24 +112,36 @@ impl TransactionExecutor { &self, account_id: AccountId, block_ref: BlockNumber, - notes: &[NoteId], + notes: InputNotes, tx_args: TransactionArgs, ) -> Result { - let tx_inputs = - maybe_await!(self.data_store.get_transaction_inputs(account_id, block_ref, notes)) - .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + // TODO: Check that the reference block is not listed here, or otherwise + // change the DataStore/executor API so that returning a ChainMmr with the reference + // block works anyway. + let ref_blocks: BTreeSet = notes + .iter() + .filter_map(InputNote::location) + .map(NoteLocation::block_num) + .collect(); + + let (account, seed) = maybe_await!(self.data_store.get_account_inputs(account_id)) + .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + + let (mmr, header) = maybe_await!(self.data_store.get_chain_inputs(ref_blocks, block_ref)) + .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + + let tx_inputs = TransactionInputs::new(account, seed, header, mmr, notes) + .map_err(TransactionExecutorError::InvalidTransactionInputs)?; let (stack_inputs, advice_inputs) = TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, None); - let advice_recorder: RecAdviceProvider = advice_inputs.into(); - // load note script MAST into the MAST store - self.mast_store.load_transaction_code(&tx_inputs, &tx_args); + let advice_recorder: RecAdviceProvider = advice_inputs.into(); let mut host = TransactionHost::new( tx_inputs.account().into(), advice_recorder, - self.mast_store.clone(), + self.mast_forest_store.clone(), self.authenticator.clone(), self.account_codes.iter().map(|code| code.commitment()).collect(), ) @@ -202,23 +196,26 @@ impl TransactionExecutor { tx_script: TransactionScript, advice_inputs: AdviceInputs, ) -> Result<[Felt; 16], TransactionExecutorError> { - let tx_inputs = - maybe_await!(self.data_store.get_transaction_inputs(account_id, block_ref, &[])) + let (account, seed) = maybe_await!(self.data_store.get_account_inputs(account_id)) + .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + + let (mmr, header) = + maybe_await!(self.data_store.get_chain_inputs(Default::default(), block_ref)) .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + let tx_inputs = TransactionInputs::new(account, seed, header, mmr, Default::default()) + .map_err(TransactionExecutorError::InvalidTransactionInputs)?; + let tx_args = TransactionArgs::new(Some(tx_script.clone()), None, Default::default()); let (stack_inputs, advice_inputs) = TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_inputs)); let advice_recorder: RecAdviceProvider = advice_inputs.into(); - // load transaction script MAST into the MAST store - self.mast_store.load_transaction_code(&tx_inputs, &tx_args); - let mut host = TransactionHost::new( tx_inputs.account().into(), advice_recorder, - self.mast_store.clone(), + self.mast_forest_store.clone(), self.authenticator.clone(), self.account_codes.iter().map(|code| code.commitment()).collect(), ) diff --git a/crates/miden-tx/src/host/mod.rs b/crates/miden-tx/src/host/mod.rs index 4d0948e7d7..e4e8e0abde 100644 --- a/crates/miden-tx/src/host/mod.rs +++ b/crates/miden-tx/src/host/mod.rs @@ -38,9 +38,7 @@ use note_builder::OutputNoteBuilder; mod tx_progress; pub use tx_progress::TransactionProgress; -use crate::{ - auth::TransactionAuthenticator, errors::TransactionHostError, executor::TransactionMastStore, -}; +use crate::{auth::TransactionAuthenticator, errors::TransactionHostError}; // TRANSACTION HOST // ================================================================================================ @@ -56,7 +54,7 @@ pub struct TransactionHost { adv_provider: A, /// MAST store which contains the code required to execute the transaction. - mast_store: Arc, + mast_store: Arc, /// Account state changes accumulated during transaction execution. /// @@ -98,7 +96,7 @@ impl TransactionHost { pub fn new( account: AccountHeader, adv_provider: A, - mast_store: Arc, + mast_store: Arc, authenticator: Option>, mut account_code_commitments: BTreeSet, ) -> Result { diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index 90ba1c7f12..c92b09589a 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -3,7 +3,7 @@ use alloc::{collections::BTreeMap, vec::Vec}; -use miden_lib::transaction::TransactionKernel; +use miden_lib::{transaction::TransactionKernel, utils::word_to_masm_push_string}; use miden_objects::{ account::{Account, AccountCode, AccountId}, assembly::Assembler, @@ -23,7 +23,6 @@ use miden_objects::{ storage::prepare_assets, }, transaction::{OutputNote, TransactionArgs, TransactionInputs, TransactionScript}, - utils::word_to_masm_push_string, vm::AdviceMap, FieldElement, }; diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index af695e65e6..39511366a3 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -1,23 +1,26 @@ #[cfg(feature = "async")] use alloc::boxed::Box; -use alloc::{rc::Rc, sync::Arc, vec::Vec}; +use alloc::{collections::BTreeSet, rc::Rc, sync::Arc, vec::Vec}; use builder::MockAuthenticator; use miden_lib::transaction::TransactionKernel; use miden_objects::{ account::{Account, AccountCode, AccountId}, assembly::Assembler, - block::BlockNumber, - note::{Note, NoteId}, - transaction::{ExecutedTransaction, InputNote, InputNotes, TransactionArgs, TransactionInputs}, + block::{BlockHeader, BlockNumber}, + note::Note, + transaction::{ + ChainMmr, ExecutedTransaction, InputNote, InputNotes, TransactionArgs, TransactionInputs, + }, }; -use vm_processor::{AdviceInputs, ExecutionError, Process}; +use rand_chacha::ChaCha20Rng; +use vm_processor::{AdviceInputs, ExecutionError, Process, Word}; use winter_maybe_async::*; use super::{executor::CodeExecutor, MockHost}; use crate::{ - auth::TransactionAuthenticator, DataStore, DataStoreError, TransactionExecutor, - TransactionExecutorError, TransactionMastStore, + auth::{BasicAuthenticator, TransactionAuthenticator}, + DataStore, DataStoreError, TransactionExecutor, TransactionExecutorError, TransactionMastStore, }; mod builder; @@ -26,11 +29,11 @@ pub use builder::TransactionContextBuilder; // TRANSACTION CONTEXT // ================================================================================================ -#[derive(Clone)] /// Represents all needed data for executing a transaction, or arbitrary code. /// /// It implements [DataStore], so transactions may be executed with /// [TransactionExecutor](crate::TransactionExecutor) +#[derive(Clone)] pub struct TransactionContext { expected_output_notes: Vec, tx_args: TransactionArgs, @@ -90,24 +93,23 @@ impl TransactionContext { } /// Executes the transaction through a [TransactionExecutor] + #[allow(clippy::arc_with_non_send_sync)] #[maybe_async] - pub fn execute(self) -> Result { + pub fn execute(&self) -> Result { let account_id = self.account().id(); let block_num = self.tx_inputs().block_header().block_num(); - let notes: Vec = - self.tx_inputs().input_notes().into_iter().map(|n| n.id()).collect(); + let notes = self.tx_inputs().input_notes().clone(); + let tx_args = self.tx_args().clone(); + let mast_forest_store = self.get_mast_store(); let authenticator = self - .authenticator + .authenticator() + .cloned() .map(|auth| Arc::new(auth) as Arc); - let mut tx_executor = TransactionExecutor::new(Arc::new(self.tx_inputs), authenticator); - - for code in self.foreign_codes { - tx_executor.load_account_code(&code); - } - - maybe_await!(tx_executor.execute_transaction(account_id, block_num, ¬es, self.tx_args)) + let tx_executor = + TransactionExecutor::new(Arc::new(self.clone()), mast_forest_store, authenticator); + maybe_await!(tx_executor.execute_transaction(account_id, block_num, notes, tx_args)) } pub fn account(&self) -> &Account { @@ -118,6 +120,15 @@ impl TransactionContext { &self.expected_output_notes } + pub fn get_mast_store(&self) -> Arc { + let mast_forest_store = TransactionMastStore::new(); + mast_forest_store.load_transaction_code(self.tx_inputs(), &self.tx_args); + for foreign_code in self.foreign_codes.iter() { + mast_forest_store.insert(foreign_code.mast()); + } + mast_forest_store.into() + } + pub fn tx_args(&self) -> &TransactionArgs { &self.tx_args } @@ -134,24 +145,31 @@ impl TransactionContext { &self.tx_inputs } - pub fn get_data_store(&self) -> Arc { - Arc::new(self.tx_inputs().clone()) + pub fn authenticator(&self) -> Option<&BasicAuthenticator> { + self.authenticator.as_ref() } } #[maybe_async_trait] -impl DataStore for TransactionInputs { +impl DataStore for TransactionContext { + #[maybe_async] + fn get_chain_inputs( + &self, + _ref_blocks: BTreeSet, + _block_header: BlockNumber, + ) -> Result<(ChainMmr, BlockHeader), DataStoreError> { + let mmr = self.tx_inputs.block_chain().clone(); + let block = self.tx_inputs.block_header().clone(); + Ok((mmr, block)) + } + #[maybe_async] - fn get_transaction_inputs( + fn get_account_inputs( &self, account_id: AccountId, - block_num: BlockNumber, - notes: &[NoteId], - ) -> Result { + ) -> Result<(Account, Option), DataStoreError> { assert_eq!(account_id, self.account().id()); - assert_eq!(block_num, self.block_header().block_num()); - assert_eq!(notes.len(), self.input_notes().num_notes()); - - Ok(self.clone()) + let account_seed = self.tx_inputs.account_seed(); + Ok((self.account().clone(), account_seed)) } } diff --git a/crates/miden-tx/src/tests/kernel_tests/mod.rs b/crates/miden-tx/src/tests/kernel_tests/mod.rs index 3338ecc3cc..ac88f1c252 100644 --- a/crates/miden-tx/src/tests/kernel_tests/mod.rs +++ b/crates/miden-tx/src/tests/kernel_tests/mod.rs @@ -1,12 +1,15 @@ use alloc::string::String; -use miden_lib::transaction::memory::{ - NOTE_MEM_SIZE, NUM_OUTPUT_NOTES_PTR, OUTPUT_NOTE_ASSETS_OFFSET, OUTPUT_NOTE_METADATA_OFFSET, - OUTPUT_NOTE_NUM_ASSETS_OFFSET, OUTPUT_NOTE_RECIPIENT_OFFSET, OUTPUT_NOTE_SECTION_OFFSET, +use miden_lib::{ + transaction::memory::{ + NOTE_MEM_SIZE, NUM_OUTPUT_NOTES_PTR, OUTPUT_NOTE_ASSETS_OFFSET, + OUTPUT_NOTE_METADATA_OFFSET, OUTPUT_NOTE_NUM_ASSETS_OFFSET, OUTPUT_NOTE_RECIPIENT_OFFSET, + OUTPUT_NOTE_SECTION_OFFSET, + }, + utils::word_to_masm_push_string, }; use miden_objects::{ - note::Note, testing::storage::prepare_assets, utils::word_to_masm_push_string, vm::StackInputs, - Felt, Hasher, Word, ONE, ZERO, + note::Note, testing::storage::prepare_assets, vm::StackInputs, Felt, Hasher, Word, ONE, ZERO, }; use vm_processor::{ContextId, Process, ProcessState}; diff --git a/crates/miden-tx/src/tests/kernel_tests/test_account.rs b/crates/miden-tx/src/tests/kernel_tests/test_account.rs index 15a6e44d23..61a89c17e4 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_account.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_account.rs @@ -5,6 +5,7 @@ use miden_lib::{ ERR_ACCOUNT_ID_UNKNOWN_VERSION, TX_KERNEL_ERRORS, }, transaction::TransactionKernel, + utils::word_to_masm_push_string, }; use miden_objects::{ account::{ @@ -27,7 +28,7 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; use vm_processor::{Digest, ExecutionError, MemAdviceProvider, ProcessState}; -use super::{word_to_masm_push_string, Felt, StackInputs, Word, ONE, ZERO}; +use super::{Felt, StackInputs, Word, ONE, ZERO}; use crate::testing::{executor::CodeExecutor, TransactionContextBuilder}; // ACCOUNT CODE TESTS diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs index cbfb64fa72..fbc1272dcb 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs @@ -1,3 +1,4 @@ +use miden_lib::utils::word_to_masm_push_string; use miden_objects::{ account::AccountId, asset::NonFungibleAsset, @@ -10,7 +11,7 @@ use miden_objects::{ }; use vm_processor::ProcessState; -use super::{word_to_masm_push_string, Felt, Hasher, Word, ONE}; +use super::{Felt, Hasher, Word, ONE}; use crate::testing::TransactionContextBuilder; #[test] diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs index 05cfbdeb43..9e8a298e82 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs @@ -8,6 +8,7 @@ use miden_lib::{ ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND, }, transaction::memory, + utils::word_to_masm_push_string, }; use miden_objects::{ account::AccountId, @@ -23,7 +24,7 @@ use miden_objects::{ }; use vm_processor::ProcessState; -use super::{word_to_masm_push_string, Felt, Word, ONE, ZERO}; +use super::{Felt, Word, ONE, ZERO}; use crate::{ assert_execution_error, testing::TransactionContextBuilder, tests::kernel_tests::read_root_mem_word, diff --git a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs index b87c085be6..f5e2420c02 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs @@ -8,6 +8,7 @@ use miden_lib::{ ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW, }, transaction::memory::NATIVE_ACCT_STORAGE_SLOTS_SECTION_PTR, + utils::word_to_masm_push_string, }; use miden_objects::{ account::AccountId, @@ -27,7 +28,7 @@ use miden_objects::{ }; use vm_processor::{Felt, ProcessState}; -use super::{word_to_masm_push_string, ONE}; +use super::ONE; use crate::{assert_execution_error, testing::TransactionContextBuilder}; // FUNGIBLE FAUCET MINT TESTS diff --git a/crates/miden-tx/src/tests/kernel_tests/test_note.rs b/crates/miden-tx/src/tests/kernel_tests/test_note.rs index 65a0968006..3f42e21e66 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_note.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_note.rs @@ -3,6 +3,7 @@ use alloc::{collections::BTreeMap, string::String}; use miden_lib::{ errors::tx_kernel_errors::ERR_NOTE_ATTEMPT_TO_ACCESS_NOTE_SENDER_FROM_INCORRECT_CONTEXT, transaction::{memory::CURRENT_INPUT_NOTE_PTR, TransactionKernel}, + utils::word_to_masm_push_string, }; use miden_objects::{ account::AccountId, @@ -15,7 +16,7 @@ use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use vm_processor::{ProcessState, Word, EMPTY_WORD, ONE}; -use super::{word_to_masm_push_string, Felt, Process, ZERO}; +use super::{Felt, Process, ZERO}; use crate::{ assert_execution_error, testing::{ @@ -623,29 +624,29 @@ pub fn test_timelock() { const TIMESTAMP_ERROR: u32 = 123; let code = format!( - " + " use.miden::note use.miden::tx - begin - # store the note inputs to memory starting at address 0 - push.0 exec.note::get_inputs - # => [num_inputs, inputs_ptr] + begin + # store the note inputs to memory starting at address 0 + push.0 exec.note::get_inputs + # => [num_inputs, inputs_ptr] - # make sure the number of inputs is 1 - eq.1 assert.err=789 - # => [inputs_ptr] + # make sure the number of inputs is 1 + eq.1 assert.err=789 + # => [inputs_ptr] - # read the timestamp at which the note can be consumed - mem_load - # => [timestamp] + # read the timestamp at which the note can be consumed + mem_load + # => [timestamp] - exec.tx::get_block_timestamp - # => [block_timestamp, timestamp] + exec.tx::get_block_timestamp + # => [block_timestamp, timestamp] + # ensure block timestamp is newer than timestamp - # ensure block timestamp is newer than timestamp - lte assert.err={TIMESTAMP_ERROR} - # => [] + lte assert.err={TIMESTAMP_ERROR} + # => [] end" ); diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index 4efbe3330b..08b19b08d6 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -16,6 +16,7 @@ use miden_lib::{ }, TransactionKernel, }, + utils::word_to_masm_push_string, }; use miden_objects::{ account::{ @@ -41,12 +42,11 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; use vm_processor::AdviceInputs; -use super::{word_to_masm_push_string, Felt, Process, ProcessState, Word, ONE, ZERO}; +use super::{Felt, Process, ProcessState, Word, ONE, ZERO}; use crate::{ assert_execution_error, testing::{MockChain, TransactionContextBuilder}, tests::kernel_tests::{read_root_mem_word, try_read_root_mem_word}, - TransactionExecutor, }; #[test] @@ -1302,33 +1302,12 @@ fn test_fpi_execute_foreign_procedure() { let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) + .foreign_account_codes(vec![foreign_account.code().clone()]) .advice_inputs(advice_inputs.clone()) .tx_script(tx_script) .build(); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); - - let mut executor = TransactionExecutor::new(tx_context.get_data_store(), None).with_tracing(); - - // load the mast forest of the foreign account's code to be able to create an account procedure - // index map and execute the specified foreign procedure - executor.load_account_code(foreign_account.code()); - - let _executed_transaction = executor - .execute_transaction( - native_account.id(), - block_ref, - ¬e_ids, - tx_context.tx_args().clone(), - ) - .map_err(|e| e.to_string()) - .unwrap(); + let _executed_transaction = tx_context.execute().map_err(|e| e.to_string()).unwrap(); } // HELPER FUNCTIONS diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index 7b7d1be16e..9dd00debd5 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -9,7 +9,7 @@ use ::assembly::{ ast::{Module, ModuleKind}, LibraryPath, }; -use miden_lib::transaction::TransactionKernel; +use miden_lib::{transaction::TransactionKernel, utils::word_to_masm_push_string}; use miden_objects::{ account::{AccountBuilder, AccountComponent, AccountStorage, StorageSlot}, assembly::DefaultSourceManager, @@ -28,8 +28,7 @@ use miden_objects::{ note::DEFAULT_NOTE_CODE, storage::{STORAGE_INDEX_0, STORAGE_INDEX_2}, }, - transaction::{ProvenTransaction, TransactionArgs, TransactionScript}, - utils::word_to_masm_push_string, + transaction::{InputNote, InputNotes, ProvenTransaction, TransactionArgs, TransactionScript}, Felt, Word, MIN_PROOF_SECURITY_LEVEL, }; use miden_prover::ProvingOptions; @@ -57,21 +56,7 @@ fn transaction_executor_witness() { .with_mock_notes_preserved() .build(); - let executor = TransactionExecutor::new(tx_context.get_data_store(), None); - - let account_id = tx_context.account().id(); - - let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); - - let executed_transaction = executor - .execute_transaction(account_id, block_ref, ¬e_ids, tx_context.tx_args().clone()) - .unwrap(); + let executed_transaction = tx_context.execute().unwrap(); let tx_inputs = executed_transaction.tx_inputs(); let tx_args = executed_transaction.tx_args(); @@ -189,8 +174,8 @@ fn executed_transaction_account_delta_new() { " ### note {i} # prepare the stack for a new note creation - push.0.1.2.3 # recipient - push.{EXECUTION_HINT} # note_execution_hint + push.0.1.2.3 # recipient + push.{EXECUTION_HINT} # note_execution_hint push.{NOTETYPE} # note_type push.{aux} # aux push.{tag} # tag @@ -211,7 +196,6 @@ fn executed_transaction_account_delta_new() { # clear the stack dropw dropw dropw dropw - ", EXECUTION_HINT = hints[i], NOTETYPE = note_types[i] as u8, @@ -230,7 +214,7 @@ fn executed_transaction_account_delta_new() { begin ## Update account storage item ## ------------------------------------------------------------------------------------ - # push a new value for the storage slot onto the stack + # push a new value for the storage slot onto the stack push.{UPDATED_SLOT_VALUE} # => [13, 11, 9, 7] @@ -243,7 +227,7 @@ fn executed_transaction_account_delta_new() { ## Update account storage map ## ------------------------------------------------------------------------------------ - # push a new VALUE for the storage map onto the stack + # push a new VALUE for the storage map onto the stack push.{UPDATED_MAP_VALUE} # => [18, 19, 20, 21] @@ -265,7 +249,7 @@ fn executed_transaction_account_delta_new() { ## Update the account nonce ## ------------------------------------------------------------------------------------ - push.1 call.account::incr_nonce drop + push.1 call.account::incr_nonce drop # => [] end ", @@ -292,7 +276,7 @@ fn executed_transaction_account_delta_new() { // expected delta // -------------------------------------------------------------------------------------------- // execute the transaction and get the witness - let executed_transaction = tx_context.clone().execute().unwrap(); + let executed_transaction = tx_context.execute().unwrap(); // nonce delta // -------------------------------------------------------------------------------------------- @@ -360,11 +344,6 @@ fn executed_transaction_account_delta_new() { #[test] fn test_empty_delta_nonce_update() { - let tx_context = TransactionContextBuilder::with_standard_account(ONE).build(); - - let executor = TransactionExecutor::new(tx_context.get_data_store(), None); - let account_id = tx_context.tx_inputs().account().id(); - let tx_script_src = " use.test::account begin @@ -384,25 +363,15 @@ fn test_empty_delta_nonce_update() { TransactionKernel::testing_assembler_with_mock_account(), ) .unwrap(); - let tx_args = TransactionArgs::new( - Some(tx_script), - None, - tx_context.tx_args().advice_inputs().clone().map, - ); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); + let tx_context = TransactionContextBuilder::with_standard_account(ONE) + .tx_script(tx_script) + .build(); // expected delta // -------------------------------------------------------------------------------------------- // execute the transaction and get the witness - let executed_transaction = - executor.execute_transaction(account_id, block_ref, ¬e_ids, tx_args).unwrap(); + let executed_transaction = tx_context.execute().unwrap(); // nonce delta // -------------------------------------------------------------------------------------------- @@ -418,13 +387,6 @@ fn test_empty_delta_nonce_update() { #[test] fn test_send_note_proc() { - let tx_context = TransactionContextBuilder::with_standard_account(ONE) - .with_mock_notes_preserved_with_account_vault_delta() - .build(); - - let executor = TransactionExecutor::new(tx_context.get_data_store(), None).with_debug_mode(); - let account_id = tx_context.tx_inputs().account().id(); - // removed assets let removed_asset_1 = FungibleAsset::mock(FUNGIBLE_ASSET_AMOUNT / 2); let removed_asset_2 = Asset::Fungible( @@ -520,25 +482,17 @@ fn test_send_note_proc() { TransactionKernel::testing_assembler_with_mock_account(), ) .unwrap(); - let tx_args = TransactionArgs::new( - Some(tx_script), - None, - tx_context.tx_args().advice_inputs().clone().map, - ); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); + let tx_context = TransactionContextBuilder::with_standard_account(ONE) + .tx_script(tx_script) + .with_mock_notes_preserved_with_account_vault_delta() + .build(); // expected delta // -------------------------------------------------------------------------------------------- // execute the transaction and get the witness - let executed_transaction = executor - .execute_transaction(account_id, block_ref, ¬e_ids, tx_args) + let executed_transaction = tx_context + .execute() .unwrap_or_else(|_| panic!("test failed in iteration {idx}")); // nonce delta @@ -561,13 +515,16 @@ fn test_send_note_proc() { } #[test] +#[allow(clippy::arc_with_non_send_sync)] fn executed_transaction_output_notes() { let tx_context = TransactionContextBuilder::with_standard_account(ONE) .with_mock_notes_preserved_with_account_vault_delta() .build(); - let executor = TransactionExecutor::new(tx_context.get_data_store(), None).with_debug_mode(); let account_id = tx_context.tx_inputs().account().id(); + let mast_store = tx_context.get_mast_store(); + let executor = + TransactionExecutor::new(Arc::new(tx_context.clone()), mast_store, None).with_debug_mode(); // removed assets let removed_asset_1 = FungibleAsset::mock(FUNGIBLE_ASSET_AMOUNT / 2); @@ -763,19 +720,15 @@ fn executed_transaction_output_notes() { tx_args.add_expected_output_note(&expected_output_note_3); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); + let notes = tx_context.tx_inputs().input_notes().iter().cloned().collect::>(); // expected delta // -------------------------------------------------------------------------------------------- // execute the transaction and get the witness - let executed_transaction = - executor.execute_transaction(account_id, block_ref, ¬e_ids, tx_args).unwrap(); + let executed_transaction = executor + .execute_transaction(account_id, block_ref, InputNotes::new(notes).unwrap(), tx_args) + .unwrap(); // output notes // -------------------------------------------------------------------------------------------- @@ -804,6 +757,7 @@ fn executed_transaction_output_notes() { } #[test] +#[allow(clippy::arc_with_non_send_sync)] fn prove_witness_and_verify() { let tx_context = TransactionContextBuilder::with_standard_account(ONE) .with_mock_notes_preserved() @@ -812,17 +766,12 @@ fn prove_witness_and_verify() { let account_id = tx_context.tx_inputs().account().id(); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); - - let executor = TransactionExecutor::new(tx_context.get_data_store(), None); - let executed_transaction = executor - .execute_transaction(account_id, block_ref, ¬e_ids, tx_context.tx_args().clone()) - .unwrap(); + let notes = tx_context.tx_inputs().input_notes().clone(); + let tx_args = tx_context.tx_args().clone(); + let mast_store = tx_context.get_mast_store(); + let executor = TransactionExecutor::new(Arc::new(tx_context), mast_store, None); + let executed_transaction = + executor.execute_transaction(account_id, block_ref, notes, tx_args).unwrap(); let executed_transaction_id = executed_transaction.id(); let proof_options = ProvingOptions::default(); @@ -842,21 +791,6 @@ fn prove_witness_and_verify() { #[test] fn test_tx_script() { - let tx_context = TransactionContextBuilder::with_standard_account(ONE) - .with_mock_notes_preserved() - .build(); - let executor = TransactionExecutor::new(tx_context.get_data_store(), None); - - let account_id = tx_context.tx_inputs().account().id(); - - let block_ref = tx_context.tx_inputs().block_header().block_num(); - let note_ids = tx_context - .tx_inputs() - .input_notes() - .iter() - .map(|note| note.id()) - .collect::>(); - let tx_script_input_key = [Felt::new(9999), Felt::new(8888), Felt::new(9999), Felt::new(8888)]; let tx_script_input_value = [Felt::new(9), Felt::new(8), Felt::new(7), Felt::new(6)]; let tx_script_src = format!( @@ -882,14 +816,13 @@ fn test_tx_script() { TransactionKernel::testing_assembler(), ) .unwrap(); - let tx_args = TransactionArgs::new( - Some(tx_script), - None, - tx_context.tx_args().advice_inputs().clone().map, - ); - let executed_transaction = - executor.execute_transaction(account_id, block_ref, ¬e_ids, tx_args); + let tx_context = TransactionContextBuilder::with_standard_account(ONE) + .with_mock_notes_preserved() + .tx_script(tx_script) + .build(); + + let executed_transaction = tx_context.execute(); assert!( executed_transaction.is_ok(), @@ -904,6 +837,7 @@ fn test_tx_script() { /// The call chain and dependency graph in this test is: /// `tx script -> account code -> external library` #[test] +#[allow(clippy::arc_with_non_send_sync)] fn transaction_executor_account_code_using_custom_library() { const EXTERNAL_LIBRARY_CODE: &str = " use.miden::account @@ -980,21 +914,25 @@ fn transaction_executor_account_code_using_custom_library() { tx_context.tx_args().advice_inputs().clone().map, ); - let mut executor = TransactionExecutor::new(tx_context.get_data_store(), None); + let account_id = tx_context.account().id(); + let block_ref = tx_context.tx_inputs().block_header().block_num(); + let mast_forest = tx_context.get_mast_store(); // Load the external library into the executor to make it available during transaction // execution. - executor.load_library(&external_library); + mast_forest.insert(external_library.mast_forest().clone()); - let account_id = tx_context.account().id(); - let block_ref = tx_context.tx_inputs().block_header().block_num(); + let executor = TransactionExecutor::new(Arc::new(tx_context), mast_forest, None); - let executed_tx = executor.execute_transaction(account_id, block_ref, &[], tx_args).unwrap(); + let executed_tx = executor + .execute_transaction(account_id, block_ref, InputNotes::::default(), tx_args) + .unwrap(); // Account's initial nonce of 1 should have been incremented by 4. assert_eq!(executed_tx.account_delta().nonce().unwrap(), Felt::new(5)); } #[test] +#[allow(clippy::arc_with_non_send_sync)] fn test_execute_program() { let test_module_source = " export.foo @@ -1031,12 +969,13 @@ fn test_execute_program() { let tx_context = TransactionContextBuilder::with_standard_account(ONE).build(); let account_id = tx_context.account().id(); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let advice_inputs = tx_context.tx_args().advice_inputs(); + let advice_inputs = tx_context.tx_args().advice_inputs().clone(); + let mast_forest = tx_context.get_mast_store(); - let executor = TransactionExecutor::new(tx_context.get_data_store(), None); + let executor = TransactionExecutor::new(Arc::new(tx_context), mast_forest, None); let stack_outputs = executor - .execute_tx_view_script(account_id, block_ref, tx_script, advice_inputs.clone()) + .execute_tx_view_script(account_id, block_ref, tx_script, advice_inputs) .unwrap(); assert_eq!(stack_outputs[..3], [Felt::new(7), Felt::new(2), ONE]); diff --git a/crates/miden-tx/tests/integration/scripts/faucet.rs b/crates/miden-tx/tests/integration/scripts/faucet.rs index c996f83d57..68f3f2ad9d 100644 --- a/crates/miden-tx/tests/integration/scripts/faucet.rs +++ b/crates/miden-tx/tests/integration/scripts/faucet.rs @@ -8,10 +8,12 @@ use miden_objects::{ asset::{Asset, FungibleAsset}, note::{NoteAssets, NoteExecutionHint, NoteId, NoteMetadata, NoteTag, NoteType}, transaction::TransactionScript, - utils::word_to_masm_push_string, Felt, }; -use miden_tx::testing::{Auth, MockChain}; +use miden_tx::{ + testing::{Auth, MockChain}, + utils::word_to_masm_push_string, +}; use crate::{ assert_transaction_executor_error, get_note_with_fungible_asset_and_script, diff --git a/crates/miden-tx/tests/integration/scripts/p2id.rs b/crates/miden-tx/tests/integration/scripts/p2id.rs index 763cf683f8..4c39280904 100644 --- a/crates/miden-tx/tests/integration/scripts/p2id.rs +++ b/crates/miden-tx/tests/integration/scripts/p2id.rs @@ -13,10 +13,12 @@ use miden_objects::{ ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE_2, ACCOUNT_ID_SENDER, }, transaction::{OutputNote, TransactionScript}, - utils::word_to_masm_push_string, Felt, }; -use miden_tx::testing::{Auth, MockChain}; +use miden_tx::{ + testing::{Auth, MockChain}, + utils::word_to_masm_push_string, +}; use crate::{assert_transaction_executor_error, prove_and_verify_transaction}; diff --git a/crates/miden-tx/tests/integration/scripts/swap.rs b/crates/miden-tx/tests/integration/scripts/swap.rs index 2e32327375..46dbe571db 100644 --- a/crates/miden-tx/tests/integration/scripts/swap.rs +++ b/crates/miden-tx/tests/integration/scripts/swap.rs @@ -5,10 +5,12 @@ use miden_objects::{ crypto::rand::RpoRandomCoin, note::{Note, NoteDetails, NoteType}, transaction::{OutputNote, TransactionScript}, - utils::word_to_masm_push_string, Felt, }; -use miden_tx::testing::{Auth, MockChain}; +use miden_tx::{ + testing::{Auth, MockChain}, + utils::word_to_masm_push_string, +}; use crate::prove_and_verify_transaction; From 0a576c0194f10627133b6609a23b44b7249b47c3 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Wed, 19 Mar 2025 15:06:21 -0300 Subject: [PATCH 02/29] test: Fix 3 tests --- crates/miden-tx/README.md | 2 +- crates/miden-tx/src/testing/tx_context/mod.rs | 1 + .../src/tests/kernel_tests/test_tx.rs | 29 ++++++++-- crates/miden-tx/src/tests/mod.rs | 58 +++++++------------ 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/crates/miden-tx/README.md b/crates/miden-tx/README.md index 42c585a750..5681863349 100644 --- a/crates/miden-tx/README.md +++ b/crates/miden-tx/README.md @@ -16,7 +16,7 @@ Once a store is available, a `TransactionExecutor` object can be used to execute ```rust let executor = TransactionExecutor::new(store); -let executed_transaction = executor.execute_transaction(account_id, block_ref, note_ids, tx_args); +let executed_transaction = executor.execute_transaction(account_id, block_ref, notes, tx_args); ``` With the transaction execution done, it is then possible to create a proof: diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index 39511366a3..b07c182a66 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -123,6 +123,7 @@ impl TransactionContext { pub fn get_mast_store(&self) -> Arc { let mast_forest_store = TransactionMastStore::new(); mast_forest_store.load_transaction_code(self.tx_inputs(), &self.tx_args); + mast_forest_store.load_account_code(self.account().code()); for foreign_code in self.foreign_codes.iter() { mast_forest_store.insert(foreign_code.mast()); } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index 08b19b08d6..172919b627 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -1214,12 +1214,12 @@ fn test_fpi_execute_foreign_procedure() { .unwrap() .with_supports_all_types(); - let foreign_account = AccountBuilder::new(ChaCha20Rng::from_entropy().gen()) + let foreign_account = AccountBuilder::new(ChaCha20Rng::from_entropy().random()) .with_component(foreign_account_component) .build_existing() .unwrap(); - let native_account = AccountBuilder::new(ChaCha20Rng::from_entropy().gen()) + let native_account = AccountBuilder::new(ChaCha20Rng::from_entropy().random()) .with_component( AccountMockComponent::new_with_slots(TransactionKernel::testing_assembler(), vec![]) .unwrap(), @@ -1302,12 +1302,33 @@ fn test_fpi_execute_foreign_procedure() { let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) - .foreign_account_codes(vec![foreign_account.code().clone()]) .advice_inputs(advice_inputs.clone()) .tx_script(tx_script) .build(); - let _executed_transaction = tx_context.execute().map_err(|e| e.to_string()).unwrap(); + let block_ref = tx_context.tx_inputs().block_header().block_num(); + let note_ids = tx_context + .tx_inputs() + .input_notes() + .iter() + .map(|note| note.id()) + .collect::>(); + + let mut executor = TransactionExecutor::new(tx_context.get_data_store(), None).with_tracing(); + + // load the mast forest of the foreign account's code to be able to create an account procedure + // index map and execute the specified foreign procedure + executor.load_account_code(foreign_account.code()); + + let _executed_transaction = executor + .execute_transaction( + native_account.id(), + block_ref, + ¬e_ids, + tx_context.tx_args().clone(), + ) + .map_err(|e| e.to_string()) + .unwrap(); } // HELPER FUNCTIONS diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index 9dd00debd5..acbf300cc9 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -9,27 +9,21 @@ use ::assembly::{ ast::{Module, ModuleKind}, LibraryPath, }; -use miden_lib::{transaction::TransactionKernel, utils::word_to_masm_push_string}; +use miden_lib::{account::wallets::BasicWallet, transaction::TransactionKernel, utils::word_to_masm_push_string}; use miden_objects::{ - account::{AccountBuilder, AccountComponent, AccountStorage, StorageSlot}, - assembly::DefaultSourceManager, - asset::{Asset, AssetVault, FungibleAsset, NonFungibleAsset}, - note::{ + account::{Account, AccountBuilder, AccountComponent, AccountStorage, StorageSlot}, assembly::DefaultSourceManager, asset::{Asset, AssetVault, FungibleAsset, NonFungibleAsset}, note::{ Note, NoteAssets, NoteExecutionHint, NoteExecutionMode, NoteHeader, NoteId, NoteInputs, NoteMetadata, NoteRecipient, NoteScript, NoteTag, NoteType, - }, - testing::{ + }, testing::{ account_component::AccountMockComponent, account_id::{ ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, }, constants::{FUNGIBLE_ASSET_AMOUNT, NON_FUNGIBLE_ASSET_DATA}, note::DEFAULT_NOTE_CODE, storage::{STORAGE_INDEX_0, STORAGE_INDEX_2}, - }, - transaction::{InputNote, InputNotes, ProvenTransaction, TransactionArgs, TransactionScript}, - Felt, Word, MIN_PROOF_SECURITY_LEVEL, + }, transaction::{InputNote, InputNotes, OutputNote, ProvenTransaction, TransactionArgs, TransactionScript}, Felt, FieldElement, Word, MIN_PROOF_SECURITY_LEVEL }; use miden_prover::ProvingOptions; use rand::{Rng, SeedableRng}; @@ -517,14 +511,12 @@ fn test_send_note_proc() { #[test] #[allow(clippy::arc_with_non_send_sync)] fn executed_transaction_output_notes() { - let tx_context = TransactionContextBuilder::with_standard_account(ONE) - .with_mock_notes_preserved_with_account_vault_delta() - .build(); - - let account_id = tx_context.tx_inputs().account().id(); - let mast_store = tx_context.get_mast_store(); - let executor = - TransactionExecutor::new(Arc::new(tx_context.clone()), mast_store, None).with_debug_mode(); + let executor_account = Account::mock( + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, + Felt::ONE, + TransactionKernel::testing_assembler(), + ); + let account_id = executor_account.id(); // removed assets let removed_asset_1 = FungibleAsset::mock(FUNGIBLE_ASSET_AMOUNT / 2); @@ -710,25 +702,18 @@ fn executed_transaction_output_notes() { TransactionKernel::testing_assembler_with_mock_account().with_debug_mode(true), ) .unwrap(); - let mut tx_args = TransactionArgs::new( - Some(tx_script), - None, - tx_context.tx_args().advice_inputs().clone().map, - ); - - tx_args.add_expected_output_note(&expected_output_note_2); - tx_args.add_expected_output_note(&expected_output_note_3); - - let block_ref = tx_context.tx_inputs().block_header().block_num(); - let notes = tx_context.tx_inputs().input_notes().iter().cloned().collect::>(); // expected delta // -------------------------------------------------------------------------------------------- // execute the transaction and get the witness - let executed_transaction = executor - .execute_transaction(account_id, block_ref, InputNotes::new(notes).unwrap(), tx_args) - .unwrap(); + let tx_context = TransactionContextBuilder::new(executor_account) + .with_mock_notes_preserved_with_account_vault_delta() + .tx_script(tx_script) + .expected_notes(vec![OutputNote::Full(expected_output_note_2.clone()), OutputNote::Full(expected_output_note_3.clone())]) + .build(); + + let executed_transaction = tx_context.execute().unwrap(); // output notes // -------------------------------------------------------------------------------------------- @@ -897,7 +882,7 @@ fn transaction_executor_account_code_using_custom_library() { .build_existing() .unwrap(); - let tx_context = TransactionContextBuilder::new(native_account).build(); + let tx_context = TransactionContextBuilder::new(native_account.clone()).build(); let tx_script = TransactionScript::compile( tx_script_src, @@ -920,7 +905,8 @@ fn transaction_executor_account_code_using_custom_library() { // Load the external library into the executor to make it available during transaction // execution. mast_forest.insert(external_library.mast_forest().clone()); - + mast_forest.load_transaction_code(tx_context.tx_inputs(), &tx_args); + mast_forest.load_account_code(native_account.code()); let executor = TransactionExecutor::new(Arc::new(tx_context), mast_forest, None); let executed_tx = executor @@ -966,7 +952,7 @@ fn test_execute_program() { let tx_script = TransactionScript::compile(source, [], assembler) .expect("failed to compile the source script"); - let tx_context = TransactionContextBuilder::with_standard_account(ONE).build(); + let tx_context = TransactionContextBuilder::with_standard_account(ONE).tx_script(tx_script.clone()).build(); let account_id = tx_context.account().id(); let block_ref = tx_context.tx_inputs().block_header().block_num(); let advice_inputs = tx_context.tx_args().advice_inputs().clone(); From 017d8fd328a77f0dce2cdaf488882bb0ef8de1d9 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Wed, 2 Apr 2025 14:57:19 -0300 Subject: [PATCH 03/29] Checkpoint --- .../src/transaction/executed_tx.rs | 7 -- .../miden-objects/src/transaction/tx_args.rs | 22 ++++-- .../src/transaction/tx_witness.rs | 9 --- crates/miden-tx/src/executor/data_store.rs | 34 +++------ crates/miden-tx/src/executor/mod.rs | 58 +++------------ .../src/testing/tx_context/builder.rs | 14 +++- crates/miden-tx/src/testing/tx_context/mod.rs | 73 +++++++------------ .../src/tests/kernel_tests/test_tx.rs | 5 +- crates/miden-tx/src/tests/mod.rs | 15 +--- 9 files changed, 78 insertions(+), 159 deletions(-) diff --git a/crates/miden-objects/src/transaction/executed_tx.rs b/crates/miden-objects/src/transaction/executed_tx.rs index d7b2e74191..e2728a4851 100644 --- a/crates/miden-objects/src/transaction/executed_tx.rs +++ b/crates/miden-objects/src/transaction/executed_tx.rs @@ -30,7 +30,6 @@ pub struct ExecutedTransaction { id: OnceCell, tx_inputs: TransactionInputs, tx_outputs: TransactionOutputs, - account_codes: Vec, account_delta: AccountDelta, tx_args: TransactionArgs, advice_witness: AdviceInputs, @@ -48,7 +47,6 @@ impl ExecutedTransaction { pub fn new( tx_inputs: TransactionInputs, tx_outputs: TransactionOutputs, - account_codes: Vec, account_delta: AccountDelta, tx_args: TransactionArgs, advice_witness: AdviceInputs, @@ -61,7 +59,6 @@ impl ExecutedTransaction { id: OnceCell::new(), tx_inputs, tx_outputs, - account_codes, account_delta, tx_args, advice_witness, @@ -150,7 +147,6 @@ impl ExecutedTransaction { tx_inputs: self.tx_inputs, tx_args: self.tx_args, advice_witness: self.advice_witness, - account_codes: self.account_codes, }; (self.account_delta, self.tx_outputs, tx_witness, self.tx_measurements) } @@ -174,7 +170,6 @@ impl Serializable for ExecutedTransaction { fn write_into(&self, target: &mut W) { self.tx_inputs.write_into(target); self.tx_outputs.write_into(target); - self.account_codes.write_into(target); self.account_delta.write_into(target); self.tx_args.write_into(target); self.advice_witness.write_into(target); @@ -186,7 +181,6 @@ impl Deserializable for ExecutedTransaction { fn read_from(source: &mut R) -> Result { let tx_inputs = TransactionInputs::read_from(source)?; let tx_outputs = TransactionOutputs::read_from(source)?; - let account_codes = Vec::::read_from(source)?; let account_delta = AccountDelta::read_from(source)?; let tx_args = TransactionArgs::read_from(source)?; let advice_witness = AdviceInputs::read_from(source)?; @@ -195,7 +189,6 @@ impl Deserializable for ExecutedTransaction { Ok(Self::new( tx_inputs, tx_outputs, - account_codes, account_delta, tx_args, advice_witness, diff --git a/crates/miden-objects/src/transaction/tx_args.rs b/crates/miden-objects/src/transaction/tx_args.rs index dcaa3a7386..d173d0d630 100644 --- a/crates/miden-objects/src/transaction/tx_args.rs +++ b/crates/miden-objects/src/transaction/tx_args.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeSet; + use alloc::{collections::BTreeMap, sync::Arc, vec::Vec}; use assembly::{Assembler, Compile}; @@ -5,10 +7,7 @@ use miden_crypto::merkle::InnerNodeInfo; use super::{Digest, Felt, Word}; use crate::{ - MastForest, MastNodeId, TransactionScriptError, - note::{NoteId, NoteRecipient}, - utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, - vm::{AdviceInputs, AdviceMap, Program}, + account::AccountCode, note::{NoteId, NoteRecipient}, utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, vm::{AdviceInputs, AdviceMap, Program}, MastForest, MastNodeId, TransactionScriptError }; // TRANSACTION ARGS @@ -27,6 +26,7 @@ pub struct TransactionArgs { tx_script: Option, note_args: BTreeMap, advice_inputs: AdviceInputs, + foreign_account_codes: BTreeSet } impl TransactionArgs { @@ -42,6 +42,7 @@ impl TransactionArgs { tx_script: Option, note_args: Option>, advice_map: AdviceMap, + foreign_account_codes: BTreeSet ) -> Self { let mut advice_inputs = AdviceInputs::default().with_map(advice_map); // add transaction script inputs to the advice inputs' map @@ -54,17 +55,18 @@ impl TransactionArgs { tx_script, note_args: note_args.unwrap_or_default(), advice_inputs, + foreign_account_codes } } /// Returns new [TransactionArgs] instantiated with the provided transaction script. pub fn with_tx_script(tx_script: TransactionScript) -> Self { - Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default()) + Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default(),BTreeSet::default()) } /// Returns new [TransactionArgs] instantiated with the provided note arguments. pub fn with_note_args(note_args: BTreeMap) -> Self { - Self::new(None, Some(note_args), AdviceMap::default()) + Self::new(None, Some(note_args), AdviceMap::default(),BTreeSet::default()) } /// Returns the provided [TransactionArgs] with advice inputs extended with the passed-in @@ -150,6 +152,7 @@ impl Serializable for TransactionArgs { self.tx_script.write_into(target); self.note_args.write_into(target); self.advice_inputs.write_into(target); + self.foreign_account_codes.write_into(target); } } @@ -158,8 +161,9 @@ impl Deserializable for TransactionArgs { let tx_script = Option::::read_from(source)?; let note_args = BTreeMap::::read_from(source)?; let advice_inputs = AdviceInputs::read_from(source)?; + let foreign_account_codes = BTreeSet::::read_from(source)?; - Ok(Self { tx_script, note_args, advice_inputs }) + Ok(Self { tx_script, note_args, advice_inputs, foreign_account_codes }) } } @@ -266,6 +270,8 @@ impl Deserializable for TransactionScript { #[cfg(test)] mod tests { + use std::collections::BTreeSet; + use vm_core::{ AdviceMap, utils::{Deserializable, Serializable}, @@ -275,7 +281,7 @@ mod tests { #[test] fn test_tx_args_serialization() { - let args = TransactionArgs::new(None, None, AdviceMap::default()); + let args = TransactionArgs::new(None, None, AdviceMap::default(),BTreeSet::default()); let bytes: std::vec::Vec = args.to_bytes(); let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap(); diff --git a/crates/miden-objects/src/transaction/tx_witness.rs b/crates/miden-objects/src/transaction/tx_witness.rs index 23c7ff1456..2a1af1b2b3 100644 --- a/crates/miden-objects/src/transaction/tx_witness.rs +++ b/crates/miden-objects/src/transaction/tx_witness.rs @@ -22,17 +22,11 @@ use crate::{ /// additional advice data to initialize the advice provide with prior to transaction execution. /// - Advice witness which contains all data requested by the VM from the advice provider while /// executing the transaction program. -/// -/// TODO: currently, the advice witness contains redundant and irrelevant data (e.g., tx inputs -/// and tx outputs; account codes and a subset of that data in advice inputs). -/// We should optimize it to contain only the minimum data required for executing/proving the -/// transaction. #[derive(Clone, Debug, PartialEq, Eq)] pub struct TransactionWitness { pub tx_inputs: TransactionInputs, pub tx_args: TransactionArgs, pub advice_witness: AdviceInputs, - pub account_codes: Vec, } // SERIALIZATION @@ -43,7 +37,6 @@ impl Serializable for TransactionWitness { self.tx_inputs.write_into(target); self.tx_args.write_into(target); self.advice_witness.write_into(target); - self.account_codes.write_into(target); } } @@ -52,12 +45,10 @@ impl Deserializable for TransactionWitness { let tx_inputs = TransactionInputs::read_from(source)?; let tx_args = TransactionArgs::read_from(source)?; let advice_witness = AdviceInputs::read_from(source)?; - let account_codes = >::read_from(source)?; Ok(Self { tx_inputs, tx_args, advice_witness, - account_codes, }) } } diff --git a/crates/miden-tx/src/executor/data_store.rs b/crates/miden-tx/src/executor/data_store.rs index 2e9331a8b4..8b4546d01b 100644 --- a/crates/miden-tx/src/executor/data_store.rs +++ b/crates/miden-tx/src/executor/data_store.rs @@ -7,7 +7,7 @@ use miden_objects::{ block::{BlockHeader, BlockNumber}, transaction::ChainMmr, }; -use vm_processor::Word; +use vm_processor::{MastForestStore, Word}; use winter_maybe_async::*; use crate::DataStoreError; @@ -18,37 +18,23 @@ use crate::DataStoreError; /// The [DataStore] trait defines the interface that transaction objects use to fetch data /// required for transaction execution. #[maybe_async_trait] -pub trait DataStore { - /// Returns blockchain-related data required to execute a transaction against a specific - /// account, that consumes specific notes. +pub trait DataStore: MastForestStore { + /// Returns all the data required to execute a transaction against the account with the specified ID and consuming input notes created in blocks in the input + /// `ref_blocks` set. /// - /// The returned [`ChainMmr`] is expected to contain the complete set of requested - /// block numbers (`ref_blocks`). + /// The highest block number in `ref_blocks` will be the transaction reference block. In general, it is recommended that bock_ref corresponds to the + /// latest block available in the data store. /// /// # Errors /// Returns an error if: + /// - The account with the specified ID could not be found in the data store. /// - The block with the specified number could not be found in the data store. /// - The combination of specified inputs resulted in a transaction input error. /// - The data store encountered some internal error #[maybe_async] - fn get_chain_inputs( - &self, - ref_blocks: BTreeSet, - block_header: BlockNumber, - ) -> Result<(ChainMmr, BlockHeader), DataStoreError>; - - /// Returns account data required to execute a transaction. - /// - /// For a new [`Account`], the corresponding seed should be returned as the second element - /// of the return tuple. - /// - /// # Errors - /// Returns an error if: - /// - The account with the specified ID could not be found in the data store. - /// - The data store encountered some internal error. - #[maybe_async] - fn get_account_inputs( + fn get_transaction_inputs( &self, account_id: AccountId, - ) -> Result<(Account, Option), DataStoreError>; + ref_blocks: BTreeSet, + ) -> Result<(Account, Option, BlockHeader, ChainMmr), DataStoreError>; } diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index d9b1b26e4d..51318a4eaf 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -38,11 +38,7 @@ pub use mast_store::TransactionMastStore; /// [TransactionAuthenticator], allowing it to be used with different backend implementations. pub struct TransactionExecutor { data_store: Arc, - mast_forest_store: Arc, authenticator: Option>, - /// Holds the code of all accounts loaded into this transaction executor via the - /// [Self::load_account_code()] method. - account_codes: BTreeSet, exec_options: ExecutionOptions, } @@ -54,14 +50,12 @@ impl TransactionExecutor { /// [TransactionAuthenticator]. pub fn new( data_store: Arc, - mast_forest_store: Arc, authenticator: Option>, ) -> Self { const _: () = assert!(MIN_TX_EXECUTION_CYCLES <= MAX_TX_EXECUTION_CYCLES); Self { data_store, - mast_forest_store, authenticator, exec_options: ExecutionOptions::new( Some(MAX_TX_EXECUTION_CYCLES), @@ -70,7 +64,6 @@ impl TransactionExecutor { false, ) .expect("Must not fail while max cycles is more than min trace length"), - account_codes: BTreeSet::new(), } } @@ -94,15 +87,6 @@ impl TransactionExecutor { self } - // STATE MUTATORS - // -------------------------------------------------------------------------------------------- - - /// Adds the commitment of the provided code to the commitments set. - pub fn load_account_commitment(&mut self, code: &AccountCode) { - // store the commitment of the foreign account code in the set - self.account_codes.insert(code.clone()); - } - // TRANSACTION EXECUTION // -------------------------------------------------------------------------------------------- @@ -123,20 +107,16 @@ impl TransactionExecutor { block_ref: BlockNumber, notes: InputNotes, tx_args: TransactionArgs, + foreign_account_codes: BTreeSet ) -> Result { - // TODO: Check that the reference block is not listed here, or otherwise - // change the DataStore/executor API so that returning a ChainMmr with the reference - // block works anyway. - let ref_blocks: BTreeSet = notes + let mut ref_blocks: BTreeSet = notes .iter() .filter_map(InputNote::location) .map(NoteLocation::block_num) .collect(); + ref_blocks.insert(block_ref); - let (account, seed) = maybe_await!(self.data_store.get_account_inputs(account_id)) - .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; - - let (mmr, header) = maybe_await!(self.data_store.get_chain_inputs(ref_blocks, block_ref)) + let (account, seed, header, mmr) = maybe_await!(self.data_store.get_transaction_inputs(account_id,ref_blocks)) .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; let tx_inputs = TransactionInputs::new(account, seed, header, mmr, notes) @@ -150,9 +130,9 @@ impl TransactionExecutor { let mut host = TransactionHost::new( tx_inputs.account().into(), advice_recorder, - self.mast_forest_store.clone(), + self.data_store.clone(), self.authenticator.clone(), - self.account_codes.iter().map(|code| code.commitment()).collect(), + foreign_account_codes.iter().map(|code| code.commitment()).collect(), ) .map_err(TransactionExecutorError::TransactionHostCreationFailed)?; @@ -165,24 +145,11 @@ impl TransactionExecutor { ) .map_err(TransactionExecutorError::TransactionProgramExecutionFailed)?; - // Attempt to retrieve used account codes based on the advice map - let account_codes = self - .account_codes - .iter() - .filter_map(|code| { - tx_args - .advice_inputs() - .mapped_values(&code.commitment()) - .and(Some(code.clone())) - }) - .collect(); - build_executed_transaction( tx_args, tx_inputs, result.stack_outputs().clone(), host, - account_codes, ) } @@ -205,13 +172,10 @@ impl TransactionExecutor { tx_script: TransactionScript, advice_inputs: AdviceInputs, ) -> Result<[Felt; 16], TransactionExecutorError> { - let (account, seed) = maybe_await!(self.data_store.get_account_inputs(account_id)) + let ref_blocks = [block_ref].into_iter().collect(); + let (account, seed, header, mmr) = maybe_await!(self.data_store.get_transaction_inputs(account_id,ref_blocks)) .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; - let (mmr, header) = - maybe_await!(self.data_store.get_chain_inputs(Default::default(), block_ref)) - .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; - let tx_inputs = TransactionInputs::new(account, seed, header, mmr, Default::default()) .map_err(TransactionExecutorError::InvalidTransactionInputs)?; @@ -224,9 +188,9 @@ impl TransactionExecutor { let mut host = TransactionHost::new( tx_inputs.account().into(), advice_recorder, - self.mast_forest_store.clone(), + self.data_store.clone(), self.authenticator.clone(), - self.account_codes.iter().map(|code| code.commitment()).collect(), + tx_args..iter().map(|code| code.commitment()).collect(), ) .map_err(TransactionExecutorError::TransactionHostCreationFailed)?; @@ -252,7 +216,6 @@ fn build_executed_transaction( tx_inputs: TransactionInputs, stack_outputs: StackOutputs, host: TransactionHost, - account_codes: Vec, ) -> Result { let (advice_recorder, account_delta, output_notes, generated_signatures, tx_progress) = host.into_parts(); @@ -296,7 +259,6 @@ fn build_executed_transaction( Ok(ExecutedTransaction::new( tx_inputs, tx_outputs, - account_codes, account_delta, tx_args, advice_witness, diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index 1a24cc7258..b5c748dd32 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -31,7 +31,7 @@ use rand_chacha::ChaCha20Rng; use vm_processor::{AdviceInputs, Felt, Word}; use super::TransactionContext; -use crate::{auth::BasicAuthenticator, testing::MockChain}; +use crate::{auth::BasicAuthenticator, testing::MockChain, TransactionMastStore}; pub type MockAuthenticator = BasicAuthenticator; @@ -658,14 +658,24 @@ impl TransactionContextBuilder { tx_args.extend_output_note_recipients(self.expected_output_notes.clone()); + let mast_store = { + let mast_forest_store = TransactionMastStore::new(); + mast_forest_store.load_transaction_code(&tx_inputs, &tx_args); + mast_forest_store.load_account_code(tx_inputs.account().code()); + for foreign_code in self.foreign_account_codes.iter() { + mast_forest_store.load_account_code(foreign_code); + } + mast_forest_store + }; + TransactionContext { expected_output_notes: self.expected_output_notes, tx_args, tx_inputs, + mast_store, authenticator: self.authenticator, advice_inputs: self.advice_inputs, assembler: self.assembler, - foreign_codes: self.foreign_account_codes, } } } diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index f6271536b2..97f5208633 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -5,16 +5,12 @@ use alloc::{collections::BTreeSet, rc::Rc, sync::Arc, vec::Vec}; use builder::MockAuthenticator; use miden_lib::transaction::TransactionKernel; use miden_objects::{ - account::{Account, AccountCode, AccountId}, - assembly::Assembler, - block::{BlockHeader, BlockNumber}, - note::Note, - transaction::{ + account::{Account, AccountCode, AccountId}, assembly::Assembler, block::{BlockHeader, BlockNumber}, note::Note, transaction::{ ChainMmr, ExecutedTransaction, InputNote, InputNotes, TransactionArgs, TransactionInputs, - }, + } }; use rand_chacha::ChaCha20Rng; -use vm_processor::{AdviceInputs, ExecutionError, Process, Word}; +use vm_processor::{AdviceInputs, Digest, ExecutionError, MastForest, MastForestStore, Process, Word}; use winter_maybe_async::*; use super::{MockHost, executor::CodeExecutor}; @@ -33,12 +29,11 @@ pub use builder::TransactionContextBuilder; /// /// It implements [DataStore], so transactions may be executed with /// [TransactionExecutor](crate::TransactionExecutor) -#[derive(Clone)] pub struct TransactionContext { expected_output_notes: Vec, tx_args: TransactionArgs, tx_inputs: TransactionInputs, - foreign_codes: Vec, + mast_store: TransactionMastStore, advice_inputs: AdviceInputs, authenticator: Option, assembler: Assembler, @@ -63,10 +58,8 @@ impl TransactionContext { ); advice_inputs.extend(self.advice_inputs.clone()); - let mast_store = Rc::new(TransactionMastStore::new()); let test_lib = TransactionKernel::kernel_as_library(); - mast_store.insert(test_lib.mast_forest().clone()); let program = self .assembler @@ -74,13 +67,12 @@ impl TransactionContext { .with_debug_mode(true) .assemble_program(code) .expect("compilation of the provided code failed"); - mast_store.insert(program.mast_forest().clone()); - for code in &self.foreign_codes { - mast_store.insert(code.mast()); - } + let mast_store = Rc::new(TransactionMastStore::new()); + mast_store.insert(program.mast_forest().clone()); mast_store.load_transaction_code(&self.tx_inputs, &self.tx_args); + mast_store.insert(test_lib.mast_forest().clone()); CodeExecutor::new(MockHost::new( self.tx_inputs.account().into(), @@ -95,24 +87,25 @@ impl TransactionContext { /// Executes the transaction through a [TransactionExecutor] #[allow(clippy::arc_with_non_send_sync)] #[maybe_async] - pub fn execute(&self) -> Result { + pub fn execute(self) -> Result { let account_id = self.account().id(); let block_num = self.tx_inputs().block_header().block_num(); let notes = self.tx_inputs().input_notes().clone(); let tx_args = self.tx_args().clone(); - let mast_forest_store = self.get_mast_store(); let authenticator = self .authenticator() .cloned() .map(|auth| Arc::new(auth) as Arc); + + // for foreign_code in self.foreign_codes.iter() { + // tx_executor.load_account_commitment(foreign_code); + // } + + let tx_executor = + TransactionExecutor::new(Arc::new(self), authenticator); - let mut tx_executor = - TransactionExecutor::new(Arc::new(self.clone()), mast_forest_store, authenticator); - for foreign_code in self.foreign_codes.iter() { - tx_executor.load_account_commitment(foreign_code); - } maybe_await!(tx_executor.execute_transaction(account_id, block_num, notes, tx_args)) } @@ -124,16 +117,6 @@ impl TransactionContext { &self.expected_output_notes } - pub fn get_mast_store(&self) -> Arc { - let mast_forest_store = TransactionMastStore::new(); - mast_forest_store.load_transaction_code(self.tx_inputs(), &self.tx_args); - mast_forest_store.load_account_code(self.account().code()); - for foreign_code in self.foreign_codes.iter() { - mast_forest_store.load_account_code(foreign_code); - } - mast_forest_store.into() - } - pub fn tx_args(&self) -> &TransactionArgs { &self.tx_args } @@ -158,23 +141,21 @@ impl TransactionContext { #[maybe_async_trait] impl DataStore for TransactionContext { #[maybe_async] - fn get_chain_inputs( + fn get_transaction_inputs( &self, + account_id: AccountId, _ref_blocks: BTreeSet, - _block_header: BlockNumber, - ) -> Result<(ChainMmr, BlockHeader), DataStoreError> { - let mmr = self.tx_inputs.block_chain().clone(); - let block = self.tx_inputs.block_header().clone(); - Ok((mmr, block)) + ) -> Result<(Account, Option, BlockHeader, ChainMmr), DataStoreError> { + assert_eq!(account_id, self.account().id()); + let (account, seed, header, mmr, _) = + self.tx_inputs.clone().into_parts().clone(); + + Ok((account, seed, header, mmr)) } +} - #[maybe_async] - fn get_account_inputs( - &self, - account_id: AccountId, - ) -> Result<(Account, Option), DataStoreError> { - assert_eq!(account_id, self.account().id()); - let account_seed = self.tx_inputs.account_seed(); - Ok((self.account().clone(), account_seed)) +impl MastForestStore for TransactionContext { + fn get(&self, procedure_hash: &Digest) -> Option> { + self.mast_store.get(procedure_hash) } } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index 19e27cd2da..3c97d03c06 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -26,14 +26,11 @@ use miden_objects::{ transaction::{OutputNote, OutputNotes}, }; -use super::{Felt, ONE, Process, ProcessState, Word, ZERO}; -use super::{Felt, ONE, ProcessState, Word, ZERO, word_to_masm_push_string}; +use super::{Felt, ONE, Process, ProcessState, Word, ZERO, word_to_masm_push_string}; use crate::{ assert_execution_error, testing::{MockChain, TransactionContextBuilder}, tests::kernel_tests::{read_root_mem_word, try_read_root_mem_word}, - assert_execution_error, testing::TransactionContextBuilder, - tests::kernel_tests::read_root_mem_word, }; #[test] diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index a710cdbbff..a82cb78baf 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -771,8 +771,7 @@ fn prove_witness_and_verify() { let block_ref = tx_context.tx_inputs().block_header().block_num(); let notes = tx_context.tx_inputs().input_notes().clone(); let tx_args = tx_context.tx_args().clone(); - let mast_store = tx_context.get_mast_store(); - let executor = TransactionExecutor::new(Arc::new(tx_context), mast_store, None); + let executor = TransactionExecutor::new(Arc::new(tx_context), None); let executed_transaction = executor.execute_transaction(account_id, block_ref, notes, tx_args).unwrap(); let executed_transaction_id = executed_transaction.id(); @@ -919,13 +918,8 @@ fn transaction_executor_account_code_using_custom_library() { let account_id = tx_context.account().id(); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let mast_forest = tx_context.get_mast_store(); - // Load the external library into the executor to make it available during transaction - // execution. - mast_forest.insert(external_library.mast_forest().clone()); - mast_forest.load_transaction_code(tx_context.tx_inputs(), &tx_args); - mast_forest.load_account_code(native_account.code()); - let executor = TransactionExecutor::new(Arc::new(tx_context), mast_forest, None); + + let executor = TransactionExecutor::new(Arc::new(tx_context), None); let executed_tx = executor .execute_transaction(account_id, block_ref, InputNotes::::default(), tx_args) @@ -976,9 +970,8 @@ fn test_execute_program() { let account_id = tx_context.account().id(); let block_ref = tx_context.tx_inputs().block_header().block_num(); let advice_inputs = tx_context.tx_args().advice_inputs().clone(); - let mast_forest = tx_context.get_mast_store(); - let executor = TransactionExecutor::new(Arc::new(tx_context), mast_forest, None); + let executor = TransactionExecutor::new(Arc::new(tx_context), None); let stack_outputs = executor .execute_tx_view_script(account_id, block_ref, tx_script, advice_inputs) From 7df20d7a11b06bd3f958014448da2bed6962a37e Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 7 Apr 2025 17:22:23 -0300 Subject: [PATCH 04/29] feat: Add ForeignTransactionInputs --- Makefile | 2 +- bin/bench-tx/src/main.rs | 7 +- crates/miden-lib/src/transaction/inputs.rs | 5 + crates/miden-lib/src/transaction/mod.rs | 29 +- .../miden-objects/src/batch/account_update.rs | 6 +- .../miden-objects/src/block/proposed_block.rs | 3 +- crates/miden-objects/src/errors.rs | 4 +- .../src/transaction/executed_tx.rs | 1 - .../miden-objects/src/transaction/inputs.rs | 129 +++++++- crates/miden-objects/src/transaction/mod.rs | 4 +- .../miden-objects/src/transaction/tx_args.rs | 39 ++- .../src/transaction/tx_witness.rs | 13 +- crates/miden-tx/src/executor/data_store.rs | 9 +- crates/miden-tx/src/executor/mast_store.rs | 5 + crates/miden-tx/src/executor/mod.rs | 43 ++- crates/miden-tx/src/prover/mod.rs | 18 +- crates/miden-tx/src/testing/mock_chain/mod.rs | 45 ++- .../src/testing/tx_context/builder.rs | 45 ++- crates/miden-tx/src/testing/tx_context/mod.rs | 36 ++- .../src/tests/kernel_tests/test_fpi.rs | 302 +++++++----------- .../src/tests/kernel_tests/test_note.rs | 5 +- .../src/tests/kernel_tests/test_prologue.rs | 3 +- .../src/tests/kernel_tests/test_tx.rs | 7 +- crates/miden-tx/src/tests/mod.rs | 60 ++-- 24 files changed, 476 insertions(+), 344 deletions(-) diff --git a/Makefile b/Makefile index 0daf7d298f..383be8c585 100644 --- a/Makefile +++ b/Makefile @@ -126,4 +126,4 @@ bench-tx: ## Run transaction benchmarks .PHONY: install-proving-service install-proving-service: ## Install proving service's CLI - $(BUILD_GENERATED_FILES_IN_SRC) cargo install --path bin/proving-service --bin miden-proving-service --locked --features concurrent + $(BUILD_GENERATED_FILES_IN_SRC) cargo install --path bin/proving-service --bin miden-proving-service --features concurrent diff --git a/bin/bench-tx/src/main.rs b/bin/bench-tx/src/main.rs index fbe511c6ae..6b6ece516c 100644 --- a/bin/bench-tx/src/main.rs +++ b/bin/bench-tx/src/main.rs @@ -71,9 +71,8 @@ pub fn benchmark_default_tx() -> Result { let block_ref = tx_context.tx_inputs().block_header().block_num(); let tx_args = tx_context.tx_args().clone(); let notes = tx_context.tx_inputs().input_notes().clone(); - let mast_store = tx_context.get_mast_store(); let executor: TransactionExecutor = - TransactionExecutor::new(Arc::new(tx_context), mast_store, None).with_tracing(); + TransactionExecutor::new(Arc::new(tx_context), None).with_tracing(); let executed_transaction = executor .execute_transaction(account_id, block_ref, notes, tx_args) .map_err(|e| e.to_string())?; @@ -118,11 +117,9 @@ pub fn benchmark_p2id() -> Result { let block_ref = tx_context.tx_inputs().block_header().block_num(); let notes = tx_context.tx_inputs().input_notes().clone(); - let mast_store = tx_context.get_mast_store(); let executor = - TransactionExecutor::new(Arc::new(tx_context), mast_store, Some(falcon_auth.clone())) - .with_tracing(); + TransactionExecutor::new(Arc::new(tx_context), Some(falcon_auth.clone())).with_tracing(); let tx_script_target = TransactionScript::compile(DEFAULT_AUTH_SCRIPT, [], TransactionKernel::assembler()) diff --git a/crates/miden-lib/src/transaction/inputs.rs b/crates/miden-lib/src/transaction/inputs.rs index ceb0011aca..de4bfe7c81 100644 --- a/crates/miden-lib/src/transaction/inputs.rs +++ b/crates/miden-lib/src/transaction/inputs.rs @@ -33,6 +33,11 @@ pub(super) fn extend_advice_inputs( add_chain_mmr_to_advice_inputs(tx_inputs.block_chain(), advice_inputs); add_account_to_advice_inputs(tx_inputs.account(), tx_inputs.account_seed(), advice_inputs); add_input_notes_to_advice_inputs(tx_inputs, tx_args, advice_inputs); + for foreign_account in tx_args.foreign_accounts() { + TransactionKernel::extend_advice_inputs_for_account(advice_inputs, foreign_account) + .unwrap(); + } + advice_inputs.extend(tx_args.advice_inputs().clone()); } diff --git a/crates/miden-lib/src/transaction/mod.rs b/crates/miden-lib/src/transaction/mod.rs index 81e7b4f7de..024d0c9401 100644 --- a/crates/miden-lib/src/transaction/mod.rs +++ b/crates/miden-lib/src/transaction/mod.rs @@ -2,12 +2,13 @@ use alloc::{string::ToString, sync::Arc, vec::Vec}; use miden_objects::{ Digest, EMPTY_WORD, Felt, TransactionOutputError, ZERO, - account::{AccountCode, AccountHeader, AccountId, AccountStorageHeader}, + account::{AccountCode, AccountId}, assembly::{Assembler, DefaultSourceManager, KernelLibrary}, block::BlockNumber, - crypto::merkle::{MerkleError, MerklePath}, + crypto::merkle::MerkleError, transaction::{ - OutputNote, OutputNotes, TransactionArgs, TransactionInputs, TransactionOutputs, + ForeignAccountInputs, OutputNote, OutputNotes, TransactionArgs, TransactionInputs, + TransactionOutputs, }, utils::{serde::Deserializable, sync::LazyLock}, vm::{AdviceInputs, AdviceMap, Program, ProgramInfo, StackInputs, StackOutputs}, @@ -199,11 +200,14 @@ impl TransactionKernel { /// account. pub fn extend_advice_inputs_for_account( advice_inputs: &mut AdviceInputs, - account_header: &AccountHeader, - account_code: &AccountCode, - storage_header: &AccountStorageHeader, - merkle_path: &MerklePath, + foreign_account_inputs: &ForeignAccountInputs, ) -> Result<(), MerkleError> { + let account_header = foreign_account_inputs.account_header(); + let storage_header = foreign_account_inputs.storage_header(); + let account_code = foreign_account_inputs.account_code(); + let merkle_path = foreign_account_inputs.merkle_proof(); + let storage_proofs = foreign_account_inputs.storage_map_proofs(); + let account_id = account_header.id(); let storage_root = account_header.storage_commitment(); let code_root = account_header.code_commitment(); @@ -227,6 +231,17 @@ impl TransactionKernel { merkle_path.inner_nodes(account_id.prefix().as_u64(), account_header.commitment())?, ); + // Load merkle nodes for storage maps + for proof in storage_proofs { + // Extend the merkle store and map with the storage maps + advice_inputs.extend_merkle_store( + proof.path().inner_nodes(proof.leaf().index().value(), proof.leaf().hash())?, + ); + // Populate advice map with Sparse Merkle Tree leaf nodes + advice_inputs + .extend_map(core::iter::once((proof.leaf().hash(), proof.leaf().to_elements()))); + } + Ok(()) } diff --git a/crates/miden-objects/src/batch/account_update.rs b/crates/miden-objects/src/batch/account_update.rs index fbde34a7c3..bd5f563e85 100644 --- a/crates/miden-objects/src/batch/account_update.rs +++ b/crates/miden-objects/src/batch/account_update.rs @@ -1,4 +1,4 @@ -use alloc::vec::Vec; +use alloc::{boxed::Box, vec::Vec}; use crate::{ Digest, @@ -117,7 +117,9 @@ impl BatchAccountUpdate { } self.details = self.details.clone().merge(tx.account_update().details().clone()).map_err( - |source_err| BatchAccountUpdateError::TransactionUpdateMergeError(tx.id(), source_err), + |source_err| { + BatchAccountUpdateError::TransactionUpdateMergeError(tx.id(), Box::new(source_err)) + }, )?; self.final_state_commitment = tx.account_update().final_state_commitment(); self.transactions.push(tx.id()); diff --git a/crates/miden-objects/src/block/proposed_block.rs b/crates/miden-objects/src/block/proposed_block.rs index f657f087c9..7d1011090f 100644 --- a/crates/miden-objects/src/block/proposed_block.rs +++ b/crates/miden-objects/src/block/proposed_block.rs @@ -1,4 +1,5 @@ use alloc::{ + boxed::Box, collections::{BTreeMap, BTreeSet}, vec::Vec, }; @@ -676,7 +677,7 @@ impl AccountUpdateAggregator { details = Some(match details { None => update_details, Some(details) => details.merge(update_details).map_err(|source| { - ProposedBlockError::AccountUpdateError { account_id, source } + ProposedBlockError::AccountUpdateError { account_id, source: Box::new(source) } })?, }); } diff --git a/crates/miden-objects/src/errors.rs b/crates/miden-objects/src/errors.rs index 39811d3d8a..e850e629a5 100644 --- a/crates/miden-objects/src/errors.rs +++ b/crates/miden-objects/src/errors.rs @@ -257,7 +257,7 @@ pub enum BatchAccountUpdateError { )] AccountUpdateInitialStateMismatch(TransactionId), #[error("failed to merge account delta from transaction {0}")] - TransactionUpdateMergeError(TransactionId, #[source] AccountDeltaError), + TransactionUpdateMergeError(TransactionId, #[source] Box), } // ASSET ERROR @@ -760,7 +760,7 @@ pub enum ProposedBlockError { #[error("failed to merge transaction delta into account {account_id}")] AccountUpdateError { account_id: AccountId, - source: AccountDeltaError, + source: Box, }, } diff --git a/crates/miden-objects/src/transaction/executed_tx.rs b/crates/miden-objects/src/transaction/executed_tx.rs index e2728a4851..e441787795 100644 --- a/crates/miden-objects/src/transaction/executed_tx.rs +++ b/crates/miden-objects/src/transaction/executed_tx.rs @@ -7,7 +7,6 @@ use super::{ TransactionOutputs, TransactionWitness, }; use crate::{ - account::AccountCode, block::BlockNumber, utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, }; diff --git a/crates/miden-objects/src/transaction/inputs.rs b/crates/miden-objects/src/transaction/inputs.rs index d29d15d38d..a66a512ae5 100644 --- a/crates/miden-objects/src/transaction/inputs.rs +++ b/crates/miden-objects/src/transaction/inputs.rs @@ -1,10 +1,14 @@ use alloc::{collections::BTreeSet, vec::Vec}; use core::fmt::Debug; +use miden_crypto::merkle::{MerklePath, SmtProof}; + use super::{BlockHeader, ChainMmr, Digest, Felt, Hasher, Word}; use crate::{ MAX_INPUT_NOTES_PER_TX, TransactionInputError, - account::{Account, AccountId, AccountIdAnchor}, + account::{ + Account, AccountCode, AccountHeader, AccountId, AccountIdAnchor, AccountStorageHeader, + }, block::BlockNumber, note::{Note, NoteId, NoteInclusionProof, NoteLocation, Nullifier}, utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, @@ -302,7 +306,7 @@ impl Default for InputNotes { } // SERIALIZATION -// ------------------------------------------------------------------------------------------------ +// ================================================================================================ impl Serializable for InputNotes { fn write_into(&self, target: &mut W) { @@ -322,7 +326,7 @@ impl Deserializable for InputNotes(notes: &[T]) -> Digest { // Note: This implementation must be kept in sync with the kernel's `process_input_notes_data` @@ -531,3 +535,122 @@ pub fn validate_account_seed( (false, None) => Ok(()), } } + +// FOREIGN ACCOUNT INPUTS +// ================================================================================================ + +/// Contains information about a foreign account, with everything required to execute its code. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ForeignAccountInputs { + /// Account header of the foreign account. + account_header: AccountHeader, + /// Header information about the account's storage. + storage_header: AccountStorageHeader, + /// Code associated with the account. + account_code: AccountCode, + /// Merkle proof of the account's inclusion in the account tree. + merkle_proof: MerklePath, + /// Storage SMT proof for storage map values that the transaction will access. + storage_map_proofs: Vec, +} + +impl ForeignAccountInputs { + /// Creates a new [`ForeignAccountInputs`] + pub fn new( + account_header: AccountHeader, + storage_header: AccountStorageHeader, + account_code: AccountCode, + merkle_proof: MerklePath, + storage_map_proofs: Vec, + ) -> ForeignAccountInputs { + ForeignAccountInputs { + account_header, + storage_header, + account_code, + merkle_proof, + storage_map_proofs, + } + } + + /// Returns the account's [`AccountId`] + pub fn id(&self) -> AccountId { + self.account_header.id() + } + + /// Returns the account's [`AccountHeader`] + pub fn account_header(&self) -> &AccountHeader { + &self.account_header + } + + /// Returns the account's [`AccountStorageHeader`]. + pub fn storage_header(&self) -> &AccountStorageHeader { + &self.storage_header + } + + /// Returns the account's storage maps. + pub fn storage_map_proofs(&self) -> &[SmtProof] { + &self.storage_map_proofs + } + + /// Returns the account's [`AccountCode`]. + pub fn account_code(&self) -> &AccountCode { + &self.account_code + } + + /// Returns the account's proof. + pub fn merkle_proof(&self) -> &MerklePath { + &self.merkle_proof + } + + /// Extends the storage proofs with the input `smt_proofs` and returns the new structure + #[must_use] + pub fn with_storage_map_proofs( + mut self, + smt_proofs: impl IntoIterator, + ) -> Self { + self.storage_map_proofs.extend(smt_proofs); + self + } + + /// Consumes the [`ForeignAccountInputs`] and returns its parts. + pub fn into_parts( + self, + ) -> (AccountHeader, AccountStorageHeader, AccountCode, MerklePath, Vec) { + ( + self.account_header, + self.storage_header, + self.account_code, + self.merkle_proof, + self.storage_map_proofs, + ) + } +} + +impl Serializable for ForeignAccountInputs { + fn write_into(&self, target: &mut W) { + self.account_header.write_into(target); + self.storage_header.write_into(target); + self.account_code.write_into(target); + self.merkle_proof.write_into(target); + self.storage_map_proofs.write_into(target); + } +} + +impl Deserializable for ForeignAccountInputs { + fn read_from( + source: &mut R, + ) -> Result { + let account_header = AccountHeader::read_from(source)?; + let storage_header = AccountStorageHeader::read_from(source)?; + let account_code = AccountCode::read_from(source)?; + let merkle_proof = MerklePath::read_from(source)?; + let storage_maps = Vec::::read_from(source)?; + Ok(ForeignAccountInputs::new( + account_header, + storage_header, + account_code, + merkle_proof, + storage_maps, + )) + } +} diff --git a/crates/miden-objects/src/transaction/mod.rs b/crates/miden-objects/src/transaction/mod.rs index fc1302be40..51e3a2338d 100644 --- a/crates/miden-objects/src/transaction/mod.rs +++ b/crates/miden-objects/src/transaction/mod.rs @@ -17,7 +17,9 @@ mod tx_witness; pub use chain_mmr::ChainMmr; pub use executed_tx::{ExecutedTransaction, TransactionMeasurements}; -pub use inputs::{InputNote, InputNotes, ToInputNoteCommitments, TransactionInputs}; +pub use inputs::{ + ForeignAccountInputs, InputNote, InputNotes, ToInputNoteCommitments, TransactionInputs, +}; pub use outputs::{OutputNote, OutputNotes, TransactionOutputs}; pub use proven_tx::{ InputNoteCommitment, ProvenTransaction, ProvenTransactionBuilder, TxAccountUpdate, diff --git a/crates/miden-objects/src/transaction/tx_args.rs b/crates/miden-objects/src/transaction/tx_args.rs index d173d0d630..b1b416c7af 100644 --- a/crates/miden-objects/src/transaction/tx_args.rs +++ b/crates/miden-objects/src/transaction/tx_args.rs @@ -1,13 +1,14 @@ -use std::collections::BTreeSet; - use alloc::{collections::BTreeMap, sync::Arc, vec::Vec}; use assembly::{Assembler, Compile}; use miden_crypto::merkle::InnerNodeInfo; -use super::{Digest, Felt, Word}; +use super::{Digest, Felt, ForeignAccountInputs, Word}; use crate::{ - account::AccountCode, note::{NoteId, NoteRecipient}, utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, vm::{AdviceInputs, AdviceMap, Program}, MastForest, MastNodeId, TransactionScriptError + MastForest, MastNodeId, TransactionScriptError, + note::{NoteId, NoteRecipient}, + utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, + vm::{AdviceInputs, AdviceMap, Program}, }; // TRANSACTION ARGS @@ -26,7 +27,7 @@ pub struct TransactionArgs { tx_script: Option, note_args: BTreeMap, advice_inputs: AdviceInputs, - foreign_account_codes: BTreeSet + foreign_accounts: Vec, } impl TransactionArgs { @@ -42,7 +43,7 @@ impl TransactionArgs { tx_script: Option, note_args: Option>, advice_map: AdviceMap, - foreign_account_codes: BTreeSet + foreign_accounts: Vec, ) -> Self { let mut advice_inputs = AdviceInputs::default().with_map(advice_map); // add transaction script inputs to the advice inputs' map @@ -55,18 +56,18 @@ impl TransactionArgs { tx_script, note_args: note_args.unwrap_or_default(), advice_inputs, - foreign_account_codes + foreign_accounts, } } /// Returns new [TransactionArgs] instantiated with the provided transaction script. pub fn with_tx_script(tx_script: TransactionScript) -> Self { - Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default(),BTreeSet::default()) + Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default(), Vec::default()) } /// Returns new [TransactionArgs] instantiated with the provided note arguments. pub fn with_note_args(note_args: BTreeMap) -> Self { - Self::new(None, Some(note_args), AdviceMap::default(),BTreeSet::default()) + Self::new(None, Some(note_args), AdviceMap::default(), Vec::default()) } /// Returns the provided [TransactionArgs] with advice inputs extended with the passed-in @@ -94,6 +95,11 @@ impl TransactionArgs { &self.advice_inputs } + /// Returns a reference to the foreign account inputs in the transaction args. + pub fn foreign_accounts(&self) -> &[ForeignAccountInputs] { + &self.foreign_accounts + } + // STATE MUTATORS // -------------------------------------------------------------------------------------------- @@ -152,7 +158,7 @@ impl Serializable for TransactionArgs { self.tx_script.write_into(target); self.note_args.write_into(target); self.advice_inputs.write_into(target); - self.foreign_account_codes.write_into(target); + self.foreign_accounts.write_into(target); } } @@ -161,9 +167,14 @@ impl Deserializable for TransactionArgs { let tx_script = Option::::read_from(source)?; let note_args = BTreeMap::::read_from(source)?; let advice_inputs = AdviceInputs::read_from(source)?; - let foreign_account_codes = BTreeSet::::read_from(source)?; + let foreign_accounts = Vec::::read_from(source)?; - Ok(Self { tx_script, note_args, advice_inputs, foreign_account_codes }) + Ok(Self { + tx_script, + note_args, + advice_inputs, + foreign_accounts, + }) } } @@ -270,8 +281,6 @@ impl Deserializable for TransactionScript { #[cfg(test)] mod tests { - use std::collections::BTreeSet; - use vm_core::{ AdviceMap, utils::{Deserializable, Serializable}, @@ -281,7 +290,7 @@ mod tests { #[test] fn test_tx_args_serialization() { - let args = TransactionArgs::new(None, None, AdviceMap::default(),BTreeSet::default()); + let args = TransactionArgs::new(None, None, AdviceMap::default(), std::vec::Vec::default()); let bytes: std::vec::Vec = args.to_bytes(); let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap(); diff --git a/crates/miden-objects/src/transaction/tx_witness.rs b/crates/miden-objects/src/transaction/tx_witness.rs index 2a1af1b2b3..43f6c1c5ed 100644 --- a/crates/miden-objects/src/transaction/tx_witness.rs +++ b/crates/miden-objects/src/transaction/tx_witness.rs @@ -1,10 +1,5 @@ -use alloc::vec::Vec; - use super::{AdviceInputs, TransactionArgs, TransactionInputs}; -use crate::{ - account::AccountCode, - utils::serde::{ByteReader, Deserializable, DeserializationError, Serializable}, -}; +use crate::utils::serde::{ByteReader, Deserializable, DeserializationError, Serializable}; // TRANSACTION WITNESS // ================================================================================================ @@ -45,10 +40,6 @@ impl Deserializable for TransactionWitness { let tx_inputs = TransactionInputs::read_from(source)?; let tx_args = TransactionArgs::read_from(source)?; let advice_witness = AdviceInputs::read_from(source)?; - Ok(Self { - tx_inputs, - tx_args, - advice_witness, - }) + Ok(Self { tx_inputs, tx_args, advice_witness }) } } diff --git a/crates/miden-tx/src/executor/data_store.rs b/crates/miden-tx/src/executor/data_store.rs index 8b4546d01b..73ec9740bc 100644 --- a/crates/miden-tx/src/executor/data_store.rs +++ b/crates/miden-tx/src/executor/data_store.rs @@ -19,11 +19,12 @@ use crate::DataStoreError; /// required for transaction execution. #[maybe_async_trait] pub trait DataStore: MastForestStore { - /// Returns all the data required to execute a transaction against the account with the specified ID and consuming input notes created in blocks in the input - /// `ref_blocks` set. + /// Returns all the data required to execute a transaction against the account with the + /// specified ID and consuming input notes created in blocks in the input `ref_blocks` set. /// - /// The highest block number in `ref_blocks` will be the transaction reference block. In general, it is recommended that bock_ref corresponds to the - /// latest block available in the data store. + /// The highest block number in `ref_blocks` will be the transaction reference block. In + /// general, it is recommended that bock_ref corresponds to the latest block available in + /// the data store. /// /// # Errors /// Returns an error if: diff --git a/crates/miden-tx/src/executor/mast_store.rs b/crates/miden-tx/src/executor/mast_store.rs index 1509f94cb4..0f0180ac96 100644 --- a/crates/miden-tx/src/executor/mast_store.rs +++ b/crates/miden-tx/src/executor/mast_store.rs @@ -71,6 +71,11 @@ impl TransactionMastStore { self.insert(note.note().script().mast().clone()); } + // load foreign account's MAST forests + for foreign_account in tx_args.foreign_accounts() { + self.load_account_code(foreign_account.account_code()); + } + // load tx script MAST into the MAST store if let Some(tx_script) = tx_args.tx_script() { self.insert(tx_script.mast().clone()); diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index 51318a4eaf..65720d1a9e 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -1,9 +1,9 @@ -use alloc::{collections::BTreeSet, sync::Arc, vec::Vec}; +use alloc::{collections::BTreeSet, sync::Arc}; use miden_lib::transaction::TransactionKernel; use miden_objects::{ Felt, MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES, ZERO, - account::{AccountCode, AccountId}, + account::AccountId, block::BlockNumber, note::NoteLocation, transaction::{ @@ -12,7 +12,7 @@ use miden_objects::{ }, vm::StackOutputs, }; -use vm_processor::{AdviceInputs, ExecutionOptions, MastForestStore, Process, RecAdviceProvider}; +use vm_processor::{AdviceInputs, ExecutionOptions, Process, RecAdviceProvider}; use winter_maybe_async::{maybe_async, maybe_await}; use super::{TransactionExecutorError, TransactionHost}; @@ -107,7 +107,6 @@ impl TransactionExecutor { block_ref: BlockNumber, notes: InputNotes, tx_args: TransactionArgs, - foreign_account_codes: BTreeSet ) -> Result { let mut ref_blocks: BTreeSet = notes .iter() @@ -116,8 +115,9 @@ impl TransactionExecutor { .collect(); ref_blocks.insert(block_ref); - let (account, seed, header, mmr) = maybe_await!(self.data_store.get_transaction_inputs(account_id,ref_blocks)) - .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + let (account, seed, header, mmr) = + maybe_await!(self.data_store.get_transaction_inputs(account_id, ref_blocks)) + .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; let tx_inputs = TransactionInputs::new(account, seed, header, mmr, notes) .map_err(TransactionExecutorError::InvalidTransactionInputs)?; @@ -132,7 +132,11 @@ impl TransactionExecutor { advice_recorder, self.data_store.clone(), self.authenticator.clone(), - foreign_account_codes.iter().map(|code| code.commitment()).collect(), + tx_args + .foreign_accounts() + .iter() + .map(|acc| acc.account_code().commitment()) + .collect(), ) .map_err(TransactionExecutorError::TransactionHostCreationFailed)?; @@ -145,12 +149,7 @@ impl TransactionExecutor { ) .map_err(TransactionExecutorError::TransactionProgramExecutionFailed)?; - build_executed_transaction( - tx_args, - tx_inputs, - result.stack_outputs().clone(), - host, - ) + build_executed_transaction(tx_args, tx_inputs, result.stack_outputs().clone(), host) } // SCRIPT EXECUTION @@ -173,13 +172,19 @@ impl TransactionExecutor { advice_inputs: AdviceInputs, ) -> Result<[Felt; 16], TransactionExecutorError> { let ref_blocks = [block_ref].into_iter().collect(); - let (account, seed, header, mmr) = maybe_await!(self.data_store.get_transaction_inputs(account_id,ref_blocks)) - .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; + let (account, seed, header, mmr) = + maybe_await!(self.data_store.get_transaction_inputs(account_id, ref_blocks)) + .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; let tx_inputs = TransactionInputs::new(account, seed, header, mmr, Default::default()) .map_err(TransactionExecutorError::InvalidTransactionInputs)?; - let tx_args = TransactionArgs::new(Some(tx_script.clone()), None, Default::default()); + let tx_args = TransactionArgs::new( + Some(tx_script.clone()), + None, + Default::default(), + Default::default(), + ); let (stack_inputs, advice_inputs) = TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_inputs)); @@ -190,7 +195,11 @@ impl TransactionExecutor { advice_recorder, self.data_store.clone(), self.authenticator.clone(), - tx_args..iter().map(|code| code.commitment()).collect(), + tx_args + .foreign_accounts() + .iter() + .map(|acc| acc.account_code().commitment()) + .collect(), ) .map_err(TransactionExecutorError::TransactionHostCreationFailed)?; diff --git a/crates/miden-tx/src/prover/mod.rs b/crates/miden-tx/src/prover/mod.rs index 69e4f4e779..f0b9172a12 100644 --- a/crates/miden-tx/src/prover/mod.rs +++ b/crates/miden-tx/src/prover/mod.rs @@ -81,17 +81,7 @@ impl TransactionProver for LocalTransactionProver { &self, tx_witness: TransactionWitness, ) -> Result { - let TransactionWitness { - tx_inputs, - tx_args, - advice_witness, - account_codes, - } = tx_witness; - - for account_code in &account_codes { - // load the code mast forest to the mast store - self.mast_store.load_account_code(account_code); - } + let TransactionWitness { tx_inputs, tx_args, advice_witness } = tx_witness; let account = tx_inputs.account(); let input_notes = tx_inputs.input_notes(); @@ -111,7 +101,11 @@ impl TransactionProver for LocalTransactionProver { advice_provider, self.mast_store.clone(), None, - account_codes.iter().map(|c| c.commitment()).collect(), + tx_args + .foreign_accounts() + .iter() + .map(|acc| acc.account_code().commitment()) + .collect(), ) .map_err(TransactionProverError::TransactionHostCreationFailed)?; diff --git a/crates/miden-tx/src/testing/mock_chain/mod.rs b/crates/miden-tx/src/testing/mock_chain/mod.rs index 5bbcc3d05a..744ff6ba9f 100644 --- a/crates/miden-tx/src/testing/mock_chain/mod.rs +++ b/crates/miden-tx/src/testing/mock_chain/mod.rs @@ -11,8 +11,8 @@ use miden_lib::{ use miden_objects::{ ACCOUNT_TREE_DEPTH, AccountError, NoteError, ProposedBatchError, ProposedBlockError, account::{ - Account, AccountBuilder, AccountComponent, AccountDelta, AccountId, AccountIdAnchor, - AccountType, AuthSecretKey, delta::AccountUpdateDetails, + Account, AccountBuilder, AccountComponent, AccountDelta, AccountHeader, AccountId, + AccountIdAnchor, AccountType, AuthSecretKey, StorageSlot, delta::AccountUpdateDetails, }, asset::{Asset, FungibleAsset, TokenSymbol}, batch::{ProposedBatch, ProvenBatch}, @@ -22,20 +22,21 @@ use miden_objects::{ }, crypto::{ dsa::rpo_falcon512::SecretKey, - merkle::{LeafIndex, Mmr, Smt}, + merkle::{LeafIndex, Mmr, Smt, SmtProof}, }, note::{Note, NoteHeader, NoteId, NoteInclusionProof, NoteType, Nullifier}, testing::account_code::DEFAULT_AUTH_SCRIPT, transaction::{ - ChainMmr, ExecutedTransaction, InputNote, InputNotes, OutputNote, ProvenTransaction, - ToInputNoteCommitments, TransactionId, TransactionInputs, TransactionScript, + ChainMmr, ExecutedTransaction, ForeignAccountInputs, InputNote, InputNotes, OutputNote, + ProvenTransaction, ToInputNoteCommitments, TransactionId, TransactionInputs, + TransactionScript, }, }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; use vm_processor::{ Digest, Felt, Word, ZERO, - crypto::{RpoRandomCoin, SimpleSmt}, + crypto::{MerklePath, RpoRandomCoin, SimpleSmt}, }; use super::TransactionContextBuilder; @@ -747,6 +748,38 @@ impl MockChain { (batch_reference_block, chain_mmr) } + /// Gets foreign account inputs to execute FPI transactions. + pub fn get_foreign_account_inputs(&self, account_id: AccountId) -> ForeignAccountInputs { + let account = self.available_account(account_id); + + let merkle_proof = MerklePath::new( + self.accounts() + .open( + &LeafIndex::::new(account_id.prefix().as_felt().as_int()) + .unwrap(), + ) + .path + .into(), + ); + + let mut storage_map_proofs = vec![]; + for slot in account.storage().slots() { + // if there are storage maps, we populate the merkle store and advice map + if let StorageSlot::Map(map) = slot { + let proofs: Vec = map.entries().map(|(key, _)| map.open(key)).collect(); + storage_map_proofs.extend(proofs); + } + } + + ForeignAccountInputs::new( + AccountHeader::from(account), + account.storage().get_header(), + account.code().clone(), + merkle_proof, + storage_map_proofs, + ) + } + /// Gets the inputs for a block for the provided batches. pub fn get_block_inputs<'batch, I>( &self, diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index b5c748dd32..4b0361315e 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -6,8 +6,8 @@ use alloc::{collections::BTreeMap, vec::Vec}; use miden_lib::{transaction::TransactionKernel, utils::word_to_masm_push_string}; use miden_objects::{ FieldElement, - account::{Account, AccountCode, AccountId}, - assembly::Assembler, + account::{Account, AccountId}, + assembly::{Assembler, Library}, asset::{Asset, FungibleAsset, NonFungibleAsset}, note::{Note, NoteExecutionHint, NoteId, NoteType}, testing::{ @@ -23,7 +23,9 @@ use miden_objects::{ note::NoteBuilder, storage::prepare_assets, }, - transaction::{OutputNote, TransactionArgs, TransactionInputs, TransactionScript}, + transaction::{ + ForeignAccountInputs, OutputNote, TransactionArgs, TransactionInputs, TransactionScript, + }, vm::AdviceMap, }; use rand::{Rng, SeedableRng}; @@ -31,7 +33,7 @@ use rand_chacha::ChaCha20Rng; use vm_processor::{AdviceInputs, Felt, Word}; use super::TransactionContext; -use crate::{auth::BasicAuthenticator, testing::MockChain, TransactionMastStore}; +use crate::{TransactionMastStore, auth::BasicAuthenticator, testing::MockChain}; pub type MockAuthenticator = BasicAuthenticator; @@ -71,7 +73,8 @@ pub struct TransactionContextBuilder { advice_inputs: AdviceInputs, authenticator: Option, expected_output_notes: Vec, - foreign_account_codes: Vec, + foreign_accounts: Vec, + libraries: Vec, input_notes: Vec, tx_script: Option, note_args: BTreeMap, @@ -93,7 +96,8 @@ impl TransactionContextBuilder { advice_inputs: Default::default(), transaction_inputs: None, note_args: BTreeMap::new(), - foreign_account_codes: vec![], + foreign_accounts: vec![], + libraries: Default::default(), } } @@ -120,7 +124,8 @@ impl TransactionContextBuilder { tx_script: None, transaction_inputs: None, note_args: BTreeMap::new(), - foreign_account_codes: vec![], + foreign_accounts: vec![], + libraries: Default::default(), } } @@ -167,8 +172,8 @@ impl TransactionContextBuilder { } /// Set foreign account codes that are used by the transaction - pub fn foreign_account_codes(mut self, codes: Vec) -> Self { - self.foreign_account_codes = codes; + pub fn foreign_accounts(mut self, inputs: Vec) -> Self { + self.foreign_accounts = inputs; self } @@ -190,6 +195,12 @@ impl TransactionContextBuilder { self } + /// Set custom libraries to add to the MAST forest store at context creation. + pub fn libraries(mut self, libraries: Vec) -> Self { + self.libraries = libraries; + self + } + /// Defines the expected output notes pub fn expected_notes(mut self, output_notes: Vec) -> Self { let output_notes = output_notes.into_iter().filter_map(|n| match n { @@ -652,18 +663,22 @@ impl TransactionContextBuilder { }, }; - let mut tx_args = - TransactionArgs::new(self.tx_script, Some(self.note_args), AdviceMap::default()) - .with_advice_inputs(self.advice_inputs.clone()); + let mut tx_args = TransactionArgs::new( + self.tx_script, + Some(self.note_args), + AdviceMap::default(), + self.foreign_accounts, + ) + .with_advice_inputs(self.advice_inputs.clone()); tx_args.extend_output_note_recipients(self.expected_output_notes.clone()); let mast_store = { let mast_forest_store = TransactionMastStore::new(); mast_forest_store.load_transaction_code(&tx_inputs, &tx_args); - mast_forest_store.load_account_code(tx_inputs.account().code()); - for foreign_code in self.foreign_account_codes.iter() { - mast_forest_store.load_account_code(foreign_code); + + for custom_library in self.libraries { + mast_forest_store.insert(custom_library.mast_forest().clone()); } mast_forest_store }; diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index 97f5208633..ab81d9b51e 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -5,12 +5,18 @@ use alloc::{collections::BTreeSet, rc::Rc, sync::Arc, vec::Vec}; use builder::MockAuthenticator; use miden_lib::transaction::TransactionKernel; use miden_objects::{ - account::{Account, AccountCode, AccountId}, assembly::Assembler, block::{BlockHeader, BlockNumber}, note::Note, transaction::{ + account::{Account, AccountId}, + assembly::Assembler, + block::{BlockHeader, BlockNumber}, + note::Note, + transaction::{ ChainMmr, ExecutedTransaction, InputNote, InputNotes, TransactionArgs, TransactionInputs, - } + }, }; use rand_chacha::ChaCha20Rng; -use vm_processor::{AdviceInputs, Digest, ExecutionError, MastForest, MastForestStore, Process, Word}; +use vm_processor::{ + AdviceInputs, Digest, ExecutionError, MastForest, MastForestStore, Process, Word, +}; use winter_maybe_async::*; use super::{MockHost, executor::CodeExecutor}; @@ -39,6 +45,10 @@ pub struct TransactionContext { assembler: Assembler, } +// TODO: remove +unsafe impl Send for TransactionContext {} +unsafe impl Sync for TransactionContext {} + impl TransactionContext { /// Executes arbitrary code within the context of a mocked transaction environment and returns /// the resulting [Process]. @@ -58,7 +68,6 @@ impl TransactionContext { ); advice_inputs.extend(self.advice_inputs.clone()); - let test_lib = TransactionKernel::kernel_as_library(); let program = self @@ -71,14 +80,18 @@ impl TransactionContext { let mast_store = Rc::new(TransactionMastStore::new()); mast_store.insert(program.mast_forest().clone()); - mast_store.load_transaction_code(&self.tx_inputs, &self.tx_args); mast_store.insert(test_lib.mast_forest().clone()); + mast_store.load_transaction_code(&self.tx_inputs, &self.tx_args); CodeExecutor::new(MockHost::new( self.tx_inputs.account().into(), advice_inputs, mast_store, - self.foreign_codes.iter().map(|code| code.commitment()).collect(), + self.tx_args + .foreign_accounts() + .iter() + .map(|acc| acc.account_code().commitment()) + .collect(), )) .stack_inputs(stack_inputs) .execute_program(program) @@ -97,14 +110,8 @@ impl TransactionContext { .authenticator() .cloned() .map(|auth| Arc::new(auth) as Arc); - - // for foreign_code in self.foreign_codes.iter() { - // tx_executor.load_account_commitment(foreign_code); - // } - - let tx_executor = - TransactionExecutor::new(Arc::new(self), authenticator); + let tx_executor = TransactionExecutor::new(Arc::new(self), authenticator); maybe_await!(tx_executor.execute_transaction(account_id, block_num, notes, tx_args)) } @@ -147,8 +154,7 @@ impl DataStore for TransactionContext { _ref_blocks: BTreeSet, ) -> Result<(Account, Option, BlockHeader, ChainMmr), DataStoreError> { assert_eq!(account_id, self.account().id()); - let (account, seed, header, mmr, _) = - self.tx_inputs.clone().into_parts().clone(); + let (account, seed, header, mmr, _) = self.tx_inputs.clone().into_parts().clone(); Ok((account, seed, header, mmr)) } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index 6427468b44..36ed4f863e 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -1,5 +1,4 @@ -use alloc::vec::Vec; -use std::{string::ToString, vec}; +use alloc::{string::ToString, sync::Arc, vec, vec::Vec}; use miden_lib::{ errors::tx_kernel_errors::{ @@ -16,14 +15,12 @@ use miden_lib::{ }, }; use miden_objects::{ - ACCOUNT_TREE_DEPTH, account::{ Account, AccountBuilder, AccountComponent, AccountProcedureInfo, AccountStorage, StorageSlot, }, - crypto::merkle::{LeafIndex, MerklePath}, testing::{account_component::AccountMockComponent, storage::STORAGE_LEAVES_2}, - transaction::TransactionScript, + transaction::{ForeignAccountInputs, InputNotes, TransactionScript}, }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; @@ -95,12 +92,11 @@ fn test_fpi_memory() { let mut mock_chain = MockChain::with_accounts(&[native_account.clone(), foreign_account.clone()]); mock_chain.seal_next_block(); - let advice_inputs = get_mock_fpi_adv_inputs(vec![&foreign_account], &mock_chain); + let fpi_inputs = mock_chain.get_foreign_account_inputs(foreign_account.id()); let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) - .foreign_account_codes(vec![foreign_account.code().clone()]) - .advice_inputs(advice_inputs.clone()) + .foreign_accounts(vec![fpi_inputs]) .build(); // GET ITEM @@ -359,16 +355,13 @@ fn test_fpi_memory_two_accounts() { foreign_account_2.clone(), ]); mock_chain.seal_next_block(); - let advice_inputs = - get_mock_fpi_adv_inputs(vec![&foreign_account_1, &foreign_account_2], &mock_chain); + let foreign_account_inputs_1 = mock_chain.get_foreign_account_inputs(foreign_account_1.id()); + + let foreign_account_inputs_2 = mock_chain.get_foreign_account_inputs(foreign_account_2.id()); let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) - .foreign_account_codes(vec![ - foreign_account_1.code().clone(), - foreign_account_2.code().clone(), - ]) - .advice_inputs(advice_inputs.clone()) + .foreign_accounts(vec![foreign_account_inputs_1, foreign_account_inputs_2]) .build(); // GET ITEM TWICE WITH TWO ACCOUNTS @@ -555,7 +548,6 @@ fn test_fpi_execute_foreign_procedure() { let mut mock_chain = MockChain::with_accounts(&[native_account.clone(), foreign_account.clone()]); mock_chain.seal_next_block(); - let advice_inputs = get_mock_fpi_adv_inputs(vec![&foreign_account], &mock_chain); let code = format!( " @@ -625,22 +617,20 @@ fn test_fpi_execute_foreign_procedure() { let tx_script = TransactionScript::compile(code, vec![], TransactionKernel::testing_assembler()).unwrap(); + let foreign_account_inputs = mock_chain.get_foreign_account_inputs(foreign_account.id()); let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) - .advice_inputs(advice_inputs.clone()) + .foreign_accounts(vec![foreign_account_inputs]) .tx_script(tx_script) .build(); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let mut executor = TransactionExecutor::new(tx_context.get_data_store(), None).with_tracing(); - - // load the mast forest of the foreign account's code to be able to create an account procedure - // index map and execute the specified foreign procedure - executor.load_account_code(foreign_account.code()); + let tx_args = tx_context.tx_args().clone(); + let executor = TransactionExecutor::new(Arc::new(tx_context), None).with_tracing(); let _executed_transaction = executor - .execute_transaction(native_account.id(), block_ref, &[], tx_context.tx_args().clone()) + .execute_transaction(native_account.id(), block_ref, InputNotes::default(), tx_args) .map_err(|e| e.to_string()) .unwrap(); } @@ -786,16 +776,20 @@ fn test_nested_fpi_cyclic_invocation() { second_foreign_account.clone(), ]); mock_chain.seal_block(None, None); - let mut advice_inputs = - get_mock_fpi_adv_inputs(vec![&first_foreign_account, &second_foreign_account], &mock_chain); + let foreign_account_inputs = vec![ + mock_chain.get_foreign_account_inputs(first_foreign_account.id()), + mock_chain.get_foreign_account_inputs(second_foreign_account.id()), + ]; // push the hashes of the foreign procedures and account IDs to the advice stack to be able to // call them dynamically. + let mut advice_inputs = AdviceInputs::default(); advice_inputs.extend_stack(*second_foreign_account.code().procedures()[0].mast_root()); advice_inputs.extend_stack([ second_foreign_account.id().suffix(), second_foreign_account.id().prefix().as_felt(), ]); + advice_inputs.extend_stack(*first_foreign_account.code().procedures()[1].mast_root()); advice_inputs.extend_stack([ first_foreign_account.id().suffix(), @@ -847,23 +841,20 @@ fn test_nested_fpi_cyclic_invocation() { let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) - .advice_inputs(advice_inputs.clone()) + .foreign_accounts(foreign_account_inputs) + .advice_inputs(advice_inputs) .tx_script(tx_script) .build(); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let mut executor = TransactionExecutor::new(tx_context.get_data_store(), None) + let tx_args = tx_context.tx_args().clone(); + let executor = TransactionExecutor::new(Arc::new(tx_context), None) .with_tracing() .with_debug_mode(); - // load the mast forest of the foreign account's code to be able to create an account procedure - // index map and execute the specified foreign procedure - executor.load_account_code(first_foreign_account.code()); - executor.load_account_code(second_foreign_account.code()); - let _executed_transaction = executor - .execute_transaction(native_account.id(), block_ref, &[], tx_context.tx_args().clone()) + .execute_transaction(native_account.id(), block_ref, InputNotes::default(), tx_args) .map_err(|e| e.to_string()) .unwrap(); } @@ -875,14 +866,16 @@ fn test_nested_fpi_cyclic_invocation() { #[test] fn test_nested_fpi_stack_overflow() { // use a custom thread to increase its stack capacity - std::thread::Builder::new().stack_size(8 * 1_048_576).spawn(||{ - let mut foreign_accounts = Vec::new(); + std::thread::Builder::new() + .stack_size(8 * 1_048_576) + .spawn(|| { + let mut foreign_accounts = Vec::new(); - let last_foreign_account_code_source = " + let last_foreign_account_code_source = " use.miden::account export.get_item_foreign - # make this foreign procedure unique to make sure that we invoke the procedure + # make this foreign procedure unique to make sure that we invoke the procedure # of the foreign account, not the native one push.1 drop @@ -899,26 +892,27 @@ fn test_nested_fpi_stack_overflow() { end "; - let storage_slots = vec![AccountStorage::mock_item_0().slot]; - let last_foreign_account_component = AccountComponent::compile( - last_foreign_account_code_source, - TransactionKernel::testing_assembler(), - storage_slots, - ) - .unwrap() - .with_supports_all_types(); + let storage_slots = vec![AccountStorage::mock_item_0().slot]; + let last_foreign_account_component = AccountComponent::compile( + last_foreign_account_code_source, + TransactionKernel::testing_assembler(), + storage_slots, + ) + .unwrap() + .with_supports_all_types(); - let last_foreign_account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) - .with_component(last_foreign_account_component) - .build_existing() - .unwrap(); + let last_foreign_account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) + .with_component(last_foreign_account_component) + .build_existing() + .unwrap(); - foreign_accounts.push(last_foreign_account); + foreign_accounts.push(last_foreign_account); - for foreign_account_index in 0..63 { - let next_account = foreign_accounts.last().unwrap(); + for foreign_account_index in 0..63 { + let next_account = foreign_accounts.last().unwrap(); - let foreign_account_code_source = format!(" + let foreign_account_code_source = format!( + " use.miden::tx use.std::sys @@ -939,48 +933,53 @@ fn test_nested_fpi_stack_overflow() { exec.sys::truncate_stack end - ", - next_account_proc_hash = next_account.code().procedures()[0].mast_root(), - next_foreign_suffix = next_account.id().suffix(), - next_foreign_prefix = next_account.id().prefix().as_felt(), - ); - - let foreign_account_component = AccountComponent::compile( - foreign_account_code_source, - TransactionKernel::testing_assembler(), - vec![], - ) - .unwrap() - .with_supports_all_types(); + ", + next_account_proc_hash = next_account.code().procedures()[0].mast_root(), + next_foreign_suffix = next_account.id().suffix(), + next_foreign_prefix = next_account.id().prefix().as_felt(), + ); + + let foreign_account_component = AccountComponent::compile( + foreign_account_code_source, + TransactionKernel::testing_assembler(), + vec![], + ) + .unwrap() + .with_supports_all_types(); + + let foreign_account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) + .with_component(foreign_account_component) + .build_existing() + .unwrap(); + + foreign_accounts.push(foreign_account) + } - let foreign_account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) - .with_component(foreign_account_component) + // ------ NATIVE ACCOUNT --------------------------------------------------------------- + let native_account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) + .with_component( + AccountMockComponent::new_with_slots( + TransactionKernel::testing_assembler(), + vec![], + ) + .unwrap(), + ) .build_existing() .unwrap(); - foreign_accounts.push(foreign_account) - } - - // ------ NATIVE ACCOUNT --------------------------------------------------------------- - let native_account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) - .with_component( - AccountMockComponent::new_with_slots(TransactionKernel::testing_assembler(), vec![]) - .unwrap(), - ) - .build_existing() - .unwrap(); - - let mut mock_chain = MockChain::with_accounts(&[ - vec![native_account.clone()], foreign_accounts.clone() - ].concat()); + let mut mock_chain = MockChain::with_accounts( + &[vec![native_account.clone()], foreign_accounts.clone()].concat(), + ); - mock_chain.seal_block(None, None); + mock_chain.seal_block(None, None); - let advice_inputs = - get_mock_fpi_adv_inputs(foreign_accounts.iter().collect::>(), &mock_chain); + let foreign_accounts: Vec = foreign_accounts + .iter() + .map(|acc| mock_chain.get_foreign_account_inputs(acc.id())) + .collect(); - let code = format!( - " + let code = format!( + " use.std::sys use.miden::tx @@ -1003,50 +1002,37 @@ fn test_nested_fpi_stack_overflow() { exec.sys::truncate_stack end ", - foreign_account_proc_hash = foreign_accounts.last().unwrap().code().procedures()[0].mast_root(), - foreign_prefix = foreign_accounts.last().unwrap().id().prefix().as_felt(), - foreign_suffix = foreign_accounts.last().unwrap().id().suffix(), - ); + foreign_account_proc_hash = + foreign_accounts.last().unwrap().account_code().procedures()[0].mast_root(), + foreign_prefix = foreign_accounts.last().unwrap().id().prefix().as_felt(), + foreign_suffix = foreign_accounts.last().unwrap().id().suffix(), + ); - let tx_script = TransactionScript::compile( - code, - vec![], - TransactionKernel::testing_assembler().with_debug_mode(true), - ) - .unwrap(); + let tx_script = TransactionScript::compile( + code, + vec![], + TransactionKernel::testing_assembler().with_debug_mode(true), + ) + .unwrap(); + + let tx_context = mock_chain + .build_tx_context(native_account.id(), &[], &[]) + .foreign_accounts(foreign_accounts) + .tx_script(tx_script) + .build(); - let tx_context = mock_chain - .build_tx_context(native_account.id(), &[], &[]) - .advice_inputs(advice_inputs.clone()) - .tx_script(tx_script) - .build(); - - let block_ref = tx_context.tx_inputs().block_header().block_num(); - - let mut executor = TransactionExecutor::new(tx_context.get_data_store(), None) - .with_tracing() - .with_debug_mode(); - - // load the mast forest of the foreign account's code to be able to create an account - // procedure index map and execute the specified foreign procedure - for foreign_account in foreign_accounts { - executor.load_account_code(foreign_account.code()); - } - - let err = executor - .execute_transaction( - native_account.id(), - block_ref, - &[], - tx_context.tx_args().clone(), - ).unwrap_err(); - - let TransactionExecutorError::TransactionProgramExecutionFailed(err) = err else { - panic!("unexpected error") - }; - - assert_execution_error!(Err::<(), _>(err), ERR_FOREIGN_ACCOUNT_MAX_NUMBER_EXCEEDED); - }).expect("thread panic external").join().expect("thread panic internal"); + let err = tx_context.execute() + .unwrap_err(); + + let TransactionExecutorError::TransactionProgramExecutionFailed(err) = err else { + panic!("unexpected error") + }; + + assert_execution_error!(Err::<(), _>(err), ERR_FOREIGN_ACCOUNT_MAX_NUMBER_EXCEEDED); + }) + .expect("thread panic external") + .join() + .expect("thread panic internal"); } /// Test that code will panic in attempt to call a procedure from the native account. @@ -1102,10 +1088,11 @@ fn test_nested_fpi_native_account_invocation() { let mut mock_chain = MockChain::with_accounts(&[native_account.clone(), foreign_account.clone()]); mock_chain.seal_block(None, None); - let mut advice_inputs = get_mock_fpi_adv_inputs(vec![&foreign_account], &mock_chain); + let foreign_account_inputs = mock_chain.get_foreign_account_inputs(foreign_account.id()); // push the hash of the native procedure and native account IDs to the advice stack to be able // to call them dynamically. + let mut advice_inputs = AdviceInputs::default(); advice_inputs.extend_stack(*native_account.code().procedures()[2].mast_root()); advice_inputs .extend_stack([native_account.id().suffix(), native_account.id().prefix().as_felt()]); @@ -1148,22 +1135,20 @@ fn test_nested_fpi_native_account_invocation() { let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) - .advice_inputs(advice_inputs.clone()) + .foreign_accounts(vec![foreign_account_inputs]) + .advice_inputs(advice_inputs) .tx_script(tx_script) .build(); let block_ref = tx_context.tx_inputs().block_header().block_num(); - let mut executor = TransactionExecutor::new(tx_context.get_data_store(), None) + let tx_args = tx_context.tx_args().clone(); + let executor = TransactionExecutor::new(Arc::new(tx_context), None) .with_tracing() .with_debug_mode(); - // load the mast forest of the foreign account's code to be able to create an account procedure - // index map and execute the specified foreign procedure - executor.load_account_code(foreign_account.code()); - let err = executor - .execute_transaction(native_account.id(), block_ref, &[], tx_context.tx_args().clone()) + .execute_transaction(native_account.id(), block_ref, InputNotes::default(), tx_args) .unwrap_err(); let TransactionExecutorError::TransactionProgramExecutionFailed(err) = err else { @@ -1176,47 +1161,6 @@ fn test_nested_fpi_native_account_invocation() { // HELPER FUNCTIONS // ================================================================================================ -fn get_mock_fpi_adv_inputs( - foreign_accounts: Vec<&Account>, - mock_chain: &MockChain, -) -> AdviceInputs { - let mut advice_inputs = AdviceInputs::default(); - - for foreign_account in foreign_accounts { - TransactionKernel::extend_advice_inputs_for_account( - &mut advice_inputs, - &foreign_account.into(), - foreign_account.code(), - &foreign_account.storage().get_header(), - // Provide the merkle path of the foreign account to be able to verify that the account - // tree has the commitment of this foreign account. Verification is done during the - // execution of the `kernel::account::validate_current_foreign_account` procedure. - &MerklePath::new( - mock_chain - .accounts() - // TODO: Update. - .open(&LeafIndex::::new(foreign_account.id().prefix().as_felt().as_int()).unwrap()) - .path - .into(), - ), - ) - .unwrap(); - - for slot in foreign_account.storage().slots() { - // if there are storage maps, we populate the merkle store and advice map - if let StorageSlot::Map(map) = slot { - // extend the merkle store and map with the storage maps - advice_inputs.extend_merkle_store(map.inner_nodes()); - // populate advice map with Sparse Merkle Tree leaf nodes - advice_inputs - .extend_map(map.leaves().map(|(_, leaf)| (leaf.hash(), leaf.to_elements()))); - } - } - } - - advice_inputs -} - fn foreign_account_data_memory_assertions(foreign_account: &Account, process: &Process) { let foreign_account_data_ptr = NATIVE_ACCOUNT_DATA_PTR + ACCOUNT_DATA_LENGTH as u32; diff --git a/crates/miden-tx/src/tests/kernel_tests/test_note.rs b/crates/miden-tx/src/tests/kernel_tests/test_note.rs index 109dfcff3e..8fab39c6ae 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_note.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_note.rs @@ -1,4 +1,4 @@ -use alloc::{collections::BTreeMap, string::String}; +use alloc::{collections::BTreeMap, string::String, vec::Vec}; use miden_lib::{ errors::tx_kernel_errors::ERR_NOTE_ATTEMPT_TO_ACCESS_NOTE_SENDER_FROM_INCORRECT_CONTEXT, @@ -11,7 +11,7 @@ use miden_objects::{ Note, NoteExecutionHint, NoteExecutionMode, NoteInputs, NoteMetadata, NoteTag, NoteType, }, testing::{account_id::ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE, note::NoteBuilder}, - transaction::TransactionArgs, + transaction::{ForeignAccountInputs, TransactionArgs}, }; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; @@ -375,6 +375,7 @@ fn test_note_script_and_note_args() { None, Some(note_args_map), tx_context.tx_args().advice_inputs().clone().map, + Vec::::new(), ); tx_context.set_tx_args(tx_args); diff --git a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs index 8587e33480..2d79480134 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs @@ -39,7 +39,7 @@ use miden_objects::{ account_id::{ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_PUBLIC_NON_FUNGIBLE_FAUCET}, constants::FUNGIBLE_FAUCET_INITIAL_BALANCE, }, - transaction::{TransactionArgs, TransactionScript}, + transaction::{ForeignAccountInputs, TransactionArgs, TransactionScript}, }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; @@ -95,6 +95,7 @@ fn test_transaction_prologue() { Some(tx_script), Some(note_args_map), tx_context.tx_args().advice_inputs().clone().map, + Vec::::new(), ); tx_context.set_tx_args(tx_args); diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index 3c97d03c06..067df68c49 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -26,11 +26,10 @@ use miden_objects::{ transaction::{OutputNote, OutputNotes}, }; -use super::{Felt, ONE, Process, ProcessState, Word, ZERO, word_to_masm_push_string}; +use super::{Felt, ONE, ProcessState, Word, ZERO}; use crate::{ - assert_execution_error, - testing::{MockChain, TransactionContextBuilder}, - tests::kernel_tests::{read_root_mem_word, try_read_root_mem_word}, + assert_execution_error, testing::TransactionContextBuilder, + tests::kernel_tests::read_root_mem_word, }; #[test] diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index a82cb78baf..59e6ac27e0 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -30,9 +30,7 @@ use miden_objects::{ note::DEFAULT_NOTE_CODE, storage::{STORAGE_INDEX_0, STORAGE_INDEX_2}, }, - transaction::{ - InputNote, InputNotes, OutputNote, ProvenTransaction, TransactionArgs, TransactionScript, - }, + transaction::{OutputNote, ProvenTransaction, TransactionScript}, }; use miden_prover::ProvingOptions; use rand::{Rng, SeedableRng}; @@ -123,10 +121,6 @@ fn executed_transaction_account_delta_new() { .build_existing() .unwrap(); - let mut tx_context = TransactionContextBuilder::new(account) - .with_mock_notes_preserved_with_account_vault_delta() - .build(); - // updated storage let updated_slot_value = [Felt::new(7), Felt::new(9), Felt::new(11), Felt::new(13)]; @@ -268,13 +262,21 @@ fn executed_transaction_account_delta_new() { ) .unwrap(); - let tx_args = TransactionArgs::new( - Some(tx_script), - None, - tx_context.tx_args().advice_inputs().clone().map, - ); + let tx_context = TransactionContextBuilder::new(account) + .with_mock_notes_preserved_with_account_vault_delta() + .tx_script(tx_script) + .build(); - tx_context.set_tx_args(tx_args); + // Storing assets that will be added to assert correctness later + let added_assets = tx_context + .tx_inputs() + .input_notes() + .iter() + .find_map(|n| { + let assets = n.note().assets(); + (assets.num_assets() == 3).then(|| assets.iter().cloned().collect::>()) + }) + .unwrap(); // expected delta // -------------------------------------------------------------------------------------------- @@ -311,18 +313,6 @@ fn executed_transaction_account_delta_new() { // vault delta // -------------------------------------------------------------------------------------------- // assert that added assets are tracked - let added_assets = tx_context - .tx_inputs() - .input_notes() - .iter() - .find(|n| n.note().assets().num_assets() == 3) - .unwrap() - .note() - .assets() - .iter() - .cloned() - .collect::>(); - assert!( executed_transaction .account_delta() @@ -899,8 +889,6 @@ fn transaction_executor_account_code_using_custom_library() { .build_existing() .unwrap(); - let tx_context = TransactionContextBuilder::new(native_account.clone()).build(); - let tx_script = TransactionScript::compile( tx_script_src, [], @@ -910,20 +898,12 @@ fn transaction_executor_account_code_using_custom_library() { ) .unwrap(); - let tx_args = TransactionArgs::new( - Some(tx_script), - None, - tx_context.tx_args().advice_inputs().clone().map, - ); - - let account_id = tx_context.account().id(); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - - let executor = TransactionExecutor::new(Arc::new(tx_context), None); + let tx_context = TransactionContextBuilder::new(native_account.clone()) + .libraries(vec![external_library]) + .tx_script(tx_script) + .build(); - let executed_tx = executor - .execute_transaction(account_id, block_ref, InputNotes::::default(), tx_args) - .unwrap(); + let executed_tx = tx_context.execute().unwrap(); // Account's initial nonce of 1 should have been incremented by 4. assert_eq!(executed_tx.account_delta().nonce().unwrap(), Felt::new(5)); From 0ac3111f6add111e45a2e07c0495b907cce522f1 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 7 Apr 2025 18:05:55 -0300 Subject: [PATCH 05/29] chore: Remove TODO --- .../miden-objects/src/batch/account_update.rs | 2 +- crates/miden-tx/src/testing/tx_context/mod.rs | 4 -- .../src/tests/kernel_tests/test_fpi.rs | 39 +++---------------- 3 files changed, 7 insertions(+), 38 deletions(-) diff --git a/crates/miden-objects/src/batch/account_update.rs b/crates/miden-objects/src/batch/account_update.rs index 20b2bc57d9..414d802694 100644 --- a/crates/miden-objects/src/batch/account_update.rs +++ b/crates/miden-objects/src/batch/account_update.rs @@ -1,4 +1,4 @@ -use alloc::{boxed::Box, vec::Vec}; +use alloc::boxed::Box; use crate::{ Digest, diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index ab81d9b51e..c3c4e1af6c 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -45,10 +45,6 @@ pub struct TransactionContext { assembler: Assembler, } -// TODO: remove -unsafe impl Send for TransactionContext {} -unsafe impl Sync for TransactionContext {} - impl TransactionContext { /// Executes arbitrary code within the context of a mocked transaction environment and returns /// the resulting [Process]. diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index 36ed4f863e..7e7e0af7f5 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -1,4 +1,4 @@ -use alloc::{string::ToString, sync::Arc, vec, vec::Vec}; +use alloc::{string::ToString, vec, vec::Vec}; use miden_lib::{ errors::tx_kernel_errors::{ @@ -20,7 +20,7 @@ use miden_objects::{ StorageSlot, }, testing::{account_component::AccountMockComponent, storage::STORAGE_LEAVES_2}, - transaction::{ForeignAccountInputs, InputNotes, TransactionScript}, + transaction::{ForeignAccountInputs, TransactionScript}, }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; @@ -28,7 +28,7 @@ use vm_processor::AdviceInputs; use super::{Process, Word, ZERO}; use crate::{ - TransactionExecutor, TransactionExecutorError, assert_execution_error, + TransactionExecutorError, assert_execution_error, testing::MockChain, tests::kernel_tests::{read_root_mem_word, try_read_root_mem_word}, }; @@ -624,15 +624,7 @@ fn test_fpi_execute_foreign_procedure() { .tx_script(tx_script) .build(); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - - let tx_args = tx_context.tx_args().clone(); - let executor = TransactionExecutor::new(Arc::new(tx_context), None).with_tracing(); - - let _executed_transaction = executor - .execute_transaction(native_account.id(), block_ref, InputNotes::default(), tx_args) - .map_err(|e| e.to_string()) - .unwrap(); + let _executed_transaction = tx_context.execute().map_err(|e| e.to_string()).unwrap(); } // NESTED FPI TESTS @@ -846,17 +838,7 @@ fn test_nested_fpi_cyclic_invocation() { .tx_script(tx_script) .build(); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - - let tx_args = tx_context.tx_args().clone(); - let executor = TransactionExecutor::new(Arc::new(tx_context), None) - .with_tracing() - .with_debug_mode(); - - let _executed_transaction = executor - .execute_transaction(native_account.id(), block_ref, InputNotes::default(), tx_args) - .map_err(|e| e.to_string()) - .unwrap(); + let _executed_transaction = tx_context.execute().map_err(|e| e.to_string()).unwrap(); } /// Test that code will panic in attempt to create more than 63 foreign accounts. @@ -1140,16 +1122,7 @@ fn test_nested_fpi_native_account_invocation() { .tx_script(tx_script) .build(); - let block_ref = tx_context.tx_inputs().block_header().block_num(); - - let tx_args = tx_context.tx_args().clone(); - let executor = TransactionExecutor::new(Arc::new(tx_context), None) - .with_tracing() - .with_debug_mode(); - - let err = executor - .execute_transaction(native_account.id(), block_ref, InputNotes::default(), tx_args) - .unwrap_err(); + let err = tx_context.execute().unwrap_err(); let TransactionExecutorError::TransactionProgramExecutionFailed(err) = err else { panic!("unexpected error") From d88556fdc0dd4242dc577b05d06f176226b7acf7 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 7 Apr 2025 18:16:46 -0300 Subject: [PATCH 06/29] chore: CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12be19b35b..5a93b4f883 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [BREAKING] Add `TransactionHeader` and include it in batches and blocks (#1247). - [BREAKING] Hash keys in storage maps before insertion into the SMT (#1250). - Added getter for proof security level in `ProvenBatch` and `ProvenBlock` (#1259). +- [BREAKING] Refactored how foreign account inputs are passed to `TransactionExecutor`, and upgraded Rust version to 1.86 (#1229). ## 0.8.1 (2025-03-26) From 4040442d492f84cd60b7a579e6269c29d207c527 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Thu, 10 Apr 2025 14:36:29 -0300 Subject: [PATCH 07/29] Revert change --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 383be8c585..0daf7d298f 100644 --- a/Makefile +++ b/Makefile @@ -126,4 +126,4 @@ bench-tx: ## Run transaction benchmarks .PHONY: install-proving-service install-proving-service: ## Install proving service's CLI - $(BUILD_GENERATED_FILES_IN_SRC) cargo install --path bin/proving-service --bin miden-proving-service --features concurrent + $(BUILD_GENERATED_FILES_IN_SRC) cargo install --path bin/proving-service --bin miden-proving-service --locked --features concurrent From fc60697a32e8a257e2a3cc58e32e5c1c86d0523f Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Thu, 10 Apr 2025 16:24:19 -0300 Subject: [PATCH 08/29] refactor: Remove unused DataStore error variant --- crates/miden-tx/src/errors/mod.rs | 4 ---- crates/miden-tx/src/executor/mod.rs | 1 + crates/miden-tx/src/lib.rs | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/miden-tx/src/errors/mod.rs b/crates/miden-tx/src/errors/mod.rs index 880da0f15f..a86c6f65d0 100644 --- a/crates/miden-tx/src/errors/mod.rs +++ b/crates/miden-tx/src/errors/mod.rs @@ -113,10 +113,6 @@ pub enum DataStoreError { AccountNotFound(AccountId), #[error("block with number {0} not found in data store")] BlockNotFound(BlockNumber), - #[error("note with id {0} is already consumed")] - NoteAlreadyConsumed(NoteId), - #[error("not with id {0} not found in data store")] - NoteNotFound(NoteId), /// Custom error variant for implementors of the [`DataStore`](crate::executor::DataStore) /// trait. #[error("{error_msg}")] diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index 65720d1a9e..dcf031237d 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -12,6 +12,7 @@ use miden_objects::{ }, vm::StackOutputs, }; +pub use vm_processor::MastForestStore; use vm_processor::{AdviceInputs, ExecutionOptions, Process, RecAdviceProvider}; use winter_maybe_async::{maybe_async, maybe_await}; diff --git a/crates/miden-tx/src/lib.rs b/crates/miden-tx/src/lib.rs index d50a3a2407..3f34dbae5b 100644 --- a/crates/miden-tx/src/lib.rs +++ b/crates/miden-tx/src/lib.rs @@ -9,7 +9,7 @@ extern crate std; pub use miden_objects::transaction::TransactionInputs; mod executor; -pub use executor::{DataStore, TransactionExecutor, TransactionMastStore}; +pub use executor::{DataStore, MastForestStore, TransactionExecutor, TransactionMastStore}; pub mod host; pub use host::{TransactionHost, TransactionProgress}; From a34b940d37f189c0ed2717a311fdbdade9ec8e2e Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Thu, 10 Apr 2025 16:33:56 -0300 Subject: [PATCH 09/29] chore: Clippy --- crates/miden-tx/src/errors/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-tx/src/errors/mod.rs b/crates/miden-tx/src/errors/mod.rs index a86c6f65d0..6b7661f5f7 100644 --- a/crates/miden-tx/src/errors/mod.rs +++ b/crates/miden-tx/src/errors/mod.rs @@ -3,7 +3,7 @@ use core::error::Error; use miden_objects::{ AccountError, Felt, ProvenTransactionError, TransactionInputError, TransactionOutputError, - account::AccountId, block::BlockNumber, note::NoteId, + account::AccountId, block::BlockNumber, }; use miden_verifier::VerificationError; use thiserror::Error; From 2f7e499aded1034bd61036e58f68c0161ca135f9 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Fri, 11 Apr 2025 12:11:12 -0300 Subject: [PATCH 10/29] refactor: TransactionArgs mutators --- .../miden-objects/src/transaction/tx_args.rs | 28 +++++++++++++------ .../src/testing/tx_context/builder.rs | 4 +-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/crates/miden-objects/src/transaction/tx_args.rs b/crates/miden-objects/src/transaction/tx_args.rs index b1b416c7af..55f6b8870a 100644 --- a/crates/miden-objects/src/transaction/tx_args.rs +++ b/crates/miden-objects/src/transaction/tx_args.rs @@ -61,19 +61,26 @@ impl TransactionArgs { } /// Returns new [TransactionArgs] instantiated with the provided transaction script. - pub fn with_tx_script(tx_script: TransactionScript) -> Self { - Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default(), Vec::default()) + #[must_use] + pub fn with_tx_script(mut self, tx_script: TransactionScript) -> Self { + self.tx_script = Some(tx_script); + self } /// Returns new [TransactionArgs] instantiated with the provided note arguments. - pub fn with_note_args(note_args: BTreeMap) -> Self { - Self::new(None, Some(note_args), AdviceMap::default(), Vec::default()) + #[must_use] + pub fn with_note_args(mut self, note_args: BTreeMap) -> Self { + self.note_args = note_args; + self } - /// Returns the provided [TransactionArgs] with advice inputs extended with the passed-in - /// `advice_inputs`. - pub fn with_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self { - self.advice_inputs.extend(advice_inputs); + /// Returns the modified [TransactionArgs] with the provided foreign account inputs. + #[must_use] + pub fn with_foreign_account_inputs( + mut self, + foreign_account_inputs: Vec, + ) -> Self { + self.foreign_accounts = foreign_account_inputs; self } @@ -142,6 +149,11 @@ impl TransactionArgs { } } + /// Extends the provided [TransactionArgs] with the passed-in `advice_inputs`. + pub fn extend_advice_inputs(&mut self, advice_inputs: AdviceInputs) { + self.advice_inputs.extend(advice_inputs); + } + /// Extends the internal advice inputs' map with the provided key-value pairs. pub fn extend_advice_map)>>(&mut self, iter: T) { self.advice_inputs.extend_map(iter) diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index 4b0361315e..ce4e4f9fd4 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -668,9 +668,9 @@ impl TransactionContextBuilder { Some(self.note_args), AdviceMap::default(), self.foreign_accounts, - ) - .with_advice_inputs(self.advice_inputs.clone()); + ); + tx_args.extend_advice_inputs(self.advice_inputs.clone()); tx_args.extend_output_note_recipients(self.expected_output_notes.clone()); let mast_store = { From 20c9d252479d90a7db0596f3ef196ee358a78863 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Fri, 11 Apr 2025 12:12:08 -0300 Subject: [PATCH 11/29] chore: Clippy --- bin/bench-tx/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bench-tx/src/main.rs b/bin/bench-tx/src/main.rs index 6b6ece516c..6af8c55338 100644 --- a/bin/bench-tx/src/main.rs +++ b/bin/bench-tx/src/main.rs @@ -124,7 +124,7 @@ pub fn benchmark_p2id() -> Result { let tx_script_target = TransactionScript::compile(DEFAULT_AUTH_SCRIPT, [], TransactionKernel::assembler()) .unwrap(); - let tx_args_target = TransactionArgs::with_tx_script(tx_script_target); + let tx_args_target = TransactionArgs::default().with_tx_script(tx_script_target); // execute transaction let executed_transaction = executor From 32a5296e78b9436658ae4864790e76e1ff352014 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Fri, 11 Apr 2025 13:37:02 -0300 Subject: [PATCH 12/29] refactor: MAST store --- crates/miden-tx/src/executor/mast_store.rs | 17 +++++++++++------ crates/miden-tx/src/prover/mod.rs | 2 +- .../miden-tx/src/testing/tx_context/builder.rs | 6 +++++- crates/miden-tx/src/testing/tx_context/mod.rs | 2 +- crates/miden-tx/src/tests/mod.rs | 2 +- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/crates/miden-tx/src/executor/mast_store.rs b/crates/miden-tx/src/executor/mast_store.rs index 4134f5a397..b9b3c79a9d 100644 --- a/crates/miden-tx/src/executor/mast_store.rs +++ b/crates/miden-tx/src/executor/mast_store.rs @@ -5,7 +5,7 @@ use miden_objects::{ Digest, account::AccountCode, assembly::mast::MastForest, - transaction::{TransactionArgs, TransactionInputs}, + transaction::{InputNote, InputNotes, TransactionArgs}, }; use vm_processor::MastForestStore; @@ -59,16 +59,21 @@ impl TransactionMastStore { /// this store. /// /// The loaded code includes: - /// - Account code for the account specified in the provided [TransactionInputs]. - /// - Note scripts for all input notes in the provided [TransactionInputs]. + /// - Account code for the account specified from the provided [AccountCode]. + /// - Note scripts for all input notes in the provided [InputNotes]. /// - Transaction script (if any) from the specified [TransactionArgs]. /// - Foreign account code (if any) from the specified [TransactionArgs]. - pub fn load_transaction_code(&self, tx_inputs: &TransactionInputs, tx_args: &TransactionArgs) { + pub fn load_transaction_code( + &self, + account_code: &AccountCode, + input_notes: &InputNotes, + tx_args: &TransactionArgs, + ) { // load account code - self.load_account_code(tx_inputs.account().code()); + self.load_account_code(account_code); // load note script MAST into the MAST store - for note in tx_inputs.input_notes() { + for note in input_notes { self.insert(note.note().script().mast().clone()); } diff --git a/crates/miden-tx/src/prover/mod.rs b/crates/miden-tx/src/prover/mod.rs index f0b9172a12..15f7a703fa 100644 --- a/crates/miden-tx/src/prover/mod.rs +++ b/crates/miden-tx/src/prover/mod.rs @@ -94,7 +94,7 @@ impl TransactionProver for LocalTransactionProver { let advice_provider: MemAdviceProvider = advice_inputs.into(); // load the store with account/note/tx_script MASTs - self.mast_store.load_transaction_code(&tx_inputs, &tx_args); + self.mast_store.load_transaction_code(account.code(), input_notes, &tx_args); let mut host: TransactionHost<_> = TransactionHost::new( account.into(), diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index ce4e4f9fd4..cad6d24b64 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -675,7 +675,11 @@ impl TransactionContextBuilder { let mast_store = { let mast_forest_store = TransactionMastStore::new(); - mast_forest_store.load_transaction_code(&tx_inputs, &tx_args); + mast_forest_store.load_transaction_code( + tx_inputs.account().code(), + tx_inputs.input_notes(), + &tx_args, + ); for custom_library in self.libraries { mast_forest_store.insert(custom_library.mast_forest().clone()); diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index c3c4e1af6c..e5f3e80058 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -77,7 +77,7 @@ impl TransactionContext { mast_store.insert(program.mast_forest().clone()); mast_store.insert(test_lib.mast_forest().clone()); - mast_store.load_transaction_code(&self.tx_inputs, &self.tx_args); + mast_store.load_transaction_code(self.account().code(), self.input_notes(), &self.tx_args); CodeExecutor::new(MockHost::new( self.tx_inputs.account().into(), diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index 59e6ac27e0..d0d7447611 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -72,7 +72,7 @@ fn transaction_executor_witness() { // load account/note/tx_script MAST to the mast_store let mast_store = Arc::new(TransactionMastStore::new()); - mast_store.load_transaction_code(tx_inputs, tx_args); + mast_store.load_transaction_code(tx_inputs.account().code(), tx_inputs.input_notes(), tx_args); let mut host: TransactionHost = TransactionHost::new( tx_inputs.account().into(), From 5965b5c656efd7f7c637e9bc5ba781e78ccac51f Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Fri, 11 Apr 2025 16:37:01 -0300 Subject: [PATCH 13/29] refactor: FPI inputs --- crates/miden-tx/src/executor/mod.rs | 9 +++++---- crates/miden-tx/src/tests/mod.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index dcf031237d..df74b4f50e 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -1,4 +1,4 @@ -use alloc::{collections::BTreeSet, sync::Arc}; +use alloc::{collections::BTreeSet, sync::Arc, vec::Vec}; use miden_lib::transaction::TransactionKernel; use miden_objects::{ @@ -7,8 +7,8 @@ use miden_objects::{ block::BlockNumber, note::NoteLocation, transaction::{ - ExecutedTransaction, InputNote, InputNotes, TransactionArgs, TransactionInputs, - TransactionScript, + ExecutedTransaction, ForeignAccountInputs, InputNote, InputNotes, TransactionArgs, + TransactionInputs, TransactionScript, }, vm::StackOutputs, }; @@ -171,6 +171,7 @@ impl TransactionExecutor { block_ref: BlockNumber, tx_script: TransactionScript, advice_inputs: AdviceInputs, + foreign_account_inputs: Vec, ) -> Result<[Felt; 16], TransactionExecutorError> { let ref_blocks = [block_ref].into_iter().collect(); let (account, seed, header, mmr) = @@ -184,7 +185,7 @@ impl TransactionExecutor { Some(tx_script.clone()), None, Default::default(), - Default::default(), + foreign_account_inputs, ); let (stack_inputs, advice_inputs) = diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index d0d7447611..d815e7ef67 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -954,7 +954,7 @@ fn test_execute_program() { let executor = TransactionExecutor::new(Arc::new(tx_context), None); let stack_outputs = executor - .execute_tx_view_script(account_id, block_ref, tx_script, advice_inputs) + .execute_tx_view_script(account_id, block_ref, tx_script, advice_inputs, Vec::default()) .unwrap(); assert_eq!(stack_outputs[..3], [Felt::new(7), Felt::new(2), ONE]); From 0a680cf964ced4f62511271c9c00c1b152220c8e Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 14 Apr 2025 16:19:49 -0300 Subject: [PATCH 14/29] reviews: propagate errors, add validations and tests --- bin/bench-tx/src/main.rs | 2 - crates/miden-lib/src/transaction/inputs.rs | 22 +-- crates/miden-lib/src/transaction/mod.rs | 32 +++-- crates/miden-objects/src/errors.rs | 2 + .../miden-objects/src/transaction/inputs.rs | 64 +++++++-- .../miden-objects/src/transaction/tx_args.rs | 16 ++- .../src/transaction/tx_witness.rs | 5 + crates/miden-tx/src/errors/mod.rs | 22 ++- crates/miden-tx/src/executor/data_store.rs | 4 +- crates/miden-tx/src/executor/mod.rs | 62 ++++++--- crates/miden-tx/src/prover/mod.rs | 12 +- crates/miden-tx/src/testing/mock_chain/mod.rs | 11 +- crates/miden-tx/src/testing/mock_host.rs | 7 +- .../src/testing/tx_context/builder.rs | 1 - crates/miden-tx/src/testing/tx_context/mod.rs | 22 ++- .../src/tests/kernel_tests/test_account.rs | 16 +-- .../src/tests/kernel_tests/test_asset.rs | 8 +- .../tests/kernel_tests/test_asset_vault.rs | 26 ++-- .../src/tests/kernel_tests/test_epilogue.rs | 18 +-- .../src/tests/kernel_tests/test_faucet.rs | 38 +++--- .../src/tests/kernel_tests/test_fpi.rs | 8 +- .../src/tests/kernel_tests/test_note.rs | 22 +-- .../src/tests/kernel_tests/test_prologue.rs | 10 +- .../src/tests/kernel_tests/test_tx.rs | 127 +++++++++++++++--- crates/miden-tx/src/tests/mod.rs | 7 +- 25 files changed, 381 insertions(+), 183 deletions(-) diff --git a/bin/bench-tx/src/main.rs b/bin/bench-tx/src/main.rs index 6af8c55338..dfc7d6729d 100644 --- a/bin/bench-tx/src/main.rs +++ b/bin/bench-tx/src/main.rs @@ -60,7 +60,6 @@ fn main() -> Result<(), String> { // ================================================================================================ /// Runs the default transaction with empty transaction script and two default notes. -#[allow(clippy::arc_with_non_send_sync)] pub fn benchmark_default_tx() -> Result { let tx_context = TransactionContextBuilder::with_standard_account(ONE) .with_mock_notes_preserved() @@ -81,7 +80,6 @@ pub fn benchmark_default_tx() -> Result { } /// Runs the transaction which consumes a P2ID note into a basic wallet. -#[allow(clippy::arc_with_non_send_sync)] pub fn benchmark_p2id() -> Result { // Create assets let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(); diff --git a/crates/miden-lib/src/transaction/inputs.rs b/crates/miden-lib/src/transaction/inputs.rs index de4bfe7c81..9dbe5f2ea0 100644 --- a/crates/miden-lib/src/transaction/inputs.rs +++ b/crates/miden-lib/src/transaction/inputs.rs @@ -1,7 +1,7 @@ use alloc::vec::Vec; use miden_objects::{ - Digest, EMPTY_WORD, Felt, FieldElement, WORD_SIZE, Word, ZERO, + Digest, EMPTY_WORD, Felt, FieldElement, TransactionInputError, WORD_SIZE, Word, ZERO, account::{Account, StorageSlot}, transaction::{ChainMmr, InputNote, TransactionArgs, TransactionInputs, TransactionScript}, vm::AdviceInputs, @@ -22,7 +22,7 @@ pub(super) fn extend_advice_inputs( tx_inputs: &TransactionInputs, tx_args: &TransactionArgs, advice_inputs: &mut AdviceInputs, -) { +) -> Result<(), TransactionInputError> { // TODO: remove this value and use a user input instead let kernel_version = 0; @@ -32,13 +32,13 @@ pub(super) fn extend_advice_inputs( add_kernel_commitments_to_advice_inputs(advice_inputs, kernel_version); add_chain_mmr_to_advice_inputs(tx_inputs.block_chain(), advice_inputs); add_account_to_advice_inputs(tx_inputs.account(), tx_inputs.account_seed(), advice_inputs); - add_input_notes_to_advice_inputs(tx_inputs, tx_args, advice_inputs); + add_input_notes_to_advice_inputs(tx_inputs, tx_args, advice_inputs)?; for foreign_account in tx_args.foreign_accounts() { - TransactionKernel::extend_advice_inputs_for_account(advice_inputs, foreign_account) - .unwrap(); + TransactionKernel::extend_advice_inputs_for_account(advice_inputs, foreign_account)?; } advice_inputs.extend(tx_args.advice_inputs().clone()); + Ok(()) } // ADVICE STACK BUILDER @@ -228,10 +228,10 @@ fn add_input_notes_to_advice_inputs( tx_inputs: &TransactionInputs, tx_args: &TransactionArgs, inputs: &mut AdviceInputs, -) { +) -> Result<(), TransactionInputError> { // if there are no input notes, nothing is added to the advice inputs if tx_inputs.input_notes().is_empty() { - return; + return Ok(()); } let mut note_data = Vec::new(); @@ -288,7 +288,12 @@ fn add_input_notes_to_advice_inputs( proof.location().node_index_in_block().into(), note.commitment(), ) - .unwrap(), + .map_err(|err| { + TransactionInputError::InvalidMerklePath( + format!("input note ID {}", note.id()), + err, + ) + })?, ); note_data.push(proof.location().block_num().into()); note_data.extend(note_block_header.sub_commitment()); @@ -305,6 +310,7 @@ fn add_input_notes_to_advice_inputs( // NOTE: keep map in sync with the `prologue::process_input_notes_data` kernel procedure inputs.extend_map([(tx_inputs.input_notes().commitment(), note_data)]); + Ok(()) } // KERNEL COMMITMENTS INJECTOR diff --git a/crates/miden-lib/src/transaction/mod.rs b/crates/miden-lib/src/transaction/mod.rs index 024d0c9401..ef5562bbb3 100644 --- a/crates/miden-lib/src/transaction/mod.rs +++ b/crates/miden-lib/src/transaction/mod.rs @@ -1,11 +1,10 @@ use alloc::{string::ToString, sync::Arc, vec::Vec}; use miden_objects::{ - Digest, EMPTY_WORD, Felt, TransactionOutputError, ZERO, + Digest, EMPTY_WORD, Felt, TransactionInputError, TransactionOutputError, ZERO, account::{AccountCode, AccountId}, assembly::{Assembler, DefaultSourceManager, KernelLibrary}, block::BlockNumber, - crypto::merkle::MerkleError, transaction::{ ForeignAccountInputs, OutputNote, OutputNotes, TransactionArgs, TransactionInputs, TransactionOutputs, @@ -115,7 +114,7 @@ impl TransactionKernel { tx_inputs: &TransactionInputs, tx_args: &TransactionArgs, init_advice_inputs: Option, - ) -> (StackInputs, AdviceInputs) { + ) -> Result<(StackInputs, AdviceInputs), TransactionInputError> { let account = tx_inputs.account(); let stack_inputs = TransactionKernel::build_input_stack( @@ -127,9 +126,9 @@ impl TransactionKernel { ); let mut advice_inputs = init_advice_inputs.unwrap_or_default(); - inputs::extend_advice_inputs(tx_inputs, tx_args, &mut advice_inputs); + inputs::extend_advice_inputs(tx_inputs, tx_args, &mut advice_inputs)?; - (stack_inputs, advice_inputs) + Ok((stack_inputs, advice_inputs)) } // ASSEMBLER CONSTRUCTOR @@ -201,11 +200,11 @@ impl TransactionKernel { pub fn extend_advice_inputs_for_account( advice_inputs: &mut AdviceInputs, foreign_account_inputs: &ForeignAccountInputs, - ) -> Result<(), MerkleError> { + ) -> Result<(), TransactionInputError> { let account_header = foreign_account_inputs.account_header(); let storage_header = foreign_account_inputs.storage_header(); let account_code = foreign_account_inputs.account_code(); - let merkle_path = foreign_account_inputs.merkle_proof(); + let merkle_path = foreign_account_inputs.account_witness(); let storage_proofs = foreign_account_inputs.storage_map_proofs(); let account_id = account_header.id(); @@ -228,14 +227,29 @@ impl TransactionKernel { // Extend the advice inputs with Merkle store data advice_inputs.extend_merkle_store( // The prefix is the index in the account tree. - merkle_path.inner_nodes(account_id.prefix().as_u64(), account_header.commitment())?, + merkle_path + .inner_nodes(account_id.prefix().as_u64(), account_header.commitment()) + .map_err(|err| { + TransactionInputError::InvalidMerklePath( + format!("foreign account ID {}", account_id), + err, + ) + })?, ); // Load merkle nodes for storage maps for proof in storage_proofs { // Extend the merkle store and map with the storage maps advice_inputs.extend_merkle_store( - proof.path().inner_nodes(proof.leaf().index().value(), proof.leaf().hash())?, + proof + .path() + .inner_nodes(proof.leaf().index().value(), proof.leaf().hash()) + .map_err(|err| { + TransactionInputError::InvalidMerklePath( + format!("foreign account ID {} storage proof", account_id), + err, + ) + })?, ); // Populate advice map with Sparse Merkle Tree leaf nodes advice_inputs diff --git a/crates/miden-objects/src/errors.rs b/crates/miden-objects/src/errors.rs index 1a4be2e5c9..1533436977 100644 --- a/crates/miden-objects/src/errors.rs +++ b/crates/miden-objects/src/errors.rs @@ -450,6 +450,8 @@ pub enum TransactionInputError { InputNoteNotInBlock(NoteId, BlockNumber), #[error("account ID computed from seed is invalid")] InvalidAccountIdSeed(#[source] AccountIdError), + #[error("merkle path for {0} is invalid")] + InvalidMerklePath(String, #[source] MerkleError), #[error( "total number of input notes is {0} which exceeds the maximum of {MAX_INPUT_NOTES_PER_TX}" )] diff --git a/crates/miden-objects/src/transaction/inputs.rs b/crates/miden-objects/src/transaction/inputs.rs index a66a512ae5..671d9b9c48 100644 --- a/crates/miden-objects/src/transaction/inputs.rs +++ b/crates/miden-objects/src/transaction/inputs.rs @@ -1,7 +1,7 @@ use alloc::{collections::BTreeSet, vec::Vec}; use core::fmt::Debug; -use miden_crypto::merkle::{MerklePath, SmtProof}; +use miden_crypto::merkle::{MerkleError, MerklePath, SmtProof}; use super::{BlockHeader, ChainMmr, Digest, Felt, Hasher, Word}; use crate::{ @@ -549,7 +549,7 @@ pub struct ForeignAccountInputs { /// Code associated with the account. account_code: AccountCode, /// Merkle proof of the account's inclusion in the account tree. - merkle_proof: MerklePath, + account_witness: MerklePath, /// Storage SMT proof for storage map values that the transaction will access. storage_map_proofs: Vec, } @@ -567,7 +567,7 @@ impl ForeignAccountInputs { account_header, storage_header, account_code, - merkle_proof, + account_witness: merkle_proof, storage_map_proofs, } } @@ -597,9 +597,15 @@ impl ForeignAccountInputs { &self.account_code } - /// Returns the account's proof. - pub fn merkle_proof(&self) -> &MerklePath { - &self.merkle_proof + /// Returns the account witness. + pub fn account_witness(&self) -> &MerklePath { + &self.account_witness + } + + /// Computes account root based on the account witness. + pub fn compute_account_root(&self) -> Result { + self.account_witness() + .compute_root(self.id().prefix().into(), self.account_header().commitment()) } /// Extends the storage proofs with the input `smt_proofs` and returns the new structure @@ -620,7 +626,7 @@ impl ForeignAccountInputs { self.account_header, self.storage_header, self.account_code, - self.merkle_proof, + self.account_witness, self.storage_map_proofs, ) } @@ -631,7 +637,7 @@ impl Serializable for ForeignAccountInputs { self.account_header.write_into(target); self.storage_header.write_into(target); self.account_code.write_into(target); - self.merkle_proof.write_into(target); + self.account_witness.write_into(target); self.storage_map_proofs.write_into(target); } } @@ -654,3 +660,45 @@ impl Deserializable for ForeignAccountInputs { )) } } + +#[cfg(test)] +mod tests { + + use miden_crypto::merkle::MerklePath; + use vm_core::{ + Felt, + utils::{Deserializable, Serializable}, + }; + + use super::ForeignAccountInputs; + use crate::{ + account::{Account, AccountCode, AccountHeader, AccountId, AccountStorage}, + asset::AssetVault, + testing::account_id::ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, + }; + + #[test] + fn serde_roundtrip() { + let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap(); + let code = AccountCode::mock(); + let vault = AssetVault::new(&vec![]).unwrap(); + let storage = AccountStorage::new(vec![]).unwrap(); + let account = Account::from_parts(id, vault, storage, code, Felt::new(10)); + + let commitment = account.commitment(); + let header: AccountHeader = account.clone().into(); + let (_, _, storage, code, _) = account.into_parts(); + + let fpi_inputs = ForeignAccountInputs::new( + header, + storage.get_header(), + code, + MerklePath::new(vec![commitment]), + vec![], + ); + + let serialized = fpi_inputs.to_bytes(); + let deserialized = ForeignAccountInputs::read_from_bytes(&serialized).unwrap(); + assert_eq!(deserialized, fpi_inputs); + } +} diff --git a/crates/miden-objects/src/transaction/tx_args.rs b/crates/miden-objects/src/transaction/tx_args.rs index 55f6b8870a..3f6bd20f96 100644 --- a/crates/miden-objects/src/transaction/tx_args.rs +++ b/crates/miden-objects/src/transaction/tx_args.rs @@ -1,4 +1,8 @@ -use alloc::{collections::BTreeMap, sync::Arc, vec::Vec}; +use alloc::{ + collections::{BTreeMap, BTreeSet}, + sync::Arc, + vec::Vec, +}; use assembly::{Assembler, Compile}; use miden_crypto::merkle::InnerNodeInfo; @@ -107,6 +111,14 @@ impl TransactionArgs { &self.foreign_accounts } + /// Collects and returns a set containing all code commitments from foreign accounts. + pub fn foreign_account_code_commitments(&self) -> BTreeSet { + self.foreign_accounts() + .iter() + .map(|acc| acc.account_code().commitment()) + .collect() + } + // STATE MUTATORS // -------------------------------------------------------------------------------------------- @@ -149,7 +161,7 @@ impl TransactionArgs { } } - /// Extends the provided [TransactionArgs] with the passed-in `advice_inputs`. + /// Extends the advice inputs in self with the provided ones. pub fn extend_advice_inputs(&mut self, advice_inputs: AdviceInputs) { self.advice_inputs.extend(advice_inputs); } diff --git a/crates/miden-objects/src/transaction/tx_witness.rs b/crates/miden-objects/src/transaction/tx_witness.rs index 43f6c1c5ed..7fd67c8eb3 100644 --- a/crates/miden-objects/src/transaction/tx_witness.rs +++ b/crates/miden-objects/src/transaction/tx_witness.rs @@ -17,6 +17,11 @@ use crate::utils::serde::{ByteReader, Deserializable, DeserializationError, Seri /// additional advice data to initialize the advice provide with prior to transaction execution. /// - Advice witness which contains all data requested by the VM from the advice provider while /// executing the transaction program. +/// +/// TODO: currently, the advice witness contains redundant and irrelevant data (e.g., tx inputs +/// and tx outputs; account codes and a subset of that data in advice inputs). +/// We should optimize it to contain only the minimum data required for executing/proving the +/// transaction. #[derive(Clone, Debug, PartialEq, Eq)] pub struct TransactionWitness { pub tx_inputs: TransactionInputs, diff --git a/crates/miden-tx/src/errors/mod.rs b/crates/miden-tx/src/errors/mod.rs index 6b7661f5f7..fa436c3f81 100644 --- a/crates/miden-tx/src/errors/mod.rs +++ b/crates/miden-tx/src/errors/mod.rs @@ -3,21 +3,21 @@ use core::error::Error; use miden_objects::{ AccountError, Felt, ProvenTransactionError, TransactionInputError, TransactionOutputError, - account::AccountId, block::BlockNumber, + account::AccountId, block::BlockNumber, note::NoteId, }; use miden_verifier::VerificationError; use thiserror::Error; -use vm_processor::ExecutionError; +use vm_processor::{ExecutionError, crypto::MerkleError}; // TRANSACTION EXECUTOR ERROR // ================================================================================================ #[derive(Debug, Error)] pub enum TransactionExecutorError { - #[error("failed to execute transaction kernel program")] - TransactionProgramExecutionFailed(#[source] ExecutionError), #[error("failed to fetch transaction inputs from the data store")] FetchTransactionInputsFailed(#[source] DataStoreError), + #[error("foreign account inputs for ID {0} are not anchored on reference block")] + ForeignAccountNotAnchoredInReference(AccountId), #[error("failed to create transaction inputs")] InvalidTransactionInputs(#[source] TransactionInputError), #[error("input account ID {input_id} does not match output account ID {output_id}")] @@ -30,10 +30,18 @@ pub enum TransactionExecutorError { expected: Option, actual: Option, }, - #[error("failed to construct transaction outputs")] - TransactionOutputConstructionFailed(#[source] TransactionOutputError), + #[error("account witness provided for account ID {0} is invalid")] + InvalidAccountWitness(AccountId, #[source] MerkleError), + #[error( + "input note {0} was created in a block past the transaction reference block number ({1})" + )] + NoteBlockPastReferenceBlock(NoteId, BlockNumber), #[error("failed to create transaction host")] TransactionHostCreationFailed(#[source] TransactionHostError), + #[error("failed to construct transaction outputs")] + TransactionOutputConstructionFailed(#[source] TransactionOutputError), + #[error("failed to execute transaction kernel program")] + TransactionProgramExecutionFailed(#[source] ExecutionError), } // TRANSACTION PROVER ERROR @@ -43,6 +51,8 @@ pub enum TransactionExecutorError { pub enum TransactionProverError { #[error("failed to apply account delta")] AccountDeltaApplyFailed(#[source] AccountError), + #[error("transaction inputs are not valid")] + InvalidTransactionInputs(#[source] TransactionInputError), #[error("failed to construct transaction outputs")] TransactionOutputConstructionFailed(#[source] TransactionOutputError), #[error("failed to build proven transaction")] diff --git a/crates/miden-tx/src/executor/data_store.rs b/crates/miden-tx/src/executor/data_store.rs index 73ec9740bc..43ff605a26 100644 --- a/crates/miden-tx/src/executor/data_store.rs +++ b/crates/miden-tx/src/executor/data_store.rs @@ -23,8 +23,8 @@ pub trait DataStore: MastForestStore { /// specified ID and consuming input notes created in blocks in the input `ref_blocks` set. /// /// The highest block number in `ref_blocks` will be the transaction reference block. In - /// general, it is recommended that bock_ref corresponds to the latest block available in - /// the data store. + /// general, it is recommended that the refernece corresponds to the latest block available + /// in the data store. /// /// # Errors /// Returns an error if: diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index df74b4f50e..ccf38fb57f 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -5,7 +5,6 @@ use miden_objects::{ Felt, MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES, ZERO, account::AccountId, block::BlockNumber, - note::NoteLocation, transaction::{ ExecutedTransaction, ForeignAccountInputs, InputNote, InputNotes, TransactionArgs, TransactionInputs, TransactionScript, @@ -32,11 +31,11 @@ pub use mast_store::TransactionMastStore; /// /// Transaction execution consists of the following steps: /// - Fetch the data required to execute a transaction from the [DataStore]. -/// - Load the code associated with the transaction into the [TransactionMastStore]. /// - Execute the transaction program and create an [ExecutedTransaction]. /// /// The transaction executor uses dynamic dispatch with trait objects for the [DataStore] and /// [TransactionAuthenticator], allowing it to be used with different backend implementations. +/// At the moment of execution, the [DataStore] is expected to provide all required MAST nodes. pub struct TransactionExecutor { data_store: Arc, authenticator: Option>, @@ -101,6 +100,9 @@ impl TransactionExecutor { /// # Errors: /// Returns an error if: /// - If required data can not be fetched from the [DataStore]. + /// - If the transaction arguments contain foreign account data not anchored in the reference + /// block. + /// - If any input notes were created in block numbers higher than the reference block. #[maybe_async] pub fn execute_transaction( &self, @@ -109,22 +111,45 @@ impl TransactionExecutor { notes: InputNotes, tx_args: TransactionArgs, ) -> Result { - let mut ref_blocks: BTreeSet = notes - .iter() - .filter_map(InputNote::location) - .map(NoteLocation::block_num) - .collect(); + // Validate that notes were not created after the reference, and build the set of required + // block numbers + let mut ref_blocks: BTreeSet = BTreeSet::new(); + for note in ¬es { + if let Some(location) = note.location() { + if location.block_num() > block_ref { + return Err(TransactionExecutorError::NoteBlockPastReferenceBlock( + note.id(), + block_ref, + )); + } + ref_blocks.insert(location.block_num()); + } + } + ref_blocks.insert(block_ref); - let (account, seed, header, mmr) = + let (account, seed, ref_header, mmr) = maybe_await!(self.data_store.get_transaction_inputs(account_id, ref_blocks)) .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; - let tx_inputs = TransactionInputs::new(account, seed, header, mmr, notes) + // Validate that foreign account inputs are anchored in the reference block + for foreign_account in tx_args.foreign_accounts() { + let computed_account_root = foreign_account.compute_account_root().map_err(|err| { + TransactionExecutorError::InvalidAccountWitness(foreign_account.id(), err) + })?; + if computed_account_root != ref_header.account_root() { + return Err(TransactionExecutorError::ForeignAccountNotAnchoredInReference( + foreign_account.id(), + )); + } + } + + let tx_inputs = TransactionInputs::new(account, seed, ref_header, mmr, notes) .map_err(TransactionExecutorError::InvalidTransactionInputs)?; let (stack_inputs, advice_inputs) = - TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, None); + TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, None) + .map_err(TransactionExecutorError::InvalidTransactionInputs)?; let advice_recorder: RecAdviceProvider = advice_inputs.into(); @@ -133,15 +158,11 @@ impl TransactionExecutor { advice_recorder, self.data_store.clone(), self.authenticator.clone(), - tx_args - .foreign_accounts() - .iter() - .map(|acc| acc.account_code().commitment()) - .collect(), + tx_args.foreign_account_code_commitments(), ) .map_err(TransactionExecutorError::TransactionHostCreationFailed)?; - // execute the transaction kernel + // Execute the transaction kernel let result = vm_processor::execute( &TransactionKernel::main(), stack_inputs, @@ -189,7 +210,8 @@ impl TransactionExecutor { ); let (stack_inputs, advice_inputs) = - TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_inputs)); + TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_inputs)) + .map_err(TransactionExecutorError::InvalidTransactionInputs)?; let advice_recorder: RecAdviceProvider = advice_inputs.into(); let mut host = TransactionHost::new( @@ -197,11 +219,7 @@ impl TransactionExecutor { advice_recorder, self.data_store.clone(), self.authenticator.clone(), - tx_args - .foreign_accounts() - .iter() - .map(|acc| acc.account_code().commitment()) - .collect(), + tx_args.foreign_account_code_commitments(), ) .map_err(TransactionExecutorError::TransactionHostCreationFailed)?; diff --git a/crates/miden-tx/src/prover/mod.rs b/crates/miden-tx/src/prover/mod.rs index 15f7a703fa..d3a4a50494 100644 --- a/crates/miden-tx/src/prover/mod.rs +++ b/crates/miden-tx/src/prover/mod.rs @@ -5,7 +5,6 @@ use alloc::{sync::Arc, vec::Vec}; use miden_lib::transaction::TransactionKernel; use miden_objects::{ account::delta::AccountUpdateDetails, - assembly::Library, transaction::{OutputNote, ProvenTransaction, ProvenTransactionBuilder, TransactionWitness}, }; pub use miden_prover::ProvingOptions; @@ -55,14 +54,6 @@ impl LocalTransactionProver { proof_options, } } - - /// Loads the provided library code into the internal MAST forest store. - /// - /// TODO: this is a work-around to support accounts which were complied with user-defined - /// libraries. Once Miden Assembler supports library vendoring, this should go away. - pub fn load_library(&mut self, library: &Library) { - self.mast_store.insert(library.mast_forest().clone()); - } } impl Default for LocalTransactionProver { @@ -90,7 +81,8 @@ impl TransactionProver for LocalTransactionProver { // execute and prove let (stack_inputs, advice_inputs) = - TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_witness)); + TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_witness)) + .map_err(TransactionProverError::InvalidTransactionInputs)?; let advice_provider: MemAdviceProvider = advice_inputs.into(); // load the store with account/note/tx_script MASTs diff --git a/crates/miden-tx/src/testing/mock_chain/mod.rs b/crates/miden-tx/src/testing/mock_chain/mod.rs index bf2ec535dc..1eb8fe7a8d 100644 --- a/crates/miden-tx/src/testing/mock_chain/mod.rs +++ b/crates/miden-tx/src/testing/mock_chain/mod.rs @@ -624,9 +624,16 @@ impl MockChain { }; let (account, seed) = if let AccountState::New = account_state { - let last_block = self.blocks.last().expect("one block should always exist"); + let epoch_block_number = self + .blocks + .last() + .expect("one block should always exist") + .header() + .epoch_block_num(); + let account_id_anchor = + self.blocks.get(epoch_block_number.as_usize()).unwrap().header(); account_builder = - account_builder.anchor(AccountIdAnchor::try_from(last_block.header()).unwrap()); + account_builder.anchor(AccountIdAnchor::try_from(account_id_anchor).unwrap()); account_builder.build().map(|(account, seed)| (account, Some(seed))).unwrap() } else { diff --git a/crates/miden-tx/src/testing/mock_host.rs b/crates/miden-tx/src/testing/mock_host.rs index 121c0aeac3..896873392e 100644 --- a/crates/miden-tx/src/testing/mock_host.rs +++ b/crates/miden-tx/src/testing/mock_host.rs @@ -1,4 +1,5 @@ -use alloc::{boxed::Box, collections::BTreeMap, rc::Rc, string::ToString, sync::Arc, vec::Vec}; +use alloc::{boxed::Box, collections::BTreeMap, rc::Rc, string::ToString, sync::Arc}; +use std::collections::BTreeSet; use miden_lib::{ errors::tx_kernel_errors::TX_KERNEL_ERRORS, @@ -38,9 +39,9 @@ impl MockHost { account: AccountHeader, advice_inputs: AdviceInputs, mast_store: Rc, - mut foreign_code_commitments: Vec, + mut foreign_code_commitments: BTreeSet, ) -> Self { - foreign_code_commitments.push(account.code_commitment()); + foreign_code_commitments.insert(account.code_commitment()); let adv_provider: MemAdviceProvider = advice_inputs.into(); let proc_index_map = AccountProcedureIndexMap::new(foreign_code_commitments, &adv_provider); diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index cad6d24b64..cf13c923e1 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -694,7 +694,6 @@ impl TransactionContextBuilder { mast_store, authenticator: self.authenticator, advice_inputs: self.advice_inputs, - assembler: self.assembler, } } } diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index e5f3e80058..03728cb242 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -42,7 +42,6 @@ pub struct TransactionContext { mast_store: TransactionMastStore, advice_inputs: AdviceInputs, authenticator: Option, - assembler: Assembler, } impl TransactionContext { @@ -56,18 +55,22 @@ impl TransactionContext { /// /// # Errors /// Returns an error if the assembly or execution of the provided code fails. - pub fn execute_code(&self, code: &str) -> Result { + pub fn execute_code( + &self, + code: &str, + assembler: Assembler, + ) -> Result { let (stack_inputs, mut advice_inputs) = TransactionKernel::prepare_inputs( &self.tx_inputs, &self.tx_args, Some(self.advice_inputs.clone()), - ); + ) + .unwrap(); advice_inputs.extend(self.advice_inputs.clone()); let test_lib = TransactionKernel::kernel_as_library(); - let program = self - .assembler + let program = assembler .clone() .with_debug_mode(true) .assemble_program(code) @@ -83,18 +86,13 @@ impl TransactionContext { self.tx_inputs.account().into(), advice_inputs, mast_store, - self.tx_args - .foreign_accounts() - .iter() - .map(|acc| acc.account_code().commitment()) - .collect(), + self.tx_args.foreign_account_code_commitments(), )) .stack_inputs(stack_inputs) .execute_program(program) } /// Executes the transaction through a [TransactionExecutor] - #[allow(clippy::arc_with_non_send_sync)] #[maybe_async] pub fn execute(self) -> Result { let account_id = self.account().id(); @@ -150,7 +148,7 @@ impl DataStore for TransactionContext { _ref_blocks: BTreeSet, ) -> Result<(Account, Option, BlockHeader, ChainMmr), DataStoreError> { assert_eq!(account_id, self.account().id()); - let (account, seed, header, mmr, _) = self.tx_inputs.clone().into_parts().clone(); + let (account, seed, header, mmr, _) = self.tx_inputs.clone().into_parts(); Ok((account, seed, header, mmr)) } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_account.rs b/crates/miden-tx/src/tests/kernel_tests/test_account.rs index b77f5b6e96..97aab95543 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_account.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_account.rs @@ -47,7 +47,7 @@ pub fn test_get_code() { end "; - let process = &tx_context.execute_code(code).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -262,7 +262,7 @@ fn test_get_item() { item_value = word_to_masm_push_string(&storage_item.slot.value()) ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } } @@ -302,7 +302,7 @@ fn test_get_map_item() { map_key = word_to_masm_push_string(&key), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -358,7 +358,7 @@ fn test_get_storage_slot_type() { item_index = storage_item.index, ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); let storage_slot_type = storage_item.slot.slot_type(); @@ -419,7 +419,7 @@ fn test_set_item() { new_storage_item_index = 0, ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } #[test] @@ -472,7 +472,7 @@ fn test_set_map_item() { new_value = word_to_masm_push_string(&new_value), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); let mut new_storage_map = AccountStorage::mock_map(); @@ -664,7 +664,7 @@ fn test_get_vault_root() { expected_vault_root = word_to_masm_push_string(&account.vault().root()), ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } // PROCEDURE AUTHENTICATION TESTS @@ -714,7 +714,7 @@ fn test_authenticate_procedure() { // Execution of this code will return an EventError(UnknownAccountProcedure) for procs // that are not in the advice provider. - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); match valid { true => assert!(process.is_ok(), "A valid procedure must successfully authenticate"), diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs index 7a7eb44144..ba90bf02de 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs @@ -1,4 +1,4 @@ -use miden_lib::utils::word_to_masm_push_string; +use miden_lib::{transaction::TransactionKernel, utils::word_to_masm_push_string}; use miden_objects::{ account::AccountId, asset::NonFungibleAsset, @@ -41,7 +41,7 @@ fn test_create_fungible_asset_succeeds() { " ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(); @@ -87,7 +87,7 @@ fn test_create_non_fungible_asset_succeeds() { word_to_masm_push_string(&Hasher::hash(&NON_FUNGIBLE_ASSET_DATA)), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!(process_state.get_stack_word(0), Word::from(non_fungible_asset)); @@ -120,7 +120,7 @@ fn test_validate_non_fungible_asset() { asset = word_to_masm_push_string(&encoded) ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!(process_state.get_stack_word(0), encoded); diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs index 96fe161dde..79480839df 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs @@ -7,7 +7,7 @@ use miden_lib::{ ERR_VAULT_NON_FUNGIBLE_ASSET_ALREADY_EXISTS, ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND, }, - transaction::memory, + transaction::{TransactionKernel, memory}, utils::word_to_masm_push_string, }; use miden_objects::{ @@ -53,7 +53,7 @@ fn test_get_balance() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); assert_eq!( process.stack.get(0).as_int(), @@ -81,7 +81,7 @@ fn test_get_balance_non_fungible_fails() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!( process, @@ -112,7 +112,7 @@ fn test_has_non_fungible_asset() { non_fungible_asset_key = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); assert_eq!(process.stack.get(0), ONE); } @@ -148,7 +148,7 @@ fn test_add_fungible_asset_success() { FUNGIBLE_ASSET = word_to_masm_push_string(&add_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -191,7 +191,7 @@ fn test_add_non_fungible_asset_fail_overflow() { FUNGIBLE_ASSET = word_to_masm_push_string(&add_fungible_asset.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_MAX_AMOUNT_EXCEEDED); assert!(account_vault.add_asset(add_fungible_asset).is_err()); @@ -227,7 +227,7 @@ fn test_add_non_fungible_asset_success() { FUNGIBLE_ASSET = word_to_masm_push_string(&add_non_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -265,7 +265,7 @@ fn test_add_non_fungible_asset_fail_duplicate() { NON_FUNGIBLE_ASSET = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_VAULT_NON_FUNGIBLE_ASSET_ALREADY_EXISTS); assert!(account_vault.add_asset(non_fungible_asset).is_err()); @@ -303,7 +303,7 @@ fn test_remove_fungible_asset_success_no_balance_remaining() { FUNGIBLE_ASSET = word_to_masm_push_string(&remove_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -344,7 +344,7 @@ fn test_remove_fungible_asset_fail_remove_too_much() { FUNGIBLE_ASSET = word_to_masm_push_string(&remove_fungible_asset.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW); } @@ -381,7 +381,7 @@ fn test_remove_fungible_asset_success_balance_remaining() { FUNGIBLE_ASSET = word_to_masm_push_string(&remove_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -426,7 +426,7 @@ fn test_remove_inexisting_non_fungible_asset_fails() { FUNGIBLE_ASSET = word_to_masm_push_string(&non_existent_non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND); assert_matches!( @@ -463,7 +463,7 @@ fn test_remove_non_fungible_asset_success() { FUNGIBLE_ASSET = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( diff --git a/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs b/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs index 2a4675a3bd..d3819beaa2 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs @@ -55,7 +55,7 @@ fn test_epilogue() { " ); - let process = tx_context.execute_code(&code).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let final_account = Account::mock( tx_context.account().id().into(), @@ -120,7 +120,7 @@ fn test_compute_output_note_id() { " ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); assert_eq!( note.assets().commitment().as_elements(), @@ -171,7 +171,7 @@ fn test_epilogue_asset_preservation_violation_too_few_input() { " ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_EPILOGUE_TOTAL_NUMBER_OF_ASSETS_MUST_STAY_THE_SAME); } @@ -205,7 +205,7 @@ fn test_epilogue_asset_preservation_violation_too_many_fungible_input() { " ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_EPILOGUE_TOTAL_NUMBER_OF_ASSETS_MUST_STAY_THE_SAME); } @@ -242,7 +242,7 @@ fn test_block_expiration_height_monotonically_decreases() { .replace("{value_2}", &v2.to_string()) .replace("{min_value}", &v2.min(v1).to_string()); - let process = &tx_context.execute_code(code).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); // Expiry block should be set to transaction's block + the stored expiration delta @@ -269,7 +269,7 @@ fn test_invalid_expiration_deltas() { for value in test_values { let code = &code_template.replace("{value_1}", &value.to_string()); - let process = tx_context.execute_code(code); + let process = tx_context.execute_code(code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_TX_INVALID_EXPIRATION_DELTA); } @@ -296,7 +296,7 @@ fn test_no_expiration_delta_set() { end "; - let process = &tx_context.execute_code(code_template).unwrap(); + let process = &tx_context.execute_code(code_template, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); // Default value should be equal to u32::max, set in the prologue @@ -341,7 +341,7 @@ fn test_epilogue_increment_nonce_success() { " ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } #[test] @@ -379,6 +379,6 @@ fn test_epilogue_increment_nonce_violation() { " ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_ACCOUNT_NONCE_DID_NOT_INCREASE_AFTER_STATE_CHANGE) } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs index 109ef55a26..d631b4d888 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs @@ -7,7 +7,7 @@ use miden_lib::{ ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN, ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW, }, - transaction::memory::NATIVE_ACCT_STORAGE_SLOTS_SECTION_PTR, + transaction::{TransactionKernel, memory::NATIVE_ACCT_STORAGE_SLOTS_SECTION_PTR}, utils::word_to_masm_push_string, }; use miden_objects::{ @@ -72,7 +72,7 @@ fn test_mint_fungible_asset_succeeds() { suffix = faucet_id.suffix(), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); let expected_final_storage_amount = FUNGIBLE_FAUCET_INITIAL_BALANCE + FUNGIBLE_ASSET_AMOUNT; @@ -109,7 +109,7 @@ fn test_mint_fungible_asset_fails_not_faucet_account() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -134,7 +134,7 @@ fn test_mint_fungible_asset_inconsistent_faucet_id() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -165,7 +165,7 @@ fn test_mint_fungible_asset_fails_saturate_max_amount() { saturating_amount = FungibleAsset::MAX_AMOUNT - FUNGIBLE_FAUCET_INITIAL_BALANCE + 1 ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FAUCET_NEW_TOTAL_SUPPLY_WOULD_EXCEED_MAX_ASSET_AMOUNT); } @@ -225,7 +225,7 @@ fn test_mint_non_fungible_asset_succeeds() { asset_vault_key = word_to_masm_push_string(&StorageMap::hash_key(asset_vault_key.into())), ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } #[test] @@ -248,7 +248,7 @@ fn test_mint_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -273,7 +273,7 @@ fn test_mint_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -303,7 +303,7 @@ fn test_mint_non_fungible_asset_fails_asset_already_exists() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_ALREADY_ISSUED); } @@ -353,7 +353,7 @@ fn test_burn_fungible_asset_succeeds() { final_input_vault_asset_amount = CONSUMED_ASSET_1_AMOUNT - FUNGIBLE_ASSET_AMOUNT, ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); let expected_final_storage_amount = FUNGIBLE_FAUCET_INITIAL_BALANCE - FUNGIBLE_ASSET_AMOUNT; @@ -390,7 +390,7 @@ fn test_burn_fungible_asset_fails_not_faucet_account() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -421,7 +421,7 @@ fn test_burn_fungible_asset_inconsistent_faucet_id() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -453,7 +453,7 @@ fn test_burn_fungible_asset_insufficient_input_amount() { saturating_amount = CONSUMED_ASSET_1_AMOUNT + 1 ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW); } @@ -518,7 +518,7 @@ fn test_burn_non_fungible_asset_succeeds() { burnt_asset_vault_key = word_to_masm_push_string(&burnt_asset_vault_key), ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } #[test] @@ -547,7 +547,7 @@ fn test_burn_non_fungible_asset_fails_does_not_exist() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_TO_BURN_NOT_FOUND); } @@ -573,7 +573,7 @@ fn test_burn_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!( process, @@ -608,7 +608,7 @@ fn test_burn_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_TO_BURN_NOT_FOUND); } @@ -657,7 +657,7 @@ fn test_is_non_fungible_asset_issued_succeeds() { non_fungible_asset_2 = word_to_masm_push_string(&non_fungible_asset_2.into()), ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } // GET TOTAL ISSUANCE TESTS @@ -691,5 +691,5 @@ fn test_get_total_issuance_succeeds() { ", ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index 7e7e0af7f5..6ae2c0e538 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -140,7 +140,7 @@ fn test_fpi_memory() { get_item_foreign_hash = foreign_account.code().procedures()[0].mast_root(), ); - let process = tx_context.execute_code(&code).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); assert_eq!( process.stack.get_word(0), @@ -194,7 +194,7 @@ fn test_fpi_memory() { get_map_item_foreign_hash = foreign_account.code().procedures()[1].mast_root(), ); - let process = tx_context.execute_code(&code).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); assert_eq!( process.stack.get_word(0), @@ -264,7 +264,7 @@ fn test_fpi_memory() { get_item_foreign_hash = foreign_account.code().procedures()[0].mast_root(), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); // Check that the second invocation of the foreign procedure from the same account does not load // the account data again: already loaded data should be reused. @@ -447,7 +447,7 @@ fn test_fpi_memory_two_accounts() { foreign_2_suffix = foreign_account_2.id().suffix(), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); // Check the correctness of the memory layout after multiple foreign procedure invocations from // different foreign accounts diff --git a/crates/miden-tx/src/tests/kernel_tests/test_note.rs b/crates/miden-tx/src/tests/kernel_tests/test_note.rs index 8fab39c6ae..8dc3e5af7c 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_note.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_note.rs @@ -46,7 +46,7 @@ fn test_get_sender_no_sender() { end "; - let process = tx_context.execute_code(code); + let process = tx_context.execute_code(code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_NOTE_ATTEMPT_TO_ACCESS_NOTE_SENDER_FROM_INCORRECT_CONTEXT); } @@ -74,7 +74,7 @@ fn test_get_sender() { end "; - let process = tx_context.execute_code(code).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); let sender = tx_context.input_notes().get_note(0).note().metadata().sender(); assert_eq!(process.stack.get(0), sender.prefix().as_felt()); @@ -129,7 +129,7 @@ fn test_get_vault_data() { note_1_num_assets = notes.get_note(1).note().assets().num_assets(), ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } #[test] fn test_get_assets() { @@ -240,7 +240,7 @@ fn test_get_assets() { NOTE_1_ASSET_ASSERTIONS = construct_asset_assertions(notes.get_note(1).note()), ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } #[test] @@ -309,7 +309,7 @@ fn test_get_inputs() { NOTE_0_PTR = 100000000, ); - tx_context.execute_code(&code).unwrap(); + tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); } #[test] @@ -332,7 +332,7 @@ fn test_note_setup() { end "; - let process = tx_context.execute_code(code).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); note_setup_stack_assertions(&process, &tx_context); note_setup_memory_assertions(&process); @@ -379,7 +379,7 @@ fn test_note_script_and_note_args() { ); tx_context.set_tx_args(tx_args); - let process = tx_context.execute_code(code).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); assert_eq!(process.stack.get_word(0), note_args[0]); @@ -426,7 +426,7 @@ fn test_get_note_serial_number() { end "; - let process = tx_context.execute_code(code).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); let serial_number = tx_context.input_notes().get_note(0).note().serial_num(); assert_eq!(process.stack.get_word(0), serial_number); @@ -477,7 +477,7 @@ fn test_get_inputs_hash() { end "; - let process = &tx_context.execute_code(code).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); let note_inputs_5_hash = @@ -549,7 +549,7 @@ fn test_get_current_script_root() { end "; - let process = tx_context.execute_code(code).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); let script_root = tx_context.input_notes().get_note(0).note().script().root(); assert_eq!(process.stack.get_word(0), script_root.as_elements()); @@ -602,7 +602,7 @@ fn test_build_note_metadata() { tag = test_metadata.tag(), ); - let process = tx_context.execute_code(&code).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let metadata_word = [ process.stack.get(3), diff --git a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs index 2d79480134..36b192d858 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs @@ -99,7 +99,7 @@ fn test_transaction_prologue() { ); tx_context.set_tx_args(tx_args); - let process = &tx_context.execute_code(code).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); global_input_memory_assertions(process, &tx_context); block_data_memory_assertions(process, &tx_context); @@ -436,7 +436,7 @@ pub fn create_account_test( end "; - tx_context.execute_code(code)?; + tx_context.execute_code(code, TransactionKernel::assembler())?; Ok(()) } @@ -647,7 +647,7 @@ pub fn create_account_invalid_seed() { end "; - let result = tx_context.execute_code(code); + let result = tx_context.execute_code(code, TransactionKernel::assembler()); assert_execution_error!(result, ERR_ACCOUNT_SEED_ANCHOR_BLOCK_COMMITMENT_DIGEST_MISMATCH) } @@ -668,7 +668,7 @@ fn test_get_blk_version() { end "; - let process = tx_context.execute_code(code).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); assert_eq!(process.stack.get(0), tx_context.tx_inputs().block_header().version().into()); } @@ -689,7 +689,7 @@ fn test_get_blk_timestamp() { end "; - let process = tx_context.execute_code(code).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); assert_eq!(process.stack.get(0), tx_context.tx_inputs().block_header().timestamp().into()); } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index 067df68c49..bc0e97db4a 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -1,13 +1,15 @@ -use alloc::vec::Vec; -use std::string::String; +use alloc::{string::String, sync::Arc, vec::Vec}; use miden_lib::{ errors::tx_kernel_errors::{ ERR_NON_FUNGIBLE_ASSET_ALREADY_EXISTS, ERR_TX_NUMBER_OF_OUTPUT_NOTES_EXCEEDS_LIMIT, }, - transaction::memory::{ - NOTE_MEM_SIZE, NUM_OUTPUT_NOTES_PTR, OUTPUT_NOTE_ASSETS_OFFSET, - OUTPUT_NOTE_METADATA_OFFSET, OUTPUT_NOTE_RECIPIENT_OFFSET, OUTPUT_NOTE_SECTION_OFFSET, + transaction::{ + TransactionKernel, + memory::{ + NOTE_MEM_SIZE, NUM_OUTPUT_NOTES_PTR, OUTPUT_NOTE_ASSETS_OFFSET, + OUTPUT_NOTE_METADATA_OFFSET, OUTPUT_NOTE_RECIPIENT_OFFSET, OUTPUT_NOTE_SECTION_OFFSET, + }, }, utils::word_to_masm_push_string, }; @@ -15,23 +17,104 @@ use miden_objects::{ FieldElement, account::AccountId, asset::NonFungibleAsset, + block::BlockNumber, note::{ Note, NoteAssets, NoteExecutionHint, NoteExecutionMode, NoteInputs, NoteMetadata, NoteRecipient, NoteTag, NoteType, }, testing::{ - account_id::{ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2}, + account_id::{ + ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, + }, constants::NON_FUNGIBLE_ASSET_DATA_2, }, - transaction::{OutputNote, OutputNotes}, + transaction::{InputNotes, OutputNote, OutputNotes, TransactionArgs}, }; use super::{Felt, ONE, ProcessState, Word, ZERO}; use crate::{ - assert_execution_error, testing::TransactionContextBuilder, + TransactionExecutor, TransactionExecutorError, assert_execution_error, + testing::{Auth, MockChain, TransactionContextBuilder}, tests::kernel_tests::read_root_mem_word, }; +#[test] +fn test_fpi_anchoring_validations() { + // Create a chain with an account + let mut mock_chain = MockChain::new(); + let account = mock_chain.add_existing_wallet(Auth::BasicAuth, vec![]); + mock_chain.seal_next_block(); + + // Retrieve inputs which will become stale + let inputs = mock_chain.get_foreign_account_inputs(account.id()); + + // Add account to modify account tree + let new_account = mock_chain.add_existing_wallet(Auth::BasicAuth, vec![]); + mock_chain.seal_next_block(); + + // Attempt to execute with older foreign account inputs + let transaction = mock_chain + .build_tx_context(new_account.id(), &[], &[]) + .foreign_accounts(vec![inputs]) + .build() + .execute(); + + assert_matches::assert_matches!( + transaction, + Err(TransactionExecutorError::ForeignAccountNotAnchoredInReference(_)) + ); +} + +#[test] +fn test_future_input_note_fails() { + // Create a chain with an account + let mut mock_chain = MockChain::new(); + let account = mock_chain.add_existing_wallet(Auth::BasicAuth, vec![]); + mock_chain.seal_block(Some(10), None); + + // Create note that will land on a future block + let note = mock_chain + .add_p2id_note( + account.id(), + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into().unwrap(), + &[], + NoteType::Private, + None, + ) + .unwrap(); + mock_chain.seal_next_block(); + + // Get as input note, and assert that the note was created after block 1 (which we'll + // use as reference) + let input_note = mock_chain + .available_notes() + .iter() + .find(|n| n.id() == note.id()) + .unwrap() + .clone(); + assert!(input_note.location().unwrap().block_num() > 1.into()); + + mock_chain.seal_next_block(); + + // Attempt to execute with a note created in the future + let tx_context = mock_chain.build_tx_context(account.id(), &[], &[]).build(); + + let tx_executor = TransactionExecutor::new(Arc::new(tx_context), None); + // Try to execute with block_ref==1 + let error = tx_executor.execute_transaction( + account.id(), + BlockNumber::from(1), + InputNotes::new(vec![input_note]).unwrap(), + TransactionArgs::default(), + ); + + assert_matches::assert_matches!( + error, + Err(TransactionExecutorError::NoteBlockPastReferenceBlock(..)) + ); +} + #[test] fn test_create_note() { let tx_context = TransactionContextBuilder::with_standard_account(ONE).build(); @@ -68,7 +151,7 @@ fn test_create_note() { tag = tag, ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); assert_eq!( read_root_mem_word(&process.into(), NUM_OUTPUT_NOTES_PTR), @@ -124,9 +207,17 @@ fn test_create_note_with_invalid_tag() { let valid_tag: Felt = NoteTag::for_local_use_case(0, 0).unwrap().into(); // Test invalid tag - assert!(tx_context.execute_code(¬e_creation_script(invalid_tag)).is_err()); + assert!( + tx_context + .execute_code(¬e_creation_script(invalid_tag), TransactionKernel::assembler()) + .is_err() + ); // Test valid tag - assert!(tx_context.execute_code(¬e_creation_script(valid_tag)).is_ok()); + assert!( + tx_context + .execute_code(¬e_creation_script(valid_tag), TransactionKernel::assembler()) + .is_ok() + ); fn note_creation_script(tag: Felt) -> String { format!( @@ -189,7 +280,7 @@ fn test_create_note_too_many_notes() { aux = Felt::ZERO, ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_TX_NUMBER_OF_OUTPUT_NOTES_EXCEEDS_LIMIT); } @@ -319,7 +410,7 @@ fn test_get_output_notes_commitment() { )), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -396,7 +487,7 @@ fn test_create_note_and_add_asset() { asset = word_to_masm_push_string(&asset), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -478,7 +569,7 @@ fn test_create_note_and_add_multiple_assets() { nft = word_to_masm_push_string(&non_fungible_asset_encoded), ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -561,7 +652,7 @@ fn test_create_note_and_add_same_nft_twice() { nft = word_to_masm_push_string(&encoded), ); - let process = tx_context.execute_code(&code); + let process = tx_context.execute_code(&code, TransactionKernel::assembler()); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_ALREADY_EXISTS); } @@ -631,7 +722,7 @@ fn test_build_recipient_hash() { aux = aux, ); - let process = &tx_context.execute_code(&code).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); assert_eq!( read_root_mem_word(&process.into(), NUM_OUTPUT_NOTES_PTR), @@ -676,7 +767,7 @@ fn test_block_procedures() { end "; - let process = &tx_context.execute_code(code).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); assert_eq!( process.stack.get_word(0), diff --git a/crates/miden-tx/src/tests/mod.rs b/crates/miden-tx/src/tests/mod.rs index d815e7ef67..3d727110ca 100644 --- a/crates/miden-tx/src/tests/mod.rs +++ b/crates/miden-tx/src/tests/mod.rs @@ -67,7 +67,8 @@ fn transaction_executor_witness() { tx_inputs, tx_args, Some(executed_transaction.advice_witness().clone()), - ); + ) + .unwrap(); let mem_advice_provider: MemAdviceProvider = advice_inputs.into(); // load account/note/tx_script MAST to the mast_store @@ -514,7 +515,6 @@ fn test_send_note_proc() { } #[test] -#[allow(clippy::arc_with_non_send_sync)] fn executed_transaction_output_notes() { let executor_account = Account::mock( ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, @@ -750,7 +750,6 @@ fn executed_transaction_output_notes() { } #[test] -#[allow(clippy::arc_with_non_send_sync)] fn prove_witness_and_verify() { let tx_context = TransactionContextBuilder::with_standard_account(ONE) .with_mock_notes_preserved() @@ -829,7 +828,6 @@ fn test_tx_script() { /// The call chain and dependency graph in this test is: /// `tx script -> account code -> external library` #[test] -#[allow(clippy::arc_with_non_send_sync)] fn transaction_executor_account_code_using_custom_library() { const EXTERNAL_LIBRARY_CODE: &str = " use.miden::account @@ -910,7 +908,6 @@ fn transaction_executor_account_code_using_custom_library() { } #[test] -#[allow(clippy::arc_with_non_send_sync)] fn test_execute_program() { let test_module_source = " export.foo From 75e1fdc55725fd729333b4d8dbf4cd8cbf1adde9 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 14 Apr 2025 16:32:08 -0300 Subject: [PATCH 15/29] test: Fix assembles --- .../src/tests/kernel_tests/test_account.rs | 25 ++++---- .../src/tests/kernel_tests/test_asset.rs | 6 +- .../tests/kernel_tests/test_asset_vault.rs | 43 +++++++++---- .../src/tests/kernel_tests/test_epilogue.rs | 32 +++++++--- .../src/tests/kernel_tests/test_faucet.rs | 60 +++++++++++++------ .../src/tests/kernel_tests/test_fpi.rs | 8 +-- .../src/tests/kernel_tests/test_note.rs | 23 +++---- .../src/tests/kernel_tests/test_prologue.rs | 10 ++-- .../src/tests/kernel_tests/test_tx.rs | 37 ++++++++---- 9 files changed, 162 insertions(+), 82 deletions(-) diff --git a/crates/miden-tx/src/tests/kernel_tests/test_account.rs b/crates/miden-tx/src/tests/kernel_tests/test_account.rs index 97aab95543..4482155f4a 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_account.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_account.rs @@ -47,7 +47,7 @@ pub fn test_get_code() { end "; - let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -262,7 +262,7 @@ fn test_get_item() { item_value = word_to_masm_push_string(&storage_item.slot.value()) ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); } } @@ -271,7 +271,7 @@ fn test_get_map_item() { let account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) .with_component( AccountMockComponent::new_with_slots( - TransactionKernel::testing_assembler(), + TransactionKernel::assembler(), vec![AccountStorage::mock_item_2().slot], ) .unwrap(), @@ -302,7 +302,9 @@ fn test_get_map_item() { map_key = word_to_masm_push_string(&key), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -358,7 +360,8 @@ fn test_get_storage_slot_type() { item_index = storage_item.index, ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = + &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); let process_state: ProcessState = process.into(); let storage_slot_type = storage_item.slot.slot_type(); @@ -419,7 +422,7 @@ fn test_set_item() { new_storage_item_index = 0, ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); } #[test] @@ -432,7 +435,7 @@ fn test_set_map_item() { let account = AccountBuilder::new(ChaCha20Rng::from_os_rng().random()) .with_component( AccountMockComponent::new_with_slots( - TransactionKernel::testing_assembler(), + TransactionKernel::assembler(), vec![AccountStorage::mock_item_2().slot], ) .unwrap(), @@ -472,7 +475,9 @@ fn test_set_map_item() { new_value = word_to_masm_push_string(&new_value), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); let mut new_storage_map = AccountStorage::mock_map(); @@ -664,7 +669,7 @@ fn test_get_vault_root() { expected_vault_root = word_to_masm_push_string(&account.vault().root()), ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); } // PROCEDURE AUTHENTICATION TESTS @@ -714,7 +719,7 @@ fn test_authenticate_procedure() { // Execution of this code will return an EventError(UnknownAccountProcedure) for procs // that are not in the advice provider. - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = tx_context.execute_code(&code, TransactionKernel::testing_assembler()); match valid { true => assert!(process.is_ok(), "A valid procedure must successfully authenticate"), diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs index ba90bf02de..92b779fe60 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs @@ -41,7 +41,7 @@ fn test_create_fungible_asset_succeeds() { " ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); let process_state: ProcessState = process.into(); let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(); @@ -87,7 +87,7 @@ fn test_create_non_fungible_asset_succeeds() { word_to_masm_push_string(&Hasher::hash(&NON_FUNGIBLE_ASSET_DATA)), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!(process_state.get_stack_word(0), Word::from(non_fungible_asset)); @@ -120,7 +120,7 @@ fn test_validate_non_fungible_asset() { asset = word_to_masm_push_string(&encoded) ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); let process_state: ProcessState = process.into(); assert_eq!(process_state.get_stack_word(0), encoded); diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs index 79480839df..e21cf2dfb6 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs @@ -53,7 +53,9 @@ fn test_get_balance() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); assert_eq!( process.stack.get(0).as_int(), @@ -81,7 +83,8 @@ fn test_get_balance_non_fungible_fails() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!( process, @@ -112,7 +115,9 @@ fn test_has_non_fungible_asset() { non_fungible_asset_key = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); assert_eq!(process.stack.get(0), ONE); } @@ -148,7 +153,9 @@ fn test_add_fungible_asset_success() { FUNGIBLE_ASSET = word_to_masm_push_string(&add_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -191,7 +198,8 @@ fn test_add_non_fungible_asset_fail_overflow() { FUNGIBLE_ASSET = word_to_masm_push_string(&add_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_MAX_AMOUNT_EXCEEDED); assert!(account_vault.add_asset(add_fungible_asset).is_err()); @@ -227,7 +235,9 @@ fn test_add_non_fungible_asset_success() { FUNGIBLE_ASSET = word_to_masm_push_string(&add_non_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -265,7 +275,8 @@ fn test_add_non_fungible_asset_fail_duplicate() { NON_FUNGIBLE_ASSET = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_VAULT_NON_FUNGIBLE_ASSET_ALREADY_EXISTS); assert!(account_vault.add_asset(non_fungible_asset).is_err()); @@ -303,7 +314,9 @@ fn test_remove_fungible_asset_success_no_balance_remaining() { FUNGIBLE_ASSET = word_to_masm_push_string(&remove_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -344,7 +357,8 @@ fn test_remove_fungible_asset_fail_remove_too_much() { FUNGIBLE_ASSET = word_to_masm_push_string(&remove_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW); } @@ -381,7 +395,9 @@ fn test_remove_fungible_asset_success_balance_remaining() { FUNGIBLE_ASSET = word_to_masm_push_string(&remove_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -426,7 +442,8 @@ fn test_remove_inexisting_non_fungible_asset_fails() { FUNGIBLE_ASSET = word_to_masm_push_string(&non_existent_non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND); assert_matches!( @@ -463,7 +480,9 @@ fn test_remove_non_fungible_asset_success() { FUNGIBLE_ASSET = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( diff --git a/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs b/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs index d3819beaa2..1e7814dd07 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs @@ -55,7 +55,9 @@ fn test_epilogue() { " ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let final_account = Account::mock( tx_context.account().id().into(), @@ -120,7 +122,9 @@ fn test_compute_output_note_id() { " ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); assert_eq!( note.assets().commitment().as_elements(), @@ -171,7 +175,8 @@ fn test_epilogue_asset_preservation_violation_too_few_input() { " ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_EPILOGUE_TOTAL_NUMBER_OF_ASSETS_MUST_STAY_THE_SAME); } @@ -205,7 +210,8 @@ fn test_epilogue_asset_preservation_violation_too_many_fungible_input() { " ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_EPILOGUE_TOTAL_NUMBER_OF_ASSETS_MUST_STAY_THE_SAME); } @@ -242,7 +248,9 @@ fn test_block_expiration_height_monotonically_decreases() { .replace("{value_2}", &v2.to_string()) .replace("{min_value}", &v2.min(v1).to_string()); - let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); // Expiry block should be set to transaction's block + the stored expiration delta @@ -269,7 +277,8 @@ fn test_invalid_expiration_deltas() { for value in test_values { let code = &code_template.replace("{value_1}", &value.to_string()); - let process = tx_context.execute_code(code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_TX_INVALID_EXPIRATION_DELTA); } @@ -296,7 +305,9 @@ fn test_no_expiration_delta_set() { end "; - let process = &tx_context.execute_code(code_template, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(code_template, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); // Default value should be equal to u32::max, set in the prologue @@ -341,7 +352,9 @@ fn test_epilogue_increment_nonce_success() { " ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); } #[test] @@ -379,6 +392,7 @@ fn test_epilogue_increment_nonce_violation() { " ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_ACCOUNT_NONCE_DID_NOT_INCREASE_AFTER_STATE_CHANGE) } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs index d631b4d888..b3dbbf5832 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs @@ -72,7 +72,9 @@ fn test_mint_fungible_asset_succeeds() { suffix = faucet_id.suffix(), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); let expected_final_storage_amount = FUNGIBLE_FAUCET_INITIAL_BALANCE + FUNGIBLE_ASSET_AMOUNT; @@ -109,7 +111,8 @@ fn test_mint_fungible_asset_fails_not_faucet_account() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -134,7 +137,8 @@ fn test_mint_fungible_asset_inconsistent_faucet_id() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -165,7 +169,8 @@ fn test_mint_fungible_asset_fails_saturate_max_amount() { saturating_amount = FungibleAsset::MAX_AMOUNT - FUNGIBLE_FAUCET_INITIAL_BALANCE + 1 ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FAUCET_NEW_TOTAL_SUPPLY_WOULD_EXCEED_MAX_ASSET_AMOUNT); } @@ -225,7 +230,9 @@ fn test_mint_non_fungible_asset_succeeds() { asset_vault_key = word_to_masm_push_string(&StorageMap::hash_key(asset_vault_key.into())), ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); } #[test] @@ -248,7 +255,8 @@ fn test_mint_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -273,7 +281,8 @@ fn test_mint_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -303,7 +312,8 @@ fn test_mint_non_fungible_asset_fails_asset_already_exists() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_ALREADY_ISSUED); } @@ -353,7 +363,9 @@ fn test_burn_fungible_asset_succeeds() { final_input_vault_asset_amount = CONSUMED_ASSET_1_AMOUNT - FUNGIBLE_ASSET_AMOUNT, ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); let expected_final_storage_amount = FUNGIBLE_FAUCET_INITIAL_BALANCE - FUNGIBLE_ASSET_AMOUNT; @@ -390,7 +402,8 @@ fn test_burn_fungible_asset_fails_not_faucet_account() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -421,7 +434,8 @@ fn test_burn_fungible_asset_inconsistent_faucet_id() { suffix = faucet_id.suffix(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -453,7 +467,8 @@ fn test_burn_fungible_asset_insufficient_input_amount() { saturating_amount = CONSUMED_ASSET_1_AMOUNT + 1 ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW); } @@ -518,7 +533,9 @@ fn test_burn_non_fungible_asset_succeeds() { burnt_asset_vault_key = word_to_masm_push_string(&burnt_asset_vault_key), ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); } #[test] @@ -547,7 +564,8 @@ fn test_burn_non_fungible_asset_fails_does_not_exist() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_TO_BURN_NOT_FOUND); } @@ -573,7 +591,8 @@ fn test_burn_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!( process, @@ -608,7 +627,8 @@ fn test_burn_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_TO_BURN_NOT_FOUND); } @@ -657,7 +677,9 @@ fn test_is_non_fungible_asset_issued_succeeds() { non_fungible_asset_2 = word_to_masm_push_string(&non_fungible_asset_2.into()), ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); } // GET TOTAL ISSUANCE TESTS @@ -691,5 +713,7 @@ fn test_get_total_issuance_succeeds() { ", ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index 6ae2c0e538..fa229fcd5f 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -140,7 +140,7 @@ fn test_fpi_memory() { get_item_foreign_hash = foreign_account.code().procedures()[0].mast_root(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); assert_eq!( process.stack.get_word(0), @@ -194,7 +194,7 @@ fn test_fpi_memory() { get_map_item_foreign_hash = foreign_account.code().procedures()[1].mast_root(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); assert_eq!( process.stack.get_word(0), @@ -264,7 +264,7 @@ fn test_fpi_memory() { get_item_foreign_hash = foreign_account.code().procedures()[0].mast_root(), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); // Check that the second invocation of the foreign procedure from the same account does not load // the account data again: already loaded data should be reused. @@ -447,7 +447,7 @@ fn test_fpi_memory_two_accounts() { foreign_2_suffix = foreign_account_2.id().suffix(), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); // Check the correctness of the memory layout after multiple foreign procedure invocations from // different foreign accounts diff --git a/crates/miden-tx/src/tests/kernel_tests/test_note.rs b/crates/miden-tx/src/tests/kernel_tests/test_note.rs index 8dc3e5af7c..33f6e2bf90 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_note.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_note.rs @@ -46,7 +46,7 @@ fn test_get_sender_no_sender() { end "; - let process = tx_context.execute_code(code, TransactionKernel::assembler()); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()); assert_execution_error!(process, ERR_NOTE_ATTEMPT_TO_ACCESS_NOTE_SENDER_FROM_INCORRECT_CONTEXT); } @@ -74,7 +74,7 @@ fn test_get_sender() { end "; - let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); let sender = tx_context.input_notes().get_note(0).note().metadata().sender(); assert_eq!(process.stack.get(0), sender.prefix().as_felt()); @@ -129,7 +129,7 @@ fn test_get_vault_data() { note_1_num_assets = notes.get_note(1).note().assets().num_assets(), ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); } #[test] fn test_get_assets() { @@ -240,7 +240,7 @@ fn test_get_assets() { NOTE_1_ASSET_ASSERTIONS = construct_asset_assertions(notes.get_note(1).note()), ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); } #[test] @@ -309,7 +309,7 @@ fn test_get_inputs() { NOTE_0_PTR = 100000000, ); - tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); } #[test] @@ -332,7 +332,7 @@ fn test_note_setup() { end "; - let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); note_setup_stack_assertions(&process, &tx_context); note_setup_memory_assertions(&process); @@ -379,7 +379,7 @@ fn test_note_script_and_note_args() { ); tx_context.set_tx_args(tx_args); - let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); assert_eq!(process.stack.get_word(0), note_args[0]); @@ -426,7 +426,7 @@ fn test_get_note_serial_number() { end "; - let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); let serial_number = tx_context.input_notes().get_note(0).note().serial_num(); assert_eq!(process.stack.get_word(0), serial_number); @@ -477,7 +477,7 @@ fn test_get_inputs_hash() { end "; - let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); let process_state: ProcessState = process.into(); let note_inputs_5_hash = @@ -549,7 +549,7 @@ fn test_get_current_script_root() { end "; - let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); let script_root = tx_context.input_notes().get_note(0).note().script().root(); assert_eq!(process.stack.get_word(0), script_root.as_elements()); @@ -602,7 +602,8 @@ fn test_build_note_metadata() { tag = test_metadata.tag(), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); let metadata_word = [ process.stack.get(3), diff --git a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs index 36b192d858..98fa10dee6 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs @@ -99,7 +99,7 @@ fn test_transaction_prologue() { ); tx_context.set_tx_args(tx_args); - let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); global_input_memory_assertions(process, &tx_context); block_data_memory_assertions(process, &tx_context); @@ -436,7 +436,7 @@ pub fn create_account_test( end "; - tx_context.execute_code(code, TransactionKernel::assembler())?; + tx_context.execute_code(code, TransactionKernel::testing_assembler())?; Ok(()) } @@ -647,7 +647,7 @@ pub fn create_account_invalid_seed() { end "; - let result = tx_context.execute_code(code, TransactionKernel::assembler()); + let result = tx_context.execute_code(code, TransactionKernel::testing_assembler()); assert_execution_error!(result, ERR_ACCOUNT_SEED_ANCHOR_BLOCK_COMMITMENT_DIGEST_MISMATCH) } @@ -668,7 +668,7 @@ fn test_get_blk_version() { end "; - let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); assert_eq!(process.stack.get(0), tx_context.tx_inputs().block_header().version().into()); } @@ -689,7 +689,7 @@ fn test_get_blk_timestamp() { end "; - let process = tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); assert_eq!(process.stack.get(0), tx_context.tx_inputs().block_header().timestamp().into()); } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index bc0e97db4a..a472b07188 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -151,7 +151,9 @@ fn test_create_note() { tag = tag, ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); assert_eq!( read_root_mem_word(&process.into(), NUM_OUTPUT_NOTES_PTR), @@ -209,13 +211,16 @@ fn test_create_note_with_invalid_tag() { // Test invalid tag assert!( tx_context - .execute_code(¬e_creation_script(invalid_tag), TransactionKernel::assembler()) + .execute_code( + ¬e_creation_script(invalid_tag), + TransactionKernel::testing_assembler() + ) .is_err() ); // Test valid tag assert!( tx_context - .execute_code(¬e_creation_script(valid_tag), TransactionKernel::assembler()) + .execute_code(¬e_creation_script(valid_tag), TransactionKernel::testing_assembler()) .is_ok() ); @@ -280,7 +285,8 @@ fn test_create_note_too_many_notes() { aux = Felt::ZERO, ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_TX_NUMBER_OF_OUTPUT_NOTES_EXCEEDS_LIMIT); } @@ -410,7 +416,9 @@ fn test_get_output_notes_commitment() { )), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -487,7 +495,9 @@ fn test_create_note_and_add_asset() { asset = word_to_masm_push_string(&asset), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -569,7 +579,9 @@ fn test_create_note_and_add_multiple_assets() { nft = word_to_masm_push_string(&non_fungible_asset_encoded), ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -652,7 +664,8 @@ fn test_create_note_and_add_same_nft_twice() { nft = word_to_masm_push_string(&encoded), ); - let process = tx_context.execute_code(&code, TransactionKernel::assembler()); + let process = + tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_ALREADY_EXISTS); } @@ -722,7 +735,9 @@ fn test_build_recipient_hash() { aux = aux, ); - let process = &tx_context.execute_code(&code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); assert_eq!( read_root_mem_word(&process.into(), NUM_OUTPUT_NOTES_PTR), @@ -767,7 +782,9 @@ fn test_block_procedures() { end "; - let process = &tx_context.execute_code(code, TransactionKernel::assembler()).unwrap(); + let process = &tx_context + .execute_code(code, TransactionKernel::testing_assembler_with_mock_account()) + .unwrap(); assert_eq!( process.stack.get_word(0), From 96c28ef43ef1c4b92baefa3f6ea91600a021b2fe Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 14 Apr 2025 16:45:29 -0300 Subject: [PATCH 16/29] reviews: Move mast_store.rs --- crates/miden-tx/src/executor/mod.rs | 3 - crates/miden-tx/src/lib.rs | 4 +- crates/miden-tx/src/prover/mast_store.rs | 109 +++++++++++++++++++++++ crates/miden-tx/src/prover/mod.rs | 4 +- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 crates/miden-tx/src/prover/mast_store.rs diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index ccf38fb57f..0c678f6a1a 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -21,9 +21,6 @@ use crate::auth::TransactionAuthenticator; mod data_store; pub use data_store::DataStore; -mod mast_store; -pub use mast_store::TransactionMastStore; - // TRANSACTION EXECUTOR // ================================================================================================ diff --git a/crates/miden-tx/src/lib.rs b/crates/miden-tx/src/lib.rs index 3f34dbae5b..a612f8ea9a 100644 --- a/crates/miden-tx/src/lib.rs +++ b/crates/miden-tx/src/lib.rs @@ -9,13 +9,13 @@ extern crate std; pub use miden_objects::transaction::TransactionInputs; mod executor; -pub use executor::{DataStore, MastForestStore, TransactionExecutor, TransactionMastStore}; +pub use executor::{DataStore, MastForestStore, TransactionExecutor}; pub mod host; pub use host::{TransactionHost, TransactionProgress}; mod prover; -pub use prover::{LocalTransactionProver, ProvingOptions, TransactionProver}; +pub use prover::{LocalTransactionProver, ProvingOptions, TransactionMastStore, TransactionProver}; mod verifier; pub use verifier::TransactionVerifier; diff --git a/crates/miden-tx/src/prover/mast_store.rs b/crates/miden-tx/src/prover/mast_store.rs new file mode 100644 index 0000000000..b9b3c79a9d --- /dev/null +++ b/crates/miden-tx/src/prover/mast_store.rs @@ -0,0 +1,109 @@ +use alloc::{collections::BTreeMap, sync::Arc}; + +use miden_lib::{MidenLib, StdLibrary, transaction::TransactionKernel, utils::sync::RwLock}; +use miden_objects::{ + Digest, + account::AccountCode, + assembly::mast::MastForest, + transaction::{InputNote, InputNotes, TransactionArgs}, +}; +use vm_processor::MastForestStore; + +// TRANSACTION MAST STORE +// ================================================================================================ + +/// A store for the code available during transaction execution. +/// +/// Transaction MAST store contains a map between procedure MAST roots and [MastForest]s containing +/// MASTs for these procedures. The VM will request [MastForest]s from the store when it encounters +/// a procedure which it doesn't have the code for. Thus, to execute a program which makes +/// references to external procedures, the store must be loaded with [MastForest]s containing these +/// procedures. +pub struct TransactionMastStore { + mast_forests: RwLock>>, +} + +#[allow(clippy::new_without_default)] +impl TransactionMastStore { + /// Returns a new [TransactionMastStore] instantiated with the default libraries. + /// + /// The default libraries include: + /// - Miden standard library (miden-stdlib). + /// - Miden rollup library (miden-lib). + /// - Transaction kernel. + pub fn new() -> Self { + let mast_forests = RwLock::new(BTreeMap::new()); + let store = Self { mast_forests }; + + // load transaction kernel MAST forest + let kernels_forest = TransactionKernel::kernel().mast_forest().clone(); + store.insert(kernels_forest); + + // load miden-stdlib MAST forest + let miden_stdlib_forest = StdLibrary::default().mast_forest().clone(); + store.insert(miden_stdlib_forest); + + // load miden lib MAST forest + let miden_lib_forest = MidenLib::default().mast_forest().clone(); + store.insert(miden_lib_forest); + + store + } + + /// Loads the provided account code into this store. + pub fn load_account_code(&self, code: &AccountCode) { + self.insert(code.mast().clone()); + } + + /// Loads code required for executing a transaction with the specified inputs and args into + /// this store. + /// + /// The loaded code includes: + /// - Account code for the account specified from the provided [AccountCode]. + /// - Note scripts for all input notes in the provided [InputNotes]. + /// - Transaction script (if any) from the specified [TransactionArgs]. + /// - Foreign account code (if any) from the specified [TransactionArgs]. + pub fn load_transaction_code( + &self, + account_code: &AccountCode, + input_notes: &InputNotes, + tx_args: &TransactionArgs, + ) { + // load account code + self.load_account_code(account_code); + + // load note script MAST into the MAST store + for note in input_notes { + self.insert(note.note().script().mast().clone()); + } + + // load foreign account's MAST forests + for foreign_account in tx_args.foreign_accounts() { + self.load_account_code(foreign_account.account_code()); + } + + // load tx script MAST into the MAST store + if let Some(tx_script) = tx_args.tx_script() { + self.insert(tx_script.mast().clone()); + } + } + + /// Registers all procedures of the provided [MastForest] with this store. + pub fn insert(&self, mast_forest: Arc) { + let mut mast_forests = self.mast_forests.write(); + + // only register procedures that are local to this forest + for proc_digest in mast_forest.local_procedure_digests() { + mast_forests.insert(proc_digest, mast_forest.clone()); + } + } +} + +// MAST FOREST STORE IMPLEMENTATION +// ================================================================================================ + +impl MastForestStore for TransactionMastStore { + fn get(&self, procedure_root: &Digest) -> Option> { + self.mast_forests.read().get(procedure_root).cloned() + } +} diff --git a/crates/miden-tx/src/prover/mod.rs b/crates/miden-tx/src/prover/mod.rs index d3a4a50494..f632db7ccf 100644 --- a/crates/miden-tx/src/prover/mod.rs +++ b/crates/miden-tx/src/prover/mod.rs @@ -13,7 +13,9 @@ use vm_processor::MemAdviceProvider; use winter_maybe_async::*; use super::{TransactionHost, TransactionProverError}; -use crate::executor::TransactionMastStore; + +mod mast_store; +pub use mast_store::TransactionMastStore; // TRANSACTION PROVER TRAIT // ================================================================================================ From 853ca80e5cde0de54a30cf1f1d90b773ea49579b Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 14 Apr 2025 16:57:36 -0300 Subject: [PATCH 17/29] fix: Remove accidentall std addition --- crates/miden-tx/src/testing/mock_host.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/miden-tx/src/testing/mock_host.rs b/crates/miden-tx/src/testing/mock_host.rs index 896873392e..1381f5c0fc 100644 --- a/crates/miden-tx/src/testing/mock_host.rs +++ b/crates/miden-tx/src/testing/mock_host.rs @@ -1,5 +1,10 @@ -use alloc::{boxed::Box, collections::BTreeMap, rc::Rc, string::ToString, sync::Arc}; -use std::collections::BTreeSet; +use alloc::{ + boxed::Box, + collections::{BTreeMap, BTreeSet}, + rc::Rc, + string::ToString, + sync::Arc, +}; use miden_lib::{ errors::tx_kernel_errors::TX_KERNEL_ERRORS, From 124d03f67bb020b814037c761391434f8ab9143c Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 14 Apr 2025 16:59:14 -0300 Subject: [PATCH 18/29] chore: Lints --- crates/miden-objects/src/transaction/inputs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-objects/src/transaction/inputs.rs b/crates/miden-objects/src/transaction/inputs.rs index 671d9b9c48..71dd4052f9 100644 --- a/crates/miden-objects/src/transaction/inputs.rs +++ b/crates/miden-objects/src/transaction/inputs.rs @@ -681,7 +681,7 @@ mod tests { fn serde_roundtrip() { let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap(); let code = AccountCode::mock(); - let vault = AssetVault::new(&vec![]).unwrap(); + let vault = AssetVault::new(&[]).unwrap(); let storage = AccountStorage::new(vec![]).unwrap(); let account = Account::from_parts(id, vault, storage, code, Felt::new(10)); From e7a88e268ecb9a63c14aa3cd417f7cc51d3c4c15 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 14 Apr 2025 17:05:35 -0300 Subject: [PATCH 19/29] test: Fix doc test build --- crates/miden-tx/src/testing/tx_context/builder.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index cf13c923e1..3af924258f 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -50,6 +50,7 @@ pub type MockAuthenticator = BasicAuthenticator; /// ``` /// # use miden_tx::testing::TransactionContextBuilder; /// # use miden_objects::{account::AccountBuilder,Felt, FieldElement}; +/// # use miden_lib::transaction::TransactionKernel; /// let tx_context = TransactionContextBuilder::with_standard_account(Felt::ONE).build(); /// /// let code = " @@ -63,7 +64,7 @@ pub type MockAuthenticator = BasicAuthenticator; /// end /// "; /// -/// let process = tx_context.execute_code(code).unwrap(); +/// let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); /// assert_eq!(process.stack.get(0), Felt::new(5),); /// ``` pub struct TransactionContextBuilder { From beb71f1935f547c4546d16544e3060396c30ee64 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Tue, 15 Apr 2025 11:35:47 -0300 Subject: [PATCH 20/29] reviews: Change name, add execute_code variant and make function private --- .../miden-objects/src/transaction/tx_args.rs | 14 +-- crates/miden-tx/src/prover/mast_store.rs | 10 +- .../src/testing/tx_context/builder.rs | 12 +-- crates/miden-tx/src/testing/tx_context/mod.rs | 10 +- .../src/tests/kernel_tests/test_account.rs | 23 ++-- .../src/tests/kernel_tests/test_asset.rs | 8 +- .../tests/kernel_tests/test_asset_vault.rs | 65 ++++++++--- .../src/tests/kernel_tests/test_epilogue.rs | 49 ++++++--- .../src/tests/kernel_tests/test_faucet.rs | 102 ++++++++++++------ .../src/tests/kernel_tests/test_fpi.rs | 8 +- .../src/tests/kernel_tests/test_note.rs | 23 ++-- .../src/tests/kernel_tests/test_prologue.rs | 10 +- .../src/tests/kernel_tests/test_tx.rs | 46 +++++--- 13 files changed, 255 insertions(+), 125 deletions(-) diff --git a/crates/miden-objects/src/transaction/tx_args.rs b/crates/miden-objects/src/transaction/tx_args.rs index 3f6bd20f96..675f03cea4 100644 --- a/crates/miden-objects/src/transaction/tx_args.rs +++ b/crates/miden-objects/src/transaction/tx_args.rs @@ -31,7 +31,7 @@ pub struct TransactionArgs { tx_script: Option, note_args: BTreeMap, advice_inputs: AdviceInputs, - foreign_accounts: Vec, + foreign_account_inputs: Vec, } impl TransactionArgs { @@ -47,7 +47,7 @@ impl TransactionArgs { tx_script: Option, note_args: Option>, advice_map: AdviceMap, - foreign_accounts: Vec, + foreign_account_inputs: Vec, ) -> Self { let mut advice_inputs = AdviceInputs::default().with_map(advice_map); // add transaction script inputs to the advice inputs' map @@ -60,7 +60,7 @@ impl TransactionArgs { tx_script, note_args: note_args.unwrap_or_default(), advice_inputs, - foreign_accounts, + foreign_account_inputs, } } @@ -84,7 +84,7 @@ impl TransactionArgs { mut self, foreign_account_inputs: Vec, ) -> Self { - self.foreign_accounts = foreign_account_inputs; + self.foreign_account_inputs = foreign_account_inputs; self } @@ -108,7 +108,7 @@ impl TransactionArgs { /// Returns a reference to the foreign account inputs in the transaction args. pub fn foreign_accounts(&self) -> &[ForeignAccountInputs] { - &self.foreign_accounts + &self.foreign_account_inputs } /// Collects and returns a set containing all code commitments from foreign accounts. @@ -182,7 +182,7 @@ impl Serializable for TransactionArgs { self.tx_script.write_into(target); self.note_args.write_into(target); self.advice_inputs.write_into(target); - self.foreign_accounts.write_into(target); + self.foreign_account_inputs.write_into(target); } } @@ -197,7 +197,7 @@ impl Deserializable for TransactionArgs { tx_script, note_args, advice_inputs, - foreign_accounts, + foreign_account_inputs: foreign_accounts, }) } } diff --git a/crates/miden-tx/src/prover/mast_store.rs b/crates/miden-tx/src/prover/mast_store.rs index b9b3c79a9d..695fb965e8 100644 --- a/crates/miden-tx/src/prover/mast_store.rs +++ b/crates/miden-tx/src/prover/mast_store.rs @@ -50,11 +50,6 @@ impl TransactionMastStore { store } - /// Loads the provided account code into this store. - pub fn load_account_code(&self, code: &AccountCode) { - self.insert(code.mast().clone()); - } - /// Loads code required for executing a transaction with the specified inputs and args into /// this store. /// @@ -97,6 +92,11 @@ impl TransactionMastStore { mast_forests.insert(proc_digest, mast_forest.clone()); } } + + /// Loads the provided account code into this store. + fn load_account_code(&self, code: &AccountCode) { + self.insert(code.mast().clone()); + } } // MAST FOREST STORE IMPLEMENTATION diff --git a/crates/miden-tx/src/testing/tx_context/builder.rs b/crates/miden-tx/src/testing/tx_context/builder.rs index 3af924258f..dd98fb7671 100644 --- a/crates/miden-tx/src/testing/tx_context/builder.rs +++ b/crates/miden-tx/src/testing/tx_context/builder.rs @@ -64,7 +64,7 @@ pub type MockAuthenticator = BasicAuthenticator; /// end /// "; /// -/// let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); +/// let process = tx_context.execute_code(code).unwrap(); /// assert_eq!(process.stack.get(0), Felt::new(5),); /// ``` pub struct TransactionContextBuilder { @@ -74,7 +74,7 @@ pub struct TransactionContextBuilder { advice_inputs: AdviceInputs, authenticator: Option, expected_output_notes: Vec, - foreign_accounts: Vec, + foreign_account_inputs: Vec, libraries: Vec, input_notes: Vec, tx_script: Option, @@ -97,7 +97,7 @@ impl TransactionContextBuilder { advice_inputs: Default::default(), transaction_inputs: None, note_args: BTreeMap::new(), - foreign_accounts: vec![], + foreign_account_inputs: vec![], libraries: Default::default(), } } @@ -125,7 +125,7 @@ impl TransactionContextBuilder { tx_script: None, transaction_inputs: None, note_args: BTreeMap::new(), - foreign_accounts: vec![], + foreign_account_inputs: vec![], libraries: Default::default(), } } @@ -174,7 +174,7 @@ impl TransactionContextBuilder { /// Set foreign account codes that are used by the transaction pub fn foreign_accounts(mut self, inputs: Vec) -> Self { - self.foreign_accounts = inputs; + self.foreign_account_inputs = inputs; self } @@ -668,7 +668,7 @@ impl TransactionContextBuilder { self.tx_script, Some(self.note_args), AdviceMap::default(), - self.foreign_accounts, + self.foreign_account_inputs, ); tx_args.extend_advice_inputs(self.advice_inputs.clone()); diff --git a/crates/miden-tx/src/testing/tx_context/mod.rs b/crates/miden-tx/src/testing/tx_context/mod.rs index 03728cb242..641ef4744b 100644 --- a/crates/miden-tx/src/testing/tx_context/mod.rs +++ b/crates/miden-tx/src/testing/tx_context/mod.rs @@ -55,7 +55,7 @@ impl TransactionContext { /// /// # Errors /// Returns an error if the assembly or execution of the provided code fails. - pub fn execute_code( + pub fn execute_code_with_assembler( &self, code: &str, assembler: Assembler, @@ -92,6 +92,14 @@ impl TransactionContext { .execute_program(program) } + /// Executes arbitrary code with a testing assembler ([TransactionKernel::testing_assembler()]). + /// + /// For more information, see the docs for [TransactionContext::execute_code_with_assembler()]. + pub fn execute_code(&self, code: &str) -> Result { + let assembler = TransactionKernel::testing_assembler(); + self.execute_code_with_assembler(code, assembler) + } + /// Executes the transaction through a [TransactionExecutor] #[maybe_async] pub fn execute(self) -> Result { diff --git a/crates/miden-tx/src/tests/kernel_tests/test_account.rs b/crates/miden-tx/src/tests/kernel_tests/test_account.rs index 4482155f4a..b71ff53a31 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_account.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_account.rs @@ -47,7 +47,7 @@ pub fn test_get_code() { end "; - let process = &tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(code).unwrap(); let process_state: ProcessState = process.into(); assert_eq!( @@ -262,7 +262,7 @@ fn test_get_item() { item_value = word_to_masm_push_string(&storage_item.slot.value()) ); - tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + tx_context.execute_code(&code).unwrap(); } } @@ -303,7 +303,10 @@ fn test_get_map_item() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -360,8 +363,7 @@ fn test_get_storage_slot_type() { item_index = storage_item.index, ); - let process = - &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(&code).unwrap(); let process_state: ProcessState = process.into(); let storage_slot_type = storage_item.slot.slot_type(); @@ -422,7 +424,7 @@ fn test_set_item() { new_storage_item_index = 0, ); - tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + tx_context.execute_code(&code).unwrap(); } #[test] @@ -476,7 +478,10 @@ fn test_set_map_item() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -669,7 +674,7 @@ fn test_get_vault_root() { expected_vault_root = word_to_masm_push_string(&account.vault().root()), ); - tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + tx_context.execute_code(&code).unwrap(); } // PROCEDURE AUTHENTICATION TESTS @@ -719,7 +724,7 @@ fn test_authenticate_procedure() { // Execution of this code will return an EventError(UnknownAccountProcedure) for procs // that are not in the advice provider. - let process = tx_context.execute_code(&code, TransactionKernel::testing_assembler()); + let process = tx_context.execute_code(&code); match valid { true => assert!(process.is_ok(), "A valid procedure must successfully authenticate"), diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs index 92b779fe60..7a7eb44144 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset.rs @@ -1,4 +1,4 @@ -use miden_lib::{transaction::TransactionKernel, utils::word_to_masm_push_string}; +use miden_lib::utils::word_to_masm_push_string; use miden_objects::{ account::AccountId, asset::NonFungibleAsset, @@ -41,7 +41,7 @@ fn test_create_fungible_asset_succeeds() { " ); - let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(&code).unwrap(); let process_state: ProcessState = process.into(); let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(); @@ -87,7 +87,7 @@ fn test_create_non_fungible_asset_succeeds() { word_to_masm_push_string(&Hasher::hash(&NON_FUNGIBLE_ASSET_DATA)), ); - let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(&code).unwrap(); let process_state: ProcessState = process.into(); assert_eq!(process_state.get_stack_word(0), Word::from(non_fungible_asset)); @@ -120,7 +120,7 @@ fn test_validate_non_fungible_asset() { asset = word_to_masm_push_string(&encoded) ); - let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(&code).unwrap(); let process_state: ProcessState = process.into(); assert_eq!(process_state.get_stack_word(0), encoded); diff --git a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs index e21cf2dfb6..86aed12248 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_asset_vault.rs @@ -54,7 +54,10 @@ fn test_get_balance() { ); let process = tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); assert_eq!( @@ -83,8 +86,10 @@ fn test_get_balance_non_fungible_fails() { suffix = faucet_id.suffix(), ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!( process, @@ -116,7 +121,10 @@ fn test_has_non_fungible_asset() { ); let process = tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); assert_eq!(process.stack.get(0), ONE); @@ -154,7 +162,10 @@ fn test_add_fungible_asset_success() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -198,8 +209,10 @@ fn test_add_non_fungible_asset_fail_overflow() { FUNGIBLE_ASSET = word_to_masm_push_string(&add_fungible_asset.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_MAX_AMOUNT_EXCEEDED); assert!(account_vault.add_asset(add_fungible_asset).is_err()); @@ -236,7 +249,10 @@ fn test_add_non_fungible_asset_success() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -275,8 +291,10 @@ fn test_add_non_fungible_asset_fail_duplicate() { NON_FUNGIBLE_ASSET = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_VAULT_NON_FUNGIBLE_ASSET_ALREADY_EXISTS); assert!(account_vault.add_asset(non_fungible_asset).is_err()); @@ -315,7 +333,10 @@ fn test_remove_fungible_asset_success_no_balance_remaining() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -357,8 +378,10 @@ fn test_remove_fungible_asset_fail_remove_too_much() { FUNGIBLE_ASSET = word_to_masm_push_string(&remove_fungible_asset.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW); } @@ -396,7 +419,10 @@ fn test_remove_fungible_asset_success_balance_remaining() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -442,8 +468,10 @@ fn test_remove_inexisting_non_fungible_asset_fails() { FUNGIBLE_ASSET = word_to_masm_push_string(&non_existent_non_fungible_asset.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND); assert_matches!( @@ -481,7 +509,10 @@ fn test_remove_non_fungible_asset_success() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); diff --git a/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs b/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs index 1e7814dd07..9db36708cd 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_epilogue.rs @@ -56,7 +56,10 @@ fn test_epilogue() { ); let process = tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let final_account = Account::mock( @@ -123,7 +126,10 @@ fn test_compute_output_note_id() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); assert_eq!( @@ -175,8 +181,10 @@ fn test_epilogue_asset_preservation_violation_too_few_input() { " ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_EPILOGUE_TOTAL_NUMBER_OF_ASSETS_MUST_STAY_THE_SAME); } @@ -210,8 +218,10 @@ fn test_epilogue_asset_preservation_violation_too_many_fungible_input() { " ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_EPILOGUE_TOTAL_NUMBER_OF_ASSETS_MUST_STAY_THE_SAME); } @@ -249,7 +259,10 @@ fn test_block_expiration_height_monotonically_decreases() { .replace("{min_value}", &v2.min(v1).to_string()); let process = &tx_context - .execute_code(code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -277,8 +290,10 @@ fn test_invalid_expiration_deltas() { for value in test_values { let code = &code_template.replace("{value_1}", &value.to_string()); - let process = - tx_context.execute_code(code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_TX_INVALID_EXPIRATION_DELTA); } @@ -306,7 +321,10 @@ fn test_no_expiration_delta_set() { "; let process = &tx_context - .execute_code(code_template, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + code_template, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -353,7 +371,10 @@ fn test_epilogue_increment_nonce_success() { ); tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); } @@ -392,7 +413,9 @@ fn test_epilogue_increment_nonce_violation() { " ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_ACCOUNT_NONCE_DID_NOT_INCREASE_AFTER_STATE_CHANGE) } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs index b3dbbf5832..5b20f041b0 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_faucet.rs @@ -73,7 +73,10 @@ fn test_mint_fungible_asset_succeeds() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -111,8 +114,10 @@ fn test_mint_fungible_asset_fails_not_faucet_account() { suffix = faucet_id.suffix(), ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -137,8 +142,10 @@ fn test_mint_fungible_asset_inconsistent_faucet_id() { suffix = faucet_id.suffix(), ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -169,8 +176,10 @@ fn test_mint_fungible_asset_fails_saturate_max_amount() { saturating_amount = FungibleAsset::MAX_AMOUNT - FUNGIBLE_FAUCET_INITIAL_BALANCE + 1 ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FAUCET_NEW_TOTAL_SUPPLY_WOULD_EXCEED_MAX_ASSET_AMOUNT); } @@ -231,7 +240,10 @@ fn test_mint_non_fungible_asset_succeeds() { ); tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); } @@ -255,8 +267,10 @@ fn test_mint_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -281,8 +295,10 @@ fn test_mint_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -312,8 +328,10 @@ fn test_mint_non_fungible_asset_fails_asset_already_exists() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_ALREADY_ISSUED); } @@ -364,7 +382,10 @@ fn test_burn_fungible_asset_succeeds() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -402,8 +423,10 @@ fn test_burn_fungible_asset_fails_not_faucet_account() { suffix = faucet_id.suffix(), ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -434,8 +457,10 @@ fn test_burn_fungible_asset_inconsistent_faucet_id() { suffix = faucet_id.suffix(), ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN); } @@ -467,8 +492,10 @@ fn test_burn_fungible_asset_insufficient_input_amount() { saturating_amount = CONSUMED_ASSET_1_AMOUNT + 1 ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_VAULT_FUNGIBLE_ASSET_AMOUNT_LESS_THAN_AMOUNT_TO_WITHDRAW); } @@ -534,7 +561,10 @@ fn test_burn_non_fungible_asset_succeeds() { ); tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); } @@ -564,8 +594,10 @@ fn test_burn_non_fungible_asset_fails_does_not_exist() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_TO_BURN_NOT_FOUND); } @@ -591,8 +623,10 @@ fn test_burn_non_fungible_asset_fails_not_faucet_account() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!( process, @@ -627,8 +661,10 @@ fn test_burn_non_fungible_asset_fails_inconsistent_faucet_id() { non_fungible_asset = word_to_masm_push_string(&non_fungible_asset_burnt.into()) ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_FAUCET_NON_FUNGIBLE_ASSET_TO_BURN_NOT_FOUND); } @@ -678,7 +714,10 @@ fn test_is_non_fungible_asset_issued_succeeds() { ); tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); } @@ -714,6 +753,9 @@ fn test_get_total_issuance_succeeds() { ); tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index fa229fcd5f..7e7e0af7f5 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -140,7 +140,7 @@ fn test_fpi_memory() { get_item_foreign_hash = foreign_account.code().procedures()[0].mast_root(), ); - let process = tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(&code).unwrap(); assert_eq!( process.stack.get_word(0), @@ -194,7 +194,7 @@ fn test_fpi_memory() { get_map_item_foreign_hash = foreign_account.code().procedures()[1].mast_root(), ); - let process = tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(&code).unwrap(); assert_eq!( process.stack.get_word(0), @@ -264,7 +264,7 @@ fn test_fpi_memory() { get_item_foreign_hash = foreign_account.code().procedures()[0].mast_root(), ); - let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(&code).unwrap(); // Check that the second invocation of the foreign procedure from the same account does not load // the account data again: already loaded data should be reused. @@ -447,7 +447,7 @@ fn test_fpi_memory_two_accounts() { foreign_2_suffix = foreign_account_2.id().suffix(), ); - let process = &tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(&code).unwrap(); // Check the correctness of the memory layout after multiple foreign procedure invocations from // different foreign accounts diff --git a/crates/miden-tx/src/tests/kernel_tests/test_note.rs b/crates/miden-tx/src/tests/kernel_tests/test_note.rs index 33f6e2bf90..8fab39c6ae 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_note.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_note.rs @@ -46,7 +46,7 @@ fn test_get_sender_no_sender() { end "; - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()); + let process = tx_context.execute_code(code); assert_execution_error!(process, ERR_NOTE_ATTEMPT_TO_ACCESS_NOTE_SENDER_FROM_INCORRECT_CONTEXT); } @@ -74,7 +74,7 @@ fn test_get_sender() { end "; - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(code).unwrap(); let sender = tx_context.input_notes().get_note(0).note().metadata().sender(); assert_eq!(process.stack.get(0), sender.prefix().as_felt()); @@ -129,7 +129,7 @@ fn test_get_vault_data() { note_1_num_assets = notes.get_note(1).note().assets().num_assets(), ); - tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + tx_context.execute_code(&code).unwrap(); } #[test] fn test_get_assets() { @@ -240,7 +240,7 @@ fn test_get_assets() { NOTE_1_ASSET_ASSERTIONS = construct_asset_assertions(notes.get_note(1).note()), ); - tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + tx_context.execute_code(&code).unwrap(); } #[test] @@ -309,7 +309,7 @@ fn test_get_inputs() { NOTE_0_PTR = 100000000, ); - tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + tx_context.execute_code(&code).unwrap(); } #[test] @@ -332,7 +332,7 @@ fn test_note_setup() { end "; - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(code).unwrap(); note_setup_stack_assertions(&process, &tx_context); note_setup_memory_assertions(&process); @@ -379,7 +379,7 @@ fn test_note_script_and_note_args() { ); tx_context.set_tx_args(tx_args); - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(code).unwrap(); assert_eq!(process.stack.get_word(0), note_args[0]); @@ -426,7 +426,7 @@ fn test_get_note_serial_number() { end "; - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(code).unwrap(); let serial_number = tx_context.input_notes().get_note(0).note().serial_num(); assert_eq!(process.stack.get_word(0), serial_number); @@ -477,7 +477,7 @@ fn test_get_inputs_hash() { end "; - let process = &tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(code).unwrap(); let process_state: ProcessState = process.into(); let note_inputs_5_hash = @@ -549,7 +549,7 @@ fn test_get_current_script_root() { end "; - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(code).unwrap(); let script_root = tx_context.input_notes().get_note(0).note().script().root(); assert_eq!(process.stack.get_word(0), script_root.as_elements()); @@ -602,8 +602,7 @@ fn test_build_note_metadata() { tag = test_metadata.tag(), ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(&code).unwrap(); let metadata_word = [ process.stack.get(3), diff --git a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs index 98fa10dee6..2d79480134 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_prologue.rs @@ -99,7 +99,7 @@ fn test_transaction_prologue() { ); tx_context.set_tx_args(tx_args); - let process = &tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = &tx_context.execute_code(code).unwrap(); global_input_memory_assertions(process, &tx_context); block_data_memory_assertions(process, &tx_context); @@ -436,7 +436,7 @@ pub fn create_account_test( end "; - tx_context.execute_code(code, TransactionKernel::testing_assembler())?; + tx_context.execute_code(code)?; Ok(()) } @@ -647,7 +647,7 @@ pub fn create_account_invalid_seed() { end "; - let result = tx_context.execute_code(code, TransactionKernel::testing_assembler()); + let result = tx_context.execute_code(code); assert_execution_error!(result, ERR_ACCOUNT_SEED_ANCHOR_BLOCK_COMMITMENT_DIGEST_MISMATCH) } @@ -668,7 +668,7 @@ fn test_get_blk_version() { end "; - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(code).unwrap(); assert_eq!(process.stack.get(0), tx_context.tx_inputs().block_header().version().into()); } @@ -689,7 +689,7 @@ fn test_get_blk_timestamp() { end "; - let process = tx_context.execute_code(code, TransactionKernel::testing_assembler()).unwrap(); + let process = tx_context.execute_code(code).unwrap(); assert_eq!(process.stack.get(0), tx_context.tx_inputs().block_header().timestamp().into()); } diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index a472b07188..46289e6047 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -152,7 +152,10 @@ fn test_create_note() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); assert_eq!( @@ -211,7 +214,7 @@ fn test_create_note_with_invalid_tag() { // Test invalid tag assert!( tx_context - .execute_code( + .execute_code_with_assembler( ¬e_creation_script(invalid_tag), TransactionKernel::testing_assembler() ) @@ -220,7 +223,10 @@ fn test_create_note_with_invalid_tag() { // Test valid tag assert!( tx_context - .execute_code(¬e_creation_script(valid_tag), TransactionKernel::testing_assembler()) + .execute_code_with_assembler( + ¬e_creation_script(valid_tag), + TransactionKernel::testing_assembler() + ) .is_ok() ); @@ -285,8 +291,10 @@ fn test_create_note_too_many_notes() { aux = Felt::ZERO, ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_TX_NUMBER_OF_OUTPUT_NOTES_EXCEEDS_LIMIT); } @@ -417,7 +425,10 @@ fn test_get_output_notes_commitment() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -496,7 +507,10 @@ fn test_create_note_and_add_asset() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -580,7 +594,10 @@ fn test_create_note_and_add_multiple_assets() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); let process_state: ProcessState = process.into(); @@ -664,8 +681,10 @@ fn test_create_note_and_add_same_nft_twice() { nft = word_to_masm_push_string(&encoded), ); - let process = - tx_context.execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()); + let process = tx_context.execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ); assert_execution_error!(process, ERR_NON_FUNGIBLE_ASSET_ALREADY_EXISTS); } @@ -736,7 +755,10 @@ fn test_build_recipient_hash() { ); let process = &tx_context - .execute_code(&code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler( + &code, + TransactionKernel::testing_assembler_with_mock_account(), + ) .unwrap(); assert_eq!( @@ -783,7 +805,7 @@ fn test_block_procedures() { "; let process = &tx_context - .execute_code(code, TransactionKernel::testing_assembler_with_mock_account()) + .execute_code_with_assembler(code, TransactionKernel::testing_assembler_with_mock_account()) .unwrap(); assert_eq!( From b4b2e1c87982bf8a4dec8e7cdcb1004e99071d6e Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Tue, 15 Apr 2025 12:25:53 -0300 Subject: [PATCH 21/29] reviews: Box string in error --- crates/miden-lib/src/transaction/inputs.rs | 2 +- crates/miden-lib/src/transaction/mod.rs | 4 ++-- crates/miden-objects/src/errors.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/miden-lib/src/transaction/inputs.rs b/crates/miden-lib/src/transaction/inputs.rs index 9dbe5f2ea0..d5395e5671 100644 --- a/crates/miden-lib/src/transaction/inputs.rs +++ b/crates/miden-lib/src/transaction/inputs.rs @@ -290,7 +290,7 @@ fn add_input_notes_to_advice_inputs( ) .map_err(|err| { TransactionInputError::InvalidMerklePath( - format!("input note ID {}", note.id()), + format!("input note ID {}", note.id()).into(), err, ) })?, diff --git a/crates/miden-lib/src/transaction/mod.rs b/crates/miden-lib/src/transaction/mod.rs index ef5562bbb3..259baacc9d 100644 --- a/crates/miden-lib/src/transaction/mod.rs +++ b/crates/miden-lib/src/transaction/mod.rs @@ -231,7 +231,7 @@ impl TransactionKernel { .inner_nodes(account_id.prefix().as_u64(), account_header.commitment()) .map_err(|err| { TransactionInputError::InvalidMerklePath( - format!("foreign account ID {}", account_id), + format!("foreign account ID {}", account_id).into(), err, ) })?, @@ -246,7 +246,7 @@ impl TransactionKernel { .inner_nodes(proof.leaf().index().value(), proof.leaf().hash()) .map_err(|err| { TransactionInputError::InvalidMerklePath( - format!("foreign account ID {} storage proof", account_id), + format!("foreign account ID {} storage proof", account_id).into(), err, ) })?, diff --git a/crates/miden-objects/src/errors.rs b/crates/miden-objects/src/errors.rs index 1533436977..c329e463c3 100644 --- a/crates/miden-objects/src/errors.rs +++ b/crates/miden-objects/src/errors.rs @@ -451,7 +451,7 @@ pub enum TransactionInputError { #[error("account ID computed from seed is invalid")] InvalidAccountIdSeed(#[source] AccountIdError), #[error("merkle path for {0} is invalid")] - InvalidMerklePath(String, #[source] MerkleError), + InvalidMerklePath(Box, #[source] MerkleError), #[error( "total number of input notes is {0} which exceeds the maximum of {MAX_INPUT_NOTES_PER_TX}" )] From cd15d1fd37d29e4a2c90c65638e23857f1d31ede Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Tue, 15 Apr 2025 13:20:37 -0300 Subject: [PATCH 22/29] reviews: Typo --- crates/miden-tx/src/executor/data_store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-tx/src/executor/data_store.rs b/crates/miden-tx/src/executor/data_store.rs index 43ff605a26..f31dee7f59 100644 --- a/crates/miden-tx/src/executor/data_store.rs +++ b/crates/miden-tx/src/executor/data_store.rs @@ -23,7 +23,7 @@ pub trait DataStore: MastForestStore { /// specified ID and consuming input notes created in blocks in the input `ref_blocks` set. /// /// The highest block number in `ref_blocks` will be the transaction reference block. In - /// general, it is recommended that the refernece corresponds to the latest block available + /// general, it is recommended that the reference corresponds to the latest block available /// in the data store. /// /// # Errors From 635cf7fb77fa0f8d5f2aa9ec25057f257a66610a Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 21 Apr 2025 16:40:13 -0300 Subject: [PATCH 23/29] chore: Merge conflicts --- crates/miden-objects/src/transaction/inputs.rs | 11 ++++++++--- crates/miden-tx/src/testing/mock_chain/mod.rs | 5 +---- crates/miden-tx/src/tests/kernel_tests/test_fpi.rs | 3 ++- crates/miden-tx/src/tests/kernel_tests/test_tx.rs | 5 ++++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/miden-objects/src/transaction/inputs.rs b/crates/miden-objects/src/transaction/inputs.rs index 1760f68034..e181a8858c 100644 --- a/crates/miden-objects/src/transaction/inputs.rs +++ b/crates/miden-objects/src/transaction/inputs.rs @@ -606,8 +606,10 @@ impl ForeignAccountInputs { /// the passed root. pub fn verify_witness(&self, tree_root: &Digest) -> Result<(), MerkleError> { let tree_index = self.account_header.id().prefix().into(); - self.account_witness.path().verify(tree_index, self.account_header.commitment(), tree_root) - } + self.account_witness + .path() + .verify(tree_index, self.account_header.commitment(), tree_root) + } /// Extends the storage proofs with the input `smt_proofs` and returns the new structure #[must_use] @@ -676,7 +678,10 @@ mod tests { use super::ForeignAccountInputs; use crate::{ - account::{Account, AccountCode, AccountHeader, AccountId, AccountStorage}, asset::AssetVault, block::AccountWitness, testing::account_id::ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE + account::{Account, AccountCode, AccountHeader, AccountId, AccountStorage}, + asset::AssetVault, + block::AccountWitness, + testing::account_id::ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, }; #[test] diff --git a/crates/miden-tx/src/testing/mock_chain/mod.rs b/crates/miden-tx/src/testing/mock_chain/mod.rs index f37d3a6bc6..d5ce817104 100644 --- a/crates/miden-tx/src/testing/mock_chain/mod.rs +++ b/crates/miden-tx/src/testing/mock_chain/mod.rs @@ -34,10 +34,7 @@ use miden_objects::{ }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; -use vm_processor::{ - Digest, Felt, Word, ZERO, - crypto::RpoRandomCoin, -}; +use vm_processor::{Digest, Felt, Word, ZERO, crypto::RpoRandomCoin}; use super::TransactionContextBuilder; use crate::auth::BasicAuthenticator; diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index de0f594240..2262b0c5e3 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -16,12 +16,13 @@ use miden_lib::{ }, }; use miden_objects::{ + FieldElement, account::{ Account, AccountBuilder, AccountComponent, AccountProcedureInfo, AccountStorage, StorageSlot, }, testing::{account_component::AccountMockComponent, storage::STORAGE_LEAVES_2}, - transaction::{ForeignAccountInputs, TransactionScript}, FieldElement, + transaction::{ForeignAccountInputs, TransactionScript}, }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index 69e83f7114..67355005b6 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -63,7 +63,10 @@ fn test_fpi_anchoring_validations() { assert_matches::assert_matches!( transaction, - Err(TransactionExecutorError::InvalidAccountWitness(_, MerkleError::ConflictingRoots{..})) + Err(TransactionExecutorError::InvalidAccountWitness( + _, + MerkleError::ConflictingRoots { .. } + )) ); } From 7b959d123be2eac6c4af73e80da17d2e914284c0 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 21 Apr 2025 17:33:13 -0300 Subject: [PATCH 24/29] tests: refactor test to work around the new validations --- .../miden-objects/src/transaction/inputs.rs | 16 ++++++++-------- crates/miden-tx/src/errors/mod.rs | 10 ++++++---- crates/miden-tx/src/executor/mod.rs | 7 ++++++- crates/miden-tx/src/testing/mock_chain/mod.rs | 1 + .../src/tests/kernel_tests/test_fpi.rs | 19 ++++++++++++++++--- .../src/tests/kernel_tests/test_tx.rs | 6 +----- 6 files changed, 38 insertions(+), 21 deletions(-) diff --git a/crates/miden-objects/src/transaction/inputs.rs b/crates/miden-objects/src/transaction/inputs.rs index e181a8858c..9ed74f041b 100644 --- a/crates/miden-objects/src/transaction/inputs.rs +++ b/crates/miden-objects/src/transaction/inputs.rs @@ -1,7 +1,7 @@ use alloc::{collections::BTreeSet, vec::Vec}; use core::fmt::Debug; -use miden_crypto::merkle::{MerkleError, SmtProof}; +use miden_crypto::merkle::{SmtProof, SmtProofError}; use super::{BlockHeader, ChainMmr, Digest, Felt, Hasher, Word}; use crate::{ @@ -602,13 +602,13 @@ impl ForeignAccountInputs { &self.account_witness } - /// Verifies that the account witness is valid for the account's state commitment toward - /// the passed root. - pub fn verify_witness(&self, tree_root: &Digest) -> Result<(), MerkleError> { - let tree_index = self.account_header.id().prefix().into(); - self.account_witness - .path() - .verify(tree_index, self.account_header.commitment(), tree_root) + /// Computes account root based on the account witness. + pub fn compute_account_root(&self) -> Result { + let smt_merkle_path = self.account_witness.path().clone(); + let smt_leaf = self.account_witness.leaf(); + let root = SmtProof::new(smt_merkle_path, smt_leaf)?.compute_root(); + + Ok(root) } /// Extends the storage proofs with the input `smt_proofs` and returns the new structure diff --git a/crates/miden-tx/src/errors/mod.rs b/crates/miden-tx/src/errors/mod.rs index 994b97cee0..d3a8cdc425 100644 --- a/crates/miden-tx/src/errors/mod.rs +++ b/crates/miden-tx/src/errors/mod.rs @@ -3,11 +3,11 @@ use core::error::Error; use miden_objects::{ AccountError, Felt, ProvenTransactionError, TransactionInputError, TransactionOutputError, - account::AccountId, block::BlockNumber, note::NoteId, + account::AccountId, block::BlockNumber, crypto::merkle::SmtProofError, note::NoteId, }; use miden_verifier::VerificationError; use thiserror::Error; -use vm_processor::{ExecutionError, crypto::MerkleError}; +use vm_processor::ExecutionError; // TRANSACTION EXECUTOR ERROR // ================================================================================================ @@ -16,6 +16,8 @@ use vm_processor::{ExecutionError, crypto::MerkleError}; pub enum TransactionExecutorError { #[error("failed to fetch transaction inputs from the data store")] FetchTransactionInputsFailed(#[source] DataStoreError), + #[error("foreign account inputs for ID {0} are not anchored on reference block")] + ForeignAccountNotAnchoredInReference(AccountId), #[error("failed to create transaction inputs")] InvalidTransactionInputs(#[source] TransactionInputError), #[error("input account ID {input_id} does not match output account ID {output_id}")] @@ -28,8 +30,8 @@ pub enum TransactionExecutorError { expected: Option, actual: Option, }, - #[error("account witness provided for account ID {0} is invalid: {1}")] - InvalidAccountWitness(AccountId, #[source] MerkleError), + #[error("account witness provided for account ID {0} is invalid")] + InvalidAccountWitness(AccountId, #[source] SmtProofError), #[error( "input note {0} was created in a block past the transaction reference block number ({1})" )] diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index 343a7c4536..0c678f6a1a 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -131,9 +131,14 @@ impl TransactionExecutor { // Validate that foreign account inputs are anchored in the reference block for foreign_account in tx_args.foreign_accounts() { - foreign_account.verify_witness(&ref_header.account_root()).map_err(|err| { + let computed_account_root = foreign_account.compute_account_root().map_err(|err| { TransactionExecutorError::InvalidAccountWitness(foreign_account.id(), err) })?; + if computed_account_root != ref_header.account_root() { + return Err(TransactionExecutorError::ForeignAccountNotAnchoredInReference( + foreign_account.id(), + )); + } } let tx_inputs = TransactionInputs::new(account, seed, ref_header, mmr, notes) diff --git a/crates/miden-tx/src/testing/mock_chain/mod.rs b/crates/miden-tx/src/testing/mock_chain/mod.rs index d5ce817104..fcc50d2ad3 100644 --- a/crates/miden-tx/src/testing/mock_chain/mod.rs +++ b/crates/miden-tx/src/testing/mock_chain/mod.rs @@ -765,6 +765,7 @@ impl MockChain { let account = self.available_account(account_id); let account_witness = self.accounts().open(account_id); + assert_eq!(account_witness.state_commitment(), account.commitment()); let mut storage_map_proofs = vec![]; for slot in account.storage().slots() { diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index 2262b0c5e3..af10c2e060 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -18,8 +18,8 @@ use miden_lib::{ use miden_objects::{ FieldElement, account::{ - Account, AccountBuilder, AccountComponent, AccountProcedureInfo, AccountStorage, - StorageSlot, + Account, AccountBuilder, AccountComponent, AccountHeader, AccountProcedureInfo, + AccountStorage, StorageSlot, }, testing::{account_component::AccountMockComponent, storage::STORAGE_LEAVES_2}, transaction::{ForeignAccountInputs, TransactionScript}, @@ -1189,12 +1189,25 @@ fn test_fpi_stale_account() { // Place the modified account in the advice provider, which will cause the commitment mismatch. let foreign_account_inputs = mock_chain.get_foreign_account_inputs(foreign_account.id()); + // We want to create a mixed ForeignAccountInputs because we want to have a valid account + // witness against the ref block, but have newer account data (ie, a new state). Otherwise, + // any non-validity of the account witness is caught in + // TransactionExecutor::execute_transaction() (see `test_fpi_anchoring_validations()` for + // context on this check) + let overridden_foreign_account_inputs = ForeignAccountInputs::new( + AccountHeader::from(foreign_account.clone()), + foreign_account.storage().get_header(), + foreign_account.code().clone(), + foreign_account_inputs.account_witness().clone(), + foreign_account_inputs.storage_map_proofs().iter().cloned().collect(), + ); + // The account tree from which the transaction inputs are fetched here has the state from the // original unmodified foreign account. This should result in the foreign account's proof to be // invalid for this account tree root. let tx_context = mock_chain .build_tx_context(native_account.id(), &[], &[]) - .foreign_accounts(vec![foreign_account_inputs]) + .foreign_accounts(vec![overridden_foreign_account_inputs]) .build(); // Attempt to run FPI. diff --git a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs index 67355005b6..46289e6047 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_tx.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_tx.rs @@ -31,7 +31,6 @@ use miden_objects::{ }, transaction::{InputNotes, OutputNote, OutputNotes, TransactionArgs}, }; -use vm_processor::crypto::MerkleError; use super::{Felt, ONE, ProcessState, Word, ZERO}; use crate::{ @@ -63,10 +62,7 @@ fn test_fpi_anchoring_validations() { assert_matches::assert_matches!( transaction, - Err(TransactionExecutorError::InvalidAccountWitness( - _, - MerkleError::ConflictingRoots { .. } - )) + Err(TransactionExecutorError::ForeignAccountNotAnchoredInReference(_)) ); } From bf97884cf3e35662e54f2c03e6a162f7f6dddb52 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 21 Apr 2025 17:59:49 -0300 Subject: [PATCH 25/29] feat: Add is_valid() --- crates/miden-lib/src/transaction/mod.rs | 2 +- .../src/account/storage/header.rs | 7 +++ .../miden-objects/src/account/storage/mod.rs | 2 +- .../miden-objects/src/transaction/inputs.rs | 28 +++++++---- crates/miden-tx/src/executor/mod.rs | 48 +++++++++++-------- .../src/tests/kernel_tests/test_fpi.rs | 2 +- 6 files changed, 57 insertions(+), 32 deletions(-) diff --git a/crates/miden-lib/src/transaction/mod.rs b/crates/miden-lib/src/transaction/mod.rs index e865787fef..3aeb292981 100644 --- a/crates/miden-lib/src/transaction/mod.rs +++ b/crates/miden-lib/src/transaction/mod.rs @@ -197,7 +197,7 @@ impl TransactionKernel { let account_header = foreign_account_inputs.account_header(); let storage_header = foreign_account_inputs.storage_header(); let account_code = foreign_account_inputs.account_code(); - let account_witness = foreign_account_inputs.account_witness(); + let account_witness = foreign_account_inputs.witness(); let storage_proofs = foreign_account_inputs.storage_map_proofs(); let account_id = account_header.id(); diff --git a/crates/miden-objects/src/account/storage/header.rs b/crates/miden-objects/src/account/storage/header.rs index a0423ae1e3..466547e482 100644 --- a/crates/miden-objects/src/account/storage/header.rs +++ b/crates/miden-objects/src/account/storage/header.rs @@ -1,5 +1,7 @@ use alloc::vec::Vec; +use vm_processor::Digest; + use super::{AccountStorage, Felt, StorageSlot, StorageSlotType, Word}; use crate::{ AccountError, ZERO, @@ -90,6 +92,11 @@ impl AccountStorageHeader { }) } + /// Computes the account storage header commitment. + pub fn compute_commitment(&self) -> Digest { + super::Hasher::hash_elements(&self.as_elements()) + } + /// Converts storage slots of this account storage header into a vector of field elements. /// /// This is done by first converting each storage slot into exactly 8 elements as follows: diff --git a/crates/miden-objects/src/account/storage/mod.rs b/crates/miden-objects/src/account/storage/mod.rs index aa72c237de..8736b1bcfe 100644 --- a/crates/miden-objects/src/account/storage/mod.rs +++ b/crates/miden-objects/src/account/storage/mod.rs @@ -273,7 +273,7 @@ fn slots_as_elements(slots: &[StorageSlot]) -> Vec { /// Computes the commitment to the given slots fn build_slots_commitment(slots: &[StorageSlot]) -> Digest { let elements = slots_as_elements(slots); - Hasher::hash_elements(&elements) + super::Hasher::hash_elements(&elements) } // SERIALIZATION diff --git a/crates/miden-objects/src/transaction/inputs.rs b/crates/miden-objects/src/transaction/inputs.rs index 9ed74f041b..475b43b51d 100644 --- a/crates/miden-objects/src/transaction/inputs.rs +++ b/crates/miden-objects/src/transaction/inputs.rs @@ -549,7 +549,7 @@ pub struct ForeignAccountInputs { /// Code associated with the account. account_code: AccountCode, /// Proof of the account's inclusion in the account tree for this account's state commitment. - account_witness: AccountWitness, + witness: AccountWitness, /// Storage SMT proof for storage map values that the transaction will access. storage_map_proofs: Vec, } @@ -560,14 +560,14 @@ impl ForeignAccountInputs { account_header: AccountHeader, storage_header: AccountStorageHeader, account_code: AccountCode, - account_witness: AccountWitness, + witness: AccountWitness, storage_map_proofs: Vec, ) -> ForeignAccountInputs { ForeignAccountInputs { account_header, storage_header, account_code, - account_witness, + witness, storage_map_proofs, } } @@ -598,19 +598,27 @@ impl ForeignAccountInputs { } /// Returns the account witness. - pub fn account_witness(&self) -> &AccountWitness { - &self.account_witness + pub fn witness(&self) -> &AccountWitness { + &self.witness } /// Computes account root based on the account witness. pub fn compute_account_root(&self) -> Result { - let smt_merkle_path = self.account_witness.path().clone(); - let smt_leaf = self.account_witness.leaf(); + let smt_merkle_path = self.witness.path().clone(); + let smt_leaf = self.witness.leaf(); let root = SmtProof::new(smt_merkle_path, smt_leaf)?.compute_root(); Ok(root) } + /// Returns `true` if the [`ForeignAccountInputs`]'s inner fields are cohesive. + pub fn is_valid(&self) -> bool { + return self.account_header.code_commitment() == self.account_code.commitment() + && self.account_header.storage_commitment() + == self.storage_header.compute_commitment() + && self.account_header.commitment() == self.witness.state_commitment(); + } + /// Extends the storage proofs with the input `smt_proofs` and returns the new structure #[must_use] pub fn with_storage_map_proofs( @@ -629,7 +637,7 @@ impl ForeignAccountInputs { self.account_header, self.storage_header, self.account_code, - self.account_witness, + self.witness, self.storage_map_proofs, ) } @@ -640,7 +648,7 @@ impl Serializable for ForeignAccountInputs { self.account_header.write_into(target); self.storage_header.write_into(target); self.account_code.write_into(target); - self.account_witness.write_into(target); + self.witness.write_into(target); self.storage_map_proofs.write_into(target); } } @@ -666,7 +674,6 @@ impl Deserializable for ForeignAccountInputs { #[cfg(test)] mod tests { - use std::vec::Vec; use miden_crypto::merkle::MerklePath; @@ -714,5 +721,6 @@ mod tests { let serialized = fpi_inputs.to_bytes(); let deserialized = ForeignAccountInputs::read_from_bytes(&serialized).unwrap(); assert_eq!(deserialized, fpi_inputs); + assert!(deserialized.is_valid()); } } diff --git a/crates/miden-tx/src/executor/mod.rs b/crates/miden-tx/src/executor/mod.rs index 0c678f6a1a..8ded1775b3 100644 --- a/crates/miden-tx/src/executor/mod.rs +++ b/crates/miden-tx/src/executor/mod.rs @@ -4,7 +4,7 @@ use miden_lib::transaction::TransactionKernel; use miden_objects::{ Felt, MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES, ZERO, account::AccountId, - block::BlockNumber, + block::{BlockHeader, BlockNumber}, transaction::{ ExecutedTransaction, ForeignAccountInputs, InputNote, InputNotes, TransactionArgs, TransactionInputs, TransactionScript, @@ -125,23 +125,13 @@ impl TransactionExecutor { ref_blocks.insert(block_ref); - let (account, seed, ref_header, mmr) = + let (account, seed, ref_block, mmr) = maybe_await!(self.data_store.get_transaction_inputs(account_id, ref_blocks)) .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; - // Validate that foreign account inputs are anchored in the reference block - for foreign_account in tx_args.foreign_accounts() { - let computed_account_root = foreign_account.compute_account_root().map_err(|err| { - TransactionExecutorError::InvalidAccountWitness(foreign_account.id(), err) - })?; - if computed_account_root != ref_header.account_root() { - return Err(TransactionExecutorError::ForeignAccountNotAnchoredInReference( - foreign_account.id(), - )); - } - } + validate_account_inputs(&tx_args, &ref_block)?; - let tx_inputs = TransactionInputs::new(account, seed, ref_header, mmr, notes) + let tx_inputs = TransactionInputs::new(account, seed, ref_block, mmr, notes) .map_err(TransactionExecutorError::InvalidTransactionInputs)?; let (stack_inputs, advice_inputs) = @@ -192,13 +182,9 @@ impl TransactionExecutor { foreign_account_inputs: Vec, ) -> Result<[Felt; 16], TransactionExecutorError> { let ref_blocks = [block_ref].into_iter().collect(); - let (account, seed, header, mmr) = + let (account, seed, ref_block, mmr) = maybe_await!(self.data_store.get_transaction_inputs(account_id, ref_blocks)) .map_err(TransactionExecutorError::FetchTransactionInputsFailed)?; - - let tx_inputs = TransactionInputs::new(account, seed, header, mmr, Default::default()) - .map_err(TransactionExecutorError::InvalidTransactionInputs)?; - let tx_args = TransactionArgs::new( Some(tx_script.clone()), None, @@ -206,6 +192,11 @@ impl TransactionExecutor { foreign_account_inputs, ); + validate_account_inputs(&tx_args, &ref_block)?; + + let tx_inputs = TransactionInputs::new(account, seed, ref_block, mmr, Default::default()) + .map_err(TransactionExecutorError::InvalidTransactionInputs)?; + let (stack_inputs, advice_inputs) = TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_inputs)) .map_err(TransactionExecutorError::InvalidTransactionInputs)?; @@ -291,3 +282,22 @@ fn build_executed_transaction( tx_progress.into(), )) } + +/// Validates the account inputs against the reference block header. +fn validate_account_inputs( + tx_args: &TransactionArgs, + ref_block: &BlockHeader, +) -> Result<(), TransactionExecutorError> { + // Validate that foreign account inputs are anchored in the reference block + for foreign_account in tx_args.foreign_accounts() { + let computed_account_root = foreign_account.compute_account_root().map_err(|err| { + TransactionExecutorError::InvalidAccountWitness(foreign_account.id(), err) + })?; + if computed_account_root != ref_block.account_root() { + return Err(TransactionExecutorError::ForeignAccountNotAnchoredInReference( + foreign_account.id(), + )); + } + } + Ok(()) +} diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index af10c2e060..f62d1f670a 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -1198,7 +1198,7 @@ fn test_fpi_stale_account() { AccountHeader::from(foreign_account.clone()), foreign_account.storage().get_header(), foreign_account.code().clone(), - foreign_account_inputs.account_witness().clone(), + foreign_account_inputs.witness().clone(), foreign_account_inputs.storage_map_proofs().iter().cloned().collect(), ); From f352972a3113be6965cc9e41f5680c3060b47fa6 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 21 Apr 2025 18:00:35 -0300 Subject: [PATCH 26/29] chore: Clippy --- crates/miden-objects/src/transaction/inputs.rs | 7 +++---- crates/miden-tx/src/tests/kernel_tests/test_fpi.rs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/miden-objects/src/transaction/inputs.rs b/crates/miden-objects/src/transaction/inputs.rs index 475b43b51d..b331bd80d4 100644 --- a/crates/miden-objects/src/transaction/inputs.rs +++ b/crates/miden-objects/src/transaction/inputs.rs @@ -613,10 +613,9 @@ impl ForeignAccountInputs { /// Returns `true` if the [`ForeignAccountInputs`]'s inner fields are cohesive. pub fn is_valid(&self) -> bool { - return self.account_header.code_commitment() == self.account_code.commitment() - && self.account_header.storage_commitment() - == self.storage_header.compute_commitment() - && self.account_header.commitment() == self.witness.state_commitment(); + self.account_header.code_commitment() == self.account_code.commitment() + && self.account_header.storage_commitment() == self.storage_header.compute_commitment() + && self.account_header.commitment() == self.witness.state_commitment() } /// Extends the storage proofs with the input `smt_proofs` and returns the new structure diff --git a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs index f62d1f670a..cc4b7f643e 100644 --- a/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs +++ b/crates/miden-tx/src/tests/kernel_tests/test_fpi.rs @@ -1199,7 +1199,7 @@ fn test_fpi_stale_account() { foreign_account.storage().get_header(), foreign_account.code().clone(), foreign_account_inputs.witness().clone(), - foreign_account_inputs.storage_map_proofs().iter().cloned().collect(), + foreign_account_inputs.storage_map_proofs().to_vec(), ); // The account tree from which the transaction inputs are fetched here has the state from the From 57579678fbe3206414d7a7224145573ba619886c Mon Sep 17 00:00:00 2001 From: igamigo Date: Mon, 21 Apr 2025 18:03:01 -0300 Subject: [PATCH 27/29] style: CHANGELOG extra newline --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba1a231d76..d5baebb56d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ - Add `AccountTree` and `PartialAccountTree` wrappers and enforce ID prefix uniqueness (#1254). - Added a retry strategy for worker's health check (#1255). - Added pretty print for `AccountCode` (#1273). - - [BREAKING] Refactored how foreign account inputs are passed to `TransactionExecutor`, and upgraded Rust version to 1.86 (#1229). ## 0.8.1 (2025-03-26) - `miden-objects` and `miden-tx` crates only. From 6503c8b8b0a48da2643568076a0909f5ba11e922 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Mon, 21 Apr 2025 18:09:49 -0300 Subject: [PATCH 28/29] chore: Renames and imports --- crates/miden-lib/src/transaction/mod.rs | 2 +- crates/miden-objects/src/account/storage/header.rs | 4 ++-- crates/miden-objects/src/account/storage/mod.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/miden-lib/src/transaction/mod.rs b/crates/miden-lib/src/transaction/mod.rs index 3aeb292981..f6eefaaa47 100644 --- a/crates/miden-lib/src/transaction/mod.rs +++ b/crates/miden-lib/src/transaction/mod.rs @@ -207,7 +207,7 @@ impl TransactionKernel { // Extend the advice inputs with the new data advice_inputs.extend_map([ - // ACCOUNT_ID -> [ID_AND_NONCE, VAULT_ROOT, STORAGE_COMMITMENT, CODE_ROOT] + // ACCOUNT_ID -> [ID_AND_NONCE, VAULT_ROOT, STORAGE_COMMITMENT, CODE_COMMITMENT] (account_key, account_header.as_elements()), // STORAGE_COMMITMENT -> [STORAGE_SLOT_DATA] (account_header.storage_commitment(), storage_header.as_elements()), diff --git a/crates/miden-objects/src/account/storage/header.rs b/crates/miden-objects/src/account/storage/header.rs index 466547e482..3214795c30 100644 --- a/crates/miden-objects/src/account/storage/header.rs +++ b/crates/miden-objects/src/account/storage/header.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use vm_processor::Digest; -use super::{AccountStorage, Felt, StorageSlot, StorageSlotType, Word}; +use super::{AccountStorage, Felt, Hasher, StorageSlot, StorageSlotType, Word}; use crate::{ AccountError, ZERO, utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, @@ -94,7 +94,7 @@ impl AccountStorageHeader { /// Computes the account storage header commitment. pub fn compute_commitment(&self) -> Digest { - super::Hasher::hash_elements(&self.as_elements()) + Hasher::hash_elements(&self.as_elements()) } /// Converts storage slots of this account storage header into a vector of field elements. diff --git a/crates/miden-objects/src/account/storage/mod.rs b/crates/miden-objects/src/account/storage/mod.rs index 8736b1bcfe..01f0b98a78 100644 --- a/crates/miden-objects/src/account/storage/mod.rs +++ b/crates/miden-objects/src/account/storage/mod.rs @@ -271,7 +271,7 @@ fn slots_as_elements(slots: &[StorageSlot]) -> Vec { } /// Computes the commitment to the given slots -fn build_slots_commitment(slots: &[StorageSlot]) -> Digest { +pub(crate) fn build_slots_commitment(slots: &[StorageSlot]) -> Digest { let elements = slots_as_elements(slots); super::Hasher::hash_elements(&elements) } From 65ea1875dc2d5b0c2f1fa0bdf0b6f08827621d7a Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Tue, 22 Apr 2025 01:19:19 -0300 Subject: [PATCH 29/29] reviews: Remove unnecessary (crate) and add note --- crates/miden-objects/src/account/storage/header.rs | 1 + crates/miden-objects/src/account/storage/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/miden-objects/src/account/storage/header.rs b/crates/miden-objects/src/account/storage/header.rs index 3214795c30..515084e096 100644 --- a/crates/miden-objects/src/account/storage/header.rs +++ b/crates/miden-objects/src/account/storage/header.rs @@ -92,6 +92,7 @@ impl AccountStorageHeader { }) } + // NOTE: The way of computing the commitment should be kept in sync with `AccountStorage` /// Computes the account storage header commitment. pub fn compute_commitment(&self) -> Digest { Hasher::hash_elements(&self.as_elements()) diff --git a/crates/miden-objects/src/account/storage/mod.rs b/crates/miden-objects/src/account/storage/mod.rs index 01f0b98a78..de3e0e76bb 100644 --- a/crates/miden-objects/src/account/storage/mod.rs +++ b/crates/miden-objects/src/account/storage/mod.rs @@ -271,9 +271,9 @@ fn slots_as_elements(slots: &[StorageSlot]) -> Vec { } /// Computes the commitment to the given slots -pub(crate) fn build_slots_commitment(slots: &[StorageSlot]) -> Digest { +pub fn build_slots_commitment(slots: &[StorageSlot]) -> Digest { let elements = slots_as_elements(slots); - super::Hasher::hash_elements(&elements) + Hasher::hash_elements(&elements) } // SERIALIZATION