diff --git a/crates/blockifier/src/execution/call_info.rs b/crates/blockifier/src/execution/call_info.rs index 104b6bc4d6..128bf13d41 100644 --- a/crates/blockifier/src/execution/call_info.rs +++ b/crates/blockifier/src/execution/call_info.rs @@ -1,6 +1,9 @@ use std::collections::HashSet; +use std::ops::Deref; 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; @@ -11,7 +14,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); #[macro_export] @@ -22,21 +25,21 @@ 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, @@ -44,7 +47,7 @@ pub struct OrderedL2ToL1Message { /// 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, @@ -53,12 +56,47 @@ pub struct CallExecution { pub gas_consumed: u64, } -/// Represents the full effects of executing an entry point, including the inner calls it invoked. #[derive(Debug, Default, Eq, PartialEq)] +pub struct VmExecutionResourcesWrapper(pub VmExecutionResources); + +impl Deref for VmExecutionResourcesWrapper { + type Target = VmExecutionResources; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl VmExecutionResourcesWrapper { + pub fn new(vm_execution_resources: VmExecutionResources) -> Self { + VmExecutionResourcesWrapper(vm_execution_resources) + } +} + +impl Serialize for VmExecutionResourcesWrapper { + fn serialize(&self, serializer: S) -> Result + 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, Serialize)] pub struct CallInfo { pub call: CallEntryPoint, pub execution: CallExecution, - pub vm_resources: VmExecutionResources, + pub vm_resources: VmExecutionResourcesWrapper, pub inner_calls: Vec, // Additional information gathered during execution. diff --git a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs index 296baefb2f..ce5c707711 100644 --- a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs +++ b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs @@ -10,7 +10,7 @@ use starknet_api::hash::StarkHash; use crate::abi::abi_utils::selector_from_name; use crate::abi::constants::{CONSTRUCTOR_ENTRY_POINT_NAME, DEFAULT_ENTRY_POINT_SELECTOR}; -use crate::execution::call_info::{CallExecution, CallInfo}; +use crate::execution::call_info::{CallExecution, CallInfo, VmExecutionResourcesWrapper}; use crate::execution::contract_class::ContractClassV0; use crate::execution::deprecated_syscalls::hint_processor::DeprecatedSyscallHintProcessor; use crate::execution::entry_point::{ @@ -253,7 +253,7 @@ pub fn finalize_execution( failed: false, gas_consumed: 0, }, - vm_resources: full_call_vm_resources.filter_unused_builtins(), + vm_resources: VmExecutionResourcesWrapper(full_call_vm_resources.filter_unused_builtins()), inner_calls: syscall_handler.inner_calls, storage_read_values: syscall_handler.read_values, accessed_storage_keys: syscall_handler.accessed_keys, diff --git a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs index 9b65f887dd..363714ff23 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs @@ -18,7 +18,7 @@ use starknet_api::{calldata, class_hash, contract_address, patricia_key, stark_f use test_case::test_case; use crate::abi::abi_utils::selector_from_name; -use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; +use crate::execution::call_info::{CallExecution, CallInfo, Retdata, VmExecutionResourcesWrapper}; use crate::execution::common_hints::ExecutionMode; use crate::execution::entry_point::{CallEntryPoint, CallType}; use crate::execution::errors::{EntryPointExecutionError, VirtualMachineExecutionError}; @@ -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: VmExecutionResourcesWrapper(storage_entry_point_vm_resources.clone()), storage_read_values: vec![stark_felt!(0_u8), stark_felt!(value + 1)], accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key + 1))]), ..Default::default() @@ -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: VmExecutionResourcesWrapper(library_call_vm_resources.clone()), 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: VmExecutionResourcesWrapper(storage_entry_point_vm_resources.clone()), storage_read_values: vec![stark_felt!(0_u8), stark_felt!(value)], accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]), ..Default::default() @@ -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: VmExecutionResourcesWrapper(main_call_vm_resources), inner_calls: vec![library_call_info, storage_call_info], ..Default::default() }; @@ -209,7 +209,10 @@ fn test_call_contract() { ..trivial_external_entry_point() }, execution: expected_execution.clone(), - vm_resources: VmExecutionResources { n_steps: 42, ..Default::default() }, + vm_resources: VmExecutionResourcesWrapper(VmExecutionResources { + n_steps: 42, + ..Default::default() + }), storage_read_values: vec![StarkFelt::ZERO, stark_felt!(value)], accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]), ..Default::default() @@ -225,11 +228,11 @@ fn test_call_contract() { ..trivial_external_entry_point() }, execution: expected_execution, - vm_resources: VmExecutionResources { + vm_resources: VmExecutionResourcesWrapper(VmExecutionResources { n_steps: 81, builtin_instance_counter: HashMap::from([(RANGE_CHECK_BUILTIN_NAME.to_string(), 1)]), ..Default::default() - }, + }), ..Default::default() }; diff --git a/crates/blockifier/src/execution/entry_point.rs b/crates/blockifier/src/execution/entry_point.rs index 787d6da2f1..de0a915b4a 100644 --- a/crates/blockifier/src/execution/entry_point.rs +++ b/crates/blockifier/src/execution/entry_point.rs @@ -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; @@ -35,14 +36,14 @@ pub const FAULTY_CLASS_HASH: &str = pub type EntryPointExecutionResult = Result; /// 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, @@ -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; diff --git a/crates/blockifier/src/execution/entry_point_execution.rs b/crates/blockifier/src/execution/entry_point_execution.rs index b3f4d15349..d285e84dd5 100644 --- a/crates/blockifier/src/execution/entry_point_execution.rs +++ b/crates/blockifier/src/execution/entry_point_execution.rs @@ -11,7 +11,7 @@ use num_traits::ToPrimitive; use starknet_api::hash::StarkFelt; use starknet_api::stark_felt; -use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; +use crate::execution::call_info::{CallExecution, CallInfo, Retdata, VmExecutionResourcesWrapper}; use crate::execution::contract_class::{ContractClassV1, EntryPointV1}; use crate::execution::entry_point::{ CallEntryPoint, EntryPointExecutionContext, EntryPointExecutionResult, ExecutionResources, @@ -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: VmExecutionResourcesWrapper(full_call_vm_resources.filter_unused_builtins()), inner_calls: syscall_handler.inner_calls, storage_read_values: syscall_handler.read_values, accessed_storage_keys: syscall_handler.accessed_keys, diff --git a/crates/blockifier/src/execution/entry_point_test.rs b/crates/blockifier/src/execution/entry_point_test.rs index c1c8d16611..de7ed570eb 100644 --- a/crates/blockifier/src/execution/entry_point_test.rs +++ b/crates/blockifier/src/execution/entry_point_test.rs @@ -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()) ); diff --git a/crates/blockifier/src/execution/syscalls/syscalls_test.rs b/crates/blockifier/src/execution/syscalls/syscalls_test.rs index 9ae38ac513..b3c87da6f0 100644 --- a/crates/blockifier/src/execution/syscalls/syscalls_test.rs +++ b/crates/blockifier/src/execution/syscalls/syscalls_test.rs @@ -27,6 +27,7 @@ use crate::abi::constants; use crate::block_context::BlockContext; use crate::execution::call_info::{ CallExecution, CallInfo, MessageToL1, OrderedEvent, OrderedL2ToL1Message, Retdata, + VmExecutionResourcesWrapper, }; use crate::execution::common_hints::ExecutionMode; use crate::execution::contract_class::ContractClassV0; @@ -554,7 +555,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: VmExecutionResourcesWrapper(storage_entry_point_vm_resources.clone()), storage_read_values: vec![stark_felt!(value + 1)], accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key + 1))]), ..Default::default() @@ -571,7 +572,7 @@ fn test_nested_library_call() { gas_consumed: REQUIRED_GAS_LIBRARY_CALL_TEST, ..CallExecution::default() }, - vm_resources: library_call_vm_resources, + vm_resources: VmExecutionResourcesWrapper(library_call_vm_resources), inner_calls: vec![nested_storage_call_info], ..Default::default() }; @@ -582,7 +583,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: VmExecutionResourcesWrapper(storage_entry_point_vm_resources), storage_read_values: vec![stark_felt!(value)], accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]), ..Default::default() @@ -600,7 +601,7 @@ fn test_nested_library_call() { gas_consumed: 316180, ..CallExecution::default() }, - vm_resources: main_call_vm_resources, + vm_resources: VmExecutionResourcesWrapper(main_call_vm_resources), inner_calls: vec![library_call_info, storage_call_info], ..Default::default() }; diff --git a/crates/blockifier/src/test_utils/prices.rs b/crates/blockifier/src/test_utils/prices.rs index 461c9b48d5..5a7a4e175d 100644 --- a/crates/blockifier/src/test_utils/prices.rs +++ b/crates/blockifier/src/test_utils/prices.rs @@ -81,4 +81,5 @@ fn fee_transfer_resources( ) .unwrap() .vm_resources + .0 } diff --git a/crates/blockifier/src/transaction/objects.rs b/crates/blockifier/src/transaction/objects.rs index f7cd52b1ae..1032c4cf82 100644 --- a/crates/blockifier/src/transaction/objects.rs +++ b/crates/blockifier/src/transaction/objects.rs @@ -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::{ @@ -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, @@ -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); impl ResourcesMapping { diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index e087c8427d..971be07d8f 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -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}; @@ -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: VmExecutionResourcesWrapper(vm_resources), execution: CallExecution { retdata, gas_consumed, ..Default::default() }, ..Default::default() }) @@ -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![ @@ -381,15 +384,15 @@ fn test_invoke_tx( gas_consumed: expected_arguments.execute_gas_consumed, ..Default::default() }, - vm_resources: expected_arguments.vm_resources, + vm_resources: VmExecutionResourcesWrapper(expected_arguments.vm_resources), inner_calls: vec![CallInfo { call: expected_return_result_call, execution: CallExecution::from_retdata(expected_return_result_retdata), - vm_resources: VmExecutionResources { + vm_resources: VmExecutionResourcesWrapper(VmExecutionResources { n_steps: 23, n_memory_holes: 0, ..Default::default() - }, + }), ..Default::default() }], ..Default::default() @@ -1622,11 +1625,11 @@ fn test_l1_handler() { gas_consumed: 19650, ..Default::default() }, - vm_resources: VmExecutionResources { + vm_resources: VmExecutionResourcesWrapper(VmExecutionResources { n_steps: 143, n_memory_holes: 1, builtin_instance_counter: HashMap::from([(RANGE_CHECK_BUILTIN_NAME.to_string(), 5)]), - }, + }), accessed_storage_keys: HashSet::from_iter(vec![accessed_storage_key]), ..Default::default() }; diff --git a/crates/native_blockifier/src/py_transaction_execution_info.rs b/crates/native_blockifier/src/py_transaction_execution_info.rs index 1a2cb1ab6b..2e384f5d6e 100644 --- a/crates/native_blockifier/src/py_transaction_execution_info.rs +++ b/crates/native_blockifier/src/py_transaction_execution_info.rs @@ -101,7 +101,7 @@ impl From 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),