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

Commit

Permalink
TransactionExecutionInfo: add serialize
Browse files Browse the repository at this point in the history
  • Loading branch information
MohammadNassar1 committed Jan 11, 2024
1 parent d6dd88b commit fc0195f
Show file tree
Hide file tree
Showing 14 changed files with 77 additions and 35 deletions.
43 changes: 36 additions & 7 deletions crates/blockifier/src/execution/call_info.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::collections::HashSet;

use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources;
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use starknet_api::core::{ClassHash, EthAddress};
use starknet_api::hash::StarkFelt;
use starknet_api::state::StorageKey;
Expand All @@ -11,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 @@ -22,29 +24,29 @@ 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,
}

#[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 @@ -53,12 +55,39 @@ pub struct CallExecution {
pub gas_consumed: u64,
}

#[derive(Debug, Default, Eq, PartialEq, derive_more::Deref, derive_more::From)]
pub struct VmExecutionResourcesWrapper(pub VmExecutionResources);

impl VmExecutionResourcesWrapper {
pub fn new(vm_execution_resources: VmExecutionResources) -> Self {
VmExecutionResourcesWrapper(vm_execution_resources)
}
}

impl Serialize for VmExecutionResourcesWrapper {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// Create a serialize struct with the appropriate number of fields.
let mut state = serializer.serialize_struct("ExecutionResourcesWrapper", 3)?;

// Serialize each field individually.
state.serialize_field("builtin_instance_counter", &self.0.builtin_instance_counter)?;
state.serialize_field("n_memory_holes", &self.0.n_memory_holes)?;
state.serialize_field("n_steps", &self.0.n_steps)?;

// Finish serializing the struct.
state.end()
}
}

/// 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,
pub vm_resources: VmExecutionResources,
pub vm_resources: VmExecutionResourcesWrapper,
pub inner_calls: Vec<CallInfo>,

// Additional information gathered during execution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ pub fn finalize_execution(
failed: false,
gas_consumed: 0,
},
vm_resources: full_call_vm_resources.filter_unused_builtins(),
vm_resources: full_call_vm_resources.filter_unused_builtins().into(),
inner_calls: syscall_handler.inner_calls,
storage_read_values: syscall_handler.read_values,
accessed_storage_keys: syscall_handler.accessed_keys,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ fn test_nested_library_call() {
let nested_storage_call_info = CallInfo {
call: nested_storage_entry_point,
execution: CallExecution::from_retdata(retdata![stark_felt!(value + 1)]),
vm_resources: storage_entry_point_vm_resources.clone(),
vm_resources: storage_entry_point_vm_resources.clone().into(),
storage_read_values: vec![stark_felt!(0_u8), stark_felt!(value + 1)],
accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key + 1))]),
..Default::default()
Expand All @@ -149,14 +149,14 @@ fn test_nested_library_call() {
let library_call_info = CallInfo {
call: library_entry_point,
execution: CallExecution::from_retdata(retdata![stark_felt!(value + 1)]),
vm_resources: library_call_vm_resources.clone(),
vm_resources: library_call_vm_resources.clone().into(),
inner_calls: vec![nested_storage_call_info],
..Default::default()
};
let storage_call_info = CallInfo {
call: storage_entry_point,
execution: CallExecution::from_retdata(retdata![stark_felt!(value)]),
vm_resources: storage_entry_point_vm_resources.clone(),
vm_resources: storage_entry_point_vm_resources.clone().into(),
storage_read_values: vec![stark_felt!(0_u8), stark_felt!(value)],
accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]),
..Default::default()
Expand All @@ -168,7 +168,7 @@ fn test_nested_library_call() {
let expected_call_info = CallInfo {
call: main_entry_point.clone(),
execution: CallExecution::from_retdata(retdata![stark_felt!(0_u8)]),
vm_resources: main_call_vm_resources,
vm_resources: main_call_vm_resources.into(),
inner_calls: vec![library_call_info, storage_call_info],
..Default::default()
};
Expand Down Expand Up @@ -209,7 +209,7 @@ fn test_call_contract() {
..trivial_external_entry_point()
},
execution: expected_execution.clone(),
vm_resources: VmExecutionResources { n_steps: 42, ..Default::default() },
vm_resources: VmExecutionResources { n_steps: 42, ..Default::default() }.into(),
storage_read_values: vec![StarkFelt::ZERO, stark_felt!(value)],
accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]),
..Default::default()
Expand All @@ -229,7 +229,8 @@ fn test_call_contract() {
n_steps: 81,
builtin_instance_counter: HashMap::from([(RANGE_CHECK_BUILTIN_NAME.to_string(), 1)]),
..Default::default()
},
}
.into(),
..Default::default()
};

Expand Down
7 changes: 4 additions & 3 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 Expand Up @@ -281,7 +282,7 @@ impl EntryPointExecutionContext {
) -> usize {
let validate_steps = validate_call_info
.as_ref()
.map(|call_info| call_info.vm_resources.n_steps)
.map(|call_info| call_info.vm_resources.0.n_steps)
.unwrap_or_default();

let overhead_steps = OS_RESOURCES.resources_for_tx_type(tx_type).n_steps;
Expand Down
2 changes: 1 addition & 1 deletion crates/blockifier/src/execution/entry_point_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ pub fn finalize_execution(
failed: call_result.failed,
gas_consumed: call_result.gas_consumed,
},
vm_resources: full_call_vm_resources.filter_unused_builtins(),
vm_resources: full_call_vm_resources.filter_unused_builtins().into(),
inner_calls: syscall_handler.inner_calls,
storage_read_values: syscall_handler.read_values,
accessed_storage_keys: syscall_handler.accessed_keys,
Expand Down
1 change: 1 addition & 0 deletions crates/blockifier/src/execution/entry_point_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ fn test_cairo1_entry_point_segment_arena() {
.execute_directly(&mut state)
.unwrap()
.vm_resources
.0
.builtin_instance_counter
.contains_key(BuiltinName::segment_arena.name())
);
Expand Down
8 changes: 4 additions & 4 deletions crates/blockifier/src/execution/syscalls/syscalls_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ fn test_nested_library_call() {
gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST,
..CallExecution::default()
},
vm_resources: storage_entry_point_vm_resources.clone(),
vm_resources: storage_entry_point_vm_resources.clone().into(),
storage_read_values: vec![stark_felt!(value + 1)],
accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key + 1))]),
..Default::default()
Expand All @@ -571,7 +571,7 @@ fn test_nested_library_call() {
gas_consumed: REQUIRED_GAS_LIBRARY_CALL_TEST,
..CallExecution::default()
},
vm_resources: library_call_vm_resources,
vm_resources: library_call_vm_resources.into(),
inner_calls: vec![nested_storage_call_info],
..Default::default()
};
Expand All @@ -582,7 +582,7 @@ fn test_nested_library_call() {
gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST,
..CallExecution::default()
},
vm_resources: storage_entry_point_vm_resources,
vm_resources: storage_entry_point_vm_resources.into(),
storage_read_values: vec![stark_felt!(value)],
accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]),
..Default::default()
Expand All @@ -600,7 +600,7 @@ fn test_nested_library_call() {
gas_consumed: 316180,
..CallExecution::default()
},
vm_resources: main_call_vm_resources,
vm_resources: main_call_vm_resources.into(),
inner_calls: vec![library_call_info, storage_call_info],
..Default::default()
};
Expand Down
1 change: 1 addition & 0 deletions crates/blockifier/src/test_utils/prices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,5 @@ fn fee_transfer_resources(
)
.unwrap()
.vm_resources
.0
}
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 @@ -139,7 +140,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 @@ -187,7 +188,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
15 changes: 10 additions & 5 deletions crates/blockifier/src/transaction/transactions_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::abi::sierra_types::next_storage_key;
use crate::block_context::BlockContext;
use crate::execution::call_info::{
CallExecution, CallInfo, MessageToL1, OrderedEvent, OrderedL2ToL1Message, Retdata,
VmExecutionResourcesWrapper,
};
use crate::execution::entry_point::{CallEntryPoint, CallType};
use crate::execution::errors::{EntryPointExecutionError, VirtualMachineExecutionError};
Expand Down Expand Up @@ -146,7 +147,7 @@ fn expected_validate_call_info(
initial_gas: Transaction::initial_gas(),
},
// The account contract we use for testing has trivial `validate` functions.
vm_resources,
vm_resources: vm_resources.into(),
execution: CallExecution { retdata, gas_consumed, ..Default::default() },
..Default::default()
})
Expand Down Expand Up @@ -207,7 +208,9 @@ fn expected_fee_transfer_call_info(
events: vec![expected_fee_transfer_event],
..Default::default()
},
vm_resources: Prices::FeeTransfer(account_address, *fee_type).into(),
vm_resources: VmExecutionResourcesWrapper(
Prices::FeeTransfer(account_address, *fee_type).into(),
),
// We read sender balance, write (which starts with read) sender balance, then the same for
// recipient. We read Uint256(BALANCE, 0) twice, then Uint256(0, 0) twice.
storage_read_values: vec![
Expand Down Expand Up @@ -381,15 +384,16 @@ fn test_invoke_tx(
gas_consumed: expected_arguments.execute_gas_consumed,
..Default::default()
},
vm_resources: expected_arguments.vm_resources,
vm_resources: expected_arguments.vm_resources.into(),
inner_calls: vec![CallInfo {
call: expected_return_result_call,
execution: CallExecution::from_retdata(expected_return_result_retdata),
vm_resources: VmExecutionResources {
n_steps: 23,
n_memory_holes: 0,
..Default::default()
},
}
.into(),
..Default::default()
}],
..Default::default()
Expand Down Expand Up @@ -1626,7 +1630,8 @@ fn test_l1_handler() {
n_steps: 143,
n_memory_holes: 1,
builtin_instance_counter: HashMap::from([(RANGE_CHECK_BUILTIN_NAME.to_string(), 5)]),
},
}
.into(),
accessed_storage_keys: HashSet::from_iter(vec![accessed_storage_key]),
..Default::default()
};
Expand Down
2 changes: 1 addition & 1 deletion crates/native_blockifier/src/py_block_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl PyBlockExecutor {
&mut self,
tx: &PyAny,
raw_contract_class: Option<&str>,
) -> NativeBlockifierResult<(PyTransactionExecutionInfo, PyBouncerInfo)> {
) -> NativeBlockifierResult<(Vec<u8>, PyTransactionExecutionInfo, PyBouncerInfo)> {
let charge_fee = true;
self.tx_executor().execute(tx, raw_contract_class, charge_fee)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl From<CallInfo> for PyCallInfo {
gas_consumed: execution.gas_consumed,
failure_flag: PyFelt::from(execution.failed as u8),
retdata: to_py_vec(execution.retdata.0, PyFelt),
execution_resources: PyVmExecutionResources::from(call_info.vm_resources),
execution_resources: PyVmExecutionResources::from(call_info.vm_resources.0),
events: to_py_vec(execution.events, PyOrderedEvent::from),
l2_to_l1_messages: to_py_vec(execution.l2_to_l1_messages, PyOrderedL2ToL1Message::from),
internal_calls: to_py_vec(call_info.inner_calls, PyCallInfo::from),
Expand Down
5 changes: 3 additions & 2 deletions crates/native_blockifier/src/py_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,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 (_bytes_tx_execution_info, _py_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 @@ -131,7 +132,7 @@ impl PyValidator {
&mut self,
tx: &PyAny,
raw_contract_class: Option<&str>,
) -> NativeBlockifierResult<(PyTransactionExecutionInfo, PyBouncerInfo)> {
) -> NativeBlockifierResult<(Vec<u8>, PyTransactionExecutionInfo, 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
6 changes: 4 additions & 2 deletions crates/native_blockifier/src/transaction_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl<S: StateReader> TransactionExecutor<S> {
tx: &PyAny,
raw_contract_class: Option<&str>,
charge_fee: bool,
) -> NativeBlockifierResult<(PyTransactionExecutionInfo, PyBouncerInfo)> {
) -> NativeBlockifierResult<(Vec<u8>, PyTransactionExecutionInfo, PyBouncerInfo)> {
let tx: Transaction = py_tx(tx, raw_contract_class)?;

let mut tx_executed_class_hashes = HashSet::<ClassHash>::new();
Expand All @@ -88,6 +88,8 @@ impl<S: StateReader> TransactionExecutor<S> {
// TODO(Elin, 01/06/2024): consider traversing the calls to collect data once.
tx_executed_class_hashes.extend(tx_execution_info.get_executed_class_hashes());
tx_visited_storage_entries.extend(tx_execution_info.get_visited_storage_entries());
let bytes_tx_execution_info =
serde_json::to_string(&tx_execution_info).unwrap().into_bytes();

// TODO(Elin, 01/06/2024): consider moving Bouncer logic to a function.
let py_tx_execution_info = PyTransactionExecutionInfo::from(tx_execution_info);
Expand All @@ -109,7 +111,7 @@ impl<S: StateReader> TransactionExecutor<S> {
self.staged_for_commit_state = Some(
transactional_state.stage(tx_executed_class_hashes, tx_visited_storage_entries),
);
Ok((py_tx_execution_info, py_bouncer_info))
Ok((bytes_tx_execution_info, py_tx_execution_info, py_bouncer_info))
}
Err(error) => {
transactional_state.abort();
Expand Down

0 comments on commit fc0195f

Please sign in to comment.