Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(katana): execute txs using iterator #1180

Merged
merged 2 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/katana/core/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?;
Expand Down
131 changes: 72 additions & 59 deletions crates/katana/core/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,22 @@ impl Default for ExecutionOutcome {
}
}

/// The result of a transaction execution.
pub type TxExecutionResult = Result<TransactionExecutionInfo, TransactionExecutionError>;

/// 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<Transaction>,
/// The state the transactions will be executed on.
state: &'a mut CachedStateWrapper<StateRefDb>,

// logs flags
Expand All @@ -111,6 +124,7 @@ impl<'a> TransactionExecutor<'a> {
state: &'a mut CachedStateWrapper<StateRefDb>,
block_context: &'a BlockContext,
charge_fee: bool,
transactions: Vec<Transaction>,
) -> Self {
Self {
state,
Expand All @@ -119,6 +133,7 @@ impl<'a> TransactionExecutor<'a> {
error_log: false,
events_log: false,
resources_log: false,
transactions: transactions.into_iter(),
}
}

Expand All @@ -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<Transaction>,
) -> Vec<Result<TransactionExecutionInfo, TransactionExecutionError>> {
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<TxExecutionResult> {
self.collect()
}
}

pub fn execute(
&mut self,
transaction: Transaction,
) -> Result<TransactionExecutionInfo, TransactionExecutionError> {
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::Item> {
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)
}
}
})
}
}

Expand Down
10 changes: 5 additions & 5 deletions crates/katana/core/src/service/block_producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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(
Expand Down
Loading