Skip to content
Draft
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
8 changes: 1 addition & 7 deletions replay/src/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ pub struct TxBenchData {
time_ns: u128,
gas_consumed: u64,
steps: u64,
failed: bool,
}

impl BenchData {
Expand Down Expand Up @@ -107,16 +106,11 @@ pub fn summarize_tx(tx: &TransactionExecution) -> (TxBenchData, Vec<CallBenchDat
time_ns: tx.time.as_nanos(),
gas_consumed: 0,
steps: 0,
failed: tx.result.is_err(),
};

let Ok(info) = &tx.result else {
return (tx_data, vec![]);
};

let mut calls = Vec::new();

for call_info in info.non_optional_call_infos() {
for call_info in tx.info.non_optional_call_infos() {
tx_data.gas_consumed += call_info.execution.gas_consumed;
tx_data.steps += call_info.resources.n_steps as u64;

Expand Down
10 changes: 3 additions & 7 deletions replay/src/block_composition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ use std::{
path::Path,
};

use blockifier::{
execution::call_info::CallInfo,
transaction::{errors::TransactionExecutionError, objects::TransactionExecutionInfo},
};
use blockifier::{execution::call_info::CallInfo, transaction::objects::TransactionExecutionInfo};
use serde::Serialize;
use starknet_api::core::{ClassHash, EntryPointSelector};

type BlockExecutionInfo = Vec<(
u64, // block number
String, // block timestamp
Vec<Result<TransactionExecutionInfo, TransactionExecutionError>>,
Vec<TransactionExecutionInfo>,
)>;

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -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,
Expand Down
104 changes: 62 additions & 42 deletions replay/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand All @@ -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<TransactionExecutionInfo>,
pub info: TransactionExecutionInfo,
pub time: Duration,
pub hash: TransactionHash,
pub block_number: BlockNumber,
Expand All @@ -43,7 +45,7 @@ pub fn execute_block(
reader: &FullStateReader,
block_number: BlockNumber,
execution_flags: ExecutionFlags,
) -> anyhow::Result<Vec<TransactionExecution>> {
) -> anyhow::Result<Vec<anyhow::Result<TransactionExecution>>> {
let _block_execution_span = info_span!("block execution", block = block_number.0).entered();

let block = reader.get_block(block_number)?;
Expand All @@ -61,7 +63,7 @@ pub fn execute_txs(
block_number: BlockNumber,
tx_hashes: Vec<TransactionHash>,
execution_flags: ExecutionFlags,
) -> anyhow::Result<Vec<TransactionExecution>> {
) -> anyhow::Result<Vec<anyhow::Result<TransactionExecution>>> {
let block_reader = BlockStateReader::new(
block_number
.prev()
Expand All @@ -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<impl StateReader>,
reader: &FullStateReader,
block_context: &BlockContext,
tx_hash: TransactionHash,
block_number: BlockNumber,
execution_flags: ExecutionFlags,
) -> anyhow::Result<TransactionExecution> {
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<impl StateReader>,
reader: &FullStateReader,
Expand All @@ -110,46 +138,40 @@ 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<TransactionExecution>,
rpc_receipt: Option<RpcTransactionReceipt>,
) {
match execution_result {
Ok(execution_info) => {
let result_string = execution_info
.info
.revert_error
.as_ref()
.map(|err| err.to_string())
.unwrap_or("ok".to_string());

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,
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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())
}
Expand Down
16 changes: 9 additions & 7 deletions replay/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -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],
Expand All @@ -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);
Expand Down Expand Up @@ -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));
}
Expand Down
30 changes: 17 additions & 13 deletions replay/src/state_dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransactionExecution>,
state: &mut CachedState<impl StateReader>,
block_number: u64,
tx_hash_str: &str,
execution_info_result: &Result<TransactionExecutionInfo, TransactionExecutionError>,
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") {
Expand All @@ -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();
}
Expand Down Expand Up @@ -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);
}
Expand Down