From 6dccfe0ddd13ddde8626fc777e311490e36b55a8 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Mon, 22 Jul 2024 11:57:41 -0400 Subject: [PATCH 1/2] remove sir executor implementation --- bin/katana/Cargo.toml | 12 +- bin/katana/src/main.rs | 15 - crates/katana/executor/Cargo.toml | 8 - .../katana/executor/src/implementation/mod.rs | 4 - .../executor/src/implementation/sir/error.rs | 43 -- .../executor/src/implementation/sir/mod.rs | 276 ------- .../executor/src/implementation/sir/state.rs | 583 -------------- .../executor/src/implementation/sir/utils.rs | 725 ------------------ 8 files changed, 4 insertions(+), 1662 deletions(-) delete mode 100644 crates/katana/executor/src/implementation/sir/error.rs delete mode 100644 crates/katana/executor/src/implementation/sir/mod.rs delete mode 100644 crates/katana/executor/src/implementation/sir/state.rs delete mode 100644 crates/katana/executor/src/implementation/sir/utils.rs diff --git a/bin/katana/Cargo.toml b/bin/katana/Cargo.toml index e6d20018b5..e83f732b4b 100644 --- a/bin/katana/Cargo.toml +++ b/bin/katana/Cargo.toml @@ -15,15 +15,15 @@ common.workspace = true console.workspace = true dojo-metrics.workspace = true katana-core.workspace = true -katana-executor.workspace = true +katana-executor = { workspace = true, features = [ "blockifier" ] } katana-primitives.workspace = true -katana-rpc-api.workspace = true katana-rpc.workspace = true +katana-rpc-api.workspace = true serde_json.workspace = true shellexpand = "3.1.0" tokio.workspace = true -tracing-subscriber.workspace = true tracing.workspace = true +tracing-subscriber.workspace = true url.workspace = true katana-slot-controller = { workspace = true, optional = true } @@ -32,11 +32,7 @@ katana-slot-controller = { workspace = true, optional = true } assert_matches.workspace = true [features] -default = [ "blockifier", "jemalloc", "messaging", "slot" ] - -blockifier = [ "katana-executor/blockifier" ] -# Disable until SIR support Cairo 2.6.3 -#sir = [ "katana-executor/sir" ] +default = [ "jemalloc", "messaging", "slot" ] jemalloc = [ "dojo-metrics/jemalloc" ] messaging = [ "katana-core/messaging" ] diff --git a/bin/katana/src/main.rs b/bin/katana/src/main.rs index 8aaccf3e44..f812234b6d 100644 --- a/bin/katana/src/main.rs +++ b/bin/katana/src/main.rs @@ -63,21 +63,6 @@ async fn main() -> Result<(), Box> { ..Default::default() }; - // TODO: Uncomment this once we enable the 'sir' feature again because it's not compatible with - // our current Cairo version (2.6.3). cfg_if::cfg_if! { - // if #[cfg(all(feature = "blockifier", feature = "sir"))] { - // compile_error!("Cannot enable both `blockifier` and `sir` features at the same - // time"); } else if #[cfg(feature = "blockifier")] { - // use katana_executor::implementation::blockifier::BlockifierFactory; - // let executor_factory = BlockifierFactory::new(cfg_env, simulation_flags); - // } else if #[cfg(feature = "sir")] { - // use katana_executor::implementation::sir::NativeExecutorFactory; - // let executor_factory = NativeExecutorFactory::new(cfg_env, simulation_flags); - // } else { - // compile_error!("At least one of the following features must be enabled: blockifier, - // sir"); } - // } - use katana_executor::implementation::blockifier::BlockifierFactory; let executor_factory = BlockifierFactory::new(cfg_env, simulation_flags); diff --git a/crates/katana/executor/Cargo.toml b/crates/katana/executor/Cargo.toml index 01f6063f1b..7134dc766c 100644 --- a/crates/katana/executor/Cargo.toml +++ b/crates/katana/executor/Cargo.toml @@ -18,12 +18,6 @@ tracing.workspace = true blockifier = { git = "https://github.com/dojoengine/blockifier", branch = "cairo-2.7", features = [ "testing" ], optional = true } katana-cairo = { workspace = true, optional = true } -# Disable SIR for now until they support Cairo 2.6.3 -# # starknet_in_rust deps -# cairo-lang-sierra = { workspace = true, optional = true } -# sir = { package = "starknet_in_rust", git = "https://github.com/dojoengine/starknet_in_rust.git", rev = "601a65e", optional = true } -# starknet-types-core = { version = "0.0.9", optional = true } - [dev-dependencies] alloy-primitives.workspace = true anyhow.workspace = true @@ -44,8 +38,6 @@ rayon.workspace = true [features] blockifier = [ "dep:blockifier", "dep:katana-cairo", "dep:starknet" ] default = [ "blockifier" ] -# native = [ "sir", "sir/cairo-native" ] -# sir = [ "dep:sir", "dep:starknet-types-core" ] [[bench]] harness = false diff --git a/crates/katana/executor/src/implementation/mod.rs b/crates/katana/executor/src/implementation/mod.rs index 48db83e370..c6ad15681a 100644 --- a/crates/katana/executor/src/implementation/mod.rs +++ b/crates/katana/executor/src/implementation/mod.rs @@ -1,7 +1,3 @@ #[cfg(feature = "blockifier")] pub mod blockifier; - -// #[cfg(feature = "sir")] -// pub mod sir; - pub mod noop; diff --git a/crates/katana/executor/src/implementation/sir/error.rs b/crates/katana/executor/src/implementation/sir/error.rs deleted file mode 100644 index 9808c04b8a..0000000000 --- a/crates/katana/executor/src/implementation/sir/error.rs +++ /dev/null @@ -1,43 +0,0 @@ -use katana_primitives::FieldElement; -use sir::transaction::error::TransactionError; - -use super::utils::{to_class_hash, to_felt}; -use crate::ExecutionError; - -impl From for ExecutionError { - fn from(error: TransactionError) -> Self { - match error { - TransactionError::ActualFeeExceedsMaxFee(actual_fee, max_fee) => { - Self::ActualFeeExceedsMaxFee { max_fee, actual_fee } - } - - TransactionError::ClassAlreadyDeclared(hash) => { - Self::ClassAlreadyDeclared(to_class_hash(&hash)) - } - - TransactionError::InvalidTransactionNonce(expected, actual) => { - let actual = FieldElement::from_dec_str(&actual).expect("must be valid"); - let expected = FieldElement::from_dec_str(&expected).expect("must be valid"); - Self::InvalidNonce { actual, expected } - } - - TransactionError::MaxFeeExceedsBalance(max_fee, low, high) => { - let balance_low = to_felt(&low); - let balance_high = to_felt(&high); - Self::InsufficientBalance { max_fee, balance_low, balance_high } - } - - TransactionError::NotDeployedContract(address) => { - let address = FieldElement::from_bytes_be(&address.0).expect("valid felt").into(); - Self::ContractNotDeployed(address) - } - - TransactionError::MaxFeeTooLow(max_fee, min) => Self::MaxFeeTooLow { max_fee, min }, - TransactionError::EntryPointNotFound(selector) => { - Self::EntryPointNotFound(to_felt(&selector)) - } - TransactionError::FeeTransferError(e) => Self::FeeTransferError(e.to_string()), - e => Self::Other(e.to_string()), - } - } -} diff --git a/crates/katana/executor/src/implementation/sir/mod.rs b/crates/katana/executor/src/implementation/sir/mod.rs deleted file mode 100644 index 6a687346dc..0000000000 --- a/crates/katana/executor/src/implementation/sir/mod.rs +++ /dev/null @@ -1,276 +0,0 @@ -mod error; -mod state; -pub mod utils; - -use std::sync::Arc; - -use katana_primitives::block::{ExecutableBlock, PartialHeader}; -use katana_primitives::env::{BlockEnv, CfgEnv}; -use katana_primitives::fee::TxFeeInfo; -use katana_primitives::transaction::{ExecutableTx, ExecutableTxWithHash, TxWithHash}; -use katana_primitives::FieldElement; -use katana_provider::traits::state::StateProvider; -use sir::definitions::block_context::{self, BlockContext}; -use sir::execution::TransactionExecutionInfo; -use sir::state::cached_state; -use sir::state::contract_class_cache::PermanentContractClassCache; -use tracing::info; - -use self::state::CachedState; -use crate::abstraction::{ - BlockExecutor, ExecutionOutput, ExecutorExt, ExecutorFactory, ExecutorResult, SimulationFlag, - StateProviderDb, -}; -use crate::utils::build_receipt; -use crate::{EntryPointCall, ExecutionError, ExecutionResult, ExecutionStats, ResultAndStates}; - -pub(crate) const LOG_TARGET: &str = "katana::executor::sir"; - -/// A factory for creating [StarknetVMProcessor] instances. -#[derive(Debug)] -pub struct NativeExecutorFactory { - cfg: CfgEnv, - flags: SimulationFlag, -} - -impl NativeExecutorFactory { - /// Create a new factory with the given configuration and simulation flags. - pub fn new(cfg: CfgEnv, flags: SimulationFlag) -> Self { - Self { cfg, flags } - } -} - -impl ExecutorFactory for NativeExecutorFactory { - fn with_state<'a, P>(&self, state: P) -> Box + 'a> - where - P: StateProvider + 'a, - { - self.with_state_and_block_env(state, BlockEnv::default()) - } - - fn with_state_and_block_env<'a, P>( - &self, - state: P, - block_env: BlockEnv, - ) -> Box + 'a> - where - P: StateProvider + 'a, - { - let cfg_env = self.cfg.clone(); - let simulation_flags = self.flags.clone(); - Box::new(StarknetVMProcessor::new(Box::new(state), block_env, cfg_env, simulation_flags)) - } - - fn cfg(&self) -> &CfgEnv { - &self.cfg - } -} - -#[derive(Debug)] -pub struct StarknetVMProcessor<'a> { - block_context: BlockContext, - state: CachedState, PermanentContractClassCache>, - transactions: Vec<(TxWithHash, ExecutionResult)>, - simulation_flags: SimulationFlag, - stats: ExecutionStats, -} - -impl<'a> StarknetVMProcessor<'a> { - pub fn new( - state: Box, - block_env: BlockEnv, - cfg_env: CfgEnv, - simulation_flags: SimulationFlag, - ) -> Self { - let transactions = Vec::new(); - let block_context = utils::block_context_from_envs(&block_env, &cfg_env); - let state = - CachedState::new(StateProviderDb(state), PermanentContractClassCache::default()); - Self { block_context, state, transactions, simulation_flags, stats: Default::default() } - } - - fn fill_block_env_from_header(&mut self, header: &PartialHeader) { - let number = header.number; - let timestamp = header.timestamp; - let sequencer_address = utils::to_sir_address(&header.sequencer_address); - - let gas_prices = block_context::GasPrices { - eth_l1_gas_price: header.gas_prices.eth, - strk_l1_gas_price: header.gas_prices.strk, - }; - - self.block_context.block_info_mut().block_number = number; - self.block_context.block_info_mut().gas_price = gas_prices; - self.block_context.block_info_mut().block_timestamp = timestamp; - self.block_context.block_info_mut().sequencer_address = sequencer_address; - } - - fn simulate_with( - &self, - transactions: Vec, - flags: &SimulationFlag, - mut op: F, - ) -> Vec - where - F: FnMut((TxWithHash, Result<(TransactionExecutionInfo, TxFeeInfo), ExecutionError>)) -> T, - { - let block_context = &self.block_context; - - let mut state = cached_state::CachedState::new( - Arc::new(&self.state), - Arc::new(PermanentContractClassCache::default()), - ); - - let mut results = Vec::with_capacity(transactions.len()); - for exec_tx in transactions { - let tx = TxWithHash::from(&exec_tx); - let res = utils::transact(exec_tx, &mut state, block_context, flags); - - results.push(op((tx, res))); - } - - results - } -} - -impl<'a> BlockExecutor<'a> for StarknetVMProcessor<'a> { - fn execute_transactions( - &mut self, - transactions: Vec, - ) -> ExecutorResult<()> { - let block_context = &self.block_context; - let flags = &self.simulation_flags; - let mut state = self.state.0.write(); - - for exec_tx in transactions { - // Collect class artifacts if its a declare tx - let class_decl_artifacts = if let ExecutableTx::Declare(tx) = exec_tx.as_ref() { - let class_hash = tx.class_hash(); - Some((class_hash, tx.compiled_class.clone(), tx.sierra_class.clone())) - } else { - None - }; - - let tx = TxWithHash::from(&exec_tx); - let res = match utils::transact(exec_tx, &mut state.inner, block_context, flags) { - Ok((info, fee)) => { - // get the trace and receipt from the execution info - let trace = utils::to_exec_info(&info); - let receipt = build_receipt(&tx, fee, &trace); - - crate::utils::log_resources(&trace.actual_resources); - crate::utils::log_events(receipt.events()); - - self.stats.l1_gas_used += receipt.fee().gas_consumed; - self.stats.cairo_steps_used += receipt.resources_used().steps as u128; - - if let Some(reason) = receipt.revert_reason() { - info!(target: LOG_TARGET, reason = %reason, "Transaction reverted."); - } - - ExecutionResult::new_success(receipt, trace) - } - Err(e) => { - info!(target: LOG_TARGET, error = %e, "Executing transaction."); - ExecutionResult::new_failed(e) - } - }; - - // if the tx succeed, inserts the class artifacts into the contract class cache - if res.is_success() { - if let Some((class_hash, compiled, sierra)) = class_decl_artifacts { - state.declared_classes.insert(class_hash, (compiled, sierra)); - } - } - - self.transactions.push((tx, res)); - } - - Ok(()) - } - - fn execute_block(&mut self, block: ExecutableBlock) -> ExecutorResult<()> { - self.fill_block_env_from_header(&block.header); - self.execute_transactions(block.body)?; - Ok(()) - } - - fn take_execution_output(&mut self) -> ExecutorResult { - let states = utils::state_update_from_cached_state(&self.state); - let transactions = std::mem::take(&mut self.transactions); - let stats = std::mem::take(&mut self.stats); - Ok(ExecutionOutput { stats, states, transactions }) - } - - fn state(&self) -> Box { - Box::new(self.state.clone()) - } - - fn transactions(&self) -> &[(TxWithHash, ExecutionResult)] { - &self.transactions - } - - fn block_env(&self) -> BlockEnv { - BlockEnv { - number: self.block_context.block_info().block_number, - timestamp: self.block_context.block_info().block_timestamp, - sequencer_address: utils::to_address( - &self.block_context.block_info().sequencer_address, - ), - l1_gas_prices: katana_primitives::block::GasPrices { - eth: self.block_context.block_info().gas_price.eth_l1_gas_price, - strk: self.block_context.block_info().gas_price.strk_l1_gas_price, - }, - } - } -} - -impl<'a> ExecutorExt for StarknetVMProcessor<'a> { - fn simulate( - &self, - transactions: Vec, - flags: SimulationFlag, - ) -> Vec { - self.simulate_with(transactions, &flags, |(tx, res)| { - let result = match res { - Ok((info, fee)) => { - // get the trace and receipt from the execution info - let trace = utils::to_exec_info(&info); - let receipt = build_receipt(&tx, fee, &trace); - ExecutionResult::new_success(receipt, trace) - } - Err(e) => ExecutionResult::new_failed(e), - }; - - ResultAndStates { result, states: Default::default() } - }) - } - - fn estimate_fee( - &self, - transactions: Vec, - flags: SimulationFlag, - ) -> Vec> { - self.simulate_with(transactions, &flags, |(_, res)| match res { - Ok((info, fee)) => { - // if the transaction was reverted, return as error - if let Some(reason) = info.revert_error { - info!(target: LOG_TARGET, reason = %reason, "Fee estimation failed."); - Err(ExecutionError::TransactionReverted { revert_error: reason }) - } else { - Ok(fee) - } - } - Err(e) => { - info!(target: LOG_TARGET, error = %e, "Estimating fee."); - Err(e) - } - }) - } - - fn call(&self, call: EntryPointCall) -> Result, ExecutionError> { - let block_context = &self.block_context; - let retdata = utils::call(call, &self.state, block_context, 1_000_000_000)?; - Ok(retdata) - } -} diff --git a/crates/katana/executor/src/implementation/sir/state.rs b/crates/katana/executor/src/implementation/sir/state.rs deleted file mode 100644 index a7334c219e..0000000000 --- a/crates/katana/executor/src/implementation/sir/state.rs +++ /dev/null @@ -1,583 +0,0 @@ -use std::collections::HashMap; -use std::sync::Arc; - -use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; -use katana_primitives::contract::{ContractAddress, Nonce, StorageKey, StorageValue}; -use katana_primitives::FieldElement; -use katana_provider::error::ProviderError; -use katana_provider::traits::contract::ContractClassProvider; -use katana_provider::traits::state::StateProvider; -use katana_provider::ProviderResult; -use parking_lot::RwLock; -use sir::core::errors::state_errors::StateError; -use sir::state::cached_state; -use sir::state::contract_class_cache::ContractClassCache; -use sir::state::state_api::StateReader; -use sir::state::state_cache::StorageEntry; -use sir::transaction::{Address, ClassHash, CompiledClassHash}; -use sir::Felt252; - -use super::utils; -use crate::abstraction::StateProviderDb; - -/// A helper trait to enforce that a type must implement both [StateProvider] and [StateReader]. -pub(super) trait StateDb: StateProvider + StateReader {} -impl StateDb for T where T: StateProvider + StateReader {} - -impl<'a> StateReader for StateProviderDb<'a> { - fn get_class_hash_at(&self, contract_address: &Address) -> Result { - match self.0.class_hash_of_contract(utils::to_address(contract_address)) { - Ok(Some(value)) => Ok(utils::to_sir_class_hash(&value)), - - Ok(None) => Ok(ClassHash::default()), - Err(e) => Err(StateError::CustomError(e.to_string())), - } - } - - fn get_compiled_class_hash( - &self, - class_hash: &ClassHash, - ) -> Result { - match self.0.compiled_class_hash_of_class_hash(utils::to_class_hash(class_hash)) { - Ok(Some(value)) => Ok(utils::to_sir_class_hash(&value)), - - Ok(None) => Err(StateError::NoneCompiledHash(*class_hash)), - Err(e) => Err(StateError::CustomError(e.to_string())), - } - } - - fn get_contract_class( - &self, - class_hash: &ClassHash, - ) -> Result - { - match self.0.class(utils::to_class_hash(class_hash)) { - Ok(Some(value)) => Ok(utils::to_sir_compiled_class(value)), - - Ok(None) => Err(StateError::NoneCompiledClass(*class_hash)), - Err(e) => Err(StateError::CustomError(e.to_string())), - } - } - - fn get_nonce_at(&self, contract_address: &Address) -> Result { - match self.0.nonce(utils::to_address(contract_address)) { - Ok(Some(value)) => Ok(utils::to_sir_felt(&value)), - - Ok(None) => Ok(Felt252::ZERO), - Err(e) => Err(StateError::CustomError(e.to_string())), - } - } - - fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { - let address = utils::to_address(&storage_entry.0); - let key = FieldElement::from_bytes_be(&storage_entry.1).unwrap(); - - match self.0.storage(address, key) { - Ok(Some(value)) => Ok(utils::to_sir_felt(&value)), - - Ok(None) => Ok(Felt252::ZERO), - Err(e) => Err(StateError::CustomError(e.to_string())), - } - } -} - -type DeclaredClass = (CompiledClass, Option); - -#[derive(Debug, Default)] -pub(super) struct CachedState(pub(super) Arc>>) -where - S: StateDb + Send + Sync, - C: ContractClassCache + Send + Sync; - -impl Clone for CachedState -where - S: StateDb + Send + Sync, - C: ContractClassCache + Send + Sync, -{ - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } -} - -#[derive(Debug, Default)] -pub(super) struct CachedStateInner -where - S: StateDb + Send + Sync, - C: ContractClassCache + Send + Sync, -{ - pub(super) inner: cached_state::CachedState, - pub(super) declared_classes: HashMap, -} - -impl CachedState -where - S: StateDb + Send + Sync, - C: ContractClassCache + Send + Sync, -{ - pub(super) fn new(state: S, classes_cache: C) -> Self { - let declared_classes = HashMap::new(); - let cached_state = cached_state::CachedState::new(Arc::new(state), Arc::new(classes_cache)); - let inner = CachedStateInner { inner: cached_state, declared_classes }; - Self(Arc::new(RwLock::new(inner))) - } -} - -impl ContractClassProvider for CachedState -where - S: StateDb + Send + Sync, - C: ContractClassCache + Send + Sync, -{ - fn class( - &self, - hash: katana_primitives::class::ClassHash, - ) -> ProviderResult> { - let state = self.0.read(); - if let Some((class, _)) = state.declared_classes.get(&hash) { - Ok(Some(class.clone())) - } else { - state.inner.state_reader.class(hash) - } - } - - fn compiled_class_hash_of_class_hash( - &self, - hash: katana_primitives::class::ClassHash, - ) -> ProviderResult> { - let state = self.0.read(); - let hash = utils::to_sir_class_hash(&hash); - - match state.inner.get_compiled_class_hash(&hash) { - Ok(value) => Ok(Some(utils::to_class_hash(&value))), - - Err(StateError::NoneCompiledHash(_)) => Ok(None), - Err(e) => Err(ProviderError::Other(e.to_string())), - } - } - - fn sierra_class( - &self, - hash: katana_primitives::class::ClassHash, - ) -> ProviderResult> { - let state = self.0.read(); - if let Some((_, sierra)) = state.declared_classes.get(&hash) { - Ok(sierra.clone()) - } else { - state.inner.state_reader.sierra_class(hash) - } - } -} - -impl StateProvider for CachedState -where - S: StateDb + Send + Sync, - C: ContractClassCache + Send + Sync, -{ - fn class_hash_of_contract( - &self, - address: ContractAddress, - ) -> ProviderResult> { - let state = self.0.read(); - - let res = state - .inner - .get_class_hash_at(&utils::to_sir_address(&address)) - .map(|v| utils::to_class_hash(&v)); - - match res { - Ok(value) if value != FieldElement::ZERO => Ok(Some(value)), - // check the inner state provider if the class hash is not found in the - // cache state or if the returned class hash is zero - Ok(_) | Err(StateError::NoneClassHash(_)) => { - state.inner.state_reader.class_hash_of_contract(address) - } - Err(e) => Err(ProviderError::Other(e.to_string())), - } - } - - fn nonce(&self, address: ContractAddress) -> ProviderResult> { - // check if the contract is deployed - if self.class_hash_of_contract(address)?.is_none() { - return Ok(None); - } - - let state = self.0.read(); - let address = utils::to_sir_address(&address); - - match state.inner.get_nonce_at(&address) { - Ok(value) => Ok(Some(utils::to_felt(&value))), - - Err(StateError::NoneNonce(_)) => Ok(None), - Err(e) => Err(ProviderError::Other(e.to_string())), - } - } - - // This function will ONLY return `None` if the contract is not deployed - // and NOT if the contract is deployed but the storage is empty. Retrieving - // non-existant storage will return FieldElement::ZERO due to the nature of - // the StateReader trait. - fn storage( - &self, - address: ContractAddress, - storage_key: StorageKey, - ) -> ProviderResult> { - // check if the contract is deployed - if self.class_hash_of_contract(address)?.is_none() { - return Ok(None); - } - - let state = self.0.read(); - - let address = utils::to_sir_address(&address); - let key = utils::to_sir_felt(&storage_key); - - match state.inner.get_storage_at(&(address, key.to_bytes_be())) { - Ok(value) => Ok(Some(utils::to_felt(&value))), - - Err(StateError::NoneStorage(_)) => Ok(None), - Err(e) => Err(ProviderError::Other(e.to_string())), - } - } -} - -impl StateReader for CachedState -where - S: StateDb + Send + Sync, - C: ContractClassCache + Send + Sync, -{ - fn get_class_hash_at(&self, contract_address: &Address) -> Result { - self.0.read().inner.get_class_hash_at(contract_address) - } - - fn get_compiled_class_hash( - &self, - class_hash: &ClassHash, - ) -> Result { - self.0.read().inner.get_compiled_class_hash(class_hash) - } - - fn get_contract_class( - &self, - class_hash: &ClassHash, - ) -> Result - { - self.0.read().inner.get_contract_class(class_hash) - } - - fn get_nonce_at(&self, contract_address: &Address) -> Result { - self.0.read().inner.get_nonce_at(contract_address) - } - - fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { - self.0.read().inner.get_storage_at(storage_entry) - } -} - -#[cfg(test)] -mod tests { - - use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; - use katana_primitives::contract::ContractAddress; - use katana_primitives::genesis::constant::{ - DEFAULT_LEGACY_ERC20_CONTRACT_CASM, DEFAULT_LEGACY_UDC_CASM, DEFAULT_OZ_ACCOUNT_CONTRACT, - DEFAULT_OZ_ACCOUNT_CONTRACT_CASM, - }; - use katana_primitives::utils::class::{parse_compiled_class, parse_sierra_class}; - use katana_primitives::FieldElement; - use katana_provider::providers::in_memory::InMemoryProvider; - use katana_provider::traits::contract::ContractClassWriter; - use katana_provider::traits::state::{StateFactoryProvider, StateProvider, StateWriter}; - use sir::state::contract_class_cache::PermanentContractClassCache; - use sir::state::state_api::{State, StateReader}; - use sir::transaction::ClassHash; - use sir::Felt252; - use starknet::macros::felt; - - use super::CachedState; - use crate::implementation::sir::utils::{ - to_sir_address, to_sir_class_hash, to_sir_compiled_class, to_sir_felt, - }; - use crate::StateProviderDb; - - fn new_sierra_class() -> (FlattenedSierraClass, CompiledClass) { - let json = include_str!("../../../../contracts/compiled/cairo1_contract.json"); - let artifact = serde_json::from_str(json).unwrap(); - let compiled_class = parse_compiled_class(artifact).unwrap(); - let sierra_class = parse_sierra_class(json).unwrap().flatten().unwrap(); - (sierra_class, compiled_class) - } - - fn state_provider() -> Box { - let address = ContractAddress::from(felt!("0x67")); - let nonce = felt!("0x7"); - let storage_key = felt!("0x1"); - let storage_value = felt!("0x2"); - let class_hash = felt!("0x123"); - let compiled_hash = felt!("0x456"); - let sierra_class = DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap(); - let class = DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone(); - let legacy_class_hash = felt!("0x111"); - let legacy_class = DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone(); - - let provider = InMemoryProvider::new(); - provider.set_nonce(address, nonce).unwrap(); - provider.set_class_hash_of_contract(address, class_hash).unwrap(); - provider.set_storage(address, storage_key, storage_value).unwrap(); - provider.set_compiled_class_hash_of_class_hash(class_hash, compiled_hash).unwrap(); - provider.set_class(class_hash, class).unwrap(); - provider.set_sierra_class(class_hash, sierra_class).unwrap(); - provider.set_class(legacy_class_hash, legacy_class).unwrap(); - - provider.latest().unwrap() - } - - #[test] - fn can_fetch_from_inner_state_provider() -> anyhow::Result<()> { - let state = state_provider(); - let classes_cache = PermanentContractClassCache::default(); - let cached_state = CachedState::new(StateProviderDb(state), classes_cache); - - let address = to_sir_address(&ContractAddress::from(felt!("0x67"))); - let legacy_class_hash = to_sir_class_hash(&felt!("0x111")); - - let actual_class_hash = cached_state.get_class_hash_at(&address)?; - let actual_nonce = cached_state.get_nonce_at(&address)?; - let actual_storage_value = - cached_state.get_storage_at(&(address.clone(), felt!("0x1").to_bytes_be()))?; - let actual_compiled_hash = cached_state.get_compiled_class_hash(&actual_class_hash)?; - let actual_class = cached_state.get_contract_class(&actual_class_hash)?; - let actual_legacy_class = cached_state.get_contract_class(&legacy_class_hash)?; - - assert_eq!(actual_nonce, to_sir_felt(&felt!("0x7"))); - assert_eq!(actual_storage_value, to_sir_felt(&felt!("0x2"))); - assert_eq!(actual_class_hash, to_sir_class_hash(&felt!("0x123"))); - assert_eq!(actual_compiled_hash, to_sir_class_hash(&felt!("0x456"))); - assert_eq!(actual_class, to_sir_compiled_class(DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone())); - assert_eq!( - actual_legacy_class, - to_sir_compiled_class(DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone()) - ); - - Ok(()) - } - - #[test] - fn can_fetch_as_state_provider() -> anyhow::Result<()> { - let sp = state_provider(); - - // cache_state native data - let new_address = ContractAddress::from(felt!("0xdead")); - let new_storage_key = felt!("0xf00"); - let new_storage_value = felt!("0xba"); - let new_legacy_class_hash = felt!("0x1234"); - let new_legacy_class = DEFAULT_LEGACY_UDC_CASM.clone(); - let new_class_hash = felt!("0x777"); - let (new_sierra_class, new_compiled_sierra_class) = new_sierra_class(); - let new_compiled_hash = felt!("0xdead"); - // let new_legacy_compiled_hash = felt!("0x5678"); - - // we're asserting that the underlying state provider doesnt have cache state native data - - let actual_new_nonce = sp.nonce(new_address)?; - let actual_new_class_hash = sp.class_hash_of_contract(new_address)?; - let actual_new_storage_value = sp.storage(new_address, new_storage_key)?; - let actual_new_legacy_class = sp.class(new_legacy_class_hash)?; - let actual_new_legacy_sierra_class = sp.class(new_legacy_class_hash)?; - let actual_new_sierra_class = sp.sierra_class(new_class_hash)?; - let actual_new_class = sp.class(new_class_hash)?; - let actual_new_compiled_class_hash = - sp.compiled_class_hash_of_class_hash(new_class_hash)?; - let actual_new_legacy_compiled_hash = - sp.compiled_class_hash_of_class_hash(new_class_hash)?; - - assert_eq!(actual_new_nonce, None, "data shouldn't exist"); - assert_eq!(actual_new_class_hash, None, "data shouldn't exist"); - assert_eq!(actual_new_storage_value, None, "data shouldn't exist"); - assert_eq!(actual_new_legacy_class, None, "data should'nt exist"); - assert_eq!(actual_new_legacy_sierra_class, None, "data shouldn't exist"); - assert_eq!(actual_new_sierra_class, None, "data shouldn't exist"); - assert_eq!(actual_new_class, None, "data shouldn't exist"); - assert_eq!(actual_new_compiled_class_hash, None, "data shouldn't exist"); - assert_eq!(actual_new_legacy_compiled_hash, None, "data shouldn't exist"); - - let classes_cache = PermanentContractClassCache::default(); - let cached_state = CachedState::new(StateProviderDb(sp), classes_cache); - - // insert some data to the cached state - { - let sir_address = to_sir_address(&new_address); - let sir_legacy_class_hash = to_sir_class_hash(&new_legacy_class_hash); - // let sir_legacy_compiled_hash = to_sir_felt(&new_compiled_hash); - let sir_storage_key = new_storage_key.to_bytes_be(); - let sir_storage_value = to_sir_felt(&new_storage_value); - let sir_class_hash = to_sir_class_hash(&new_class_hash); - let sir_compiled_hash = to_sir_felt(&new_compiled_hash); - - let lock = &mut cached_state.0.write(); - let sir_state = &mut lock.inner; - - sir_state.increment_nonce(&sir_address)?; - sir_state.set_class_hash_at(sir_address.clone(), sir_legacy_class_hash)?; - sir_state.set_storage_at(&(sir_address.clone(), sir_storage_key), sir_storage_value); - sir_state.set_contract_class( - &sir_class_hash, - &to_sir_compiled_class(new_compiled_sierra_class.clone()), - )?; - sir_state.set_compiled_class_hash( - &Felt252::from_bytes_be(&sir_class_hash.0), - &sir_compiled_hash, - )?; - sir_state.set_contract_class( - &sir_legacy_class_hash, - &to_sir_compiled_class(DEFAULT_LEGACY_UDC_CASM.clone()), - )?; - - let declared_classes = &mut lock.declared_classes; - declared_classes.insert(new_legacy_class_hash, (new_legacy_class.clone(), None)); - declared_classes.insert( - new_class_hash, - (new_compiled_sierra_class.clone(), Some(new_sierra_class.clone())), - ); - } - - // assert that can fetch data from the underlyign state provider - let sp: Box = Box::new(cached_state); - - let address = ContractAddress::from(felt!("0x67")); - let class_hash = felt!("0x123"); - let legacy_class_hash = felt!("0x111"); - - let actual_class_hash = sp.class_hash_of_contract(address)?; - let actual_nonce = sp.nonce(address)?; - let actual_storage_value = sp.storage(address, felt!("0x1"))?; - let actual_class = sp.class(class_hash)?; - let actual_sierra_class = sp.sierra_class(class_hash)?; - let actual_compiled_hash = sp.compiled_class_hash_of_class_hash(class_hash)?; - let actual_legacy_class = sp.class(legacy_class_hash)?; - - assert_eq!(actual_nonce, Some(felt!("0x7"))); - assert_eq!(actual_class_hash, Some(class_hash)); - assert_eq!(actual_storage_value, Some(felt!("0x2"))); - assert_eq!(actual_compiled_hash, Some(felt!("0x456"))); - assert_eq!(actual_class, Some(DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone())); - assert_eq!(actual_sierra_class, Some(DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten()?)); - assert_eq!(actual_legacy_class, Some(DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone())); - - // assert that can fetch data native to the cached state from the state provider - - let actual_new_class_hash = sp.class_hash_of_contract(new_address)?; - let actual_new_nonce = sp.nonce(new_address)?; - let actual_new_storage_value = sp.storage(new_address, new_storage_key)?; - let actual_new_class = sp.class(new_class_hash)?; - let actual_new_sierra = sp.sierra_class(new_class_hash)?; - let actual_new_compiled_hash = sp.compiled_class_hash_of_class_hash(new_class_hash)?; - let actual_legacy_class = sp.class(new_legacy_class_hash)?; - let actual_legacy_sierra = sp.sierra_class(new_legacy_class_hash)?; - // let actual_new_legacy_compiled_hash = - // sp.compiled_class_hash_of_class_hash(new_legacy_class_hash)?; - - assert_eq!(actual_new_nonce, Some(felt!("0x1")), "data should be in cached state"); - assert_eq!( - actual_new_class_hash, - Some(new_legacy_class_hash), - "data should be in cached state" - ); - assert_eq!( - actual_new_storage_value, - Some(new_storage_value), - "data should be in cached state" - ); - assert_eq!(actual_new_class, Some(new_compiled_sierra_class)); - assert_eq!(actual_new_sierra, Some(new_sierra_class)); - assert_eq!(actual_new_compiled_hash, Some(new_compiled_hash)); - assert_eq!(actual_legacy_class, Some(new_legacy_class)); - assert_eq!(actual_legacy_sierra, None, "legacy class should not have sierra class"); - - Ok(()) - } - - #[test] - fn fetch_non_existant_data() -> anyhow::Result<()> { - let db = InMemoryProvider::new(); - - let address = ContractAddress::from(felt!("0x1")); - let class_hash = felt!("0x123"); - let storage_key = felt!("0x1"); - - // edge case: the StateProvider::storage impl of CachedState will return - // default value for non-existant storage key of an existant contract. It will - // only return None if the contract does not exist. The intended behaviour for - // StateProvider::storage is to return None if the storage key or contract address - // does not exist. - let edge_address = ContractAddress::from(felt!("0x2")); - db.set_class_hash_of_contract(edge_address, class_hash)?; - - let sp = db.latest()?; - - let classes_cache = PermanentContractClassCache::default(); - let cached_state = CachedState::new(StateProviderDb(sp), classes_cache); - - let actual_nonce = cached_state - .get_nonce_at(&to_sir_address(&address)) - .expect("should return default value"); - let actual_storage_value = cached_state - .get_storage_at(&(to_sir_address(&address), storage_key.to_bytes_be())) - .expect("should return default value"); - let actual_class_hash = cached_state - .get_class_hash_at(&to_sir_address(&address)) - .expect("should return default value"); - let actual_compiled_hash = - cached_state.get_compiled_class_hash(&to_sir_class_hash(&class_hash)); - let actual_compiled_class = - cached_state.get_contract_class(&to_sir_class_hash(&class_hash)); - let actual_edge_storage_value = cached_state - .get_storage_at(&(to_sir_address(&edge_address), storage_key.to_bytes_be())) - .expect("should return default value"); - - assert_eq!( - actual_nonce, - Felt252::ZERO, - "nonce of nonexistant contract should default to zero" - ); - assert_eq!( - actual_storage_value, - Felt252::ZERO, - "value of nonexistant contract and storage key should default to zero" - ); - assert_eq!( - actual_edge_storage_value, - Felt252::ZERO, - "value of nonexistant storage key but existant contract should default to zero" - ); - assert_eq!( - actual_class_hash, - ClassHash::default(), - "class hash of nonexistant contract should default to zero" - ); - assert!( - actual_compiled_hash.unwrap_err().to_string().contains("No compiled class hash found") - ); - assert!(actual_compiled_class.unwrap_err().to_string().contains("No compiled class found")); - - let sp: Box = Box::new(cached_state); - - let actual_nonce = sp.nonce(address)?; - let actual_storage_value = sp.storage(address, storage_key)?; - let actual_edge_storage_value = sp.storage(edge_address, storage_key)?; - let actual_class_hash = sp.class_hash_of_contract(address)?; - let actual_compiled_hash = sp.compiled_class_hash_of_class_hash(class_hash)?; - let actual_class = sp.class(class_hash)?; - - assert_eq!(actual_nonce, None, "nonce of nonexistant contract should be None"); - assert_eq!(actual_class_hash, None, "class hash of nonexistant contract should be None"); - assert_eq!(actual_storage_value, None, "value of nonexistant contract should be None"); - assert_eq!( - actual_edge_storage_value, - Some(FieldElement::ZERO), - "edge case: value of nonexistant storage key but existant contract should return zero" - ); - assert_eq!(actual_compiled_hash, None); - assert_eq!(actual_class, None); - - Ok(()) - } -} diff --git a/crates/katana/executor/src/implementation/sir/utils.rs b/crates/katana/executor/src/implementation/sir/utils.rs deleted file mode 100644 index 584ffa5ead..0000000000 --- a/crates/katana/executor/src/implementation/sir/utils.rs +++ /dev/null @@ -1,725 +0,0 @@ -use std::collections::HashMap; -use std::str::FromStr; -use std::sync::Arc; - -use katana_primitives::class::{CompiledClass, CompiledClassHash, DeprecatedCompiledClass}; -use katana_primitives::contract::{ContractAddress, StorageKey, StorageValue}; -use katana_primitives::env::{BlockEnv, CfgEnv}; -use katana_primitives::fee::TxFeeInfo; -use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; -use katana_primitives::trace::TxExecInfo; -use katana_primitives::transaction::{ - DeployAccountTx, ExecutableTx, ExecutableTxWithHash, InvokeTx, -}; -use katana_primitives::FieldElement; -use sir::definitions::block_context::{ - BlockContext, FeeTokenAddresses, FeeType, GasPrices, StarknetOsConfig, -}; -use sir::definitions::constants::TRANSACTION_VERSION; -use sir::execution::execution_entry_point::ExecutionEntryPoint; -use sir::execution::{CallInfo, CallType, TransactionExecutionContext, TransactionExecutionInfo}; -use sir::services::api::contract_classes::compiled_class::CompiledClass as SirCompiledClass; -use sir::services::api::contract_classes::deprecated_contract_class::ContractClass as SirDeprecatedContractClass; -use sir::state::contract_class_cache::{ContractClassCache, PermanentContractClassCache}; -use sir::state::state_api::StateReader; -use sir::state::state_cache::StateCache; -use sir::state::{cached_state, BlockInfo, ExecutionResourcesManager, StateDiff}; -use sir::transaction::error::TransactionError; -use sir::transaction::fee::{calculate_tx_fee, calculate_tx_l1_gas_usage}; -use sir::transaction::{ - Address, ClassHash, CurrentAccountTxFields, DataAvailabilityMode, Declare, DeclareDeprecated, - DeployAccount, InvokeFunction, L1Handler, ResourceBounds, Transaction, - VersionSpecificAccountTxFields, -}; -use sir::utils::calculate_sn_keccak; -use sir::EntryPointType; -use starknet::core::types::PriceUnit; -use starknet_types_core::felt::Felt; - -use super::state::{CachedState, StateDb}; -use super::SimulationFlag; -use crate::{EntryPointCall, ExecutionError}; - -pub(super) fn transact( - tx: ExecutableTxWithHash, - state: &mut cached_state::CachedState, - block_context: &BlockContext, - simulation_flag: &SimulationFlag, -) -> Result<(TransactionExecutionInfo, TxFeeInfo), ExecutionError> -where - S: StateReader, - C: ContractClassCache, -{ - let tx = to_executor_tx(tx, simulation_flag)?; - let fee_type = tx.fee_type(); - - let info = tx.execute( - state, - block_context, - u128::MAX, // TODO: this should be set as part of the transaction fee - #[cfg(feature = "native")] - None, - )?; - - // There are a few case where the `actual_fee` field of the transaction info is not set where - // the fee is skipped and thus not charged for the transaction (e.g. when the - // `skip_fee_transfer` is explicitly set, or when the transaction `max_fee` is set to 0). In - // these cases, we still want to calculate the fee. - let overall_fee = if info.actual_fee == 0 { - calculate_tx_fee(&info.actual_resources, block_context, &fee_type)? - } else { - info.actual_fee - }; - - let gas_consumed = calculate_tx_l1_gas_usage(&info.actual_resources, block_context)?; - let (unit, gas_price) = match fee_type { - FeeType::Eth => (PriceUnit::Wei, block_context.get_gas_price_by_fee_type(&FeeType::Eth)), - FeeType::Strk => (PriceUnit::Fri, block_context.get_gas_price_by_fee_type(&FeeType::Strk)), - }; - let fee = TxFeeInfo { gas_consumed, gas_price, unit, overall_fee }; - - Ok((info, fee)) -} - -pub fn call( - request: EntryPointCall, - state: impl StateReader, - block_context: &BlockContext, - initial_gas: u128, -) -> Result, ExecutionError> { - let mut state = cached_state::CachedState::new( - Arc::new(state), - Arc::new(PermanentContractClassCache::default()), - ); - - let contract_address = to_sir_address(&request.contract_address); - let entry_point_selector = to_sir_felt(&request.entry_point_selector); - let calldata = request.calldata.iter().map(to_sir_felt).collect::>(); - let call_type = Some(CallType::Call); - let caller_address = Address::default(); - let entry_point_type = EntryPointType::External; - - let call = ExecutionEntryPoint::new( - contract_address, - calldata, - entry_point_selector, - caller_address, - entry_point_type, - call_type, - None, - initial_gas, - ); - - let max_steps = block_context.invoke_tx_max_n_steps(); - let mut resources_manager = ExecutionResourcesManager::default(); - let mut tx_execution_context = TransactionExecutionContext::new( - Address::default(), - Felt::default(), - Vec::new(), - Default::default(), - Felt::default(), - block_context.invoke_tx_max_n_steps(), - *TRANSACTION_VERSION, - ); - - let result = call.execute( - &mut state, - block_context, - &mut resources_manager, - &mut tx_execution_context, - false, - max_steps, - #[cfg(feature = "native")] - None, - )?; - - let info = result.call_info.expect("should exist in call result"); - let retdata = info.retdata.iter().map(to_felt).collect(); - - Ok(retdata) -} - -fn to_executor_tx( - katana_tx: ExecutableTxWithHash, - simulation_flag: &SimulationFlag, -) -> Result { - match katana_tx.transaction { - ExecutableTx::Invoke(tx) => match tx { - InvokeTx::V1(tx) => { - let version = Felt::ONE; - let contract_address = to_sir_address(&tx.sender_address); - let entry_point = Felt::from_bytes_be(&calculate_sn_keccak(b"__execute__")); - let ver_specifc_fields = VersionSpecificAccountTxFields::Deprecated(tx.max_fee); - let calldata = tx.calldata.iter().map(to_sir_felt).collect::>(); - let signature = tx.signature.iter().map(to_sir_felt).collect::>(); - let nonce = Some(to_sir_felt(&tx.nonce)); - let tx_hash = to_sir_felt(&katana_tx.hash); - - let tx = InvokeFunction::new_with_tx_hash( - contract_address, - entry_point, - ver_specifc_fields, - version, - calldata, - signature, - nonce, - tx_hash, - )?; - - let tx = tx.create_for_simulation( - simulation_flag.skip_validate, - simulation_flag.skip_execute, - simulation_flag.skip_fee_transfer, - simulation_flag.ignore_max_fee, - simulation_flag.skip_nonce_check, - ); - - Ok(tx) - } - - InvokeTx::V3(tx) => { - let version = Felt::THREE; - let contract_address = to_sir_address(&tx.sender_address); - let entry_point = Felt::from_bytes_be(&calculate_sn_keccak(b"__execute__")); - - let ver_specifc_fields = to_sir_current_account_tx_fields( - tx.tip, - tx.resource_bounds.l1_gas, - tx.resource_bounds.l2_gas, - tx.nonce_data_availability_mode, - tx.fee_data_availability_mode, - tx.paymaster_data, - tx.account_deployment_data, - ); - - let calldata = tx.calldata.iter().map(to_sir_felt).collect::>(); - let signature = tx.signature.iter().map(to_sir_felt).collect::>(); - let nonce = Some(to_sir_felt(&tx.nonce)); - let tx_hash = to_sir_felt(&katana_tx.hash); - - let tx = InvokeFunction::new_with_tx_hash( - contract_address, - entry_point, - ver_specifc_fields, - version, - calldata, - signature, - nonce, - tx_hash, - )?; - - let tx = tx.create_for_simulation( - simulation_flag.skip_validate, - simulation_flag.skip_execute, - simulation_flag.skip_fee_transfer, - simulation_flag.ignore_max_fee, - simulation_flag.skip_nonce_check, - ); - - Ok(tx) - } - }, - - ExecutableTx::DeployAccount(tx) => match tx { - DeployAccountTx::V1(tx) => { - let version = Felt::ONE; - let class_hash = to_sir_class_hash(&tx.class_hash); - let ver_specifc_fields = VersionSpecificAccountTxFields::Deprecated(tx.max_fee); - let calldata = tx.constructor_calldata.iter().map(to_sir_felt).collect(); - let signature = tx.signature.iter().map(to_sir_felt).collect::>(); - let nonce = to_sir_felt(&tx.nonce); - let tx_hash = to_sir_felt(&katana_tx.hash); - - let tx = DeployAccount::new_with_tx_hash( - class_hash, - ver_specifc_fields, - version, - nonce, - calldata, - signature, - nonce, - tx_hash, - )?; - - let tx = tx.create_for_simulation( - simulation_flag.skip_validate, - simulation_flag.skip_execute, - simulation_flag.skip_fee_transfer, - simulation_flag.ignore_max_fee, - simulation_flag.skip_nonce_check, - ); - - Ok(tx) - } - - DeployAccountTx::V3(tx) => { - let version = Felt::THREE; - - let class_hash = to_sir_class_hash(&tx.class_hash); - let ver_specifc_fields = to_sir_current_account_tx_fields( - tx.tip, - tx.resource_bounds.l1_gas, - tx.resource_bounds.l2_gas, - tx.nonce_data_availability_mode, - tx.fee_data_availability_mode, - tx.paymaster_data, - vec![], - ); - let calldata = tx.constructor_calldata.iter().map(to_sir_felt).collect(); - let signature = tx.signature.iter().map(to_sir_felt).collect::>(); - let nonce = to_sir_felt(&tx.nonce); - let tx_hash = to_sir_felt(&katana_tx.hash); - - let tx = DeployAccount::new_with_tx_hash( - class_hash, - ver_specifc_fields, - version, - nonce, - calldata, - signature, - nonce, - tx_hash, - )?; - - let tx = tx.create_for_simulation( - simulation_flag.skip_validate, - simulation_flag.skip_execute, - simulation_flag.skip_fee_transfer, - simulation_flag.ignore_max_fee, - simulation_flag.skip_nonce_check, - ); - - Ok(tx) - } - }, - - ExecutableTx::Declare(declare) => match declare.transaction { - katana_primitives::transaction::DeclareTx::V1(tx) => { - let sender_address = to_sir_address(&tx.sender_address); - let max_fee = tx.max_fee; - let version = Felt::ONE; - let signature = tx.signature.iter().map(to_sir_felt).collect::>(); - let nonce = to_sir_felt(&tx.nonce); - let tx_hash = to_sir_felt(&katana_tx.hash); - let class_hash = to_sir_class_hash(&tx.class_hash); - - let CompiledClass::Deprecated(class) = declare.compiled_class else { panic!() }; - let contract_class = to_sir_deprecated_class(class.clone()); - - let tx = DeclareDeprecated::new_with_tx_and_class_hash( - contract_class, - sender_address, - max_fee, - version, - signature, - nonce, - tx_hash, - class_hash, - )?; - - let tx = tx.create_for_simulation( - simulation_flag.skip_validate, - simulation_flag.skip_execute, - simulation_flag.skip_fee_transfer, - simulation_flag.ignore_max_fee, - simulation_flag.skip_nonce_check, - ); - - Ok(tx) - } - - katana_primitives::transaction::DeclareTx::V2(tx) => { - let sierra_contract_class = None; - let sierra_class_hash = to_sir_felt(&tx.class_hash); - let compiled_class_hash = to_sir_felt(&tx.compiled_class_hash); - let sender_address = to_sir_address(&tx.sender_address); - let account_tx_fields = VersionSpecificAccountTxFields::Deprecated(tx.max_fee); - let version = Felt::TWO; - let signature = tx.signature.iter().map(to_sir_felt).collect::>(); - let nonce = to_sir_felt(&tx.nonce); - let tx_hash = to_sir_felt(&katana_tx.hash); - - let CompiledClass::Class(class) = declare.compiled_class else { panic!() }; - let casm_contract_class = Some(class.casm.clone()); - - let tx = Declare::new_with_sierra_class_hash_and_tx_hash( - sierra_contract_class, - sierra_class_hash, - casm_contract_class, - compiled_class_hash, - sender_address, - account_tx_fields, - version, - signature, - nonce, - tx_hash, - )?; - - let tx = tx.create_for_simulation( - simulation_flag.skip_validate, - simulation_flag.skip_execute, - simulation_flag.skip_fee_transfer, - simulation_flag.ignore_max_fee, - simulation_flag.skip_nonce_check, - ); - - Ok(tx) - } - - katana_primitives::transaction::DeclareTx::V3(tx) => { - let sierra_contract_class = None; - let sierra_class_hash = to_sir_felt(&tx.class_hash); - let compiled_class_hash = to_sir_felt(&tx.compiled_class_hash); - let sender_address = to_sir_address(&tx.sender_address); - let ver_specifc_fields = to_sir_current_account_tx_fields( - tx.tip, - tx.resource_bounds.l1_gas, - tx.resource_bounds.l2_gas, - tx.nonce_data_availability_mode, - tx.fee_data_availability_mode, - tx.paymaster_data, - tx.account_deployment_data, - ); - let version = Felt::THREE; - let signature = tx.signature.iter().map(to_sir_felt).collect::>(); - let nonce = to_sir_felt(&tx.nonce); - let tx_hash = to_sir_felt(&katana_tx.hash); - - let CompiledClass::Class(class) = declare.compiled_class else { panic!() }; - let casm_contract_class = Some(class.casm.clone()); - - let tx = Declare::new_with_sierra_class_hash_and_tx_hash( - sierra_contract_class, - sierra_class_hash, - casm_contract_class, - compiled_class_hash, - sender_address, - ver_specifc_fields, - version, - signature, - nonce, - tx_hash, - )?; - - let tx = tx.create_for_simulation( - simulation_flag.skip_validate, - simulation_flag.skip_execute, - simulation_flag.skip_fee_transfer, - simulation_flag.ignore_max_fee, - simulation_flag.skip_nonce_check, - ); - - Ok(tx) - } - }, - - ExecutableTx::L1Handler(tx) => { - let contract_address = to_sir_address(&tx.contract_address); - let entry_point = to_sir_felt(&tx.entry_point_selector); - let calldata = tx.calldata.iter().map(to_sir_felt).collect::>(); - let nonce = to_sir_felt(&tx.nonce); - let paid_fee_on_l1 = Some(Felt::from(tx.paid_fee_on_l1)); - let tx_hash = to_sir_felt(&katana_tx.hash); - - let tx = L1Handler::new_with_tx_hash( - contract_address, - entry_point, - calldata, - nonce, - paid_fee_on_l1, - tx_hash, - )?; - - let tx = tx - .create_for_simulation(simulation_flag.skip_validate, simulation_flag.skip_execute); - - Ok(tx) - } - } -} - -fn state_diff_from_state_cache(mut cache: StateCache) -> StateDiff { - let address_to_class_hash = std::mem::take(cache.class_hash_writes_mut()); - let address_to_nonce = std::mem::take(cache.nonce_writes_mut()); - let class_hash_to_compiled_class = std::mem::take(cache.compiled_class_hash_writes_mut()); - let storage_updates = sir::utils::to_state_diff_storage_mapping(cache.storage_writes()); - - StateDiff::new( - address_to_class_hash, - address_to_nonce, - class_hash_to_compiled_class, - storage_updates, - ) -} - -pub(super) fn to_felt(value: &Felt) -> FieldElement { - FieldElement::from_bytes_be(&value.to_bytes_be()).unwrap() -} - -pub(super) fn to_sir_felt(value: &FieldElement) -> Felt { - Felt::from_bytes_be(&value.to_bytes_be()) -} - -pub(super) fn to_address(value: &Address) -> ContractAddress { - ContractAddress::new(FieldElement::from_bytes_be(&value.0.to_bytes_be()).unwrap()) -} - -pub(super) fn to_sir_address(value: &ContractAddress) -> Address { - Address(to_sir_felt(&value.0)) -} - -pub(super) fn to_class_hash(value: &ClassHash) -> katana_primitives::class::ClassHash { - FieldElement::from_bytes_be(&value.0).unwrap() -} - -pub(super) fn to_sir_class_hash(value: &katana_primitives::class::ClassHash) -> ClassHash { - ClassHash(value.to_bytes_be()) -} - -pub(super) fn to_sir_compiled_class(class: CompiledClass) -> SirCompiledClass { - match class { - CompiledClass::Class(class) => { - let casm = Arc::new(class.casm); - let sierra = Some(Arc::new((class.sierra.program, class.sierra.entry_points_by_type))); - SirCompiledClass::Casm { casm, sierra } - } - - CompiledClass::Deprecated(class) => { - let class = Arc::new(to_sir_deprecated_class(class)); - SirCompiledClass::Deprecated(class) - } - } -} - -pub(super) fn to_sir_deprecated_class( - class: DeprecatedCompiledClass, -) -> SirDeprecatedContractClass { - let json = serde_json::to_string(&class).unwrap(); - SirDeprecatedContractClass::from_str(&json).unwrap() -} - -fn to_sir_current_account_tx_fields( - tip: u64, - l1_gas_resource_bounds: starknet::core::types::ResourceBounds, - l2_gas_resource_bounds: starknet::core::types::ResourceBounds, - nonce_data_availability_mode: starknet::core::types::DataAvailabilityMode, - fee_data_availability_mode: starknet::core::types::DataAvailabilityMode, - paymaster_data: Vec, - account_deployment_data: Vec, -) -> VersionSpecificAccountTxFields { - fn to_sir_da_mode(mode: starknet::core::types::DataAvailabilityMode) -> DataAvailabilityMode { - match mode { - starknet::core::types::DataAvailabilityMode::L1 => DataAvailabilityMode::L1, - starknet::core::types::DataAvailabilityMode::L2 => DataAvailabilityMode::L2, - } - } - - fn to_sir_resource_bounds( - resource_bounds: starknet::core::types::ResourceBounds, - ) -> ResourceBounds { - ResourceBounds { - max_amount: resource_bounds.max_amount, - max_price_per_unit: resource_bounds.max_price_per_unit, - } - } - - let l1_resource_bounds = to_sir_resource_bounds(l1_gas_resource_bounds); - let l2_resource_bounds = Some(to_sir_resource_bounds(l2_gas_resource_bounds)); - let nonce_data_availability_mode = to_sir_da_mode(nonce_data_availability_mode); - let fee_data_availability_mode = to_sir_da_mode(fee_data_availability_mode); - let paymaster_data = paymaster_data.iter().map(to_sir_felt).collect::>(); - let account_deployment_data = - account_deployment_data.iter().map(to_sir_felt).collect::>(); - - VersionSpecificAccountTxFields::Current(CurrentAccountTxFields { - tip, - paymaster_data, - l1_resource_bounds, - l2_resource_bounds, - account_deployment_data, - fee_data_availability_mode, - nonce_data_availability_mode, - }) -} - -pub fn to_exec_info(exec_info: &TransactionExecutionInfo) -> TxExecInfo { - TxExecInfo { - validate_call_info: exec_info.validate_info.clone().map(from_sir_call_info), - execute_call_info: exec_info.call_info.clone().map(from_sir_call_info), - fee_transfer_call_info: exec_info.fee_transfer_info.clone().map(from_sir_call_info), - actual_fee: exec_info.actual_fee, - actual_resources: exec_info - .actual_resources - .clone() - .into_iter() - .map(|(k, v)| (k, v as u64)) - .collect(), - revert_error: exec_info.revert_error.clone(), - // exec_info.tx_type being dropped here. - } -} - -fn from_sir_call_info(call_info: CallInfo) -> katana_primitives::trace::CallInfo { - katana_primitives::trace::CallInfo { - contract_address: to_address(&call_info.contract_address), - caller_address: to_address(&call_info.caller_address), - call_type: match call_info.call_type { - Some(CallType::Call) => katana_primitives::trace::CallType::Call, - Some(CallType::Delegate) => katana_primitives::trace::CallType::Delegate, - _ => panic!("CallType is expected"), - }, - code_address: call_info.code_address.as_ref().map(to_address), - class_hash: call_info.class_hash.as_ref().map(to_class_hash), - entry_point_selector: to_felt( - &call_info.entry_point_selector.expect("EntryPointSelector is expected"), - ), - entry_point_type: match call_info.entry_point_type { - Some(EntryPointType::External) => katana_primitives::trace::EntryPointType::External, - Some(EntryPointType::L1Handler) => katana_primitives::trace::EntryPointType::L1Handler, - Some(EntryPointType::Constructor) => { - katana_primitives::trace::EntryPointType::Constructor - } - _ => panic!("EntryPointType is expected"), - }, - calldata: call_info.calldata.iter().map(to_felt).collect(), - retdata: call_info.retdata.iter().map(to_felt).collect(), - execution_resources: if let Some(ei) = call_info.execution_resources { - katana_primitives::trace::ExecutionResources { - n_steps: ei.n_steps as u64, - n_memory_holes: ei.n_memory_holes as u64, - builtin_instance_counter: ei - .builtin_instance_counter - .into_iter() - .map(|(k, v)| (k, v as u64)) - .collect(), - } - } else { - katana_primitives::trace::ExecutionResources::default() - }, - events: call_info - .events - .iter() - .map(|e| katana_primitives::event::OrderedEvent { - order: e.order, - keys: e.keys.iter().map(to_felt).collect(), - data: e.data.iter().map(to_felt).collect(), - }) - .collect(), - l2_to_l1_messages: call_info - .l2_to_l1_messages - .iter() - .map(|m| katana_primitives::message::OrderedL2ToL1Message { - order: m.order as u64, - from_address: to_address(&call_info.contract_address), - to_address: *to_address(&m.to_address), - payload: m.payload.iter().map(to_felt).collect(), - }) - .collect(), - storage_read_values: call_info - .storage_read_values - .into_iter() - .map(|f| to_felt(&f)) - .collect(), - accessed_storage_keys: call_info.accessed_storage_keys.iter().map(to_class_hash).collect(), - inner_calls: call_info - .internal_calls - .iter() - .map(|c| from_sir_call_info(c.clone())) - .collect(), - gas_consumed: call_info.gas_consumed, - failed: call_info.failure_flag, - } -} - -pub(super) fn block_context_from_envs(block_env: &BlockEnv, cfg_env: &CfgEnv) -> BlockContext { - let chain_id = to_sir_felt(&cfg_env.chain_id.id()); - let fee_token_addreses = FeeTokenAddresses::new( - to_sir_address(&cfg_env.fee_token_addresses.eth), - to_sir_address(&cfg_env.fee_token_addresses.strk), - ); - - let gas_price = GasPrices { - eth_l1_gas_price: block_env.l1_gas_prices.eth, - strk_l1_gas_price: block_env.l1_gas_prices.strk, - }; - - let block_info = BlockInfo { - gas_price, - block_number: block_env.number, - block_timestamp: block_env.timestamp, - sequencer_address: to_sir_address(&block_env.sequencer_address), - }; - - BlockContext::new( - StarknetOsConfig::new(chain_id, fee_token_addreses), - Default::default(), - Default::default(), - cfg_env.vm_resource_fee_cost.clone(), - cfg_env.invoke_tx_max_n_steps as u64, - cfg_env.validate_max_n_steps as u64, - block_info, - Default::default(), - false, - ) -} -pub(super) fn state_update_from_cached_state( - state: &CachedState, -) -> StateUpdatesWithDeclaredClasses -where - S: StateDb, - C: ContractClassCache + Send + Sync, -{ - use katana_primitives::class::ClassHash; - - let state = &mut state.0.write(); - let state_changes = std::mem::take(state.inner.cache_mut()); - let state_diffs = state_diff_from_state_cache(state_changes); - let compiled_classes = std::mem::take(&mut state.declared_classes); - - let nonce_updates: HashMap = - state_diffs.address_to_nonce().iter().map(|(k, v)| (to_address(k), to_felt(v))).collect(); - - let declared_classes: HashMap = state_diffs - .class_hash_to_compiled_class() - .iter() - .map(|(k, v)| (to_class_hash(k), to_class_hash(v))) - .collect(); - - let contract_updates: HashMap = state_diffs - .address_to_class_hash() - .iter() - .map(|(k, v)| (to_address(k), to_class_hash(v))) - .collect(); - - let storage_updates: HashMap> = state_diffs - .storage_updates() - .iter() - .map(|(k, v)| { - let k = to_address(k); - let v = v.iter().map(|(k, v)| (to_felt(k), to_felt(v))).collect(); - (k, v) - }) - .collect(); - - let total_classes = declared_classes.len(); - let mut declared_compiled_classes = HashMap::with_capacity(total_classes); - let mut declared_sierra_classes = HashMap::with_capacity(total_classes); - - for (hash, (compiled, sierra)) in compiled_classes { - declared_compiled_classes.insert(hash, compiled); - if let Some(sierra) = sierra { - declared_sierra_classes.insert(hash, sierra); - } - } - - StateUpdatesWithDeclaredClasses { - declared_sierra_classes, - declared_compiled_classes, - state_updates: StateUpdates { - nonce_updates, - storage_updates, - contract_updates, - declared_classes, - }, - } -} From bd46f85e3146a2b318e28eb43ce5cf862db298c5 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Mon, 22 Jul 2024 12:02:15 -0400 Subject: [PATCH 2/2] remove tests --- .github/workflows/ci.yml | 2 -- crates/katana/executor/tests/executor.rs | 17 ----------------- crates/katana/executor/tests/fixtures/mod.rs | 13 ------------- crates/katana/executor/tests/simulate.rs | 19 ------------------- 4 files changed, 51 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10a7f3da6c..66aa96e503 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,6 @@ jobs: chmod +x /tmp/bins/katana KATANA_RUNNER_BIN=/tmp/bins/katana cargo llvm-cov nextest --no-report --all-features --workspace --exclude katana --build-jobs 20 cargo llvm-cov nextest --no-report -p katana - # TODO(kariy): uncomment this line when `sir` feature support Cairo 2.6.3 - # cargo llvm-cov nextest --no-report -p katana --no-default-features --features sir cargo llvm-cov report --lcov --output-path lcov.info - uses: codecov/codecov-action@v4 with: diff --git a/crates/katana/executor/tests/executor.rs b/crates/katana/executor/tests/executor.rs index 9c97ffe6c9..4673cf2f11 100644 --- a/crates/katana/executor/tests/executor.rs +++ b/crates/katana/executor/tests/executor.rs @@ -334,20 +334,3 @@ mod blockifier { test_executor_with_valid_blocks_impl(factory, state, blocks) } } - -#[cfg(feature = "sir")] -mod sir { - use fixtures::sir::factory; - use katana_executor::implementation::sir::NativeExecutorFactory; - - use super::*; - - #[rstest::rstest] - fn test_executor_with_valid_blocks( - factory: NativeExecutorFactory, - #[from(state_provider)] state: Box, - #[from(valid_blocks)] blocks: [ExecutableBlock; 3], - ) { - test_executor_with_valid_blocks_impl(factory, state, blocks) - } -} diff --git a/crates/katana/executor/tests/fixtures/mod.rs b/crates/katana/executor/tests/fixtures/mod.rs index 8adb5493a1..62c524cba3 100644 --- a/crates/katana/executor/tests/fixtures/mod.rs +++ b/crates/katana/executor/tests/fixtures/mod.rs @@ -259,16 +259,3 @@ pub mod blockifier { BlockifierFactory::new(cfg, flags) } } - -#[cfg(feature = "sir")] -pub mod sir { - use katana_executor::implementation::sir::NativeExecutorFactory; - use katana_executor::SimulationFlag; - - use super::{cfg, flags, CfgEnv}; - - #[rstest::fixture] - pub fn factory(cfg: CfgEnv, #[with(true)] flags: SimulationFlag) -> NativeExecutorFactory { - NativeExecutorFactory::new(cfg, flags) - } -} diff --git a/crates/katana/executor/tests/simulate.rs b/crates/katana/executor/tests/simulate.rs index 076f2ba013..65441c63ff 100644 --- a/crates/katana/executor/tests/simulate.rs +++ b/crates/katana/executor/tests/simulate.rs @@ -96,22 +96,3 @@ mod blockifier { test_simulate_tx_impl(executor_factory, block_env, state_provider, tx, flags); } } - -#[cfg(feature = "sir")] -mod sir { - use fixtures::sir::factory; - use katana_executor::implementation::sir::NativeExecutorFactory; - - use super::*; - - #[apply(simulate_tx)] - fn test_simulate_tx( - #[with(factory::default())] executor_factory: NativeExecutorFactory, - block_env: BlockEnv, - state_provider: Box, - #[case] tx: ExecutableTxWithHash, - #[case] flags: SimulationFlag, - ) { - test_simulate_tx_impl(executor_factory, block_env, state_provider, tx, flags); - } -}