From 1683c47654ab78c84173f11c20ef9f47270215b3 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware Date: Tue, 3 Dec 2024 11:47:21 +0200 Subject: [PATCH] refactor(blockifier): min compiler version for sierra gas type --- .../src/execution/contract_class.rs | 27 ++++++++----------- .../src/execution/contract_class_test.rs | 2 +- crates/blockifier/src/test_utils/contracts.rs | 7 ++--- .../blockifier/src/test_utils/struct_impls.rs | 13 ++++++++- crates/blockifier/src/versioned_constants.rs | 3 ++- .../src/state_reader/compile.rs | 2 +- .../src/py_block_executor_test.rs | 10 +++++-- .../papyrus_execution/src/execution_utils.rs | 5 ++-- crates/papyrus_execution/src/lib.rs | 4 +-- crates/papyrus_execution/src/state_reader.rs | 8 +++--- .../src/state_reader_test.rs | 13 ++++++--- .../papyrus_state_reader/src/papyrus_state.rs | 8 +++--- crates/starknet_api/src/contract_class.rs | 10 ++++--- crates/starknet_gateway/src/compilation.rs | 5 ++-- .../starknet_gateway/src/rpc_state_reader.rs | 6 ++--- .../src/rpc_state_reader_test.rs | 7 ++++- 16 files changed, 81 insertions(+), 49 deletions(-) diff --git a/crates/blockifier/src/execution/contract_class.rs b/crates/blockifier/src/execution/contract_class.rs index 976397bd182..2e88fc4d403 100644 --- a/crates/blockifier/src/execution/contract_class.rs +++ b/crates/blockifier/src/execution/contract_class.rs @@ -18,10 +18,9 @@ use cairo_vm::types::program::Program; use cairo_vm::types::relocatable::MaybeRelocatable; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use itertools::Itertools; -use semver::Version; use serde::de::Error as DeserializationError; use serde::{Deserialize, Deserializer, Serialize}; -use starknet_api::contract_class::{ContractClass, EntryPointType, SierraVersion}; +use starknet_api::contract_class::{ContractClass, EntryPointType, SierraVersion, VersionedCasm}; use starknet_api::core::EntryPointSelector; use starknet_api::deprecated_contract_class::{ ContractClass as DeprecatedContractClass, @@ -38,7 +37,6 @@ use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo #[cfg(feature = "cairo_native")] use crate::execution::native::contract_class::NativeCompiledClassV1; use crate::transaction::errors::TransactionExecutionError; -use crate::versioned_constants::CompilerVersion; #[cfg(test)] #[path = "contract_class_test.rs"] @@ -93,7 +91,7 @@ impl TryFrom for RunnableCompiledClass { fn try_from(raw_contract_class: ContractClass) -> Result { let contract_class: Self = match raw_contract_class { ContractClass::V0(raw_contract_class) => Self::V0(raw_contract_class.try_into()?), - ContractClass::V1(raw_contract_class) => Self::V1(raw_contract_class.try_into()?), + ContractClass::V1(versioned_casm) => Self::V1(versioned_casm.try_into()?), }; Ok(contract_class) @@ -151,7 +149,7 @@ impl RunnableCompiledClass { /// Returns whether this contract should run using Cairo steps or Sierra gas. pub fn tracked_resource( &self, - min_sierra_version: &CompilerVersion, + min_sierra_version: &SierraVersion, last_tracked_resource: Option<&TrackedResource>, ) -> TrackedResource { let contract_tracked_resource = match self { @@ -283,8 +281,8 @@ impl CompiledClassV1 { } /// Returns whether this contract should run using Cairo steps or Sierra gas. - pub fn tracked_resource(&self, min_sierra_version: &CompilerVersion) -> TrackedResource { - if *min_sierra_version <= self.compiler_version { + pub fn tracked_resource(&self, min_sierra_version: &SierraVersion) -> TrackedResource { + if *min_sierra_version <= self.sierra_version { TrackedResource::SierraGas } else { TrackedResource::CairoSteps @@ -310,7 +308,8 @@ impl CompiledClassV1 { pub fn try_from_json_string(raw_contract_class: &str) -> Result { let casm_contract_class: CasmContractClass = serde_json::from_str(raw_contract_class)?; - let contract_class = CompiledClassV1::try_from(casm_contract_class)?; + let sierra_version = SierraVersion::default(); + let contract_class = CompiledClassV1::try_from((casm_contract_class, sierra_version))?; Ok(contract_class) } @@ -412,7 +411,7 @@ pub struct ContractClassV1Inner { pub program: Program, pub entry_points_by_type: EntryPointsByType, pub hints: HashMap, - pub compiler_version: CompilerVersion, + pub sierra_version: SierraVersion, bytecode_segment_lengths: NestedIntList, } @@ -435,10 +434,10 @@ impl HasSelector for EntryPointV1 { } } -impl TryFrom for CompiledClassV1 { +impl TryFrom for CompiledClassV1 { type Error = ProgramError; - fn try_from(class: CasmContractClass) -> Result { + fn try_from((class, sierra_version): VersionedCasm) -> Result { let data: Vec = class.bytecode.iter().map(|x| MaybeRelocatable::from(Felt::from(&x.value))).collect(); @@ -484,15 +483,11 @@ impl TryFrom for CompiledClassV1 { let bytecode_segment_lengths = class .bytecode_segment_lengths .unwrap_or_else(|| NestedIntList::Leaf(program.data_len())); - let compiler_version = CompilerVersion( - Version::parse(&class.compiler_version) - .unwrap_or_else(|_| panic!("Invalid version: '{}'", class.compiler_version)), - ); Ok(CompiledClassV1(Arc::new(ContractClassV1Inner { program, entry_points_by_type, hints: string_to_hint, - compiler_version, + sierra_version, bytecode_segment_lengths, }))) } diff --git a/crates/blockifier/src/execution/contract_class_test.rs b/crates/blockifier/src/execution/contract_class_test.rs index bbf9bedc6c2..15a76af858c 100644 --- a/crates/blockifier/src/execution/contract_class_test.rs +++ b/crates/blockifier/src/execution/contract_class_test.rs @@ -14,7 +14,7 @@ fn test_get_visited_segments() { program: Default::default(), entry_points_by_type: Default::default(), hints: Default::default(), - compiler_version: Default::default(), + sierra_version: Default::default(), bytecode_segment_lengths: NestedIntList::Node(vec![ NestedIntList::Leaf(151), NestedIntList::Leaf(104), diff --git a/crates/blockifier/src/test_utils/contracts.rs b/crates/blockifier/src/test_utils/contracts.rs index 66ae844cced..b9e24b0b846 100644 --- a/crates/blockifier/src/test_utils/contracts.rs +++ b/crates/blockifier/src/test_utils/contracts.rs @@ -169,9 +169,10 @@ impl FeatureContract { CairoVersion::Cairo0 => { ContractClass::V0(DeprecatedContractClass::from_file(&self.get_compiled_path())) } - CairoVersion::Cairo1(RunnableCairo1::Casm) => { - ContractClass::V1(CasmContractClass::from_file(&self.get_compiled_path())) - } + CairoVersion::Cairo1(RunnableCairo1::Casm) => ContractClass::V1(( + CasmContractClass::from_file(&self.get_compiled_path()), + self.get_sierra_version(), + )), #[cfg(feature = "cairo_native")] CairoVersion::Cairo1(RunnableCairo1::Native) => { panic!("Native contracts are not supported by this function.") diff --git a/crates/blockifier/src/test_utils/struct_impls.rs b/crates/blockifier/src/test_utils/struct_impls.rs index fe9fdebff55..a16d98db0ac 100644 --- a/crates/blockifier/src/test_utils/struct_impls.rs +++ b/crates/blockifier/src/test_utils/struct_impls.rs @@ -12,6 +12,7 @@ use cairo_native::executor::AotContractExecutor; use serde_json::Value; use starknet_api::block::{BlockInfo, BlockNumber, BlockTimestamp, NonzeroGasPrice}; use starknet_api::contract_address; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ChainId, ClassHash}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; @@ -262,6 +263,16 @@ impl NativeCompiledClassV1 { .extract_sierra_program() .expect("Cannot extract sierra program from sierra contract class"); + let sierra_version_values = sierra_contract_class + .sierra_program + .iter() + .take(3) + .map(|x| x.value.clone()) + .collect::>(); + + let sierra_version = SierraVersion::extract_from_program(&sierra_version_values) + .expect("Cannot extract sierra version from sierra program"); + let executor = AotContractExecutor::new( &sierra_program, &sierra_contract_class.entry_points_by_type, @@ -273,7 +284,7 @@ impl NativeCompiledClassV1 { let casm_contract_class = CasmContractClass::from_contract_class(sierra_contract_class, false, usize::MAX) .expect("Cannot compile sierra contract class into casm contract class"); - let casm = CompiledClassV1::try_from(casm_contract_class) + let casm = CompiledClassV1::try_from((casm_contract_class, sierra_version)) .expect("Cannot get CompiledClassV1 from CasmContractClass"); NativeCompiledClassV1::new(executor, casm) diff --git a/crates/blockifier/src/versioned_constants.rs b/crates/blockifier/src/versioned_constants.rs index 9e46492fa80..5f516e072ec 100644 --- a/crates/blockifier/src/versioned_constants.rs +++ b/crates/blockifier/src/versioned_constants.rs @@ -17,6 +17,7 @@ use serde::de::Error as DeserializationError; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::{Map, Number, Value}; use starknet_api::block::{GasPrice, StarknetVersion}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::ContractAddress; use starknet_api::execution_resources::{GasAmount, GasVector}; use starknet_api::transaction::fields::GasVectorComputationMode; @@ -185,7 +186,7 @@ pub struct VersionedConstants { pub max_recursion_depth: usize, pub validate_max_n_steps: u32, pub validate_max_sierra_gas: GasAmount, - pub min_compiler_version_for_sierra_gas: CompilerVersion, + pub min_compiler_version_for_sierra_gas: SierraVersion, // BACKWARD COMPATIBILITY: If true, the segment_arena builtin instance counter will be // multiplied by 3. This offsets a bug in the old vm where the counter counted the number of // cells used by instances of the builtin, instead of the number of instances. diff --git a/crates/blockifier_reexecution/src/state_reader/compile.rs b/crates/blockifier_reexecution/src/state_reader/compile.rs index 7e1f8b901ea..05a51cbae60 100644 --- a/crates/blockifier_reexecution/src/state_reader/compile.rs +++ b/crates/blockifier_reexecution/src/state_reader/compile.rs @@ -102,7 +102,7 @@ pub fn sierra_to_versioned_contract_class_v1( ) // TODO(Aviv): Reconsider the unwrap. .unwrap(); - Ok((ContractClass::V1(casm), sierra_version)) + Ok((ContractClass::V1((casm, sierra_version.clone())), sierra_version)) } /// Compile a CompressedLegacyContractClass to a ContractClass V0 using cairo_lang_starknet_classes. diff --git a/crates/native_blockifier/src/py_block_executor_test.rs b/crates/native_blockifier/src/py_block_executor_test.rs index d223df4657a..2b359d8e151 100644 --- a/crates/native_blockifier/src/py_block_executor_test.rs +++ b/crates/native_blockifier/src/py_block_executor_test.rs @@ -7,6 +7,7 @@ use cached::Cached; use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use pretty_assertions::assert_eq; use starknet_api::class_hash; +use starknet_api::contract_class::SierraVersion; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::state::SierraContractClass; use starknet_types_core::felt::Felt; @@ -32,8 +33,13 @@ fn global_contract_cache_update() { entry_points_by_type: Default::default(), }; let sierra = SierraContractClass::default(); - let contract_class = - RunnableCompiledClass::V1(CompiledClassV1::try_from(casm.clone()).unwrap()); + let contract_class = RunnableCompiledClass::V1( + CompiledClassV1::try_from(( + casm.clone(), + SierraVersion::extract_from_program(&sierra.sierra_program).unwrap(), + )) + .unwrap(), + ); let class_hash = class_hash!("0x1"); let temp_storage_path = tempfile::tempdir().unwrap().into_path(); diff --git a/crates/papyrus_execution/src/execution_utils.rs b/crates/papyrus_execution/src/execution_utils.rs index ac1d986419a..63edee929f5 100644 --- a/crates/papyrus_execution/src/execution_utils.rs +++ b/crates/papyrus_execution/src/execution_utils.rs @@ -70,10 +70,11 @@ pub(crate) fn get_versioned_contract_class( let (Some(casm), Some(sierra)) = txn.get_casm_and_sierra(class_hash)? else { return Err(ExecutionUtilsError::CasmTableNotSynced); }; + let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program)?; let runnable_compiled_class = RunnableCompiledClass::V1( - CompiledClassV1::try_from(casm).map_err(ExecutionUtilsError::ProgramError)?, + CompiledClassV1::try_from((casm, sierra_version.clone())) + .map_err(ExecutionUtilsError::ProgramError)?, ); - let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program)?; return Ok(Some(VersionedRunnableCompiledClass::Cairo1(( runnable_compiled_class, sierra_version, diff --git a/crates/papyrus_execution/src/lib.rs b/crates/papyrus_execution/src/lib.rs index bb16e097a87..5f9db37b84b 100644 --- a/crates/papyrus_execution/src/lib.rs +++ b/crates/papyrus_execution/src/lib.rs @@ -894,7 +894,7 @@ fn to_blockifier_tx( sierra_version, ) => { let class_info = ClassInfo::new( - &compiled_class.into(), + &(compiled_class, sierra_version.clone()).into(), sierra_program_length, abi_length, sierra_version, @@ -923,7 +923,7 @@ fn to_blockifier_tx( sierra_version, ) => { let class_info = ClassInfo::new( - &compiled_class.into(), + &(compiled_class, sierra_version.clone()).into(), sierra_program_length, abi_length, sierra_version, diff --git a/crates/papyrus_execution/src/state_reader.rs b/crates/papyrus_execution/src/state_reader.rs index da3377d71c4..e34bc62b348 100644 --- a/crates/papyrus_execution/src/state_reader.rs +++ b/crates/papyrus_execution/src/state_reader.rs @@ -88,10 +88,12 @@ impl BlockifierStateReader for ExecutionStateReader { .and_then(|pending_data| pending_data.classes.get_class(class_hash)) { let runnable_compiled_class = RunnableCompiledClass::V1( - CompiledClassV1::try_from(pending_casm).map_err(StateError::ProgramError)?, + CompiledClassV1::try_from(( + pending_casm, + SierraVersion::extract_from_program(&sierra.sierra_program)?, + )) + .map_err(StateError::ProgramError)?, ); - let _sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program)?; - // TODO(AVIV): Use the sierra version when the return type is updated. return Ok(runnable_compiled_class); } } diff --git a/crates/papyrus_execution/src/state_reader_test.rs b/crates/papyrus_execution/src/state_reader_test.rs index 93a71249655..afc79697364 100644 --- a/crates/papyrus_execution/src/state_reader_test.rs +++ b/crates/papyrus_execution/src/state_reader_test.rs @@ -24,6 +24,7 @@ use papyrus_storage::header::HeaderStorageWriter; use papyrus_storage::state::StateStorageWriter; use papyrus_storage::test_utils::get_test_storage; use starknet_api::block::{BlockBody, BlockHash, BlockHeader, BlockHeaderWithoutHash, BlockNumber}; +use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, CompiledClassHash, Nonce}; use starknet_api::hash::StarkHash; use starknet_api::state::{SierraContractClass, StateNumber, ThinStateDiff}; @@ -48,9 +49,11 @@ fn read_state() { let storage_value1 = felt!(888_u128); // The class is not used in the execution, so it can be default. let class0 = SierraContractClass::default(); + let sierra_version0 = SierraVersion::extract_from_program(&class0.sierra_program).unwrap(); let casm0 = get_test_casm(); - let blockifier_casm0 = - RunnableCompiledClass::V1(CompiledClassV1::try_from(casm0.clone()).unwrap()); + let blockifier_casm0 = RunnableCompiledClass::V1( + CompiledClassV1::try_from((casm0.clone(), sierra_version0)).unwrap(), + ); let compiled_class_hash0 = CompiledClassHash(StarkHash::default()); let class_hash1 = ClassHash(1u128.into()); @@ -65,8 +68,10 @@ fn read_state() { let mut casm2 = get_test_casm(); casm2.bytecode[0] = BigUintAsHex { value: 12345u32.into() }; let class2 = SierraContractClass::default(); - let blockifier_casm2 = - RunnableCompiledClass::V1(CompiledClassV1::try_from(casm2.clone()).unwrap()); + let sierra_version2 = SierraVersion::extract_from_program(&class2.sierra_program).unwrap(); + let blockifier_casm2 = RunnableCompiledClass::V1( + CompiledClassV1::try_from((casm2.clone(), sierra_version2)).unwrap(), + ); let nonce1 = Nonce(felt!(2_u128)); let class_hash3 = ClassHash(567_u128.into()); let class_hash4 = ClassHash(89_u128.into()); diff --git a/crates/papyrus_state_reader/src/papyrus_state.rs b/crates/papyrus_state_reader/src/papyrus_state.rs index bfa5e01c41f..3346e2b2ee4 100644 --- a/crates/papyrus_state_reader/src/papyrus_state.rs +++ b/crates/papyrus_state_reader/src/papyrus_state.rs @@ -49,6 +49,7 @@ impl PapyrusReader { &self, class_hash: ClassHash, ) -> StateResult { + // TODO(AVIV): Return RunnableCompiledClass. let state_number = StateNumber(self.latest_block); let class_declaration_block_number = self .reader()? @@ -69,9 +70,10 @@ impl PapyrusReader { database is inconsistent.", ); let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program)?; - let runnable_compiled = - RunnableCompiledClass::V1(CompiledClassV1::try_from(casm_compiled_class)?); - + let runnable_compiled = RunnableCompiledClass::V1(CompiledClassV1::try_from(( + casm_compiled_class, + sierra_version.clone(), + ))?); return Ok(VersionedRunnableCompiledClass::Cairo1((runnable_compiled, sierra_version))); } diff --git a/crates/starknet_api/src/contract_class.rs b/crates/starknet_api/src/contract_class.rs index c8a295d57aa..e418f66f835 100644 --- a/crates/starknet_api/src/contract_class.rs +++ b/crates/starknet_api/src/contract_class.rs @@ -30,25 +30,27 @@ pub enum EntryPointType { L1Handler, } +pub type VersionedCasm = (CasmContractClass, SierraVersion); + /// Represents a raw Starknet contract class. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, derive_more::From)] pub enum ContractClass { V0(DeprecatedContractClass), - V1(CasmContractClass), + V1(VersionedCasm), } impl ContractClass { pub fn compiled_class_hash(&self) -> CompiledClassHash { match self { ContractClass::V0(_) => panic!("Cairo 0 doesn't have compiled class hash."), - ContractClass::V1(casm_contract_class) => { + ContractClass::V1((casm_contract_class, _sierra_version)) => { CompiledClassHash(casm_contract_class.compiled_class_hash()) } } } } -#[derive(Deref, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +#[derive(Deref, Serialize, Deserialize, Clone, Debug, Eq, PartialEq, PartialOrd)] pub struct SierraVersion(Version); impl SierraVersion { @@ -132,7 +134,7 @@ impl ClassInfo { pub fn bytecode_length(&self) -> usize { match &self.contract_class { ContractClass::V0(contract_class) => contract_class.bytecode_length(), - ContractClass::V1(contract_class) => contract_class.bytecode.len(), + ContractClass::V1((contract_class, _sierra_version)) => contract_class.bytecode.len(), } } diff --git a/crates/starknet_gateway/src/compilation.rs b/crates/starknet_gateway/src/compilation.rs index b446aa7fb07..393194c9a0f 100644 --- a/crates/starknet_gateway/src/compilation.rs +++ b/crates/starknet_gateway/src/compilation.rs @@ -39,12 +39,13 @@ impl GatewayCompiler { let rpc_contract_class = &tx.contract_class; let cairo_lang_contract_class = into_contract_class_for_compilation(rpc_contract_class); - let casm_contract_class = self.compile(cairo_lang_contract_class)?; - let sierra_version = SierraVersion::extract_from_program(&rpc_contract_class.sierra_program) .map_err(|e| GatewaySpecError::UnexpectedError { data: (e.to_string()) })?; + let casm_contract_class = + (self.compile(cairo_lang_contract_class)?, sierra_version.clone()).into(); + Ok(ClassInfo { contract_class: ContractClass::V1(casm_contract_class), sierra_program_length: rpc_contract_class.sierra_program.len(), diff --git a/crates/starknet_gateway/src/rpc_state_reader.rs b/crates/starknet_gateway/src/rpc_state_reader.rs index 62e637a2925..2126b7051f0 100644 --- a/crates/starknet_gateway/src/rpc_state_reader.rs +++ b/crates/starknet_gateway/src/rpc_state_reader.rs @@ -10,7 +10,7 @@ use reqwest::blocking::Client as BlockingClient; use serde::Serialize; use serde_json::{json, Value}; use starknet_api::block::{BlockInfo, BlockNumber}; -use starknet_api::contract_class::SierraVersion; +use starknet_api::contract_class::VersionedCasm; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; @@ -145,11 +145,11 @@ impl BlockifierStateReader for RpcStateReader { let result = self.send_rpc_request("starknet_getCompiledContractClass", get_compiled_class_params)?; - let (contract_class, _): (CompiledContractClass, SierraVersion) = + let versioned_casm: VersionedCasm = serde_json::from_value(result).map_err(serde_err_to_state_err)?; match contract_class { CompiledContractClass::V1(contract_class_v1) => Ok(RunnableCompiledClass::V1( - CompiledClassV1::try_from(contract_class_v1).map_err(StateError::ProgramError)?, + CompiledClassV1::try_from(versioned_casm).map_err(StateError::ProgramError)?, )), CompiledContractClass::V0(contract_class_v0) => Ok(RunnableCompiledClass::V0( CompiledClassV0::try_from(contract_class_v0).map_err(StateError::ProgramError)?, diff --git a/crates/starknet_gateway/src/rpc_state_reader_test.rs b/crates/starknet_gateway/src/rpc_state_reader_test.rs index 514518636ad..cc0a915554c 100644 --- a/crates/starknet_gateway/src/rpc_state_reader_test.rs +++ b/crates/starknet_gateway/src/rpc_state_reader_test.rs @@ -173,6 +173,8 @@ async fn test_get_compiled_class() { entry_points_by_type: Default::default(), }; + let expected_sierra_version = SierraVersion::default(); + let mock = mock_rpc_interaction( &mut server, &config.json_rpc_version, @@ -193,7 +195,10 @@ async fn test_get_compiled_class() { .await .unwrap() .unwrap(); - assert_eq!(result, RunnableCompiledClass::V1(expected_result.try_into().unwrap())); + assert_eq!( + result, + RunnableCompiledClass::V1((expected_result, expected_sierra_version).try_into().unwrap()) + ); mock.assert_async().await; }