diff --git a/crates/blockifier/src/transaction/errors.rs b/crates/blockifier/src/transaction/errors.rs index dbb0c7f0d9..1058c0867b 100644 --- a/crates/blockifier/src/transaction/errors.rs +++ b/crates/blockifier/src/transaction/errors.rs @@ -69,8 +69,6 @@ pub enum TransactionExecutionError { {max_order}." )] InvalidOrder { object: String, order: usize, max_order: usize }, - #[error("Invalid Transaction Execution Info. Field {field} was not found.")] - InvalidTransactionExecutionInfo { field: String }, #[error("The `validate` entry point should return `VALID`. Got {actual:?}.")] InvalidValidateReturnData { actual: Retdata }, #[error( diff --git a/crates/blockifier/src/transaction/transaction_utils.rs b/crates/blockifier/src/transaction/transaction_utils.rs index ed6c8bae51..2eac3dfed4 100644 --- a/crates/blockifier/src/transaction/transaction_utils.rs +++ b/crates/blockifier/src/transaction/transaction_utils.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use cairo_vm::vm::runners::builtin_runner::SEGMENT_ARENA_BUILTIN_NAME; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources; use starknet_api::transaction::TransactionVersion; use super::objects::GasVector; @@ -13,7 +12,7 @@ use crate::fee::os_usage::get_additional_os_resources; use crate::transaction::errors::TransactionExecutionError; use crate::transaction::objects::{ResourcesMapping, TransactionExecutionResult}; use crate::transaction::transaction_types::TransactionType; -use crate::utils::{merge_hashmaps, usize_from_u128}; +use crate::utils::usize_from_u128; /// Calculates the total resources needed to include the transaction in a Starknet block as /// most-recent (recent w.r.t. application on the given state). @@ -86,39 +85,3 @@ pub fn verify_contract_class_version( } } } - -// TODO(Ayelet, 01/02/2024): Move to VmExecutionResourcesWrapper when merged. -pub fn vm_execution_resources_to_hash_map( - execution_resources: VmExecutionResources, -) -> HashMap { - let mut result = execution_resources.builtin_instance_counter.clone(); - result.insert( - String::from("n_steps"), - execution_resources.n_steps + execution_resources.n_memory_holes, - ); - result -} - -type ResourcesMap = HashMap; - -// TODO(Arni, 24/01/2024): Add state_diff_size to tx_weights -pub fn calculate_tx_weights( - additional_os_resources: VmExecutionResources, - actual_resources: ResourcesMap, - message_segment_length: usize, -) -> Result { - let mut tx_weights: HashMap = HashMap::new(); - let mut cairo_resource_usage: HashMap = actual_resources; - let value = cairo_resource_usage.remove("l1_gas_usage").ok_or( - TransactionExecutionError::InvalidTransactionExecutionInfo { - field: "l1_gas_usage".to_string(), - }, - )?; - tx_weights.insert("gas_weight".to_string(), value); - let os_cairo_usage: HashMap = - vm_execution_resources_to_hash_map(additional_os_resources); - let cairo_usage = merge_hashmaps(&cairo_resource_usage, &os_cairo_usage); - tx_weights.extend(cairo_usage); - tx_weights.insert("message_segment_length".to_string(), message_segment_length); - Ok(tx_weights) -} diff --git a/crates/blockifier/src/utils.rs b/crates/blockifier/src/utils.rs index 42b856e223..c6c513ea77 100644 --- a/crates/blockifier/src/utils.rs +++ b/crates/blockifier/src/utils.rs @@ -1,6 +1,4 @@ use std::collections::HashMap; -use std::hash::Hash; -use std::ops::{Add, AddAssign}; use crate::transaction::errors::NumericConversionError; @@ -24,21 +22,6 @@ pub const fn const_max(a: u128, b: u128) -> u128 { [a, b][(a < b) as usize] } -pub fn merge_hashmaps(x: &HashMap, y: &HashMap) -> HashMap -where - K: Hash + Eq + Clone, - V: Add + AddAssign + Default + Clone, -{ - let mut result = x.clone(); - for (key, value) in y { - result - .entry(key.clone()) - .and_modify(|v| v.add_assign(value.clone())) - .or_insert(value.clone()); - } - result -} - /// Conversion from usize to u128. Currently, usize has 64 bits, so this conversion should never /// fail. pub fn usize_from_u128(val: u128) -> Result { diff --git a/crates/native_blockifier/src/py_transaction_execution_info.rs b/crates/native_blockifier/src/py_transaction_execution_info.rs index 5146941b5f..3162b79c32 100644 --- a/crates/native_blockifier/src/py_transaction_execution_info.rs +++ b/crates/native_blockifier/src/py_transaction_execution_info.rs @@ -1,8 +1,12 @@ use std::collections::{HashMap, HashSet}; +use blockifier::abi::constants; use blockifier::execution::call_info::{CallInfo, OrderedEvent, OrderedL2ToL1Message}; use blockifier::execution::entry_point::CallType; -use blockifier::transaction::objects::TransactionExecutionInfo; +use blockifier::transaction::objects::{ + ResourcesMapping, TransactionExecutionInfo, TransactionExecutionResult, +}; +use cairo_vm::serde::deserialize_program::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources as VmExecutionResources; use pyo3::prelude::*; use starknet_api::deprecated_contract_class::EntryPointType; @@ -217,14 +221,73 @@ impl From for PyVmExecutionResources { #[pyclass] #[derive(Clone, Default)] -// TODO(Ayelet, 24/01/2024): Consider remove message_segment_length, state_diff_size. pub struct PyBouncerInfo { #[pyo3(get)] - // The number of felts needed to store L1<>L2 messages. - pub message_segment_length: usize, + pub state_diff_size: usize, // The number of felts needed to store the state diff. #[pyo3(get)] - // The number of felts needed to store the state diff. - pub state_diff_size: usize, + pub l1_gas_amount: usize, #[pyo3(get)] - pub tx_weights: HashMap, + pub message_segment_length: usize, // The number of felts needed to store L1<>L2 messages. + #[pyo3(get)] + pub execution_resources: PyVmExecutionResources, +} + +impl PyBouncerInfo { + pub fn calculate( + tx_actual_resources: &ResourcesMapping, + tx_additional_os_resources: VmExecutionResources, + message_segment_length: usize, + state_diff_size: usize, + ) -> TransactionExecutionResult { + let l1_gas_amount = *tx_actual_resources + .0 + .get("l1_gas_usage") + .expect("Invalid Transaction Execution Info. Field l1_gas_usage was not found."); + + // TODO(Ayelet, 04/02/2024): Consider defining a constant list. + let builtin_ordered_list = [ + BuiltinName::output, + BuiltinName::pedersen, + BuiltinName::range_check, + BuiltinName::ecdsa, + BuiltinName::bitwise, + BuiltinName::ec_op, + BuiltinName::keccak, + BuiltinName::poseidon, + ]; + let builtin_instance_counter: HashMap = builtin_ordered_list + .iter() + .map(|name| { + ( + name.name().to_string(), + tx_actual_resources.0.get(name.name()).copied().unwrap_or_default(), + ) + }) + .collect(); + let tx_actual_resources = VmExecutionResources { + n_steps: tx_actual_resources + .0 + .get(constants::N_STEPS_RESOURCE) + .copied() + .unwrap_or_default(), + n_memory_holes: tx_actual_resources + .0 + .get("n_memory_holes") + .copied() + .unwrap_or_default(), + builtin_instance_counter, + }; + + let mut merged_resources = &tx_additional_os_resources + &tx_actual_resources; + // Memory holes are counted as steps. + merged_resources.n_steps += merged_resources.n_memory_holes; + merged_resources.n_memory_holes = 0; + + Ok(Self { + state_diff_size, + l1_gas_amount, + message_segment_length, + execution_resources: PyVmExecutionResources::from(merged_resources), + }) + } } diff --git a/crates/native_blockifier/src/transaction_executor.rs b/crates/native_blockifier/src/transaction_executor.rs index 2b1a03a84c..a80530e74d 100644 --- a/crates/native_blockifier/src/transaction_executor.rs +++ b/crates/native_blockifier/src/transaction_executor.rs @@ -14,7 +14,6 @@ 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; @@ -135,24 +134,22 @@ impl TransactionExecutor { 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, + let typed_tx_execution_info = TypedTransactionExecutionInfo { + info: tx_execution_info, + tx_type: tx_type.to_string(), + }; + let actual_resources = &typed_tx_execution_info.info.actual_resources; + let py_bouncer_info = PyBouncerInfo::calculate( actual_resources, + additional_os_resources, message_segment_length, + state_diff_size, )?; - let py_bouncer_info = - PyBouncerInfo { message_segment_length, state_diff_size, tx_weights }; + self.staged_for_commit_state = Some( transactional_state.stage(tx_executed_class_hashes, tx_visited_storage_entries), ); - - 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)?; - Ok((raw_tx_execution_info, py_bouncer_info)) } Err(error) => {