Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
perf(native_blockifier): transaction execution info add serialize
Browse files Browse the repository at this point in the history
  • Loading branch information
MohammadNassar1 committed Jan 31, 2024
1 parent bb30f51 commit 4d61fae
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 27 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 18 additions & 7 deletions crates/blockifier/src/execution/call_info.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};

use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources;
use serde::{Deserialize, Serialize};
use starknet_api::core::{ClassHash, EthAddress};
use starknet_api::hash::StarkFelt;
use starknet_api::state::StorageKey;
Expand All @@ -12,7 +13,7 @@ use crate::state::cached_state::StorageEntry;
use crate::transaction::errors::TransactionExecutionError;
use crate::transaction::objects::TransactionExecutionResult;

#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct Retdata(pub Vec<StarkFelt>);

#[macro_export]
Expand All @@ -23,7 +24,7 @@ macro_rules! retdata {
}

#[cfg_attr(test, derive(Clone))]
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
pub struct OrderedEvent {
pub order: usize,
pub event: EventContent,
Expand Down Expand Up @@ -53,22 +54,22 @@ impl MessageL1CostInfo {
}

#[cfg_attr(test, derive(Clone))]
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
pub struct MessageToL1 {
pub to_address: EthAddress,
pub payload: L2ToL1Payload,
}

#[cfg_attr(test, derive(Clone))]
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
pub struct OrderedL2ToL1Message {
pub order: usize,
pub message: MessageToL1,
}

/// Represents the effects of executing a single entry point.
#[cfg_attr(test, derive(Clone))]
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
pub struct CallExecution {
pub retdata: Retdata,
pub events: Vec<OrderedEvent>,
Expand All @@ -77,11 +78,21 @@ pub struct CallExecution {
pub gas_consumed: u64,
}

// This struct is used to implement `serde` functionality in a remote `VmExecutionResources` Struct.
#[derive(Debug, Default, Deserialize, derive_more::From, Eq, PartialEq, Serialize)]
#[serde(remote = "VmExecutionResources")]
struct VmExecutionResourcesDef {
n_steps: usize,
n_memory_holes: usize,
builtin_instance_counter: HashMap<String, usize>,
}

/// Represents the full effects of executing an entry point, including the inner calls it invoked.
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
pub struct CallInfo {
pub call: CallEntryPoint,
pub execution: CallExecution,
#[serde(with = "VmExecutionResourcesDef")]
pub vm_resources: VmExecutionResources,
pub inner_calls: Vec<CallInfo>,

Expand Down
5 changes: 3 additions & 2 deletions crates/blockifier/src/execution/entry_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::sync::Arc;
use cairo_vm::vm::runners::cairo_runner::{
ExecutionResources as VmExecutionResources, ResourceTracker, RunResources,
};
use serde::Serialize;
use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector};
use starknet_api::deprecated_contract_class::EntryPointType;
use starknet_api::hash::StarkFelt;
Expand Down Expand Up @@ -35,14 +36,14 @@ pub const FAULTY_CLASS_HASH: &str =
pub type EntryPointExecutionResult<T> = Result<T, EntryPointExecutionError>;

/// Represents a the type of the call (used for debugging).
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Serialize)]
pub enum CallType {
#[default]
Call = 0,
Delegate = 1,
}
/// Represents a call to an entry point of a Starknet contract.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct CallEntryPoint {
// The class hash is not given if it can be deduced from the storage address.
pub class_hash: Option<ClassHash>,
Expand Down
5 changes: 3 additions & 2 deletions crates/blockifier/src/transaction/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet};
use cairo_felt::Felt252;
use itertools::concat;
use num_traits::Pow;
use serde::Serialize;
use starknet_api::core::{ClassHash, ContractAddress, Nonce};
use starknet_api::data_availability::DataAvailabilityMode;
use starknet_api::transaction::{
Expand Down Expand Up @@ -146,7 +147,7 @@ pub struct CommonAccountFields {
}

/// Contains the information gathered by the execution of a transaction.
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
pub struct TransactionExecutionInfo {
/// Transaction validation call info; [None] for `L1Handler`.
pub validate_call_info: Option<CallInfo>,
Expand Down Expand Up @@ -194,7 +195,7 @@ impl TransactionExecutionInfo {

/// A mapping from a transaction execution resource to its actual usage.
#[cfg_attr(test, derive(Clone))]
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
pub struct ResourcesMapping(pub HashMap<String, usize>);

impl ResourcesMapping {
Expand Down
4 changes: 2 additions & 2 deletions crates/blockifier/src/transaction/transaction_types.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::str::FromStr;

use serde::Deserialize;
use serde::{Deserialize, Serialize};
use strum_macros::EnumIter;

use crate::transaction::errors::ParseError;

#[derive(Clone, Copy, Debug, Deserialize, EnumIter, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Debug, Deserialize, EnumIter, Eq, Hash, PartialEq, Serialize)]
pub enum TransactionType {
Declare,
DeployAccount,
Expand Down
1 change: 1 addition & 0 deletions crates/native_blockifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ num-bigint.workspace = true
papyrus_storage = { workspace = true, features = ["testing"] }
pyo3 = { workspace = true, features = ["num-bigint", "hashbrown"] }
pyo3-log.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["arbitrary_precision"] }
starknet_api = { workspace = true, features = ["testing"] }
thiserror.workspace = true
Expand Down
12 changes: 8 additions & 4 deletions crates/native_blockifier/src/py_block_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::sync::Arc;

use blockifier::block_context::{BlockContext, BlockInfo, ChainInfo, FeeTokenAddresses, GasPrices};
use blockifier::state::cached_state::{GlobalContractCache, GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST};
use blockifier::state::cached_state::GlobalContractCache;
use blockifier::versioned_constants::VersionedConstants;
use pyo3::prelude::*;
use starknet_api::block::{BlockNumber, BlockTimestamp};
Expand All @@ -11,11 +11,11 @@ use starknet_api::hash::StarkFelt;

use crate::errors::{NativeBlockifierError, NativeBlockifierResult};
use crate::py_state_diff::{PyBlockInfo, PyStateDiff};
use crate::py_transaction_execution_info::{PyBouncerInfo, PyTransactionExecutionInfo};
use crate::py_transaction_execution_info::PyBouncerInfo;
use crate::py_utils::{int_to_chain_id, py_attr, versioned_constants_with_overrides, PyFelt};
use crate::state_readers::papyrus_state::PapyrusReader;
use crate::storage::{PapyrusStorage, Storage, StorageConfig};
use crate::transaction_executor::TransactionExecutor;
use crate::transaction_executor::{RawTransactionExecutionInfo, TransactionExecutor};

#[cfg(test)]
#[path = "py_block_executor_test.rs"]
Expand Down Expand Up @@ -87,7 +87,7 @@ impl PyBlockExecutor {
&mut self,
tx: &PyAny,
raw_contract_class: Option<&str>,
) -> NativeBlockifierResult<(PyTransactionExecutionInfo, PyBouncerInfo)> {
) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> {
let charge_fee = true;
self.tx_executor().execute(tx, raw_contract_class, charge_fee)
}
Expand Down Expand Up @@ -197,6 +197,8 @@ impl PyBlockExecutor {
#[pyo3(signature = (general_config, path))]
#[staticmethod]
fn create_for_testing(general_config: PyGeneralConfig, path: std::path::PathBuf) -> Self {
use blockifier::state::cached_state::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST;

Self {
storage: Box::new(PapyrusStorage::new_for_testing(
path,
Expand All @@ -223,6 +225,8 @@ impl PyBlockExecutor {

#[cfg(any(feature = "testing", test))]
pub fn create_for_testing_with_storage(storage: impl Storage + Send + 'static) -> Self {
use blockifier::state::cached_state::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST;

Self {
storage: Box::new(storage),
general_config: PyGeneralConfig::default(),
Expand Down
13 changes: 8 additions & 5 deletions crates/native_blockifier/src/py_validator.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use blockifier::execution::call_info::CallInfo;
use blockifier::fee::actual_cost::ActualCost;
use blockifier::fee::fee_checks::PostValidationReport;
use blockifier::state::cached_state::{GlobalContractCache, GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST};
use blockifier::state::cached_state::GlobalContractCache;
use blockifier::state::state_api::StateReader;
use blockifier::transaction::account_transaction::AccountTransaction;
use blockifier::transaction::objects::{AccountTransactionContext, TransactionExecutionResult};
Expand All @@ -15,10 +15,10 @@ use crate::errors::NativeBlockifierResult;
use crate::py_block_executor::PyGeneralConfig;
use crate::py_state_diff::PyBlockInfo;
use crate::py_transaction::py_account_tx;
use crate::py_transaction_execution_info::{PyBouncerInfo, PyTransactionExecutionInfo};
use crate::py_transaction_execution_info::PyBouncerInfo;
use crate::py_utils::{versioned_constants_with_overrides, PyFelt};
use crate::state_readers::py_state_reader::PyStateReader;
use crate::transaction_executor::TransactionExecutor;
use crate::transaction_executor::{RawTransactionExecutionInfo, TransactionExecutor};

/// Manages transaction validation for pre-execution flows.
#[pyclass]
Expand Down Expand Up @@ -72,7 +72,8 @@ impl PyValidator {
// before `__validate_deploy__`. The execution already includes all necessary validations,
// so they are skipped here.
if let AccountTransaction::DeployAccount(_deploy_account_tx) = account_tx {
let (_py_tx_execution_info, _py_bouncer_info) = self.execute(tx, raw_contract_class)?;
let (_raw_tx_execution_info, _py_bouncer_info) =
self.execute(tx, raw_contract_class)?;
// TODO(Ayelet, 09/11/2023): Check call succeeded.

return Ok(());
Expand Down Expand Up @@ -110,6 +111,8 @@ impl PyValidator {
state_reader_proxy: &PyAny,
next_block_info: PyBlockInfo,
) -> NativeBlockifierResult<Self> {
use blockifier::state::cached_state::GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST;

let tx_executor = TransactionExecutor::new(
PyStateReader::new(state_reader_proxy),
&general_config,
Expand All @@ -126,7 +129,7 @@ impl PyValidator {
&mut self,
tx: &PyAny,
raw_contract_class: Option<&str>,
) -> NativeBlockifierResult<(PyTransactionExecutionInfo, PyBouncerInfo)> {
) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> {
let limit_execution_steps_by_resource_bounds = true;
self.tx_executor.execute(tx, raw_contract_class, limit_execution_steps_by_resource_bounds)
}
Expand Down
37 changes: 32 additions & 5 deletions crates/native_blockifier/src/transaction_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,34 @@ use blockifier::state::cached_state::{
};
use blockifier::state::state_api::{State, StateReader};
use blockifier::transaction::account_transaction::AccountTransaction;
use blockifier::transaction::objects::TransactionExecutionInfo;
use blockifier::transaction::transaction_execution::Transaction;
use blockifier::transaction::transaction_utils::calculate_tx_weights;
use blockifier::transaction::transactions::{ExecutableTransaction, ValidatableTransaction};
use blockifier::versioned_constants::VersionedConstants;
use cairo_vm::vm::runners::builtin_runner::HASH_BUILTIN_NAME;
use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources;
use pyo3::prelude::*;
use serde::Serialize;
use starknet_api::core::ClassHash;

use crate::errors::{NativeBlockifierError, NativeBlockifierResult};
use crate::py_block_executor::{into_block_context, PyGeneralConfig};
use crate::py_state_diff::{PyBlockInfo, PyStateDiff};
use crate::py_transaction::py_tx;
use crate::py_transaction_execution_info::{PyBouncerInfo, PyTransactionExecutionInfo};
use crate::py_transaction_execution_info::PyBouncerInfo;
use crate::py_utils::PyFelt;

pub(crate) type RawTransactionExecutionInfo = Vec<u8>;

#[pyclass]
#[derive(Debug, Serialize)]
pub(crate) struct TypedTransactionExecutionInfo {
#[serde(flatten)]
info: TransactionExecutionInfo,
tx_type: String,
}

pub struct TransactionExecutor<S: StateReader> {
pub block_context: BlockContext,

Expand Down Expand Up @@ -72,7 +84,8 @@ impl<S: StateReader> TransactionExecutor<S> {
tx: &PyAny,
raw_contract_class: Option<&str>,
charge_fee: bool,
) -> NativeBlockifierResult<(PyTransactionExecutionInfo, PyBouncerInfo)> {
) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> {
let tx_type: &str = tx.getattr("tx_type")?.getattr("name")?.extract()?;
let tx: Transaction = py_tx(tx, raw_contract_class)?;
let l1_handler_payload_size: usize =
if let Transaction::L1HandlerTransaction(l1_handler_tx) = &tx {
Expand All @@ -91,8 +104,11 @@ impl<S: StateReader> TransactionExecutor<S> {
match tx_execution_result {
Ok(tx_execution_info) => {
// TODO(Elin, 01/06/2024): consider traversing the calls to collect data once.
// TODO(Elin, 01/06/2024): consider moving Bouncer logic to a function.
tx_executed_class_hashes.extend(tx_execution_info.get_executed_class_hashes());
tx_visited_storage_entries.extend(tx_execution_info.get_visited_storage_entries());

// Count message to L1 resources.
let call_infos: IntoIter<&CallInfo> =
[&tx_execution_info.validate_call_info, &tx_execution_info.execute_call_info]
.iter()
Expand All @@ -102,7 +118,7 @@ impl<S: StateReader> TransactionExecutor<S> {
let MessageL1CostInfo { l2_to_l1_payload_lengths: _, message_segment_length } =
MessageL1CostInfo::calculate(call_infos, Some(l1_handler_payload_size))?;

// TODO(Elin, 01/06/2024): consider moving Bouncer logic to a function.
// Count additional OS resources.
let mut additional_os_resources = get_casm_hash_calculation_resources(
&mut transactional_state,
&self.executed_class_hashes,
Expand All @@ -112,7 +128,11 @@ impl<S: StateReader> TransactionExecutor<S> {
&self.visited_storage_entries,
&tx_visited_storage_entries,
)?;

// Count blob resources.
let state_diff_size = 0;

// Finalize counting logic.
let actual_resources = tx_execution_info.actual_resources.0.clone();
let tx_weights = calculate_tx_weights(
additional_os_resources,
Expand All @@ -124,8 +144,15 @@ impl<S: StateReader> TransactionExecutor<S> {
self.staged_for_commit_state = Some(
transactional_state.stage(tx_executed_class_hashes, tx_visited_storage_entries),
);
let py_tx_execution_info = PyTransactionExecutionInfo::from(tx_execution_info);
Ok((py_tx_execution_info, py_bouncer_info))

let typed_tx_execution_info = TypedTransactionExecutionInfo {
info: tx_execution_info,
tx_type: tx_type.to_string(),
};
let raw_tx_execution_info = serde_json::to_vec(&typed_tx_execution_info)
.map_err(NativeBlockifierError::SerdeError)?;

Ok((raw_tx_execution_info, py_bouncer_info))
}
Err(error) => {
transactional_state.abort();
Expand Down

0 comments on commit 4d61fae

Please sign in to comment.