diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index a57690686a..745fe78a06 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -185,9 +185,9 @@ impl Backend { let mut estimations = Vec::with_capacity(transactions.len()); - let results = TransactionExecutor::new(&mut state, &block_context, false) + let results = TransactionExecutor::new(&mut state, &block_context, false, transactions) .with_error_log() - .execute_many(transactions); + .execute(); for res in results { let exec_info = res?; diff --git a/crates/katana/core/src/execution.rs b/crates/katana/core/src/execution.rs index fd599ffbdf..e11f5a314d 100644 --- a/crates/katana/core/src/execution.rs +++ b/crates/katana/core/src/execution.rs @@ -95,9 +95,22 @@ impl Default for ExecutionOutcome { } } +/// The result of a transaction execution. +pub type TxExecutionResult = Result; + +/// A transaction executor. +/// +/// The transactions will be executed in an iterator fashion, sequentially, in the +/// exact order they are provided to the executor. The execution is done within its implementation +/// of the [`Iterator`] trait. pub struct TransactionExecutor<'a> { + /// A flag to enable/disable fee charging. charge_fee: bool, + /// The block context the transactions will be executed on. block_context: &'a BlockContext, + /// The transactions to be executed (in the exact order they are in the iterator). + transactions: std::vec::IntoIter, + /// The state the transactions will be executed on. state: &'a mut CachedStateWrapper, // logs flags @@ -111,6 +124,7 @@ impl<'a> TransactionExecutor<'a> { state: &'a mut CachedStateWrapper, block_context: &'a BlockContext, charge_fee: bool, + transactions: Vec, ) -> Self { Self { state, @@ -119,6 +133,7 @@ impl<'a> TransactionExecutor<'a> { error_log: false, events_log: false, resources_log: false, + transactions: transactions.into_iter(), } } @@ -133,78 +148,76 @@ impl<'a> TransactionExecutor<'a> { pub fn with_resources_log(self) -> Self { Self { resources_log: true, ..self } } -} -impl<'a> TransactionExecutor<'a> { - pub fn execute_many( - &mut self, - transactions: Vec, - ) -> Vec> { - transactions.into_iter().map(|tx| self.execute(tx)).collect() + /// A method to conveniently execute all the transactions and return their results. + pub fn execute(self) -> Vec { + self.collect() } +} - pub fn execute( - &mut self, - transaction: Transaction, - ) -> Result { - let sierra = if let Transaction::Declare(DeclareTransaction { - sierra_class: Some(sierra_class), - inner, - .. - }) = &transaction - { - Some((inner.class_hash(), sierra_class.clone())) - } else { - None - }; - - let res = match transaction.into() { - ExecutionTransaction::AccountTransaction(tx) => { - tx.execute(&mut self.state.inner_mut(), self.block_context, self.charge_fee) - } - ExecutionTransaction::L1HandlerTransaction(tx) => { - tx.execute(&mut self.state.inner_mut(), self.block_context, self.charge_fee) - } - }; - - match res { - Ok(exec_info) => { - if let Some((class_hash, sierra_class)) = sierra { - self.state - .set_sierra_class(class_hash, sierra_class) - .expect("failed to set sierra class"); +impl<'a> Iterator for TransactionExecutor<'a> { + type Item = TxExecutionResult; + fn next(&mut self) -> Option { + self.transactions.next().map(|tx| { + let sierra = if let Transaction::Declare(DeclareTransaction { + sierra_class: Some(sierra_class), + inner, + .. + }) = &tx + { + Some((inner.class_hash(), sierra_class.clone())) + } else { + None + }; + + let res = match tx.into() { + ExecutionTransaction::AccountTransaction(tx) => { + tx.execute(&mut self.state.inner_mut(), self.block_context, self.charge_fee) } + ExecutionTransaction::L1HandlerTransaction(tx) => { + tx.execute(&mut self.state.inner_mut(), self.block_context, self.charge_fee) + } + }; + + match res { + Ok(exec_info) => { + if let Some((class_hash, sierra_class)) = sierra { + self.state + .set_sierra_class(class_hash, sierra_class) + .expect("failed to set sierra class"); + } - if self.error_log { - if let Some(err) = &exec_info.revert_error { - let formatted_err = format!("{:?}", err).replace("\\n", "\n"); - warn!(target: "executor", "Transaction execution error: {formatted_err}"); + if self.error_log { + if let Some(err) = &exec_info.revert_error { + let formatted_err = format!("{:?}", err).replace("\\n", "\n"); + warn!(target: "executor", "Transaction execution error: {formatted_err}"); + } } - } - if self.resources_log { - trace!( - target: "executor", - "Transaction resource usage: {}", - pretty_print_resources(&exec_info.actual_resources) - ); - } + if self.resources_log { + trace!( + target: "executor", + "Transaction resource usage: {}", + pretty_print_resources(&exec_info.actual_resources) + ); + } + + if self.events_log { + trace_events(&events_from_exec_info(&exec_info)); + } - if self.events_log { - trace_events(&events_from_exec_info(&exec_info)); + Ok(exec_info) } - Ok(exec_info) - } + Err(err) => { + if self.error_log { + warn_message_transaction_error_exec_error(&err); + } - Err(err) => { - if self.error_log { - warn_message_transaction_error_exec_error(&err); + Err(err) } - - Err(err) } - } + }) } } diff --git a/crates/katana/core/src/service/block_producer.rs b/crates/katana/core/src/service/block_producer.rs index be8dbd6726..1f03d8c95a 100644 --- a/crates/katana/core/src/service/block_producer.rs +++ b/crates/katana/core/src/service/block_producer.rs @@ -228,16 +228,15 @@ impl IntervalBlockProducer { &mut state, &self.backend.env.read().block, !self.backend.config.read().disable_fee, + transactions.clone(), ) .with_error_log() .with_events_log() .with_resources_log() - .execute_many(transactions.clone()) - .into_iter() .zip(transactions) .map(|(res, tx)| match res { - Ok(exec_info) => { - let executed_tx = ExecutedTransaction::new(tx, exec_info); + Ok(execution_info) => { + let executed_tx = ExecutedTransaction::new(tx, execution_info); MaybeInvalidExecutedTransaction::Valid(Arc::new(executed_tx)) } Err(err) => { @@ -354,11 +353,12 @@ impl InstantBlockProducer { &mut state, &block_context, !backend.config.read().disable_fee, + transactions.clone(), ) .with_error_log() .with_events_log() .with_resources_log() - .execute_many(transactions.clone()); + .execute(); let outcome = backend .do_mine_block(create_execution_outcome(