From 3debc321ba0344aae4b3ae93a86dd06668173a60 Mon Sep 17 00:00:00 2001 From: Noam Spiegelstein Date: Mon, 16 Dec 2024 17:51:07 +0200 Subject: [PATCH] feat(starknet_state_sync): implement state sync get compiled class --- .../starknet_gateway/src/sync_state_reader.rs | 17 ++++++- crates/starknet_state_sync/src/lib.rs | 47 +++++++++++++++++++ .../src/communication.rs | 41 +++++++++++++++- .../starknet_state_sync_types/src/errors.rs | 17 +++++-- 4 files changed, 116 insertions(+), 6 deletions(-) diff --git a/crates/starknet_gateway/src/sync_state_reader.rs b/crates/starknet_gateway/src/sync_state_reader.rs index a0012782c87..17c9dba8200 100644 --- a/crates/starknet_gateway/src/sync_state_reader.rs +++ b/crates/starknet_gateway/src/sync_state_reader.rs @@ -3,6 +3,7 @@ use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; use futures::executor::block_on; use starknet_api::block::{BlockInfo, BlockNumber}; +use starknet_api::contract_class::ContractClass; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_state_sync_types::communication::SharedStateSyncClient; @@ -55,8 +56,20 @@ impl BlockifierStateReader for SyncStateReader { Ok(res) } - fn get_compiled_class(&self, _class_hash: ClassHash) -> StateResult { - todo!() + fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { + let contract_class = block_on( + self.state_sync_client.get_compiled_class_deprecated(self.block_number, class_hash), + ) + .map_err(|e| StateError::StateReadError(e.to_string()))?; + + match contract_class { + ContractClass::V1(casm_contract_class) => { + Ok(RunnableCompiledClass::V1(casm_contract_class.try_into()?)) + } + ContractClass::V0(deprecated_contract_class) => { + Ok(RunnableCompiledClass::V0(deprecated_contract_class.try_into()?)) + } + } } fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { diff --git a/crates/starknet_state_sync/src/lib.rs b/crates/starknet_state_sync/src/lib.rs index 62fa58dd79d..e3277e70cca 100644 --- a/crates/starknet_state_sync/src/lib.rs +++ b/crates/starknet_state_sync/src/lib.rs @@ -3,10 +3,12 @@ pub mod runner; use async_trait::async_trait; use papyrus_storage::body::BodyStorageReader; +use papyrus_storage::compiled_class::CasmStorageReader; use papyrus_storage::db::TransactionKind; use papyrus_storage::state::StateStorageReader; use papyrus_storage::{StorageReader, StorageTxn}; use starknet_api::block::BlockNumber; +use starknet_api::contract_class::{ContractClass, SierraVersion}; use starknet_api::core::{ClassHash, ContractAddress, Nonce, BLOCK_HASH_TABLE_ADDRESS}; use starknet_api::state::{StateNumber, StorageKey}; use starknet_sequencer_infra::component_definitions::{ComponentRequestHandler, ComponentStarter}; @@ -55,6 +57,11 @@ impl ComponentRequestHandler for StateSync self.get_class_hash_at(block_number, contract_address), ) } + StateSyncRequest::GetCompiledClassDeprecated(block_number, class_hash) => { + StateSyncResponse::GetCompiledClassDeprecated( + self.get_compiled_class_deprecated(block_number, class_hash), + ) + } } } } @@ -134,6 +141,46 @@ impl StateSync { .ok_or(StateSyncError::ContractNotFound(contract_address))?; Ok(class_hash) } + + fn get_compiled_class_deprecated( + &self, + block_number: BlockNumber, + class_hash: ClassHash, + ) -> StateSyncResult { + let txn = self.storage_reader.begin_ro_txn()?; + let latest_block_number = txn.get_compiled_class_marker()?.prev(); + if latest_block_number.is_none_or(|latest_block_number| latest_block_number < block_number) + { + return Err(StateSyncError::BlockNotFound(block_number)); + } + + let state_reader = txn.get_state_reader()?; + + // Check if this class exists in the Cairo1 classes table. + if let Some(class_definition_block_number) = + state_reader.get_class_definition_block_number(&class_hash)? + { + if class_definition_block_number > block_number { + return Err(StateSyncError::ClassNotFound(class_hash)); + } + + let (option_casm, option_sierra) = txn.get_casm_and_sierra(&class_hash)?; + + // Check if both options are `Some`. If not, since we verified the block number is + // smaller than the casm marker, we return that the class doesnt exist. + let (casm, sierra) = + option_casm.zip(option_sierra).ok_or(StateSyncError::ClassNotFound(class_hash))?; + let sierra_version = SierraVersion::extract_from_program(&sierra.sierra_program)?; + return Ok(ContractClass::V1((casm, sierra_version))); + } + + // Check if this class exists in the Cairo0 classes table. + let state_number = StateNumber::unchecked_right_after_block(block_number); + let deprecated_compiled_contract_class = state_reader + .get_deprecated_class_definition_at(state_number, &class_hash)? + .ok_or(StateSyncError::ClassNotFound(class_hash))?; + Ok(ContractClass::V0(deprecated_compiled_contract_class)) + } } fn verify_synced_up_to( diff --git a/crates/starknet_state_sync_types/src/communication.rs b/crates/starknet_state_sync_types/src/communication.rs index 98ede7f5a24..8b4cccab1fd 100644 --- a/crates/starknet_state_sync_types/src/communication.rs +++ b/crates/starknet_state_sync_types/src/communication.rs @@ -4,6 +4,7 @@ use async_trait::async_trait; use papyrus_proc_macros::handle_response_variants; use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; +use starknet_api::contract_class::ContractClass; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_sequencer_infra::component_client::{ @@ -56,7 +57,13 @@ pub trait StateSyncClient: Send + Sync { contract_address: ContractAddress, ) -> StateSyncClientResult; - // TODO: Add get_compiled_class for StateSyncReader + // TODO: Remove this and fix sync state reader once the compiler component is ready. + async fn get_compiled_class_deprecated( + &self, + block_number: BlockNumber, + class_hash: ClassHash, + ) -> StateSyncClientResult; + // TODO: Add get_compiled_class_hash for StateSyncReader // TODO: Add get_block_info for StateSyncReader } @@ -83,6 +90,7 @@ pub enum StateSyncRequest { GetStorageAt(BlockNumber, ContractAddress, StorageKey), GetNonceAt(BlockNumber, ContractAddress), GetClassHashAt(BlockNumber, ContractAddress), + GetCompiledClassDeprecated(BlockNumber, ClassHash), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -92,6 +100,7 @@ pub enum StateSyncResponse { GetStorageAt(StateSyncResult), GetNonceAt(StateSyncResult), GetClassHashAt(StateSyncResult), + GetCompiledClassDeprecated(StateSyncResult), } #[async_trait] @@ -165,6 +174,21 @@ impl StateSyncClient for LocalStateSyncClient { StateSyncError ) } + + async fn get_compiled_class_deprecated( + &self, + block_number: BlockNumber, + class_hash: ClassHash, + ) -> StateSyncClientResult { + let request = StateSyncRequest::GetCompiledClassDeprecated(block_number, class_hash); + let response = self.send(request).await; + handle_response_variants!( + StateSyncResponse, + GetCompiledClassDeprecated, + StateSyncClientError, + StateSyncError + ) + } } #[async_trait] @@ -238,4 +262,19 @@ impl StateSyncClient for RemoteStateSyncClient { StateSyncError ) } + + async fn get_compiled_class_deprecated( + &self, + block_number: BlockNumber, + class_hash: ClassHash, + ) -> StateSyncClientResult { + let request = StateSyncRequest::GetCompiledClassDeprecated(block_number, class_hash); + let response = self.send(request).await; + handle_response_variants!( + StateSyncResponse, + GetCompiledClassDeprecated, + StateSyncClientError, + StateSyncError + ) + } } diff --git a/crates/starknet_state_sync_types/src/errors.rs b/crates/starknet_state_sync_types/src/errors.rs index 7fd0c09f0e3..c09afd6535f 100644 --- a/crates/starknet_state_sync_types/src/errors.rs +++ b/crates/starknet_state_sync_types/src/errors.rs @@ -1,7 +1,8 @@ use papyrus_storage::StorageError; use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; -use starknet_api::core::ContractAddress; +use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::StarknetApiError; use thiserror::Error; #[derive(Debug, Error, Serialize, Deserialize, Clone)] @@ -12,10 +13,14 @@ pub enum StateSyncError { BlockNotFound(BlockNumber), #[error("Contract address {0} was not found")] ContractNotFound(ContractAddress), - // StorageError does not derive Serialize, Deserialize and Clone Traits. - // We put the string of the error instead. + #[error("Class hash {0} was not found")] + ClassNotFound(ClassHash), + // StorageError and StarknetApiError do not derive Serialize, Deserialize and Clone Traits. + // We put the string of the errors instead. #[error("Unexpected storage error: {0}")] StorageError(String), + #[error("Unexpected starknet api error: {0}")] + StarknetApiError(String), } impl From for StateSyncError { @@ -23,3 +28,9 @@ impl From for StateSyncError { StateSyncError::StorageError(error.to_string()) } } + +impl From for StateSyncError { + fn from(error: StarknetApiError) -> Self { + StateSyncError::StarknetApiError(error.to_string()) + } +}