diff --git a/replay/src/benchmark.rs b/replay/src/benchmark.rs index 3be3b3a3..4c99816a 100644 --- a/replay/src/benchmark.rs +++ b/replay/src/benchmark.rs @@ -44,7 +44,6 @@ pub struct TxBenchData { time_ns: u128, gas_consumed: u64, steps: u64, - failed: bool, } impl BenchData { @@ -107,16 +106,11 @@ pub fn summarize_tx(tx: &TransactionExecution) -> (TxBenchData, Vec>, + Vec, )>; #[derive(Debug, Serialize)] @@ -57,8 +54,7 @@ pub fn save_entry_point_execution( for (block_number, block_timestamp, executions) in executions { let entrypoints = executions .into_iter() - .map(|execution_rst| { - let execution = execution_rst.unwrap(); + .map(|execution| { let mut block_entry_point = TxEntryPoint { validate_call_info: None, execute_call_info: None, diff --git a/replay/src/execution.rs b/replay/src/execution.rs index bcb650fd..97da81fc 100644 --- a/replay/src/execution.rs +++ b/replay/src/execution.rs @@ -5,10 +5,12 @@ use blockifier::{ blockifier_versioned_constants::VersionedConstants, bouncer::BouncerConfig, context::BlockContext, - state::{cached_state::CachedState, state_api::StateReader}, + state::{ + cached_state::{CachedState, TransactionalState}, + state_api::StateReader, + }, transaction::{ - account_transaction::ExecutionFlags, - objects::{TransactionExecutionInfo, TransactionExecutionResult}, + account_transaction::ExecutionFlags, objects::TransactionExecutionInfo, transaction_execution::Transaction as BlockifierTransaction, transactions::ExecutableTransaction, }, @@ -33,7 +35,7 @@ use tracing::{error, info, info_span}; // so we allow dead code to silence warnings. #[allow(dead_code)] pub struct TransactionExecution { - pub result: TransactionExecutionResult, + pub info: TransactionExecutionInfo, pub time: Duration, pub hash: TransactionHash, pub block_number: BlockNumber, @@ -43,7 +45,7 @@ pub fn execute_block( reader: &FullStateReader, block_number: BlockNumber, execution_flags: ExecutionFlags, -) -> anyhow::Result> { +) -> anyhow::Result>> { let _block_execution_span = info_span!("block execution", block = block_number.0).entered(); let block = reader.get_block(block_number)?; @@ -61,7 +63,7 @@ pub fn execute_txs( block_number: BlockNumber, tx_hashes: Vec, execution_flags: ExecutionFlags, -) -> anyhow::Result> { +) -> anyhow::Result>> { let block_reader = BlockStateReader::new( block_number .prev() @@ -74,22 +76,48 @@ pub fn execute_txs( let mut executions = vec![]; for tx_hash in tx_hashes { - if let Ok(execution) = execute_tx( + executions.push(execute_and_process_tx( &mut state, reader, &block_context, tx_hash, + block_number, execution_flags.clone(), - ) - .inspect_err(|err| error!("failed to execute transaction: {}", err)) - { - executions.push(execution); - } + )); } Ok(executions) } +pub fn execute_and_process_tx( + state: &mut CachedState, + reader: &FullStateReader, + block_context: &BlockContext, + tx_hash: TransactionHash, + block_number: BlockNumber, + execution_flags: ExecutionFlags, +) -> anyhow::Result { + let mut state = TransactionalState::create_transactional(state); + let execution_result = execute_tx( + &mut state, + reader, + block_context, + tx_hash, + execution_flags.clone(), + ); + + log_execution_result(&execution_result, reader.get_tx_receipt(tx_hash).ok()); + + #[cfg(feature = "state_dump")] + crate::state_dump::save_execution_result(&execution_result, &mut state, block_number, tx_hash); + + #[cfg(feature = "with-libfunc-profiling")] + crate::libfunc_profile::create_libfunc_profile(tx_hash.to_hex_string()); + + state.commit(); + execution_result +} + pub fn execute_tx( state: &mut CachedState, reader: &FullStateReader, @@ -110,27 +138,25 @@ pub fn execute_tx( info!("starting transaction execution"); let pre_execute_instant = Instant::now(); - let execution_result = tx.execute(state, block_context); + let execution_info = tx.execute(state, block_context)?; let execution_time = pre_execute_instant.elapsed(); - // TODO: Move this to the caller. - // This function should only execute the transaction and return relevant information. - #[cfg(feature = "state_dump")] - crate::state_dump::create_state_dump( - state, - block_context.block_info().block_number.0, - &tx_hash.to_hex_string(), - &execution_result, - ); - - // TODO: Move this to the caller. - // This function should only execute the transaction and return relevant information. - #[cfg(feature = "with-libfunc-profiling")] - crate::libfunc_profile::create_libfunc_profile(tx_hash.to_hex_string()); + Ok(TransactionExecution { + info: execution_info, + time: execution_time, + hash: tx_hash, + block_number: block_context.block_info().block_number, + }) +} - match &execution_result { +fn log_execution_result( + execution_result: &anyhow::Result, + rpc_receipt: Option, +) { + match execution_result { Ok(execution_info) => { let result_string = execution_info + .info .revert_error .as_ref() .map(|err| err.to_string()) @@ -138,18 +164,14 @@ pub fn execute_tx( info!("transaction execution finished: {}", result_string); - let receipt = reader.get_tx_receipt(tx_hash)?; - validate_tx_with_receipt(execution_info, receipt); + if let Some(rpc_receipt) = rpc_receipt { + validate_tx_with_receipt(&execution_info.info, rpc_receipt); + } + } + Err(err) => { + error!("transaction execution failed: {}", err) } - Err(err) => error!("transaction execution failed: {err}"), } - - Ok(TransactionExecution { - result: execution_result, - time: execution_time, - hash: tx_hash, - block_number: block_context.block_info().block_number, - }) } /// Validates the transaction execution with the network receipt, @@ -517,8 +539,7 @@ mod tests { }; let mut execution = execute_tx(&mut state, &full_reader, &block_context, tx_hash, flags) .expect("failed to execute transaction") - .result - .expect("transaction execution failed"); + .info; normalize_execution_info(&mut execution); let summary = execution.summarize(block_context.versioned_constants()); @@ -568,8 +589,7 @@ mod tests { }; let execution = execute_tx(&mut state, &full_reader, &block_context, tx_hash, flags) .expect("failed to execute transaction") - .result - .expect("transaction execution failed"); + .info; assert!(execution.is_reverted()) } diff --git a/replay/src/main.rs b/replay/src/main.rs index 3d09201e..ff0e2def 100644 --- a/replay/src/main.rs +++ b/replay/src/main.rs @@ -294,7 +294,7 @@ fn main() { for _ in 0..number_of_runs { for block_number in block_start..=block_end { - let mut block_executions = execute_block( + let block_executions = execute_block( &full_reader, BlockNumber(block_number), execution_flags.clone(), @@ -306,8 +306,7 @@ fn main() { 0, "cache miss during a benchmark" ); - - executions.append(&mut block_executions); + executions.extend(block_executions.into_iter().filter_map(Result::ok)); } } @@ -357,7 +356,7 @@ fn main() { let mut executions = Vec::new(); for _ in 0..number_of_runs { - let mut block_executions = execute_txs( + let block_executions = execute_txs( &full_reader, block_number, vec![tx_hash], @@ -370,8 +369,7 @@ fn main() { 0, "cache miss during a benchmark" ); - - executions.append(&mut block_executions); + executions.extend(block_executions.into_iter().filter_map(Result::ok)); } let benchmarking_data = benchmark::BenchData::aggregate(&executions); @@ -449,7 +447,11 @@ fn main() { ) .expect("failed to execute block"); - let entrypoints = executions.into_iter().map(|tx| tx.result).collect(); + let entrypoints = executions + .into_iter() + .filter_map(Result::ok) + .map(|x| x.info) + .collect(); block_executions.push((block_number, block_timestamp, entrypoints)); } diff --git a/replay/src/state_dump.rs b/replay/src/state_dump.rs index 14d29c31..723966ec 100644 --- a/replay/src/state_dump.rs +++ b/replay/src/state_dump.rs @@ -18,29 +18,33 @@ use blockifier::{ cached_state::{CachedState, StateMaps, StorageEntry}, state_api::StateReader, }, - transaction::{errors::TransactionExecutionError, objects::TransactionExecutionInfo}, + transaction::objects::TransactionExecutionInfo, }; use cairo_vm::types::builtin_name::BuiltinName; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet_api::{ + block::BlockNumber, contract_class::EntryPointType, core::{ClassHash, CompiledClassHash, ContractAddress, EntryPointSelector, Nonce}, execution_resources::{GasAmount, GasVector}, state::StorageKey, - transaction::fields::{Calldata, Fee}, + transaction::{ + fields::{Calldata, Fee}, + TransactionHash, + }, }; use starknet_types_core::felt::Felt; use tracing::error; -pub fn create_state_dump( +use crate::execution::TransactionExecution; + +pub fn save_execution_result( + execution_result: &anyhow::Result, state: &mut CachedState, - block_number: u64, - tx_hash_str: &str, - execution_info_result: &Result, + block_number: BlockNumber, + tx_hash: TransactionHash, ) { - use std::path::Path; - let root = if cfg!(feature = "only_cairo_vm") { Path::new("state_dumps/vm") } else if cfg!(feature = "with-sierra-emu") { @@ -52,12 +56,12 @@ pub fn create_state_dump( std::fs::create_dir_all(&root).ok(); - let mut path = root.join(tx_hash_str); + let mut path = root.join(tx_hash.to_fixed_hex_string()); path.set_extension("json"); - match execution_info_result { - Ok(execution_info) => { - dump_state_diff(state, execution_info, &path) + match execution_result { + Ok(execution) => { + dump_state_diff(state, &execution.info, &path) .inspect_err(|err| error!("failed to dump state diff: {err}")) .ok(); } @@ -98,7 +102,7 @@ fn dump_state_diff( Ok(()) } -fn dump_error(err: &TransactionExecutionError, path: &Path) -> anyhow::Result<()> { +fn dump_error(err: &anyhow::Error, path: &Path) -> anyhow::Result<()> { if let Some(parent) = path.parent() { let _ = fs::create_dir_all(parent); }