diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 6e46f8e08a..ea344c313f 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -1,11 +1,14 @@ use std::collections::HashMap; use std::sync::Arc; -use blockifier::block::{BlockInfo, GasPrices}; +use blockifier::block::{pre_process_block, BlockInfo, BlockNumberHashPair, GasPrices}; use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses}; use blockifier::state::cached_state::{GlobalContractCache, GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST}; +use blockifier::transaction::objects::TransactionExecutionInfo; +use blockifier::transaction::transaction_execution::Transaction; use blockifier::versioned_constants::VersionedConstants; use pyo3::prelude::*; +use serde::Serialize; use starknet_api::block::{BlockNumber, BlockTimestamp}; use starknet_api::core::{ChainId, ContractAddress}; use starknet_api::hash::StarkFelt; @@ -15,6 +18,7 @@ use crate::errors::{ NativeBlockifierResult, }; use crate::py_state_diff::{PyBlockInfo, PyStateDiff}; +use crate::py_transaction::py_tx; 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; @@ -25,6 +29,14 @@ use crate::transaction_executor::{RawTransactionExecutionInfo, TransactionExecut #[path = "py_block_executor_test.rs"] mod py_block_executor_test; +#[pyclass] +#[derive(Debug, Serialize)] +pub(crate) struct TypedTransactionExecutionInfo { + #[serde(flatten)] + pub info: TransactionExecutionInfo, + pub tx_type: String, +} + #[pyclass] pub struct PyBlockExecutor { pub general_config: PyGeneralConfig, @@ -95,14 +107,28 @@ impl PyBlockExecutor { raw_contract_class: Option<&str>, ) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> { let charge_fee = true; - self.tx_executor().execute(tx, raw_contract_class, charge_fee) + let tx_type: &str = tx.getattr("tx_type")?.getattr("name")?.extract()?; + let tx: Transaction = py_tx(tx, raw_contract_class)?; + let (tx_execution_info, py_bouncer_info) = self.tx_executor().execute(tx, charge_fee)?; + 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)) } /// Returns the state diff and a list of contract class hash with the corresponding list of /// visited PC values. pub fn finalize(&mut self, is_pending_block: bool) -> (PyStateDiff, Vec<(PyFelt, Vec)>) { log::debug!("Finalizing execution..."); - let finalized_state = self.tx_executor().finalize(is_pending_block); + let (commitment_state_diff, visited_pcs) = self.tx_executor().finalize(is_pending_block); + let visited_pcs = visited_pcs + .into_iter() + .map(|(class_hash, class_visited_pcs_vec)| { + (PyFelt::from(class_hash), class_visited_pcs_vec) + }) + .collect(); + let finalized_state = (PyStateDiff::from(commitment_state_diff), visited_pcs); log::debug!("Finalized execution."); finalized_state @@ -113,7 +139,12 @@ impl PyBlockExecutor { &mut self, old_block_number_and_hash: Option<(u64, PyFelt)>, ) -> NativeBlockifierResult<()> { - self.tx_executor().pre_process_block(old_block_number_and_hash) + let old_block_number_and_hash = old_block_number_and_hash + .map(|(block_number, block_hash)| BlockNumberHashPair::new(block_number, block_hash.0)); + let state = &mut self.tx_executor().state; + pre_process_block(state, old_block_number_and_hash)?; + + Ok(()) } pub fn commit_tx(&mut self) { diff --git a/crates/native_blockifier/src/py_validator.rs b/crates/native_blockifier/src/py_validator.rs index 8b8fd234a3..b5a617e71d 100644 --- a/crates/native_blockifier/src/py_validator.rs +++ b/crates/native_blockifier/src/py_validator.rs @@ -5,7 +5,9 @@ use blockifier::fee::fee_checks::PostValidationReport; use blockifier::state::cached_state::{GlobalContractCache, GLOBAL_CONTRACT_CACHE_SIZE_FOR_TEST}; use blockifier::state::state_api::StateReader; use blockifier::transaction::account_transaction::AccountTransaction; -use blockifier::transaction::objects::{TransactionExecutionResult, TransactionInfo}; +use blockifier::transaction::objects::{ + TransactionExecutionInfo, TransactionExecutionResult, TransactionInfo, +}; use blockifier::transaction::transaction_execution::Transaction; use blockifier::versioned_constants::VersionedConstants; use pyo3::prelude::*; @@ -15,11 +17,11 @@ use starknet_api::hash::StarkFelt; 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::{py_account_tx, py_tx}; 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::{RawTransactionExecutionInfo, TransactionExecutor}; +use crate::transaction_executor::TransactionExecutor; /// Manages transaction validation for pre-execution flows. #[pyclass] @@ -74,8 +76,7 @@ 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 (_raw_tx_execution_info, _py_bouncer_info) = - self.execute(tx, raw_contract_class)?; + let (_tx_execution_info, _py_bouncer_info) = self.execute(tx, raw_contract_class)?; // TODO(Ayelet, 09/11/2023): Check call succeeded. return Ok(()); @@ -122,20 +123,22 @@ impl PyValidator { )?; Ok(Self { max_nonce_for_validation_skip: Nonce(StarkFelt::ONE), tx_executor }) } +} +impl PyValidator { /// Applicable solely to account deployment transactions: the execution of the constructor /// is required before they can be validated. fn execute( &mut self, tx: &PyAny, raw_contract_class: Option<&str>, - ) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> { + ) -> NativeBlockifierResult<(TransactionExecutionInfo, PyBouncerInfo)> { let limit_execution_steps_by_resource_bounds = true; - self.tx_executor.execute(tx, raw_contract_class, limit_execution_steps_by_resource_bounds) + let tx: Transaction = py_tx(tx, raw_contract_class)?; + + self.tx_executor.execute(tx, limit_execution_steps_by_resource_bounds) } -} -impl PyValidator { fn perform_pre_validation_stage( &mut self, account_tx: &AccountTransaction, diff --git a/crates/native_blockifier/src/transaction_executor.rs b/crates/native_blockifier/src/transaction_executor.rs index 2b1a03a84c..33f3b39baa 100644 --- a/crates/native_blockifier/src/transaction_executor.rs +++ b/crates/native_blockifier/src/transaction_executor.rs @@ -2,13 +2,13 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; use std::vec::IntoIter; -use blockifier::block::{pre_process_block, BlockNumberHashPair}; use blockifier::context::BlockContext; use blockifier::execution::call_info::{CallInfo, MessageL1CostInfo}; use blockifier::execution::entry_point::ExecutionResources; use blockifier::fee::actual_cost::ActualCost; use blockifier::state::cached_state::{ - CachedState, GlobalContractCache, StagedTransactionalState, StorageEntry, TransactionalState, + CachedState, CommitmentStateDiff, GlobalContractCache, StagedTransactionalState, StorageEntry, + TransactionalState, }; use blockifier::state::state_api::{State, StateReader}; use blockifier::transaction::account_transaction::AccountTransaction; @@ -19,27 +19,15 @@ use blockifier::transaction::transactions::{ExecutableTransaction, ValidatableTr 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_state_diff::PyBlockInfo; use crate::py_transaction_execution_info::PyBouncerInfo; -use crate::py_utils::PyFelt; pub(crate) type RawTransactionExecutionInfo = Vec; -#[pyclass] -#[derive(Debug, Serialize)] -pub(crate) struct TypedTransactionExecutionInfo { - #[serde(flatten)] - info: TransactionExecutionInfo, - tx_type: String, -} - // TODO(Gilad): make this hold TransactionContext instead of BlockContext. pub struct TransactionExecutor { pub block_context: BlockContext, @@ -83,12 +71,9 @@ impl TransactionExecutor { /// (used for counting purposes). pub fn execute( &mut self, - tx: &PyAny, - raw_contract_class: Option<&str>, + tx: Transaction, charge_fee: bool, - ) -> NativeBlockifierResult<(RawTransactionExecutionInfo, PyBouncerInfo)> { - let tx_type: &str = tx.getattr("tx_type")?.getattr("name")?.extract()?; - let tx: Transaction = py_tx(tx, raw_contract_class)?; + ) -> NativeBlockifierResult<(TransactionExecutionInfo, PyBouncerInfo)> { let l1_handler_payload_size: usize = if let Transaction::L1HandlerTransaction(l1_handler_tx) = &tx { l1_handler_tx.payload_size() @@ -146,14 +131,7 @@ impl TransactionExecutor { 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)) + Ok((tx_execution_info, py_bouncer_info)) } Err(error) => { transactional_state.abort(); @@ -197,7 +175,10 @@ impl TransactionExecutor { /// Returns the state diff and a list of contract class hash with the corresponding list of /// visited PC values. - pub fn finalize(&mut self, is_pending_block: bool) -> (PyStateDiff, Vec<(PyFelt, Vec)>) { + pub fn finalize( + &mut self, + is_pending_block: bool, + ) -> (CommitmentStateDiff, Vec<(ClassHash, Vec)>) { // Do not cache classes that were declared during a pending block. // They will be redeclared, and should not be cached since the content of this block is // transient. @@ -213,24 +194,11 @@ impl TransactionExecutor { .map(|(class_hash, class_visited_pcs)| { let mut class_visited_pcs_vec: Vec<_> = class_visited_pcs.iter().cloned().collect(); class_visited_pcs_vec.sort(); - (PyFelt::from(*class_hash), class_visited_pcs_vec) + (*class_hash, class_visited_pcs_vec) }) .collect(); - (PyStateDiff::from(self.state.to_state_diff()), visited_pcs) - } - - // Block pre-processing; see `block::pre_process_block` documentation. - pub fn pre_process_block( - &mut self, - old_block_number_and_hash: Option<(u64, PyFelt)>, - ) -> NativeBlockifierResult<()> { - let old_block_number_and_hash = old_block_number_and_hash - .map(|(block_number, block_hash)| BlockNumberHashPair::new(block_number, block_hash.0)); - - pre_process_block(&mut self.state, old_block_number_and_hash)?; - - Ok(()) + (self.state.to_state_diff(), visited_pcs) } pub fn commit(&mut self) {