diff --git a/crates/blockifier/src/blockifier/stateful_validator.rs b/crates/blockifier/src/blockifier/stateful_validator.rs index bb89e3d5fc..740bfbfd25 100644 --- a/crates/blockifier/src/blockifier/stateful_validator.rs +++ b/crates/blockifier/src/blockifier/stateful_validator.rs @@ -17,8 +17,7 @@ use crate::state::errors::StateError; use crate::state::state_api::StateReader; use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::errors::{TransactionExecutionError, TransactionPreValidationError}; -use crate::transaction::transaction_execution::Transaction; -use crate::transaction::transactions::ValidatableTransaction; +use crate::transaction::transactions::{Transaction, ValidatableTransaction}; #[cfg(test)] #[path = "stateful_validator_test.rs"] diff --git a/crates/blockifier/src/blockifier/transaction_executor.rs b/crates/blockifier/src/blockifier/transaction_executor.rs index 2d7bfa857d..5b52f4c054 100644 --- a/crates/blockifier/src/blockifier/transaction_executor.rs +++ b/crates/blockifier/src/blockifier/transaction_executor.rs @@ -22,8 +22,7 @@ use crate::state::errors::StateError; use crate::state::state_api::StateReader; use crate::transaction::errors::TransactionExecutionError; use crate::transaction::objects::TransactionExecutionInfo; -use crate::transaction::transaction_execution::Transaction; -use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags}; +use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags, Transaction}; #[cfg(test)] #[path = "transaction_executor_test.rs"] diff --git a/crates/blockifier/src/blockifier/transaction_executor_test.rs b/crates/blockifier/src/blockifier/transaction_executor_test.rs index b0139de8ba..75043e87ea 100644 --- a/crates/blockifier/src/blockifier/transaction_executor_test.rs +++ b/crates/blockifier/src/blockifier/transaction_executor_test.rs @@ -26,8 +26,7 @@ use crate::transaction::test_utils::{ account_invoke_tx, block_context, calculate_class_info_for_testing, create_test_init_data, emit_n_events_tx, l1_resource_bounds, TestInitData, }; -use crate::transaction::transaction_execution::Transaction; -use crate::transaction::transactions::L1HandlerTransaction; +use crate::transaction::transactions::{L1HandlerTransaction, Transaction}; use crate::{declare_tx_args, deploy_account_tx_args, invoke_tx_args, nonce}; fn tx_executor_test_body( diff --git a/crates/blockifier/src/concurrency/worker_logic.rs b/crates/blockifier/src/concurrency/worker_logic.rs index 60d5b19e71..937e5e292a 100644 --- a/crates/blockifier/src/concurrency/worker_logic.rs +++ b/crates/blockifier/src/concurrency/worker_logic.rs @@ -20,8 +20,7 @@ use crate::state::cached_state::{ }; use crate::state::state_api::{StateReader, UpdatableState}; use crate::transaction::objects::{TransactionExecutionInfo, TransactionExecutionResult}; -use crate::transaction::transaction_execution::Transaction; -use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags}; +use crate::transaction::transactions::{ExecutableTransaction, ExecutionFlags, Transaction}; #[cfg(test)] #[path = "worker_logic_test.rs"] diff --git a/crates/blockifier/src/concurrency/worker_logic_test.rs b/crates/blockifier/src/concurrency/worker_logic_test.rs index 1f28b1ee4f..b0ef818a02 100644 --- a/crates/blockifier/src/concurrency/worker_logic_test.rs +++ b/crates/blockifier/src/concurrency/worker_logic_test.rs @@ -36,7 +36,7 @@ use crate::transaction::test_utils::{ account_invoke_tx, calculate_class_info_for_testing, emit_n_events_tx, max_fee, max_resource_bounds, }; -use crate::transaction::transaction_execution::Transaction; +use crate::transaction::transactions::Transaction; use crate::{declare_tx_args, invoke_tx_args, nonce, storage_key}; fn trivial_calldata_invoke_tx( diff --git a/crates/blockifier/src/test_utils/transfers_generator.rs b/crates/blockifier/src/test_utils/transfers_generator.rs index 3d3a6a911d..6c5b8a1838 100644 --- a/crates/blockifier/src/test_utils/transfers_generator.rs +++ b/crates/blockifier/src/test_utils/transfers_generator.rs @@ -17,7 +17,7 @@ use crate::test_utils::invoke::invoke_tx; use crate::test_utils::{CairoVersion, NonceManager, BALANCE, MAX_FEE}; use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::constants::TRANSFER_ENTRY_POINT_NAME; -use crate::transaction::transaction_execution::Transaction; +use crate::transaction::transactions::Transaction; const N_ACCOUNTS: u16 = 10000; const N_TXS: usize = 1000; diff --git a/crates/blockifier/src/transaction.rs b/crates/blockifier/src/transaction.rs index 78ee679cae..2a74aa1c8d 100644 --- a/crates/blockifier/src/transaction.rs +++ b/crates/blockifier/src/transaction.rs @@ -6,7 +6,6 @@ pub mod errors; pub mod objects; #[cfg(any(feature = "testing", test))] pub mod test_utils; -pub mod transaction_execution; pub mod transaction_types; pub mod transaction_utils; pub mod transactions; diff --git a/crates/blockifier/src/transaction/transaction_execution.rs b/crates/blockifier/src/transaction/transaction_execution.rs deleted file mode 100644 index e617ad1c5f..0000000000 --- a/crates/blockifier/src/transaction/transaction_execution.rs +++ /dev/null @@ -1,193 +0,0 @@ -use std::sync::Arc; - -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use starknet_api::core::{calculate_contract_address, ContractAddress}; -use starknet_api::transaction::{Fee, Transaction as StarknetApiTransaction, TransactionHash}; - -use crate::bouncer::verify_tx_weights_in_bounds; -use crate::context::BlockContext; -use crate::execution::contract_class::ClassInfo; -use crate::execution::entry_point::EntryPointExecutionContext; -use crate::fee::actual_cost::TransactionReceipt; -use crate::state::cached_state::TransactionalState; -use crate::state::state_api::UpdatableState; -use crate::transaction::account_transaction::AccountTransaction; -use crate::transaction::errors::TransactionFeeError; -use crate::transaction::objects::{ - TransactionExecutionInfo, TransactionExecutionResult, TransactionInfo, TransactionInfoCreator, -}; -use crate::transaction::transactions::{ - DeclareTransaction, DeployAccountTransaction, Executable, ExecutableTransaction, - ExecutionFlags, InvokeTransaction, L1HandlerTransaction, -}; - -// TODO: Move into transaction.rs, makes more sense to be defined there. -#[derive(Debug, derive_more::From)] -pub enum Transaction { - AccountTransaction(AccountTransaction), - L1HandlerTransaction(L1HandlerTransaction), -} - -impl Transaction { - pub fn from_api( - tx: StarknetApiTransaction, - tx_hash: TransactionHash, - class_info: Option, - paid_fee_on_l1: Option, - deployed_contract_address: Option, - only_query: bool, - ) -> TransactionExecutionResult { - match tx { - StarknetApiTransaction::L1Handler(l1_handler) => { - Ok(Self::L1HandlerTransaction(L1HandlerTransaction { - tx: l1_handler, - tx_hash, - paid_fee_on_l1: paid_fee_on_l1 - .expect("L1Handler should be created with the fee paid on L1"), - })) - } - StarknetApiTransaction::Declare(declare) => { - let non_optional_class_info = - class_info.expect("Declare should be created with a ClassInfo."); - let declare_tx = match only_query { - true => { - DeclareTransaction::new_for_query(declare, tx_hash, non_optional_class_info) - } - false => DeclareTransaction::new(declare, tx_hash, non_optional_class_info), - }; - Ok(Self::AccountTransaction(AccountTransaction::Declare(declare_tx?))) - } - StarknetApiTransaction::DeployAccount(deploy_account) => { - let contract_address = match deployed_contract_address { - Some(address) => address, - None => calculate_contract_address( - deploy_account.contract_address_salt(), - deploy_account.class_hash(), - &deploy_account.constructor_calldata(), - ContractAddress::default(), - )?, - }; - let deploy_account_tx = match only_query { - true => DeployAccountTransaction::new_for_query( - deploy_account, - tx_hash, - contract_address, - ), - false => { - DeployAccountTransaction::new(deploy_account, tx_hash, contract_address) - } - }; - Ok(Self::AccountTransaction(AccountTransaction::DeployAccount(deploy_account_tx))) - } - StarknetApiTransaction::Invoke(invoke) => { - let invoke_tx = match only_query { - true => InvokeTransaction::new_for_query(invoke, tx_hash), - false => InvokeTransaction::new(invoke, tx_hash), - }; - Ok(Self::AccountTransaction(AccountTransaction::Invoke(invoke_tx))) - } - _ => unimplemented!(), - } - } -} - -impl TransactionInfoCreator for Transaction { - fn create_tx_info(&self) -> TransactionInfo { - match self { - Self::AccountTransaction(account_tx) => account_tx.create_tx_info(), - Self::L1HandlerTransaction(l1_handler_tx) => l1_handler_tx.create_tx_info(), - } - } -} - -impl ExecutableTransaction for L1HandlerTransaction { - fn execute_raw( - &self, - state: &mut TransactionalState<'_, U>, - block_context: &BlockContext, - _execution_flags: ExecutionFlags, - ) -> TransactionExecutionResult { - let tx_context = Arc::new(block_context.to_tx_context(self)); - - let mut execution_resources = ExecutionResources::default(); - let mut context = EntryPointExecutionContext::new_invoke(tx_context.clone(), true)?; - let mut remaining_gas = block_context.versioned_constants.tx_initial_gas(); - let execute_call_info = - self.run_execute(state, &mut execution_resources, &mut context, &mut remaining_gas)?; - let l1_handler_payload_size = self.payload_size(); - - let TransactionReceipt { - fee: actual_fee, - da_gas, - resources: actual_resources, - gas: total_gas, - } = TransactionReceipt::from_l1_handler( - &tx_context, - l1_handler_payload_size, - execute_call_info.iter(), - &state.get_actual_state_changes()?, - &execution_resources, - )?; - - let paid_fee = self.paid_fee_on_l1; - // For now, assert only that any amount of fee was paid. - // The error message still indicates the required fee. - if paid_fee == Fee(0) { - return Err(TransactionFeeError::InsufficientL1Fee { paid_fee, actual_fee })?; - } - - Ok(TransactionExecutionInfo { - validate_call_info: None, - execute_call_info, - fee_transfer_call_info: None, - transaction_receipt: TransactionReceipt { - fee: Fee::default(), - da_gas, - resources: actual_resources, - gas: total_gas, - }, - revert_error: None, - }) - } -} - -impl ExecutableTransaction for Transaction { - fn execute_raw( - &self, - state: &mut TransactionalState<'_, U>, - block_context: &BlockContext, - execution_flags: ExecutionFlags, - ) -> TransactionExecutionResult { - // TODO(Yoni, 1/8/2024): consider unimplementing the ExecutableTransaction trait for inner - // types, since now running Transaction::execute_raw is not identical to - // AccountTransaction::execute_raw. - let concurrency_mode = execution_flags.concurrency_mode; - let tx_execution_info = match self { - Self::AccountTransaction(account_tx) => { - account_tx.execute_raw(state, block_context, execution_flags)? - } - Self::L1HandlerTransaction(tx) => { - tx.execute_raw(state, block_context, execution_flags)? - } - }; - - // Check if the transaction is too large to fit any block. - // TODO(Yoni, 1/8/2024): consider caching these two. - let tx_execution_summary = tx_execution_info.summarize(); - let mut tx_state_changes_keys = state.get_actual_state_changes()?.into_keys(); - tx_state_changes_keys.update_sequencer_key_in_storage( - &block_context.to_tx_context(self), - &tx_execution_info, - concurrency_mode, - ); - verify_tx_weights_in_bounds( - state, - &tx_execution_summary, - &tx_execution_info.transaction_receipt.resources, - &tx_state_changes_keys, - &block_context.bouncer_config, - )?; - - Ok(tx_execution_info) - } -} diff --git a/crates/blockifier/src/transaction/transactions.rs b/crates/blockifier/src/transaction/transactions.rs index 4e3188c150..2f7d4c4f96 100644 --- a/crates/blockifier/src/transaction/transactions.rs +++ b/crates/blockifier/src/transaction/transactions.rs @@ -2,15 +2,19 @@ use std::sync::Arc; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use starknet_api::calldata; -use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::core::{ + calculate_contract_address, ClassHash, CompiledClassHash, ContractAddress, Nonce, +}; use starknet_api::deprecated_contract_class::EntryPointType; use starknet_api::transaction::{ AccountDeploymentData, Calldata, ContractAddressSalt, DeclareTransactionV2, - DeclareTransactionV3, Fee, TransactionHash, TransactionSignature, TransactionVersion, + DeclareTransactionV3, Fee, Transaction as StarknetApiTransaction, TransactionHash, + TransactionSignature, TransactionVersion, }; use starknet_types_core::felt::Felt; use crate::abi::abi_utils::selector_from_name; +use crate::bouncer::verify_tx_weights_in_bounds; use crate::context::{BlockContext, TransactionContext}; use crate::execution::call_info::CallInfo; use crate::execution::contract_class::{ClassInfo, ContractClass}; @@ -18,11 +22,13 @@ use crate::execution::entry_point::{ CallEntryPoint, CallType, ConstructorContext, EntryPointExecutionContext, }; use crate::execution::execution_utils::execute_deployment; +use crate::fee::actual_cost::TransactionReceipt; use crate::state::cached_state::TransactionalState; use crate::state::errors::StateError; use crate::state::state_api::{State, UpdatableState}; +use crate::transaction::account_transaction::AccountTransaction; use crate::transaction::constants; -use crate::transaction::errors::TransactionExecutionError; +use crate::transaction::errors::{TransactionExecutionError, TransactionFeeError}; use crate::transaction::objects::{ CommonAccountFields, CurrentTransactionInfo, DeprecatedTransactionInfo, HasRelatedFeeType, TransactionExecutionInfo, TransactionExecutionResult, TransactionInfo, TransactionInfoCreator, @@ -47,7 +53,6 @@ pub struct ExecutionFlags { pub validate: bool, pub concurrency_mode: bool, } - pub trait ExecutableTransaction: Sized { /// Executes the transaction in a transactional manner /// (if it fails, given state does not modify). @@ -570,3 +575,173 @@ impl TransactionInfoCreator for L1HandlerTransaction { }) } } + +#[derive(Debug, derive_more::From)] +pub enum Transaction { + AccountTransaction(AccountTransaction), + L1HandlerTransaction(L1HandlerTransaction), +} + +impl Transaction { + pub fn from_api( + tx: StarknetApiTransaction, + tx_hash: TransactionHash, + class_info: Option, + paid_fee_on_l1: Option, + deployed_contract_address: Option, + only_query: bool, + ) -> TransactionExecutionResult { + match tx { + StarknetApiTransaction::L1Handler(l1_handler) => { + Ok(Self::L1HandlerTransaction(L1HandlerTransaction { + tx: l1_handler, + tx_hash, + paid_fee_on_l1: paid_fee_on_l1 + .expect("L1Handler should be created with the fee paid on L1"), + })) + } + StarknetApiTransaction::Declare(declare) => { + let non_optional_class_info = + class_info.expect("Declare should be created with a ClassInfo."); + let declare_tx = match only_query { + true => { + DeclareTransaction::new_for_query(declare, tx_hash, non_optional_class_info) + } + false => DeclareTransaction::new(declare, tx_hash, non_optional_class_info), + }; + Ok(Self::AccountTransaction(AccountTransaction::Declare(declare_tx?))) + } + StarknetApiTransaction::DeployAccount(deploy_account) => { + let contract_address = match deployed_contract_address { + Some(address) => address, + None => calculate_contract_address( + deploy_account.contract_address_salt(), + deploy_account.class_hash(), + &deploy_account.constructor_calldata(), + ContractAddress::default(), + )?, + }; + let deploy_account_tx = match only_query { + true => DeployAccountTransaction::new_for_query( + deploy_account, + tx_hash, + contract_address, + ), + false => { + DeployAccountTransaction::new(deploy_account, tx_hash, contract_address) + } + }; + Ok(Self::AccountTransaction(AccountTransaction::DeployAccount(deploy_account_tx))) + } + StarknetApiTransaction::Invoke(invoke) => { + let invoke_tx = match only_query { + true => InvokeTransaction::new_for_query(invoke, tx_hash), + false => InvokeTransaction::new(invoke, tx_hash), + }; + Ok(Self::AccountTransaction(AccountTransaction::Invoke(invoke_tx))) + } + _ => unimplemented!(), + } + } +} + +impl TransactionInfoCreator for Transaction { + fn create_tx_info(&self) -> TransactionInfo { + match self { + Self::AccountTransaction(account_tx) => account_tx.create_tx_info(), + Self::L1HandlerTransaction(l1_handler_tx) => l1_handler_tx.create_tx_info(), + } + } +} + +impl ExecutableTransaction for L1HandlerTransaction { + fn execute_raw( + &self, + state: &mut TransactionalState<'_, U>, + block_context: &BlockContext, + _execution_flags: ExecutionFlags, + ) -> TransactionExecutionResult { + let tx_context = Arc::new(block_context.to_tx_context(self)); + + let mut execution_resources = ExecutionResources::default(); + let mut context = EntryPointExecutionContext::new_invoke(tx_context.clone(), true)?; + let mut remaining_gas = block_context.versioned_constants.tx_initial_gas(); + let execute_call_info = + self.run_execute(state, &mut execution_resources, &mut context, &mut remaining_gas)?; + let l1_handler_payload_size = self.payload_size(); + + let TransactionReceipt { + fee: actual_fee, + da_gas, + resources: actual_resources, + gas: total_gas, + } = TransactionReceipt::from_l1_handler( + &tx_context, + l1_handler_payload_size, + execute_call_info.iter(), + &state.get_actual_state_changes()?, + &execution_resources, + )?; + + let paid_fee = self.paid_fee_on_l1; + // For now, assert only that any amount of fee was paid. + // The error message still indicates the required fee. + if paid_fee == Fee(0) { + return Err(TransactionFeeError::InsufficientL1Fee { paid_fee, actual_fee })?; + } + + Ok(TransactionExecutionInfo { + validate_call_info: None, + execute_call_info, + fee_transfer_call_info: None, + transaction_receipt: TransactionReceipt { + fee: Fee::default(), + da_gas, + resources: actual_resources, + gas: total_gas, + }, + revert_error: None, + }) + } +} + +impl ExecutableTransaction for Transaction { + fn execute_raw( + &self, + state: &mut TransactionalState<'_, U>, + block_context: &BlockContext, + execution_flags: ExecutionFlags, + ) -> TransactionExecutionResult { + // TODO(Yoni, 1/8/2024): consider unimplementing the ExecutableTransaction trait for inner + // types, since now running Transaction::execute_raw is not identical to + // AccountTransaction::execute_raw. + let concurrency_mode = execution_flags.concurrency_mode; + let tx_execution_info = match self { + Self::AccountTransaction(account_tx) => { + account_tx.execute_raw(state, block_context, execution_flags)? + } + Self::L1HandlerTransaction(tx) => { + tx.execute_raw(state, block_context, execution_flags)? + } + }; + + // Check if the transaction is too large to fit any block. + // TODO(Yoni, 1/8/2024): consider caching these two. + let tx_execution_summary = tx_execution_info.summarize(); + let mut tx_state_changes_keys = state.get_actual_state_changes()?.into_keys(); + tx_state_changes_keys.update_sequencer_key_in_storage( + &block_context.to_tx_context(self), + &tx_execution_info, + concurrency_mode, + ); + verify_tx_weights_in_bounds( + state, + &tx_execution_summary, + &tx_execution_info.transaction_receipt.resources, + &tx_state_changes_keys, + &block_context.bouncer_config, + )?; + + Ok(tx_execution_info) + } +} diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index bf3c244eba..8e2529a258 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -9,7 +9,7 @@ use blockifier::execution::call_info::CallInfo; use blockifier::state::cached_state::CachedState; use blockifier::state::global_cache::GlobalContractCache; use blockifier::transaction::objects::{GasVector, ResourcesMapping, TransactionExecutionInfo}; -use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::Transaction; use blockifier::versioned_constants::VersionedConstants; use pyo3::prelude::*; use pyo3::types::{PyBytes, PyList}; diff --git a/crates/native_blockifier/src/py_transaction.rs b/crates/native_blockifier/src/py_transaction.rs index e793cd5144..2cf9f78c7e 100644 --- a/crates/native_blockifier/src/py_transaction.rs +++ b/crates/native_blockifier/src/py_transaction.rs @@ -4,8 +4,8 @@ use blockifier::execution::contract_class::{ ClassInfo, ContractClass, ContractClassV0, ContractClassV1, }; use blockifier::transaction::account_transaction::AccountTransaction; -use blockifier::transaction::transaction_execution::Transaction; use blockifier::transaction::transaction_types::TransactionType; +use blockifier::transaction::transactions::Transaction; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use starknet_api::transaction::{Resource, ResourceBounds};