diff --git a/Cargo.lock b/Cargo.lock index d928f75e40..03ac1ed70a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6607,7 +6607,6 @@ name = "katana-db" version = "0.6.0-alpha.4" dependencies = [ "anyhow", - "blockifier", "cairo-lang-starknet", "cairo-vm", "criterion", @@ -6648,6 +6647,7 @@ dependencies = [ "anyhow", "base64 0.21.7", "blockifier", + "cairo-lang-sierra", "cairo-lang-starknet", "cairo-vm", "derive_more", diff --git a/crates/katana/core/src/backend/contract.rs b/crates/katana/core/src/backend/contract.rs index 7e6e9ddf37..e66cf748ad 100644 --- a/crates/katana/core/src/backend/contract.rs +++ b/crates/katana/core/src/backend/contract.rs @@ -1,7 +1,7 @@ -use blockifier::execution::contract_class::ContractClassV0; +use katana_primitives::contract::DeprecatedCompiledClass; use starknet::core::types::FlattenedSierraClass; pub enum StarknetContract { - Legacy(ContractClassV0), + Legacy(DeprecatedCompiledClass), Sierra(FlattenedSierraClass), } diff --git a/crates/katana/core/src/sequencer.rs b/crates/katana/core/src/sequencer.rs index 76fd67d355..ea3921e80f 100644 --- a/crates/katana/core/src/sequencer.rs +++ b/crates/katana/core/src/sequencer.rs @@ -13,7 +13,7 @@ use katana_executor::blockifier::PendingState; use katana_primitives::block::{BlockHash, BlockHashOrNumber, BlockIdOrTag, BlockNumber}; use katana_primitives::chain::ChainId; use katana_primitives::contract::{ - ClassHash, CompiledContractClass, ContractAddress, Nonce, StorageKey, StorageValue, + ClassHash, CompiledClass, ContractAddress, Nonce, StorageKey, StorageValue, }; use katana_primitives::event::{ContinuationToken, ContinuationTokenError}; use katana_primitives::receipt::Event; @@ -244,8 +244,8 @@ impl KatanaSequencer { }; match class { - CompiledContractClass::V0(class) => Ok(Some(StarknetContract::Legacy(class))), - CompiledContractClass::V1(_) => { + CompiledClass::Deprecated(class) => Ok(Some(StarknetContract::Legacy(class))), + CompiledClass::Class(_) => { let class = ContractClassProvider::sierra_class(&state, class_hash)? .map(StarknetContract::Sierra); Ok(class) diff --git a/crates/katana/core/src/service/block_producer.rs b/crates/katana/core/src/service/block_producer.rs index 56055ad142..84e526d1c4 100644 --- a/crates/katana/core/src/service/block_producer.rs +++ b/crates/katana/core/src/service/block_producer.rs @@ -248,7 +248,7 @@ impl IntervalBlockProducer { trace!(target: "miner", "created new block: {}", outcome.block_number); backend.update_block_env(&mut block_env); - pending_state.reset_state(StateRefDb(new_state), block_env, cfg_env); + pending_state.reset_state(new_state, block_env, cfg_env); Ok(outcome) } diff --git a/crates/katana/executor/Cargo.toml b/crates/katana/executor/Cargo.toml index a862e7a71a..afdffb3ca9 100644 --- a/crates/katana/executor/Cargo.toml +++ b/crates/katana/executor/Cargo.toml @@ -7,8 +7,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -katana-primitives = { path = "../primitives" } -katana-provider = { path = "../storage/provider" } +katana-primitives.workspace = true +katana-provider.workspace = true anyhow.workspace = true convert_case.workspace = true diff --git a/crates/katana/executor/src/blockifier/mod.rs b/crates/katana/executor/src/blockifier/mod.rs index 6da2ddc95c..725551c4bd 100644 --- a/crates/katana/executor/src/blockifier/mod.rs +++ b/crates/katana/executor/src/blockifier/mod.rs @@ -11,9 +11,8 @@ use blockifier::transaction::objects::TransactionExecutionInfo; use blockifier::transaction::transaction_execution::Transaction; use blockifier::transaction::transactions::ExecutableTransaction; use katana_primitives::env::{BlockEnv, CfgEnv}; -use katana_primitives::transaction::{ - DeclareTxWithClass, ExecutableTx, ExecutableTxWithHash, TxWithHash, -}; +use katana_primitives::transaction::{ExecutableTx, ExecutableTxWithHash, TxWithHash}; +use katana_provider::traits::state::StateProvider; use parking_lot::RwLock; use tracing::{trace, warn}; @@ -145,13 +144,9 @@ fn execute_tx( charge_fee: bool, validate: bool, ) -> TxExecutionResult { - let sierra = if let ExecutableTx::Declare(DeclareTxWithClass { - transaction, - sierra_class: Some(sierra_class), - .. - }) = tx.as_ref() - { - Some((transaction.class_hash(), sierra_class.clone())) + let class_declaration_params = if let ExecutableTx::Declare(tx) = tx.as_ref() { + let class_hash = tx.class_hash(); + Some((class_hash, tx.compiled_class.clone(), tx.sierra_class.clone())) } else { None }; @@ -166,8 +161,12 @@ fn execute_tx( }; if res.is_ok() { - if let Some((class_hash, sierra_class)) = sierra { - state.sierra_class_mut().insert(class_hash, sierra_class); + if let Some((class_hash, compiled_class, sierra_class)) = class_declaration_params { + state.class_cache.write().compiled.insert(class_hash, compiled_class); + + if let Some(sierra_class) = sierra_class { + state.class_cache.write().sierra.insert(class_hash, sierra_class); + } } } @@ -198,9 +197,9 @@ impl PendingState { } } - pub fn reset_state(&self, state: StateRefDb, block_env: BlockEnv, cfg_env: CfgEnv) { + pub fn reset_state(&self, state: Box, block_env: BlockEnv, cfg_env: CfgEnv) { *self.block_envs.write() = (block_env, cfg_env); - self.state.reset_with_new_state(state); + self.state.reset_with_new_state(StateRefDb(state)); } pub fn add_executed_txs(&self, transactions: Vec<(TxWithHash, TxExecutionResult)>) { diff --git a/crates/katana/executor/src/blockifier/state.rs b/crates/katana/executor/src/blockifier/state.rs index 56f7afc18d..713b3da405 100644 --- a/crates/katana/executor/src/blockifier/state.rs +++ b/crates/katana/executor/src/blockifier/state.rs @@ -2,8 +2,9 @@ use std::collections::HashMap; use blockifier::state::cached_state::{CachedState, GlobalContractCache}; use blockifier::state::errors::StateError; -use blockifier::state::state_api::StateReader; -use katana_primitives::contract::FlattenedSierraClass; +use blockifier::state::state_api::{StateReader, StateResult}; +use katana_primitives::contract::{CompiledClass, FlattenedSierraClass}; +use katana_primitives::conversion::blockifier::to_class; use katana_primitives::FieldElement; use katana_provider::traits::contract::ContractClassProvider; use katana_provider::traits::state::StateProvider; @@ -14,6 +15,12 @@ use starknet_api::hash::StarkHash; use starknet_api::patricia_key; use starknet_api::state::StorageKey; +mod primitives { + pub use katana_primitives::contract::{ + ClassHash, CompiledClassHash, ContractAddress, Nonce, StorageKey, StorageValue, + }; +} + /// A state db only provide read access. /// /// This type implements the [`StateReader`] trait so that it can be used as a with [`CachedState`]. @@ -25,50 +32,47 @@ impl StateRefDb { } } -impl ContractClassProvider for StateRefDb { - fn class( +impl StateProvider for StateRefDb { + fn class_hash_of_contract( &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - self.0.class(hash) + address: primitives::ContractAddress, + ) -> ProviderResult> { + self.0.class_hash_of_contract(address) } - fn compiled_class_hash_of_class_hash( + fn nonce( &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - self.0.compiled_class_hash_of_class_hash(hash) + address: primitives::ContractAddress, + ) -> ProviderResult> { + self.0.nonce(address) } - fn sierra_class( + fn storage( &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - self.0.sierra_class(hash) + address: primitives::ContractAddress, + storage_key: primitives::StorageKey, + ) -> ProviderResult> { + self.0.storage(address, storage_key) } } -impl StateProvider for StateRefDb { - fn nonce( - &self, - address: katana_primitives::contract::ContractAddress, - ) -> ProviderResult> { - self.0.nonce(address) +impl ContractClassProvider for StateRefDb { + fn class(&self, hash: primitives::ClassHash) -> ProviderResult> { + self.0.class(hash) } - fn class_hash_of_contract( + fn compiled_class_hash_of_class_hash( &self, - address: katana_primitives::contract::ContractAddress, - ) -> ProviderResult> { - self.0.class_hash_of_contract(address) + hash: primitives::ClassHash, + ) -> ProviderResult> { + self.0.compiled_class_hash_of_class_hash(hash) } - fn storage( + fn sierra_class( &self, - address: katana_primitives::contract::ContractAddress, - storage_key: katana_primitives::contract::StorageKey, - ) -> ProviderResult> { - self.0.storage(address, storage_key) + hash: primitives::ClassHash, + ) -> ProviderResult> { + self.0.sierra_class(hash) } } @@ -76,7 +80,7 @@ impl StateReader for StateRefDb { fn get_nonce_at( &mut self, contract_address: starknet_api::core::ContractAddress, - ) -> blockifier::state::state_api::StateResult { + ) -> StateResult { StateProvider::nonce(&self.0, contract_address.into()) .map(|n| Nonce(n.unwrap_or_default().into())) .map_err(|e| StateError::StateReadError(e.to_string())) @@ -86,7 +90,7 @@ impl StateReader for StateRefDb { &mut self, contract_address: starknet_api::core::ContractAddress, key: starknet_api::state::StorageKey, - ) -> blockifier::state::state_api::StateResult { + ) -> StateResult { StateProvider::storage(&self.0, contract_address.into(), (*key.0.key()).into()) .map(|v| v.unwrap_or_default().into()) .map_err(|e| StateError::StateReadError(e.to_string())) @@ -95,7 +99,7 @@ impl StateReader for StateRefDb { fn get_class_hash_at( &mut self, contract_address: starknet_api::core::ContractAddress, - ) -> blockifier::state::state_api::StateResult { + ) -> StateResult { StateProvider::class_hash_of_contract(&self.0, contract_address.into()) .map(|v| ClassHash(v.unwrap_or_default().into())) .map_err(|e| StateError::StateReadError(e.to_string())) @@ -104,7 +108,7 @@ impl StateReader for StateRefDb { fn get_compiled_class_hash( &mut self, class_hash: starknet_api::core::ClassHash, - ) -> blockifier::state::state_api::StateResult { + ) -> StateResult { if let Some(hash) = ContractClassProvider::compiled_class_hash_of_class_hash(&self.0, class_hash.0.into()) .map_err(|e| StateError::StateReadError(e.to_string()))? @@ -118,35 +122,41 @@ impl StateReader for StateRefDb { fn get_compiled_contract_class( &mut self, class_hash: starknet_api::core::ClassHash, - ) -> blockifier::state::state_api::StateResult< - blockifier::execution::contract_class::ContractClass, - > { + ) -> StateResult { if let Some(class) = ContractClassProvider::class(&self.0, class_hash.0.into()) .map_err(|e| StateError::StateReadError(e.to_string()))? { - Ok(class) + to_class(class).map_err(|e| StateError::StateReadError(e.to_string())) } else { Err(StateError::UndeclaredClassHash(class_hash)) } } } +#[derive(Default)] +pub struct ClassCache { + pub(crate) compiled: HashMap, + pub(crate) sierra: HashMap, +} + pub struct CachedStateWrapper { inner: Mutex>, - sierra_class: RwLock>, + pub(crate) class_cache: RwLock, } impl CachedStateWrapper { pub fn new(db: StateRefDb) -> Self { Self { - sierra_class: Default::default(), + class_cache: RwLock::new(ClassCache::default()), inner: Mutex::new(CachedState::new(db, GlobalContractCache::default())), } } pub(super) fn reset_with_new_state(&self, db: StateRefDb) { *self.inner() = CachedState::new(db, GlobalContractCache::default()); - self.sierra_class_mut().clear(); + let mut lock = self.class_cache.write(); + lock.compiled.clear(); + lock.sierra.clear(); } pub fn inner( @@ -154,35 +164,18 @@ impl CachedStateWrapper { ) -> parking_lot::lock_api::MutexGuard<'_, RawMutex, CachedState> { self.inner.lock() } - - pub fn sierra_class( - &self, - ) -> parking_lot::RwLockReadGuard< - '_, - HashMap, - > { - self.sierra_class.read() - } - - pub fn sierra_class_mut( - &self, - ) -> parking_lot::RwLockWriteGuard< - '_, - HashMap, - > { - self.sierra_class.write() - } } impl ContractClassProvider for CachedStateWrapper { fn class( &self, hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - let Ok(class) = self.inner().get_compiled_contract_class(ClassHash(hash.into())) else { - return Ok(None); - }; - Ok(Some(class)) + ) -> ProviderResult> { + if let res @ Some(_) = self.class_cache.read().compiled.get(&hash).cloned() { + Ok(res) + } else { + self.inner().state.class(hash) + } } fn compiled_class_hash_of_class_hash( @@ -199,7 +192,7 @@ impl ContractClassProvider for CachedStateWrapper { &self, hash: katana_primitives::contract::ClassHash, ) -> ProviderResult> { - if let Some(class) = self.sierra_class().get(&hash) { + if let Some(class) = self.class_cache.read().sierra.get(&hash) { Ok(Some(class.clone())) } else { self.inner.lock().state.0.sierra_class(hash) diff --git a/crates/katana/executor/src/blockifier/transactions.rs b/crates/katana/executor/src/blockifier/transactions.rs index 4560a4d2d5..53c3ea2f59 100644 --- a/crates/katana/executor/src/blockifier/transactions.rs +++ b/crates/katana/executor/src/blockifier/transactions.rs @@ -5,6 +5,7 @@ use ::blockifier::transaction::transaction_execution::Transaction; use ::blockifier::transaction::transactions::{DeployAccountTransaction, InvokeTransaction}; use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::transactions::{DeclareTransaction, L1HandlerTransaction}; +use katana_primitives::conversion::blockifier::to_class; use katana_primitives::transaction::{ DeclareTx, DeployAccountTx, ExecutableTx, ExecutableTxWithHash, InvokeTx, }; @@ -191,8 +192,12 @@ impl From for BlockifierTx { } }; - let tx = DeclareTransaction::new(tx, TransactionHash(hash.into()), contract_class) - .expect("class mismatch"); + let tx = DeclareTransaction::new( + tx, + TransactionHash(hash.into()), + to_class(contract_class).unwrap(), + ) + .expect("class mismatch"); Transaction::AccountTransaction(AccountTransaction::Declare(tx)) } diff --git a/crates/katana/executor/src/blockifier/utils.rs b/crates/katana/executor/src/blockifier/utils.rs index 5ec42972a5..21db9c8d3d 100644 --- a/crates/katana/executor/src/blockifier/utils.rs +++ b/crates/katana/executor/src/blockifier/utils.rs @@ -239,19 +239,21 @@ pub fn get_state_update_from_cached_state( ) -> StateUpdatesWithDeclaredClasses { let state_diff = state.inner().to_state_diff(); - let declared_sierra_classes = state.sierra_class().clone(); + let declared_sierra_classes = state.class_cache.read().sierra.clone(); - let declared_compiled_classes = state_diff - .class_hash_to_compiled_class_hash - .iter() - .map(|(class_hash, _)| { - let class = state.class(class_hash.0.into()).unwrap().expect("must exist if declared"); - (class_hash.0.into(), class) - }) - .collect::>(); + let declared_compiled_classes = + state_diff + .class_hash_to_compiled_class_hash + .iter() + .map(|(class_hash, _)| { + let class = + state.class(class_hash.0.into()).unwrap().expect("must exist if declared"); + (class_hash.0.into(), class) + }) + .collect::>(); let nonce_updates = state_diff diff --git a/crates/katana/primitives/Cargo.toml b/crates/katana/primitives/Cargo.toml index 534176db9f..1ad3897313 100644 --- a/crates/katana/primitives/Cargo.toml +++ b/crates/katana/primitives/Cargo.toml @@ -15,7 +15,7 @@ lazy_static = "1.4.0" rand = { version = "0.8.5", features = [ "small_rng" ] } rayon.workspace = true serde.workspace = true -serde_json.workspace = true +serde_json = { workspace = true, features = [ "arbitrary_precision" ] } serde_with.workspace = true starknet-crypto = "0.6.1" starknet.workspace = true @@ -25,6 +25,7 @@ thiserror.workspace = true blockifier.workspace = true cairo-lang-starknet.workspace = true +cairo-lang-sierra.workspace = true flate2.workspace = true starknet_api.workspace = true diff --git a/crates/katana/primitives/src/contract.rs b/crates/katana/primitives/src/contract.rs index eae4df0ab7..efbc169eaa 100644 --- a/crates/katana/primitives/src/contract.rs +++ b/crates/katana/primitives/src/contract.rs @@ -1,5 +1,6 @@ use std::fmt; +use cairo_lang_starknet::casm_contract_class::CasmContractClass; use derive_more::Deref; use starknet::core::utils::normalize_address; @@ -60,12 +61,27 @@ pub struct GenericContractInfo { pub class_hash: ClassHash, } -/// Represents a runnable Starknet contract class (meaning, the program is runnable by the VM). -#[cfg(feature = "blockifier")] -pub type CompiledContractClass = ::blockifier::execution::contract_class::ContractClass; -/// V0 of the compiled contract class -#[cfg(feature = "blockifier")] -pub type CompiledContractClassV0 = ::blockifier::execution::contract_class::ContractClassV0; -/// V1 of the compiled contract class -#[cfg(feature = "blockifier")] -pub type CompiledContractClassV1 = ::blockifier::execution::contract_class::ContractClassV1; +pub type DeprecatedCompiledClass = ::starknet_api::deprecated_contract_class::ContractClass; + +#[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SierraProgram { + pub program: cairo_lang_sierra::program::Program, + pub entry_points_by_type: cairo_lang_starknet::contract_class::ContractEntryPoints, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SierraCompiledClass { + pub casm: CasmContractClass, + pub sierra: SierraProgram, +} + +/// Executable contract class +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone, Eq, PartialEq, derive_more::From)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum CompiledClass { + Deprecated(DeprecatedCompiledClass), + Class(SierraCompiledClass), +} diff --git a/crates/katana/primitives/src/conversion/blockifier.rs b/crates/katana/primitives/src/conversion/blockifier.rs index 80751fb896..eade10ec20 100644 --- a/crates/katana/primitives/src/conversion/blockifier.rs +++ b/crates/katana/primitives/src/conversion/blockifier.rs @@ -1,11 +1,14 @@ //! Translation layer for converting the primitive types to the execution engine types. +use blockifier::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV1}; +use cairo_vm::types::errors::program_errors::ProgramError; use starknet::core::utils::parse_cairo_short_string; use starknet_api::core::{ContractAddress, PatriciaKey}; use starknet_api::hash::StarkHash; use starknet_api::patricia_key; use crate::chain::ChainId; +use crate::contract::CompiledClass; impl From for ContractAddress { fn from(address: crate::contract::ContractAddress) -> Self { @@ -29,6 +32,18 @@ impl From for starknet_api::core::ChainId { } } +pub fn to_class(class: CompiledClass) -> Result { + match class { + CompiledClass::Deprecated(class) => { + Ok(ContractClass::V0(ContractClassV0::try_from(class)?)) + } + + CompiledClass::Class(class) => { + Ok(ContractClass::V1(ContractClassV1::try_from(class.casm)?)) + } + } +} + #[cfg(test)] mod tests { use starknet::core::utils::parse_cairo_short_string; diff --git a/crates/katana/primitives/src/conversion/rpc.rs b/crates/katana/primitives/src/conversion/rpc.rs index fcb286d5e0..d9bb8a3ed2 100644 --- a/crates/katana/primitives/src/conversion/rpc.rs +++ b/crates/katana/primitives/src/conversion/rpc.rs @@ -1,54 +1,40 @@ use std::collections::{BTreeMap, HashMap}; use std::io::{self, Read, Write}; use std::mem; -use std::str::FromStr; -use anyhow::{anyhow, Result}; -use blockifier::execution::contract_class::ContractClassV0; +use anyhow::{Context, Result}; use cairo_lang_starknet::casm_contract_class::CasmContractClass; -use cairo_vm::felt::Felt252; -use cairo_vm::serde::deserialize_program::{ - serialize_program_data, ApTracking, OffsetValue, ProgramJson, ValueAddress, -}; -use cairo_vm::types::instruction::Register; -use cairo_vm::types::program::Program; -use serde::{Deserialize, Serialize, Serializer}; -use serde_json::{json, Number}; +use serde::Deserialize; +use serde_json::json; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; pub use starknet::core::types::contract::legacy::{LegacyContractClass, LegacyProgram}; use starknet::core::types::contract::legacy::{ LegacyDebugInfo, LegacyFlowTrackingData, LegacyHint, LegacyIdentifier, LegacyReferenceManager, - RawLegacyAbiEntry, RawLegacyEntryPoints, }; pub use starknet::core::types::contract::CompiledClass; use starknet::core::types::{ - CompressedLegacyContractClass, ContractClass, LegacyContractEntryPoint, LegacyEntryPointsByType, + CompressedLegacyContractClass, ContractClass, FunctionStateMutability, LegacyContractAbiEntry, + LegacyContractEntryPoint, LegacyEntryPointsByType, LegacyEventAbiEntry, LegacyEventAbiType, + LegacyFunctionAbiEntry, LegacyFunctionAbiType, LegacyStructAbiEntry, LegacyStructAbiType, + LegacyStructMember, LegacyTypedParameter, +}; +use starknet_api::deprecated_contract_class::{ + ContractClassAbiEntry, EntryPoint, EntryPointType, TypedParameter, }; -use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointType}; use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, CompiledContractClassV0, - FlattenedSierraClass, + ClassHash, CompiledClassHash, DeprecatedCompiledClass, FlattenedSierraClass, + SierraCompiledClass, SierraProgram, }; use crate::FieldElement; -mod primitives { - pub use crate::contract::{CompiledContractClass, ContractAddress, Nonce}; - pub use crate::transaction::{DeclareTx, DeployAccountTx, InvokeTx, L1HandlerTx, Tx}; - pub use crate::FieldElement; -} - -use cairo_vm::serde::deserialize_program::{Attribute, BuiltinName, DebugInfo, HintParams, Member}; -use cairo_vm::types::relocatable::MaybeRelocatable; - -/// Converts the legacy inner compiled class type [CompiledContractClassV0] into its RPC equivalent +/// Converts the legacy inner compiled class type [DeprecatedCompiledClass] into its RPC equivalent /// [`ContractClass`]. pub fn legacy_inner_to_rpc_class( - legacy_contract_class: CompiledContractClassV0, + legacy_contract_class: DeprecatedCompiledClass, ) -> Result { - // Convert [EntryPointType] (blockifier type) into [LegacyEntryPointsByType] (RPC type) - fn to_rpc_legacy_entry_points_by_type( + fn to_rpc_entry_points( entries: &HashMap>, ) -> Result { fn collect_entry_points( @@ -57,7 +43,7 @@ pub fn legacy_inner_to_rpc_class( ) -> Result> { Ok(entries .get(entry_point_type) - .ok_or(anyhow!("Missing {entry_point_type:?} entry point",))? + .context(format!("Missing {entry_point_type:?} entry point"))? .iter() .map(|e| LegacyContractEntryPoint { offset: e.offset.0 as u64, @@ -73,37 +59,100 @@ pub fn legacy_inner_to_rpc_class( }) } - let entry_points_by_type = - to_rpc_legacy_entry_points_by_type(&legacy_contract_class.entry_points_by_type)?; + fn convert_typed_param(param: Vec) -> Vec { + param + .into_iter() + .map(|param| LegacyTypedParameter { name: param.name, r#type: param.r#type }) + .collect() + } + + fn convert_abi_entry(abi: ContractClassAbiEntry) -> LegacyContractAbiEntry { + match abi { + ContractClassAbiEntry::Function(a) => { + LegacyContractAbiEntry::Function(LegacyFunctionAbiEntry { + name: a.name, + r#type: LegacyFunctionAbiType::Function, + inputs: convert_typed_param(a.inputs), + outputs: convert_typed_param(a.outputs), + state_mutability: a.state_mutability.map(|_| FunctionStateMutability::View), + }) + } - let compressed_program = compress_legacy_program_data(legacy_contract_class.program.clone())?; + ContractClassAbiEntry::Event(a) => LegacyContractAbiEntry::Event(LegacyEventAbiEntry { + name: a.name, + r#type: LegacyEventAbiType::Event, + data: convert_typed_param(a.data), + keys: convert_typed_param(a.keys), + }), + + ContractClassAbiEntry::Constructor(a) => { + LegacyContractAbiEntry::Function(LegacyFunctionAbiEntry { + name: a.name, + r#type: LegacyFunctionAbiType::Constructor, + inputs: convert_typed_param(a.inputs), + outputs: convert_typed_param(a.outputs), + state_mutability: a.state_mutability.map(|_| FunctionStateMutability::View), + }) + } + + ContractClassAbiEntry::Struct(a) => { + LegacyContractAbiEntry::Struct(LegacyStructAbiEntry { + name: a.name, + size: a.size as u64, + r#type: LegacyStructAbiType::Struct, + members: a + .members + .into_iter() + .map(|m| LegacyStructMember { + name: m.param.name, + offset: m.offset as u64, + r#type: m.param.r#type, + }) + .collect(), + }) + } - Ok(ContractClass::Legacy(CompressedLegacyContractClass { - program: compressed_program, - abi: None, - entry_points_by_type, - })) + ContractClassAbiEntry::L1Handler(a) => { + LegacyContractAbiEntry::Function(LegacyFunctionAbiEntry { + name: a.name, + r#type: LegacyFunctionAbiType::L1Handler, + inputs: convert_typed_param(a.inputs), + outputs: convert_typed_param(a.outputs), + state_mutability: a.state_mutability.map(|_| FunctionStateMutability::View), + }) + } + } + } + + fn convert_abi(abi: Option>) -> Option> { + abi.map(|abi| abi.into_iter().map(convert_abi_entry).collect()) + } + + let abi = convert_abi(legacy_contract_class.abi); + let program = compress_legacy_program_data(legacy_contract_class.program.clone())?; + let entry_points_by_type = to_rpc_entry_points(&legacy_contract_class.entry_points_by_type)?; + + Ok(ContractClass::Legacy(CompressedLegacyContractClass { abi, program, entry_points_by_type })) } /// Convert the given [`FlattenedSierraClass`] into the inner compiled class type -/// [`CompiledContractClass`] along with its class hashes. +/// [`CompiledClassHash`] along with its class hashes. pub fn flattened_sierra_to_compiled_class( contract_class: &FlattenedSierraClass, -) -> Result<(ClassHash, CompiledClassHash, CompiledContractClass)> { +) -> Result<(ClassHash, CompiledClassHash, crate::contract::CompiledClass)> { let class_hash = contract_class.class_hash(); - let contract_class = rpc_to_cairo_contract_class(contract_class)?; - let casm_contract = CasmContractClass::from_contract_class(contract_class, true)?; + let class = rpc_to_cairo_contract_class(contract_class)?; + + let program = class.extract_sierra_program()?; + let entry_points_by_type = class.entry_points_by_type.clone(); + let sierra = SierraProgram { program, entry_points_by_type }; - // compute compiled class hash - let res = serde_json::to_string(&casm_contract)?; - let compiled_class: CompiledClass = serde_json::from_str(&res)?; + let casm = CasmContractClass::from_contract_class(class, true)?; + let compiled_hash = FieldElement::from_bytes_be(&casm.compiled_class_hash().to_be_bytes())?; - Ok(( - class_hash, - compiled_class.class_hash()?, - CompiledContractClass::V1(casm_contract.try_into()?), - )) + let class = crate::contract::CompiledClass::Class(SierraCompiledClass { casm, sierra }); + Ok((class_hash, compiled_hash, class)) } /// Compute the compiled class hash from the given [`FlattenedSierraClass`]. @@ -117,65 +166,20 @@ pub fn compiled_class_hash_from_flattened_sierra_class( } /// Converts a legacy RPC compiled contract class [CompressedLegacyContractClass] type to the inner -/// compiled class type [CompiledContractClass] along with its class hash. -pub fn legacy_rpc_to_inner_compiled_class( +/// compiled class type [CompiledClass](crate::contract::CompiledClass) along with its class hash. +pub fn legacy_rpc_to_compiled_class( compressed_legacy_contract: &CompressedLegacyContractClass, -) -> Result<(ClassHash, CompiledContractClass)> { +) -> Result<(ClassHash, crate::contract::CompiledClass)> { let class_json = json!({ "abi": compressed_legacy_contract.abi.clone().unwrap_or_default(), "entry_points_by_type": compressed_legacy_contract.entry_points_by_type, "program": decompress_legacy_program_data(&compressed_legacy_contract.program)?, }); - #[allow(unused)] - #[derive(Deserialize)] - struct LegacyAttribute { - #[serde(default)] - accessible_scopes: Vec, - end_pc: u64, - flow_tracking_data: Option, - name: String, - start_pc: u64, - value: String, - } - - #[allow(unused)] - #[serde_as] - #[derive(Deserialize)] - pub struct LegacyProgram { - attributes: Option>, - builtins: Vec, - compiler_version: Option, - #[serde_as(as = "Vec")] - data: Vec, - debug_info: Option, - hints: BTreeMap>, - identifiers: BTreeMap, - main_scope: String, - prime: String, - reference_manager: LegacyReferenceManager, - } - - #[allow(unused)] - #[derive(Deserialize)] - struct LegacyContractClassJson { - abi: Vec, - entry_points_by_type: RawLegacyEntryPoints, - program: LegacyProgram, - } - - // SAFETY: `LegacyContractClassJson` MUST maintain same memory layout as `LegacyContractClass`. - // This would only work if the fields are in the same order and have the same size. Though, - // both types are using default Rust repr, which means there is no guarantee by the compiler - // that the memory layout of both types will be the same despite comprised of the same - // fields and types. - let class: LegacyContractClassJson = serde_json::from_value(class_json.clone())?; - let class: LegacyContractClass = unsafe { mem::transmute(class) }; + let deprecated_class: DeprecatedCompiledClass = serde_json::from_value(class_json.clone())?; + let class_hash = serde_json::from_value::(class_json)?.class_hash()?; - let inner_class: ContractClassV0 = serde_json::from_value(class_json)?; - let class_hash = class.class_hash()?; - - Ok((class_hash, CompiledContractClass::V0(inner_class))) + Ok((class_hash, crate::contract::CompiledClass::Deprecated(deprecated_class))) } /// Converts `starknet-rs` RPC [FlattenedSierraClass] type to Cairo's @@ -197,82 +201,11 @@ fn rpc_to_cairo_contract_class( }) } -fn compress_legacy_program_data(legacy_program: Program) -> Result, io::Error> { - fn felt_as_dec_str( - value: &Option, - serializer: S, - ) -> Result { - let dec_str = format!("{}", value.clone().unwrap_or_default().to_signed_felt()); - let number = Number::from_str(&dec_str).expect("valid number"); - number.serialize(serializer) - } - - fn value_address_in_str_format( - value_address: &ValueAddress, - serializer: S, - ) -> Result { - serializer.serialize_str(&parse_value_address_to_str(value_address.clone())) - } - - fn zero_if_none(pc: &Option, serializer: S) -> Result { - serializer.serialize_u64(pc.as_ref().map_or(0, |x| *x as u64)) - } - - #[derive(Serialize)] - struct Identifier { - #[serde(skip_serializing_if = "Option::is_none")] - pc: Option, - #[serde(rename = "type")] - #[serde(skip_serializing_if = "Option::is_none")] - type_: Option, - #[serde(serialize_with = "felt_as_dec_str")] - #[serde(skip_serializing_if = "Option::is_none")] - value: Option, - #[serde(skip_serializing_if = "Option::is_none")] - full_name: Option, - #[serde(skip_serializing_if = "Option::is_none")] - members: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - cairo_type: Option, - } - - #[derive(Serialize)] - struct Reference { - ap_tracking_data: ApTracking, - #[serde(serialize_with = "zero_if_none")] - pc: Option, - #[serde(rename(serialize = "value"))] - #[serde(serialize_with = "value_address_in_str_format")] - value_address: ValueAddress, - } - - #[derive(Serialize)] - struct ReferenceManager { - references: Vec, - } +fn compress_legacy_program_data( + legacy_program: starknet_api::deprecated_contract_class::Program, +) -> Result, io::Error> { + let bytes = serde_json::to_vec(&legacy_program)?; - #[derive(Serialize)] - struct SerializableProgramJson { - prime: String, - builtins: Vec, - #[serde(serialize_with = "serialize_program_data")] - data: Vec, - identifiers: HashMap, - hints: BTreeMap>, - reference_manager: ReferenceManager, - attributes: Vec, - debug_info: Option, - } - - // SAFETY: `SerializableProgramJson` MUST maintain same memory layout as `ProgramJson`. This - // would only work if the fields are in the same order and have the same size. Though, both - // types are using default Rust repr, which means there is no guarantee by the compiler that the - // memory layout of both types will be the same despite comprised of the same fields and - // types. - let program: ProgramJson = ProgramJson::from(legacy_program); - let program: SerializableProgramJson = unsafe { mem::transmute(program) }; - - let bytes = serde_json::to_vec(&program)?; let mut gzip_encoder = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::fast()); Write::write_all(&mut gzip_encoder, &bytes)?; gzip_encoder.finish() @@ -293,6 +226,7 @@ fn decompress_legacy_program_data(data: &[u8]) -> Result Result String { - fn handle_offset_ref(offset: i32, str: &mut String) { - if offset == 0 { - return; - } - - str.push_str(" + "); - str.push_str(&if offset.is_negative() { format!("({offset})") } else { offset.to_string() }) - } - - fn handle_offset_val(value: OffsetValue, str: &mut String) { - match value { - OffsetValue::Reference(rx, offset, deref) => { - let mut tmp = String::from(match rx { - Register::FP => "fp", - Register::AP => "ap", - }); - - handle_offset_ref(offset, &mut tmp); - - if deref { - str.push_str(&format!("[{tmp}]")); - } else { - str.push_str(&tmp); - } - } - - OffsetValue::Value(value) => handle_offset_ref(value, str), - - OffsetValue::Immediate(value) => { - if value == Felt252::from(0u32) { - return; - } - - str.push_str(" + "); - str.push_str(&value.to_string()); - } - } - } - - let mut str = String::new(); - let is_value: bool; - - if let OffsetValue::Immediate(_) = value_address.offset2 { - is_value = false; - } else { - is_value = true; - } - - handle_offset_val(value_address.offset1, &mut str); - handle_offset_val(value_address.offset2, &mut str); - - str.push_str(", "); - str.push_str(&value_address.value_type); - - if is_value { - str.push('*'); - } - - str = format!("cast({str})"); - - if value_address.dereference { - str = format!("[{str}]"); - } - - str -} - #[cfg(test)] mod tests { + use starknet::core::types::ContractClass; - use super::{legacy_inner_to_rpc_class, legacy_rpc_to_inner_compiled_class}; - use crate::utils::class::parse_compiled_class_v0; + use super::{legacy_inner_to_rpc_class, legacy_rpc_to_compiled_class}; + use crate::contract::{CompiledClass, DeprecatedCompiledClass}; + use crate::genesis::constant::DEFAULT_OZ_ACCOUNT_CONTRACT; + use crate::utils::class::parse_deprecated_compiled_class; - // There are some discrepancies between the legacy RPC and the inner compiled class types which - // results in some data lost during the conversion. Therefore, we are unable to assert for - // equality between the original and the converted class. Instead, we assert that the conversion - // is successful and that the converted class can be converted back #[test] fn legacy_rpc_to_inner_and_back() { - let class_json = include_str!("../../contracts/compiled/account.json"); - let class = parse_compiled_class_v0(class_json).unwrap(); + let json = include_str!("../../contracts/compiled/account.json"); + let json = serde_json::from_str(json).unwrap(); + let class: DeprecatedCompiledClass = parse_deprecated_compiled_class(json).unwrap(); - let Ok(ContractClass::Legacy(compressed_legacy_class)) = legacy_inner_to_rpc_class(class) + let Ok(ContractClass::Legacy(compressed_legacy_class)) = + legacy_inner_to_rpc_class(class.clone()) else { panic!("Expected legacy class"); }; - legacy_rpc_to_inner_compiled_class(&compressed_legacy_class).unwrap(); + let (_, converted_class) = legacy_rpc_to_compiled_class(&compressed_legacy_class).unwrap(); + + let CompiledClass::Deprecated(converted) = converted_class else { panic!("invalid class") }; + + assert_eq!(class.abi, converted.abi); + assert_eq!(class.program, converted.program); + assert_eq!(class.entry_points_by_type, converted.entry_points_by_type); + } + + #[test] + fn flattened_sierra_class_to_compiled_class() { + let sierra = DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap(); + assert!(super::flattened_sierra_to_compiled_class(&sierra).is_ok()); } } diff --git a/crates/katana/primitives/src/genesis/constant.rs b/crates/katana/primitives/src/genesis/constant.rs index d7dd569b91..6d3c295b8a 100644 --- a/crates/katana/primitives/src/genesis/constant.rs +++ b/crates/katana/primitives/src/genesis/constant.rs @@ -2,7 +2,7 @@ use lazy_static::lazy_static; use starknet::core::utils::get_storage_var_address; use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, SierraClass, StorageKey, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, SierraClass, StorageKey, }; use crate::utils::class::{parse_compiled_class, parse_sierra_class}; use crate::FieldElement; @@ -126,14 +126,15 @@ pub const DEFAULT_OZ_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH: CompiledClassHash = lazy_static! { // Default fee token contract - pub static ref DEFAULT_LEGACY_ERC20_CONTRACT_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/erc20.json")).unwrap(); + // pub static ref DEFAULT_LEGACY_ERC20_CONTRACT_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/erc20.json")).unwrap(); + pub static ref DEFAULT_LEGACY_ERC20_CONTRACT_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../contracts/compiled/erc20.json")); // Default universal deployer - pub static ref DEFAULT_LEGACY_UDC_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/universal_deployer.json")).unwrap(); + pub static ref DEFAULT_LEGACY_UDC_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../contracts/compiled/universal_deployer.json")); // Default account contract pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT: SierraClass = parse_sierra_class(include_str!("../../contracts/compiled/oz_account_080.json")).unwrap(); - pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/oz_account_080.json")).unwrap(); + pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../contracts/compiled/oz_account_080.json")); } @@ -144,3 +145,8 @@ lazy_static! { pub(super) fn get_fee_token_balance_base_storage_address(address: ContractAddress) -> FieldElement { get_storage_var_address("ERC20_balances", &[address.into()]).unwrap() } + +fn read_compiled_class_artifact(artifact: &str) -> CompiledClass { + let value = serde_json::from_str(artifact).unwrap(); + parse_compiled_class(value).unwrap() +} diff --git a/crates/katana/primitives/src/genesis/json.rs b/crates/katana/primitives/src/genesis/json.rs index 11f445575a..92dce1e9c6 100644 --- a/crates/katana/primitives/src/genesis/json.rs +++ b/crates/katana/primitives/src/genesis/json.rs @@ -11,8 +11,7 @@ use std::str::FromStr; use std::sync::Arc; use base64::prelude::*; -use cairo_lang_starknet::casm_contract_class::{CasmContractClass, StarknetSierraCompilationError}; -use cairo_lang_starknet::contract_class::ContractClass; +use cairo_lang_starknet::casm_contract_class::StarknetSierraCompilationError; use cairo_vm::types::errors::program_errors::ProgramError; use ethers::types::U256; use rayon::prelude::*; @@ -38,10 +37,10 @@ use super::constant::{ use super::{FeeTokenConfig, Genesis, GenesisAllocation, UniversalDeployerConfig}; use crate::block::{BlockHash, BlockNumber, GasPrices}; use crate::contract::{ - ClassHash, CompiledContractClass, CompiledContractClassV0, CompiledContractClassV1, - ContractAddress, SierraClass, StorageKey, StorageValue, + ClassHash, CompiledClass, ContractAddress, SierraClass, StorageKey, StorageValue, }; use crate::genesis::GenesisClass; +use crate::utils::class::{parse_compiled_class_v1, parse_deprecated_compiled_class}; use crate::FieldElement; type Object = Map; @@ -282,28 +281,24 @@ impl TryFrom for Genesis { let (class_hash, compiled_class_hash, sierra, casm) = match sierra { Ok(sierra) => { - let casm: ContractClass = serde_json::from_value(artifact)?; - let casm = CasmContractClass::from_contract_class(casm, true)?; + let class = parse_compiled_class_v1(artifact)?; // check if the class hash is provided, otherwise compute it from the // artifacts let class_hash = class_hash.unwrap_or(sierra.class_hash()?); - let compiled_hash = casm.compiled_class_hash().to_be_bytes(); + let compiled_hash = class.casm.compiled_class_hash().to_be_bytes(); ( class_hash, FieldElement::from_bytes_be(&compiled_hash)?, Some(Arc::new(sierra.flatten()?)), - Arc::new(CompiledContractClass::V1(CompiledContractClassV1::try_from( - casm, - )?)), + Arc::new(CompiledClass::Class(class)), ) } // if the artifact is not a sierra contract, we check if it's a legacy contract Err(_) => { - let casm: CompiledContractClassV0 = - serde_json::from_value(artifact.clone())?; + let casm = parse_deprecated_compiled_class(artifact.clone())?; let class_hash = if let Some(class_hash) = class_hash { class_hash @@ -313,7 +308,7 @@ impl TryFrom for Genesis { casm.class_hash()? }; - (class_hash, class_hash, None, Arc::new(CompiledContractClass::V0(casm))) + (class_hash, class_hash, None, Arc::new(CompiledClass::Deprecated(casm))) } }; diff --git a/crates/katana/primitives/src/genesis/mod.rs b/crates/katana/primitives/src/genesis/mod.rs index 52d6e18fb4..45a700a272 100644 --- a/crates/katana/primitives/src/genesis/mod.rs +++ b/crates/katana/primitives/src/genesis/mod.rs @@ -25,8 +25,8 @@ use self::constant::{ }; use crate::block::{Block, BlockHash, BlockNumber, GasPrices, Header}; use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - StorageKey, StorageValue, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, StorageKey, + StorageValue, }; use crate::state::StateUpdatesWithDeclaredClasses; use crate::utils::split_u256; @@ -61,7 +61,7 @@ pub struct GenesisClass { pub compiled_class_hash: CompiledClassHash, /// The casm class definition. #[serde(skip_serializing)] - pub casm: Arc, + pub casm: Arc, /// The sierra class definition. #[serde(skip_serializing)] pub sierra: Option>, diff --git a/crates/katana/primitives/src/state.rs b/crates/katana/primitives/src/state.rs index 2c67c062b9..a14b445ece 100644 --- a/crates/katana/primitives/src/state.rs +++ b/crates/katana/primitives/src/state.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - Nonce, StorageKey, StorageValue, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, Nonce, + StorageKey, StorageValue, }; /// State updates. @@ -29,5 +29,5 @@ pub struct StateUpdatesWithDeclaredClasses { /// A mapping of class hashes to their sierra classes definition. pub declared_sierra_classes: HashMap, /// A mapping of class hashes to their compiled classes definition. - pub declared_compiled_classes: HashMap, + pub declared_compiled_classes: HashMap, } diff --git a/crates/katana/primitives/src/transaction.rs b/crates/katana/primitives/src/transaction.rs index 76b3c4671b..d974a9fbde 100644 --- a/crates/katana/primitives/src/transaction.rs +++ b/crates/katana/primitives/src/transaction.rs @@ -4,8 +4,7 @@ use starknet::core::types::{DataAvailabilityMode, ResourceBoundsMapping}; use crate::chain::ChainId; use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - Nonce, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, Nonce, }; use crate::utils::transaction::{ compute_declare_v1_tx_hash, compute_declare_v2_tx_hash, compute_declare_v3_tx_hash, @@ -103,7 +102,7 @@ pub struct DeclareTxWithClass { /// The Sierra class, if any. pub sierra_class: Option, /// The compiled contract class. - pub compiled_class: CompiledContractClass, + pub compiled_class: CompiledClass, /// The raw transaction. #[deref] #[as_ref] @@ -114,7 +113,7 @@ impl DeclareTxWithClass { pub fn new_with_classes( transaction: DeclareTx, sierra_class: FlattenedSierraClass, - compiled_class: CompiledContractClass, + compiled_class: CompiledClass, ) -> Self { Self { sierra_class: Some(sierra_class), compiled_class, transaction } } diff --git a/crates/katana/primitives/src/utils/class.rs b/crates/katana/primitives/src/utils/class.rs index c97ae06a83..fe92c31cea 100644 --- a/crates/katana/primitives/src/utils/class.rs +++ b/crates/katana/primitives/src/utils/class.rs @@ -1,33 +1,39 @@ use anyhow::Result; use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_lang_starknet::contract_class::ContractClass; +use serde_json::Value; use crate::contract::{ - CompiledContractClass, CompiledContractClassV0, CompiledContractClassV1, SierraClass, + CompiledClass, DeprecatedCompiledClass, SierraClass, SierraCompiledClass, SierraProgram, }; -/// Parse a [`str`] into a [`CompiledContractClass`]. -pub fn parse_compiled_class(class: &str) -> Result { - if let Ok(class) = parse_compiled_class_v1(class) { - Ok(CompiledContractClass::V1(class)) +pub fn parse_compiled_class(artifact: Value) -> Result { + if let Ok(class) = parse_compiled_class_v1(artifact.clone()) { + Ok(CompiledClass::Class(class)) } else { - Ok(CompiledContractClass::V0(parse_compiled_class_v0(class)?)) + Ok(CompiledClass::Deprecated(parse_deprecated_compiled_class(artifact)?)) } } -/// Parse a [`str`] into a [`CompiledContractClassV1`]. -pub fn parse_compiled_class_v1(class: &str) -> Result { - let class: ContractClass = serde_json::from_str(class)?; - let class = CasmContractClass::from_contract_class(class, true)?; - Ok(CompiledContractClassV1::try_from(class)?) -} +pub fn parse_compiled_class_v1(class: Value) -> Result { + let class: ContractClass = serde_json::from_value(class)?; -/// Parse a [`str`] into a [`CompiledContractClassV0`]. -pub fn parse_compiled_class_v0(class: &str) -> Result { - serde_json::from_str(class) + let program = class.extract_sierra_program()?; + let entry_points_by_type = class.entry_points_by_type.clone(); + let sierra = SierraProgram { program, entry_points_by_type }; + + let casm = CasmContractClass::from_contract_class(class, true)?; + + Ok(SierraCompiledClass { casm, sierra }) } /// Parse a [`str`] into a [`SierraClass`]. pub fn parse_sierra_class(class: &str) -> Result { serde_json::from_str(class) } + +pub fn parse_deprecated_compiled_class( + class: Value, +) -> Result { + serde_json::from_value(class) +} diff --git a/crates/katana/rpc/rpc-types/src/transaction.rs b/crates/katana/rpc/rpc-types/src/transaction.rs index c48faf34b6..a1ec00f27d 100644 --- a/crates/katana/rpc/rpc-types/src/transaction.rs +++ b/crates/katana/rpc/rpc-types/src/transaction.rs @@ -6,7 +6,7 @@ use katana_primitives::chain::ChainId; use katana_primitives::contract::{ClassHash, ContractAddress}; use katana_primitives::conversion::rpc::{ compiled_class_hash_from_flattened_sierra_class, flattened_sierra_to_compiled_class, - legacy_rpc_to_inner_compiled_class, + legacy_rpc_to_compiled_class, }; use katana_primitives::transaction::{ DeclareTx, DeclareTxV1, DeclareTxV2, DeclareTxV3, DeclareTxWithClass, DeployAccountTx, @@ -93,7 +93,7 @@ impl BroadcastedDeclareTx { match self.0 { BroadcastedDeclareTransaction::V1(tx) => { let (class_hash, compiled_class) = - legacy_rpc_to_inner_compiled_class(&tx.contract_class)?; + legacy_rpc_to_compiled_class(&tx.contract_class)?; Ok(DeclareTxWithClass { compiled_class, diff --git a/crates/katana/storage/db/Cargo.toml b/crates/katana/storage/db/Cargo.toml index 87de9a249d..68c9ac316c 100644 --- a/crates/katana/storage/db/Cargo.toml +++ b/crates/katana/storage/db/Cargo.toml @@ -17,7 +17,6 @@ serde_json.workspace = true tempfile = { version = "3.8.1", optional = true } thiserror.workspace = true -blockifier.workspace = true cairo-vm.workspace = true starknet_api.workspace = true diff --git a/crates/katana/storage/db/benches/codec.rs b/crates/katana/storage/db/benches/codec.rs index fb7f5ab36c..d04b0043bc 100644 --- a/crates/katana/storage/db/benches/codec.rs +++ b/crates/katana/storage/db/benches/codec.rs @@ -1,19 +1,19 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use katana_db::codecs::{Compress, Decompress}; -use katana_db::models::class::StoredContractClass; -use katana_primitives::contract::CompiledContractClass; +use katana_primitives::contract::CompiledClass; use katana_primitives::utils::class::parse_compiled_class; -fn compress_contract(contract: CompiledContractClass) -> Vec { - StoredContractClass::from(contract).compress() +fn compress_contract(contract: CompiledClass) -> Vec { + Compress::compress(contract) } -fn decompress_contract(compressed: &[u8]) -> CompiledContractClass { - CompiledContractClass::from(StoredContractClass::decompress(compressed).unwrap()) +fn decompress_contract(compressed: &[u8]) -> CompiledClass { + ::decompress(compressed).unwrap() } fn compress_contract_with_main_codec(c: &mut Criterion) { - let class = parse_compiled_class(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let json = serde_json::from_str(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let class = parse_compiled_class(json).unwrap(); c.bench_function("compress world contract", |b| { b.iter_with_large_drop(|| compress_contract(black_box(class.clone()))) @@ -21,7 +21,8 @@ fn compress_contract_with_main_codec(c: &mut Criterion) { } fn decompress_contract_with_main_codec(c: &mut Criterion) { - let class = parse_compiled_class(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let json = serde_json::from_str(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let class = parse_compiled_class(json).unwrap(); let compressed = compress_contract(class); c.bench_function("decompress world contract", |b| { diff --git a/crates/katana/storage/db/src/codecs/postcard.rs b/crates/katana/storage/db/src/codecs/postcard.rs index fa692c5e8d..3b9ceb4338 100644 --- a/crates/katana/storage/db/src/codecs/postcard.rs +++ b/crates/katana/storage/db/src/codecs/postcard.rs @@ -3,11 +3,11 @@ use katana_primitives::contract::{ContractAddress, GenericContractInfo}; use katana_primitives::receipt::Receipt; use katana_primitives::transaction::Tx; use katana_primitives::FieldElement; +use postcard; use super::{Compress, Decompress}; use crate::error::CodecError; use crate::models::block::StoredBlockBodyIndices; -use crate::models::class::StoredContractClass; use crate::models::contract::ContractInfoChangeList; macro_rules! impl_compress_and_decompress_for_table_values { @@ -37,7 +37,6 @@ impl_compress_and_decompress_for_table_values!( FieldElement, ContractAddress, Vec, - StoredContractClass, GenericContractInfo, StoredBlockBodyIndices, ContractInfoChangeList diff --git a/crates/katana/storage/db/src/models/class.rs b/crates/katana/storage/db/src/models/class.rs index 42dd987fc9..f0d2a4a4b3 100644 --- a/crates/katana/storage/db/src/models/class.rs +++ b/crates/katana/storage/db/src/models/class.rs @@ -1,519 +1,17 @@ -//! Serializable without using custome functions +use katana_primitives::contract::CompiledClass; -use std::collections::HashMap; -use std::num::NonZeroUsize; -use std::sync::Arc; +use crate::codecs::{Compress, Decompress}; +use crate::error::CodecError; -use blockifier::execution::contract_class::{ - ContractClass, ContractClassV0, ContractClassV0Inner, ContractClassV1, ContractClassV1Inner, -}; -use cairo_vm::felt::Felt252; -use cairo_vm::hint_processor::hint_processor_definition::HintReference; -use cairo_vm::serde::deserialize_program::{ - ApTracking, Attribute, BuiltinName, FlowTrackingData, HintParams, Identifier, - InstructionLocation, Member, OffsetValue, -}; -use cairo_vm::types::program::{HintsCollection, Program, SharedProgramData}; -use cairo_vm::types::relocatable::MaybeRelocatable; -use serde::{Deserialize, Serialize}; -use starknet_api::core::EntryPointSelector; -use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType}; - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub enum StoredContractClass { - V0(StoredContractClassV0), - V1(StoredContractClassV1), -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct StoredContractClassV0 { - pub program: SerializableProgram, - pub entry_points_by_type: HashMap>, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct StoredContractClassV1 { - pub program: SerializableProgram, - pub hints: HashMap>, - pub entry_points_by_type: HashMap>, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableEntryPoint { - pub selector: EntryPointSelector, - pub offset: SerializableEntryPointOffset, -} - -impl From for SerializableEntryPoint { - fn from(value: EntryPoint) -> Self { - Self { selector: value.selector, offset: value.offset.into() } - } -} - -impl From for EntryPoint { - fn from(value: SerializableEntryPoint) -> Self { - Self { selector: value.selector, offset: value.offset.into() } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableEntryPointOffset(pub usize); - -impl From for SerializableEntryPointOffset { - fn from(value: EntryPointOffset) -> Self { - Self(value.0) - } -} - -impl From for EntryPointOffset { - fn from(value: SerializableEntryPointOffset) -> Self { - Self(value.0) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableEntryPointV1 { - pub selector: EntryPointSelector, - pub offset: SerializableEntryPointOffset, - pub builtins: Vec, -} - -impl From for blockifier::execution::contract_class::EntryPointV1 { - fn from(value: SerializableEntryPointV1) -> Self { - blockifier::execution::contract_class::EntryPointV1 { - selector: value.selector, - offset: value.offset.into(), - builtins: value.builtins, - } - } -} - -impl From for SerializableEntryPointV1 { - fn from(value: blockifier::execution::contract_class::EntryPointV1) -> Self { - SerializableEntryPointV1 { - selector: value.selector, - offset: value.offset.into(), - builtins: value.builtins, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableProgram { - pub shared_program_data: SerializableSharedProgramData, - pub constants: HashMap, - pub builtins: Vec, -} - -impl From for SerializableProgram { - fn from(value: Program) -> Self { - Self { - shared_program_data: value.shared_program_data.as_ref().clone().into(), - constants: value.constants, - builtins: value.builtins, - } - } -} - -impl From for Program { - fn from(value: SerializableProgram) -> Self { - Self { - shared_program_data: Arc::new(value.shared_program_data.into()), - constants: value.constants, - builtins: value.builtins, - } - } -} - -// Fields of `SerializableProgramData` must not rely on `deserialize_any` -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableSharedProgramData { - pub data: Vec, - pub hints_collection: SerializableHintsCollection, - pub main: Option, - pub start: Option, - pub end: Option, - pub error_message_attributes: Vec, - pub instruction_locations: Option>, - pub identifiers: HashMap, - pub reference_manager: Vec, -} - -impl From for SerializableSharedProgramData { - fn from(value: SharedProgramData) -> Self { - Self { - data: value.data, - hints_collection: value.hints_collection.into(), - main: value.main, - start: value.start, - end: value.end, - error_message_attributes: value - .error_message_attributes - .into_iter() - .map(|a| a.into()) - .collect(), - instruction_locations: value.instruction_locations, - identifiers: value.identifiers.into_iter().map(|(k, v)| (k, v.into())).collect(), - reference_manager: value.reference_manager.into_iter().map(|r| r.into()).collect(), - } - } -} - -impl From for SharedProgramData { - fn from(value: SerializableSharedProgramData) -> Self { - Self { - data: value.data, - hints_collection: value.hints_collection.into(), - main: value.main, - start: value.start, - end: value.end, - error_message_attributes: value - .error_message_attributes - .into_iter() - .map(|a| a.into()) - .collect(), - instruction_locations: value.instruction_locations, - identifiers: value.identifiers.into_iter().map(|(k, v)| (k, v.into())).collect(), - reference_manager: value.reference_manager.into_iter().map(|r| r.into()).collect(), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableHintParams { - pub code: String, - pub accessible_scopes: Vec, - pub flow_tracking_data: SerializableFlowTrackingData, -} - -impl From for SerializableHintParams { - fn from(value: HintParams) -> Self { - Self { - code: value.code, - accessible_scopes: value.accessible_scopes, - flow_tracking_data: value.flow_tracking_data.into(), - } - } -} - -impl From for HintParams { - fn from(value: SerializableHintParams) -> Self { - Self { - code: value.code, - accessible_scopes: value.accessible_scopes, - flow_tracking_data: value.flow_tracking_data.into(), - } - } -} - -type HintRange = Option<(usize, NonZeroUsize)>; - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableHintsCollection { - pub hints: Vec, - pub hints_ranges: Vec, -} - -impl From for SerializableHintsCollection { - fn from(value: HintsCollection) -> Self { - Self { - hints_ranges: value.hints_ranges, - hints: value.hints.into_iter().map(|h| h.into()).collect(), - } - } -} - -impl From for HintsCollection { - fn from(value: SerializableHintsCollection) -> Self { - Self { - hints_ranges: value.hints_ranges, - hints: value.hints.into_iter().map(|h| h.into()).collect(), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableIdentifier { - pub pc: Option, - pub type_: Option, - pub value: Option, - pub full_name: Option, - pub members: Option>, - pub cairo_type: Option, -} - -impl From for SerializableIdentifier { - fn from(value: Identifier) -> Self { - Self { - pc: value.pc, - type_: value.type_, - value: value.value, - full_name: value.full_name, - members: value.members, - cairo_type: value.cairo_type, - } - } -} - -impl From for Identifier { - fn from(value: SerializableIdentifier) -> Self { - Self { - pc: value.pc, - type_: value.type_, - value: value.value, - full_name: value.full_name, - members: value.members, - cairo_type: value.cairo_type, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableHintReference { - pub offset1: OffsetValue, - pub offset2: OffsetValue, - pub dereference: bool, - pub ap_tracking_data: Option, - pub cairo_type: Option, -} - -impl From for SerializableHintReference { - fn from(value: HintReference) -> Self { - Self { - offset1: value.offset1, - offset2: value.offset2, - dereference: value.dereference, - ap_tracking_data: value.ap_tracking_data, - cairo_type: value.cairo_type, - } - } -} - -impl From for HintReference { - fn from(value: SerializableHintReference) -> Self { - Self { - offset1: value.offset1, - offset2: value.offset2, - dereference: value.dereference, - ap_tracking_data: value.ap_tracking_data, - cairo_type: value.cairo_type, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableAttribute { - pub name: String, - pub start_pc: usize, - pub end_pc: usize, - pub value: String, - pub flow_tracking_data: Option, -} - -impl From for SerializableAttribute { - fn from(value: Attribute) -> Self { - Self { - name: value.name, - start_pc: value.start_pc, - end_pc: value.end_pc, - value: value.value, - flow_tracking_data: value.flow_tracking_data.map(|d| d.into()), - } - } -} - -impl From for Attribute { - fn from(value: SerializableAttribute) -> Self { - Self { - name: value.name, - start_pc: value.start_pc, - end_pc: value.end_pc, - value: value.value, - flow_tracking_data: value.flow_tracking_data.map(|d| d.into()), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableFlowTrackingData { - pub ap_tracking: ApTracking, - pub reference_ids: HashMap, -} - -impl From for SerializableFlowTrackingData { - fn from(value: FlowTrackingData) -> Self { - Self { ap_tracking: value.ap_tracking, reference_ids: value.reference_ids } +impl Compress for CompiledClass { + type Compressed = Vec; + fn compress(self) -> Self::Compressed { + serde_json::to_vec(&self).unwrap() } } -impl From for FlowTrackingData { - fn from(value: SerializableFlowTrackingData) -> Self { - Self { ap_tracking: value.ap_tracking, reference_ids: value.reference_ids } - } -} - -impl From for ContractClass { - fn from(value: StoredContractClass) -> Self { - match value { - StoredContractClass::V0(v0) => { - ContractClass::V0(ContractClassV0(Arc::new(ContractClassV0Inner { - program: v0.program.into(), - entry_points_by_type: v0 - .entry_points_by_type - .into_iter() - .map(|(k, v)| (k, v.into_iter().map(|h| h.into()).collect())) - .collect(), - }))) - } - StoredContractClass::V1(v1) => { - ContractClass::V1(ContractClassV1(Arc::new(ContractClassV1Inner { - hints: v1 - .hints - .clone() - .into_iter() - .map(|(k, v)| (k, serde_json::from_slice(&v).expect("valid hint"))) - .collect(), - program: v1.program.into(), - entry_points_by_type: v1 - .entry_points_by_type - .into_iter() - .map(|(k, v)| { - ( - k, - v.into_iter() - .map(Into::into) - .collect::>(), - ) - }) - .collect::>(), - }))) - } - } - } -} - -impl From for StoredContractClass { - fn from(value: ContractClass) -> Self { - match value { - ContractClass::V0(v0) => { - let entry_points_by_type = v0 - .entry_points_by_type - .clone() - .into_iter() - .map(|(k, v)| (k, v.into_iter().map(SerializableEntryPoint::from).collect())) - .collect(); - - StoredContractClass::V0(StoredContractClassV0 { - program: v0.program.clone().into(), - entry_points_by_type, - }) - } - - ContractClass::V1(v1) => StoredContractClass::V1(StoredContractClassV1 { - program: v1.program.clone().into(), - entry_points_by_type: v1 - .entry_points_by_type - .clone() - .into_iter() - .map(|(k, v)| { - ( - k, - v.into_iter() - .map(Into::into) - .collect::>(), - ) - }) - .collect::>(), - hints: v1 - .hints - .clone() - .into_iter() - .map(|(k, v)| (k, serde_json::to_vec(&v).expect("valid hint"))) - .collect(), - }), - } - } -} - -#[cfg(test)] -mod tests { - use cairo_lang_starknet::casm_contract_class::CasmContractClass; - use katana_primitives::contract::CompiledContractClass; - use starknet_api::hash::StarkFelt; - use starknet_api::stark_felt; - - use super::*; - use crate::codecs::{Compress, Decompress}; - - #[test] - fn serialize_deserialize_legacy_entry_points() { - let non_serde = vec![ - EntryPoint { - offset: EntryPointOffset(0x25f), - selector: EntryPointSelector(stark_felt!( - "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3" - )), - }, - EntryPoint { - offset: EntryPointOffset(0x1b2), - selector: EntryPointSelector(stark_felt!( - "0x29e211664c0b63c79638fbea474206ca74016b3e9a3dc4f9ac300ffd8bdf2cd" - )), - }, - EntryPoint { - offset: EntryPointOffset(0x285), - selector: EntryPointSelector(stark_felt!( - "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895" - )), - }, - ]; - - // convert to serde and back - let serde: Vec = - non_serde.iter().map(|e| e.clone().into()).collect(); - - // convert to json - let json = serde_json::to_vec(&serde).unwrap(); - let serde: Vec = serde_json::from_slice(&json).unwrap(); - - let same_non_serde: Vec = serde.iter().map(|e| e.clone().into()).collect(); - - assert_eq!(non_serde, same_non_serde); - } - - #[test] - fn compress_and_decompress_contract_class() { - let class = - serde_json::from_slice(include_bytes!("../../benches/artifacts/dojo_world_240.json")) - .unwrap(); - - let class = CasmContractClass::from_contract_class(class, true).unwrap(); - let class = CompiledContractClass::V1(ContractClassV1::try_from(class).unwrap()); - - let compressed = StoredContractClass::from(class.clone()).compress(); - let decompressed = ::decompress(compressed).unwrap(); - - let actual_class = CompiledContractClass::from(decompressed); - - assert_eq!(class, actual_class); - } - - #[test] - fn compress_and_decompress_legacy_contract_class() { - let class: ContractClassV0 = serde_json::from_slice(include_bytes!( - "../../../../primitives/contracts/compiled/account.json" - )) - .unwrap(); - - let class = CompiledContractClass::V0(class); - - let compressed = StoredContractClass::from(class.clone()).compress(); - let decompressed = ::decompress(compressed).unwrap(); - - let actual_class = CompiledContractClass::from(decompressed); - - assert_eq!(class, actual_class); +impl Decompress for CompiledClass { + fn decompress>(bytes: B) -> Result { + serde_json::from_slice(bytes.as_ref()).map_err(|e| CodecError::Decode(e.to_string())) } } diff --git a/crates/katana/storage/db/src/tables.rs b/crates/katana/storage/db/src/tables.rs index 4af836df20..ab601fc3a4 100644 --- a/crates/katana/storage/db/src/tables.rs +++ b/crates/katana/storage/db/src/tables.rs @@ -1,14 +1,13 @@ use katana_primitives::block::{BlockHash, BlockNumber, FinalityStatus, Header}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, - StorageKey, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, + GenericContractInfo, StorageKey, }; use katana_primitives::receipt::Receipt; use katana_primitives::transaction::{Tx, TxHash, TxNumber}; use crate::codecs::{Compress, Decode, Decompress, Encode}; use crate::models::block::StoredBlockBodyIndices; -use crate::models::class::StoredContractClass; use crate::models::contract::{ContractClassChange, ContractInfoChangeList, ContractNonceChange}; use crate::models::storage::{ ContractStorageEntry, ContractStorageKey, StorageEntry, StorageEntryChangeList, @@ -159,7 +158,7 @@ define_tables_enum! {[ (Transactions, TableType::Table), (Receipts, TableType::Table), (CompiledClassHashes, TableType::Table), - (CompiledContractClasses, TableType::Table), + (CompiledClasses, TableType::Table), (SierraClasses, TableType::Table), (ContractInfo, TableType::Table), (ContractStorage, TableType::DupSort), @@ -197,7 +196,7 @@ tables! { /// Store compiled classes CompiledClassHashes: (ClassHash) => CompiledClassHash, /// Store compiled contract classes according to its compiled class hash - CompiledContractClasses: (ClassHash) => StoredContractClass, + CompiledClasses: (ClassHash) => CompiledClass, /// Store Sierra classes according to its class hash SierraClasses: (ClassHash) => FlattenedSierraClass, /// Store contract information according to its contract address @@ -246,7 +245,7 @@ mod tests { assert_eq!(Tables::ALL[8].name(), Transactions::NAME); assert_eq!(Tables::ALL[9].name(), Receipts::NAME); assert_eq!(Tables::ALL[10].name(), CompiledClassHashes::NAME); - assert_eq!(Tables::ALL[11].name(), CompiledContractClasses::NAME); + assert_eq!(Tables::ALL[11].name(), CompiledClasses::NAME); assert_eq!(Tables::ALL[12].name(), SierraClasses::NAME); assert_eq!(Tables::ALL[13].name(), ContractInfo::NAME); assert_eq!(Tables::ALL[14].name(), ContractStorage::NAME); diff --git a/crates/katana/storage/provider/src/lib.rs b/crates/katana/storage/provider/src/lib.rs index baf44e836f..c03b4a020a 100644 --- a/crates/katana/storage/provider/src/lib.rs +++ b/crates/katana/storage/provider/src/lib.rs @@ -6,7 +6,7 @@ use katana_primitives::block::{ SealedBlockWithStatus, }; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, StorageKey, StorageValue, }; use katana_primitives::env::BlockEnv; @@ -248,7 +248,7 @@ where self.provider.compiled_class_hash_of_class_hash(hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { self.provider.class(hash) } @@ -304,7 +304,7 @@ impl ContractClassWriter for BlockchainProvider where Db: ContractClassWriter, { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.provider.set_class(hash, class) } diff --git a/crates/katana/storage/provider/src/providers/db/mod.rs b/crates/katana/storage/provider/src/providers/db/mod.rs index bf5ad85ca7..516ce46f31 100644 --- a/crates/katana/storage/provider/src/providers/db/mod.rs +++ b/crates/katana/storage/provider/src/providers/db/mod.rs @@ -587,7 +587,7 @@ impl BlockWriter for DbProvider { } for (hash, compiled_class) in states.declared_compiled_classes { - db_tx.put::(hash, compiled_class.into())?; + db_tx.put::(hash, compiled_class)?; } for (class_hash, sierra_class) in states.declared_sierra_classes { diff --git a/crates/katana/storage/provider/src/providers/db/state.rs b/crates/katana/storage/provider/src/providers/db/state.rs index e72b5cfbd1..0c9793be00 100644 --- a/crates/katana/storage/provider/src/providers/db/state.rs +++ b/crates/katana/storage/provider/src/providers/db/state.rs @@ -6,7 +6,7 @@ use katana_db::models::storage::{ContractStorageKey, StorageEntry}; use katana_db::tables; use katana_primitives::block::BlockNumber; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, Nonce, StorageKey, StorageValue, }; @@ -69,9 +69,9 @@ impl StateWriter for DbProvider { } impl ContractClassWriter for DbProvider { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.0.update(move |db_tx| -> ProviderResult<()> { - db_tx.put::(hash, class.into())?; + db_tx.put::(hash, class)?; Ok(()) })? } @@ -109,9 +109,9 @@ impl LatestStateProvider { } impl ContractClassProvider for LatestStateProvider { - fn class(&self, hash: ClassHash) -> ProviderResult> { - let class = self.0.get::(hash)?; - Ok(class.map(CompiledContractClass::from)) + fn class(&self, hash: ClassHash) -> ProviderResult> { + let class = self.0.get::(hash)?; + Ok(class) } fn compiled_class_hash_of_class_hash( @@ -222,10 +222,10 @@ impl ContractClassProvider for HistoricalStateProvider { } } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if self.compiled_class_hash_of_class_hash(hash)?.is_some() { - let contract = self.tx.get::(hash)?; - Ok(contract.map(CompiledContractClass::from)) + let contract = self.tx.get::(hash)?; + Ok(contract) } else { Ok(None) } diff --git a/crates/katana/storage/provider/src/providers/fork/backend.rs b/crates/katana/storage/provider/src/providers/fork/backend.rs index 41f92f63f2..ea5a5940ed 100644 --- a/crates/katana/storage/provider/src/providers/fork/backend.rs +++ b/crates/katana/storage/provider/src/providers/fork/backend.rs @@ -11,12 +11,12 @@ use futures::stream::Stream; use futures::{Future, FutureExt}; use katana_primitives::block::BlockHashOrNumber; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, Nonce, StorageKey, StorageValue, }; use katana_primitives::conversion::rpc::{ compiled_class_hash_from_flattened_sierra_class, flattened_sierra_to_compiled_class, - legacy_rpc_to_inner_compiled_class, + legacy_rpc_to_compiled_class, }; use katana_primitives::FieldElement; use parking_lot::Mutex; @@ -449,7 +449,7 @@ impl ContractClassProvider for SharedStateProvider { } } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if let Some(class) = self.0.shared_contract_classes.compiled_classes.read().get(&hash) { return Ok(Some(class.clone())); } @@ -465,7 +465,7 @@ impl ContractClassProvider for SharedStateProvider { let (class_hash, compiled_class_hash, casm, sierra) = match class { ContractClass::Legacy(class) => { - let (_, compiled_class) = legacy_rpc_to_inner_compiled_class(&class).map_err(|e| { + let (_, compiled_class) = legacy_rpc_to_compiled_class(&class).map_err(|e| { error!(target: "forked_backend", "error while parsing legacy class {hash:#x}: {e}"); ProviderError::ParsingError(e.to_string()) })?; diff --git a/crates/katana/storage/provider/src/providers/fork/mod.rs b/crates/katana/storage/provider/src/providers/fork/mod.rs index 0f1f6558f5..47c644bb26 100644 --- a/crates/katana/storage/provider/src/providers/fork/mod.rs +++ b/crates/katana/storage/provider/src/providers/fork/mod.rs @@ -10,7 +10,7 @@ use katana_primitives::block::{ SealedBlockWithStatus, }; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, }; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; @@ -464,7 +464,7 @@ impl BlockWriter for ForkedProvider { } impl ContractClassWriter for ForkedProvider { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.state.shared_contract_classes.compiled_classes.write().insert(hash, class); Ok(()) } diff --git a/crates/katana/storage/provider/src/providers/fork/state.rs b/crates/katana/storage/provider/src/providers/fork/state.rs index a607f27f6d..3593cda493 100644 --- a/crates/katana/storage/provider/src/providers/fork/state.rs +++ b/crates/katana/storage/provider/src/providers/fork/state.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, Nonce, StorageKey, StorageValue, }; @@ -83,7 +83,7 @@ impl ContractClassProvider for CacheStateDb { ContractClassProvider::compiled_class_hash_of_class_hash(&self.db, hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if let class @ Some(_) = self.shared_contract_classes.compiled_classes.read().get(&hash) { return Ok(class.cloned()); } @@ -125,7 +125,7 @@ impl ContractClassProvider for LatestStateProvider { ContractClassProvider::sierra_class(&self.0, hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { ContractClassProvider::class(&self.0, hash) } @@ -199,7 +199,7 @@ impl ContractClassProvider for ForkedSnapshot { ContractClassProvider::compiled_class_hash_of_class_hash(&self.inner.db, hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if self.inner.compiled_class_hashes.get(&hash).is_some() { Ok(self.classes.compiled_classes.read().get(&hash).cloned()) } else { diff --git a/crates/katana/storage/provider/src/providers/in_memory/cache.rs b/crates/katana/storage/provider/src/providers/in_memory/cache.rs index 43ad2a33e8..01e44a924e 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/cache.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/cache.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use katana_db::models::block::StoredBlockBodyIndices; use katana_primitives::block::{BlockHash, BlockNumber, FinalityStatus, Header}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, StorageKey, StorageValue, }; use katana_primitives::receipt::Receipt; @@ -16,7 +16,7 @@ type ContractStorageMap = HashMap; type SierraClassesMap = HashMap; -type CompiledClassesMap = HashMap; +type CompiledClassesMap = HashMap; type CompiledClassHashesMap = HashMap; #[derive(Default)] diff --git a/crates/katana/storage/provider/src/providers/in_memory/mod.rs b/crates/katana/storage/provider/src/providers/in_memory/mod.rs index daaef199dd..e52898c6ca 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/mod.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/mod.rs @@ -10,7 +10,7 @@ use katana_primitives::block::{ SealedBlockWithStatus, }; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, }; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; @@ -458,7 +458,7 @@ impl BlockWriter for InMemoryProvider { } impl ContractClassWriter for InMemoryProvider { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.state.shared_contract_classes.compiled_classes.write().insert(hash, class); Ok(()) } diff --git a/crates/katana/storage/provider/src/providers/in_memory/state.rs b/crates/katana/storage/provider/src/providers/in_memory/state.rs index aba2343a74..195adbedf2 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/state.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/state.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use katana_primitives::block::BlockNumber; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, Nonce, StorageKey, StorageValue, }; @@ -157,7 +157,7 @@ impl ContractClassProvider for InMemorySnapshot { } } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if self.compiled_class_hash_of_class_hash(hash)?.is_some() { Ok(self.classes.compiled_classes.read().get(&hash).cloned()) } else { @@ -213,7 +213,7 @@ impl ContractClassProvider for LatestStateProvider { Ok(class) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { let class = self.0.shared_contract_classes.compiled_classes.read().get(&hash).cloned(); Ok(class) } diff --git a/crates/katana/storage/provider/src/traits/contract.rs b/crates/katana/storage/provider/src/traits/contract.rs index d8ea80ccb5..d832b33063 100644 --- a/crates/katana/storage/provider/src/traits/contract.rs +++ b/crates/katana/storage/provider/src/traits/contract.rs @@ -1,5 +1,5 @@ use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, }; @@ -21,7 +21,7 @@ pub trait ContractClassProvider: Send + Sync { ) -> ProviderResult>; /// Returns the compiled class definition of a contract class given its class hash. - fn class(&self, hash: ClassHash) -> ProviderResult>; + fn class(&self, hash: ClassHash) -> ProviderResult>; /// Retrieves the Sierra class definition of a contract class given its class hash. fn sierra_class(&self, hash: ClassHash) -> ProviderResult>; @@ -38,7 +38,7 @@ pub trait ContractClassWriter: Send + Sync { ) -> ProviderResult<()>; /// Returns the compiled class definition of a contract class given its class hash. - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()>; + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()>; /// Retrieves the Sierra class definition of a contract class given its class hash. fn set_sierra_class(&self, hash: ClassHash, sierra: FlattenedSierraClass) diff --git a/crates/katana/storage/provider/tests/class.rs b/crates/katana/storage/provider/tests/class.rs index b0c9cf9d65..39c0574424 100644 --- a/crates/katana/storage/provider/tests/class.rs +++ b/crates/katana/storage/provider/tests/class.rs @@ -7,7 +7,7 @@ use fixtures::{ }; use katana_primitives::block::{BlockHashOrNumber, BlockNumber}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, FlattenedSierraClass, + ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass, }; use katana_primitives::genesis::constant::{ DEFAULT_LEGACY_ERC20_CONTRACT_CASM, DEFAULT_LEGACY_UDC_CASM, @@ -19,12 +19,8 @@ use katana_provider::BlockchainProvider; use rstest_reuse::{self, *}; use starknet::macros::felt; -type ClassHashAndClasses = ( - ClassHash, - Option, - Option, - Option, -); +type ClassHashAndClasses = + (ClassHash, Option, Option, Option); fn assert_state_provider_class( state_provider: Box, @@ -38,7 +34,7 @@ fn assert_state_provider_class( let actual_sierra_class = state_provider.sierra_class(class_hash)?; assert!( - if let Some(CompiledContractClass::V1(_)) = &actual_compiled_class { + if let Some(CompiledClass::Class(_)) = &actual_compiled_class { actual_sierra_class.is_some() } else { actual_sierra_class.is_none() diff --git a/crates/katana/storage/provider/tests/fixtures.rs b/crates/katana/storage/provider/tests/fixtures.rs index fe5cf28f89..a1591fceed 100644 --- a/crates/katana/storage/provider/tests/fixtures.rs +++ b/crates/katana/storage/provider/tests/fixtures.rs @@ -6,7 +6,7 @@ use katana_primitives::block::{ BlockHashOrNumber, FinalityStatus, Header, SealedBlock, SealedBlockWithStatus, SealedHeader, }; use katana_primitives::contract::{ - CompiledContractClass, ContractAddress, FlattenedSierraClass, SierraClass, + CompiledClass, ContractAddress, FlattenedSierraClass, SierraClass, }; use katana_primitives::genesis::constant::{ DEFAULT_LEGACY_ERC20_CONTRACT_CASM, DEFAULT_LEGACY_UDC_CASM, @@ -32,9 +32,12 @@ lazy_static! { let provider = runner.owned_provider(); (runner, Arc::new(provider)) }; - pub static ref DOJO_WORLD_COMPILED_CLASS: CompiledContractClass = - parse_compiled_class(include_str!("../../db/benches/artifacts/dojo_world_240.json")) - .unwrap(); + pub static ref DOJO_WORLD_COMPILED_CLASS: CompiledClass = { + let json = + serde_json::from_str(include_str!("../../db/benches/artifacts/dojo_world_240.json")) + .unwrap(); + parse_compiled_class(json).unwrap() + }; pub static ref DOJO_WORLD_SIERRA_CLASS: FlattenedSierraClass = { let sierra_class: SierraClass = serde_json::from_str(include_str!("../../db/benches/artifacts/dojo_world_240.json"))