diff --git a/Cargo.lock b/Cargo.lock index 847f3a4c48..85c85c7aef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1501,6 +1501,7 @@ dependencies = [ "indexmap 2.6.0", "itertools 0.12.1", "keccak", + "lazy_static", "log", "num-bigint 0.4.6", "num-integer", diff --git a/crates/blockifier/Cargo.toml b/crates/blockifier/Cargo.toml index 91a021fb75..6e919383f3 100644 --- a/crates/blockifier/Cargo.toml +++ b/crates/blockifier/Cargo.toml @@ -35,6 +35,7 @@ derive_more.workspace = true indexmap.workspace = true itertools.workspace = true keccak.workspace = true +lazy_static.workspace = true log.workspace = true num-bigint.workspace = true num-integer.workspace = true diff --git a/crates/blockifier/src/execution/native/contract_class.rs b/crates/blockifier/src/execution/native/contract_class.rs index b4ec966e9d..9189647de8 100644 --- a/crates/blockifier/src/execution/native/contract_class.rs +++ b/crates/blockifier/src/execution/native/contract_class.rs @@ -13,6 +13,7 @@ use crate::execution::contract_class::{ContractClassV1, EntryPointsByType, HasSe use crate::execution::entry_point::CallEntryPoint; use crate::execution::errors::PreExecutionError; use crate::execution::native::utils::contract_entrypoint_to_entrypoint_selector; + #[derive(Clone, Debug, PartialEq, Eq)] pub struct NativeContractClassV1(pub Arc); impl Deref for NativeContractClassV1 { diff --git a/crates/blockifier/src/test_utils/contracts.rs b/crates/blockifier/src/test_utils/contracts.rs index a19ee4501e..9a40676aec 100644 --- a/crates/blockifier/src/test_utils/contracts.rs +++ b/crates/blockifier/src/test_utils/contracts.rs @@ -188,7 +188,10 @@ impl FeatureContract { pub fn get_runnable_class(&self) -> RunnableContractClass { #[cfg(feature = "cairo_native")] if CairoVersion::Native == self.cairo_version() { - let native_contract_class = NativeContractClassV1::from_file(&self.get_compiled_path()); + let native_contract_class = + NativeContractClassV1::compile_or_get_cached(&self.get_compiled_path()).into(); + // let native_contract_class = + // NativeContractClassV1::from_file(&self.get_compiled_path()); return RunnableContractClass::V1Native(native_contract_class); } diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index bc2fa03d99..49ab34e953 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -1,4 +1,8 @@ +#[cfg(feature = "cairo_native")] +use std::collections::HashMap; use std::sync::Arc; +#[cfg(feature = "cairo_native")] +use std::sync::RwLock; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; #[cfg(feature = "cairo_native")] @@ -6,6 +10,8 @@ use cairo_lang_starknet_classes::contract_class::ContractClass as SierraContract #[cfg(feature = "cairo_native")] use cairo_native::executor::AotContractExecutor; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +#[cfg(feature = "cairo_native")] +use lazy_static::lazy_static; use serde_json::Value; use starknet_api::block::{BlockNumber, BlockTimestamp, NonzeroGasPrice}; use starknet_api::contract_address; @@ -238,6 +244,12 @@ impl BouncerWeights { } } +#[cfg(feature = "cairo_native")] +lazy_static! { + /// A cache for compiled native contract classes. + static ref CACHED: RwLock> = RwLock::new(HashMap::new()); +} + #[cfg(feature = "cairo_native")] impl NativeContractClassV1 { /// Convenience function to construct a NativeContractClassV1 from a raw contract class. @@ -270,4 +282,21 @@ impl NativeContractClassV1 { let raw_contract_class = get_raw_contract_class(contract_path); Self::try_from_json_string(&raw_contract_class) } + + /// Compile a contract from a file or get it from the cache. + pub fn compile_or_get_cached(path: &str) -> NativeContractClassV1 { + { + let cache = CACHED.read().unwrap(); + if let Some(cached_class) = cache.get(path) { + return cached_class.clone(); + } + } + + let class = NativeContractClassV1::from_file(path); + + let mut cache = CACHED.write().unwrap(); + cache.insert(path.to_string(), class.clone()); + + class + } }