From 6b9cadca320eb3234dc5e9aed09a4e690681c2b7 Mon Sep 17 00:00:00 2001 From: Barak Date: Thu, 1 Feb 2024 11:48:49 +0200 Subject: [PATCH 1/3] refactor(execution, native_blockifier): make TransactionExecutor.execute() work w/o Py objects --- .../src/py_block_executor.rs | 21 ++++++++++++++- crates/native_blockifier/src/py_validator.rs | 21 ++++++++------- .../src/transaction_executor.rs | 27 +++---------------- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 6e46f8e08a..2ac14ec0c6 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -4,8 +4,11 @@ use std::sync::Arc; use blockifier::block::{BlockInfo, 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,7 +107,14 @@ 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 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..8f6a098c82 100644 --- a/crates/native_blockifier/src/transaction_executor.rs +++ b/crates/native_blockifier/src/transaction_executor.rs @@ -19,27 +19,16 @@ 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_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 +72,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 +132,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(); From 1ba07339519c4482a0bf5da076c80539f3980baa Mon Sep 17 00:00:00 2001 From: Barak Date: Thu, 1 Feb 2024 20:26:01 +0200 Subject: [PATCH 2/3] refactor(execution, native_blockifier): make TransactionExecutor.finalize() work without Py objects --- crates/native_blockifier/src/py_block_executor.rs | 9 ++++++++- .../native_blockifier/src/transaction_executor.rs | 14 +++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 2ac14ec0c6..a21c01adf1 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -121,7 +121,14 @@ impl PyBlockExecutor { /// 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 diff --git a/crates/native_blockifier/src/transaction_executor.rs b/crates/native_blockifier/src/transaction_executor.rs index 8f6a098c82..06043a6a2c 100644 --- a/crates/native_blockifier/src/transaction_executor.rs +++ b/crates/native_blockifier/src/transaction_executor.rs @@ -8,7 +8,8 @@ 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; @@ -23,7 +24,7 @@ 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_state_diff::PyBlockInfo; use crate::py_transaction_execution_info::PyBouncerInfo; use crate::py_utils::PyFelt; @@ -176,7 +177,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. @@ -192,11 +196,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) + (self.state.to_state_diff(), visited_pcs) } // Block pre-processing; see `block::pre_process_block` documentation. From d8abfd0b33d26da005d4ddf15635849055c16ae4 Mon Sep 17 00:00:00 2001 From: Barak Date: Sun, 4 Feb 2024 11:12:51 +0200 Subject: [PATCH 3/3] refactor(execution, native_blockifier): move pre_process_block to PyBlockExecutor --- crates/native_blockifier/src/py_block_executor.rs | 9 +++++++-- .../native_blockifier/src/transaction_executor.rs | 15 --------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index a21c01adf1..ea344c313f 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -1,7 +1,7 @@ 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; @@ -139,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/transaction_executor.rs b/crates/native_blockifier/src/transaction_executor.rs index 06043a6a2c..33f3b39baa 100644 --- a/crates/native_blockifier/src/transaction_executor.rs +++ b/crates/native_blockifier/src/transaction_executor.rs @@ -2,7 +2,6 @@ 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; @@ -26,7 +25,6 @@ use crate::errors::{NativeBlockifierError, NativeBlockifierResult}; use crate::py_block_executor::{into_block_context, PyGeneralConfig}; use crate::py_state_diff::PyBlockInfo; use crate::py_transaction_execution_info::PyBouncerInfo; -use crate::py_utils::PyFelt; pub(crate) type RawTransactionExecutionInfo = Vec; @@ -203,19 +201,6 @@ impl TransactionExecutor { (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(()) - } - pub fn commit(&mut self) { let Some(finalized_transactional_state) = self.staged_for_commit_state.take() else { panic!("commit called without a transactional state")