From 528afd48b8f4fe88ddca98c6641ccd1a8cd9bb7a Mon Sep 17 00:00:00 2001 From: Noam Spiegelstein Date: Mon, 16 Dec 2024 17:46:18 +0200 Subject: [PATCH] feat(starknet_state_sync): implement sync state reader get storage at --- Cargo.lock | 4 ++ crates/blockifier/Cargo.toml | 1 + crates/blockifier/src/state/errors.rs | 3 ++ crates/starknet_gateway/Cargo.toml | 1 + .../starknet_gateway/src/sync_state_reader.rs | 13 ++++-- crates/starknet_state_sync/Cargo.toml | 1 + crates/starknet_state_sync/src/lib.rs | 39 ++++++++++++++++ crates/starknet_state_sync_types/Cargo.toml | 1 + .../src/communication.rs | 45 ++++++++++++++++++- 9 files changed, 104 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31b699dbad..b545ced538 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1512,6 +1512,7 @@ dependencies = [ "starknet-types-core", "starknet_api", "starknet_sierra_compile", + "starknet_state_sync_types", "strum 0.25.0", "strum_macros 0.25.3", "tempfile", @@ -10417,6 +10418,7 @@ dependencies = [ "blockifier", "cairo-lang-sierra-to-casm", "cairo-lang-starknet-classes", + "futures", "mempool_test_utils", "mockall", "mockito 1.5.0", @@ -10775,6 +10777,7 @@ dependencies = [ "papyrus_p2p_sync", "papyrus_storage", "serde", + "starknet-types-core", "starknet_api", "starknet_sequencer_infra", "starknet_state_sync_types", @@ -10790,6 +10793,7 @@ dependencies = [ "papyrus_proc_macros", "papyrus_storage", "serde", + "starknet-types-core", "starknet_api", "starknet_sequencer_infra", "thiserror", diff --git a/crates/blockifier/Cargo.toml b/crates/blockifier/Cargo.toml index 8ee89d0e33..8d0cf906ad 100644 --- a/crates/blockifier/Cargo.toml +++ b/crates/blockifier/Cargo.toml @@ -54,6 +54,7 @@ stacker = { workspace = true, optional = true } starknet-types-core.workspace = true starknet_api.workspace = true starknet_sierra_compile = { workspace = true, optional = true } +starknet_state_sync_types.workspace = true strum.workspace = true strum_macros.workspace = true tempfile.workspace = true diff --git a/crates/blockifier/src/state/errors.rs b/crates/blockifier/src/state/errors.rs index c3ad9fbf0d..82f34085b1 100644 --- a/crates/blockifier/src/state/errors.rs +++ b/crates/blockifier/src/state/errors.rs @@ -4,6 +4,7 @@ use num_bigint::{BigUint, TryFromBigIntError}; use starknet_api::core::{ClassHash, ContractAddress}; use starknet_api::state::SierraContractClass; use starknet_api::StarknetApiError; +use starknet_state_sync_types::communication::StateSyncClientError; use thiserror::Error; use crate::abi::constants; @@ -32,6 +33,8 @@ pub enum StateError { /// Represents all unexpected errors that may occur while reading from state. #[error("Failed to read from state: {0}.")] StateReadError(String), + #[error(transparent)] + StateSyncClientError(#[from] StateSyncClientError), } /// Ensures that the CASM and Sierra classes are coupled - Meaning that they both exist or are diff --git a/crates/starknet_gateway/Cargo.toml b/crates/starknet_gateway/Cargo.toml index 51a43817b4..6420c9ba5e 100644 --- a/crates/starknet_gateway/Cargo.toml +++ b/crates/starknet_gateway/Cargo.toml @@ -16,6 +16,7 @@ async-trait.workspace = true axum.workspace = true blockifier = { workspace = true, features = ["testing"] } cairo-lang-starknet-classes.workspace = true +futures.workspace = true mempool_test_utils.workspace = true papyrus_config.workspace = true papyrus_network_types.workspace = true diff --git a/crates/starknet_gateway/src/sync_state_reader.rs b/crates/starknet_gateway/src/sync_state_reader.rs index 838283e1ee..8f706bdbfb 100644 --- a/crates/starknet_gateway/src/sync_state_reader.rs +++ b/crates/starknet_gateway/src/sync_state_reader.rs @@ -1,5 +1,6 @@ use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; +use futures::executor::block_on; use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; @@ -32,10 +33,16 @@ impl MempoolStateReader for SyncStateReader { impl BlockifierStateReader for SyncStateReader { fn get_storage_at( &self, - _contract_address: ContractAddress, - _key: StorageKey, + contract_address: ContractAddress, + key: StorageKey, ) -> StateResult { - todo!() + let res = block_on(self.shared_state_sync_client.get_storage_at( + self.block_number, + contract_address, + key, + ))?; + + Ok(res.unwrap_or_default()) } fn get_nonce_at(&self, _contract_address: ContractAddress) -> StateResult { diff --git a/crates/starknet_state_sync/Cargo.toml b/crates/starknet_state_sync/Cargo.toml index 0f70c2e590..1691687717 100644 --- a/crates/starknet_state_sync/Cargo.toml +++ b/crates/starknet_state_sync/Cargo.toml @@ -16,6 +16,7 @@ papyrus_network.workspace = true papyrus_p2p_sync.workspace = true papyrus_storage.workspace = true serde.workspace = true +starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } starknet_sequencer_infra.workspace = true starknet_state_sync_types.workspace = true diff --git a/crates/starknet_state_sync/src/lib.rs b/crates/starknet_state_sync/src/lib.rs index b6e373e707..daa6207682 100644 --- a/crates/starknet_state_sync/src/lib.rs +++ b/crates/starknet_state_sync/src/lib.rs @@ -6,6 +6,8 @@ use papyrus_storage::body::BodyStorageReader; use papyrus_storage::state::StateStorageReader; use papyrus_storage::StorageReader; use starknet_api::block::BlockNumber; +use starknet_api::core::{ContractAddress, BLOCK_HASH_TABLE_ADDRESS}; +use starknet_api::state::{StateNumber, StorageKey}; use starknet_sequencer_infra::component_definitions::{ComponentRequestHandler, ComponentStarter}; use starknet_sequencer_infra::component_server::{LocalComponentServer, RemoteComponentServer}; use starknet_state_sync_types::communication::{ @@ -13,7 +15,9 @@ use starknet_state_sync_types::communication::{ StateSyncResponse, StateSyncResult, }; +use starknet_state_sync_types::errors::StateSyncError; use starknet_state_sync_types::state_sync_types::SyncBlock; +use starknet_types_core::felt::Felt; use crate::config::StateSyncConfig; use crate::runner::StateSyncRunner; @@ -39,6 +43,13 @@ impl ComponentRequestHandler for StateSync StateSyncRequest::AddNewBlock(_block_number, _sync_block) => { todo!() } + StateSyncRequest::GetStorageAt(block_number, contract_address, storage_key) => { + StateSyncResponse::GetStorageAt(self.get_storage_at( + block_number, + contract_address, + storage_key, + )) + } } } } @@ -58,6 +69,34 @@ impl StateSync { Ok(None) } + + fn get_storage_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + storage_key: StorageKey, + ) -> StateSyncResult> { + let txn = self.storage_reader.begin_ro_txn()?; + + if let Some(state_number) = StateNumber::right_after_block(block_number) { + let state_reader = txn.get_state_reader()?; + let res = state_reader.get_storage_at(state_number, &contract_address, &storage_key)?; + + // If the contract is not deployed, res will be 0. Checking if that's the case so + // that we'll return an error instead. + // Contract address 0x1 is a special address, it stores the block + // hashes. Contracts are not deployed to this address. + if res == Felt::default() && contract_address != BLOCK_HASH_TABLE_ADDRESS { + // check if the contract exists + state_reader.get_class_hash_at(state_number, &contract_address)?.ok_or_else( + || StateSyncError::StorageError("Contract not found".to_string()), + )?; + } + return Ok(Some(res)); + } + + Ok(None) + } } pub type LocalStateSyncServer = diff --git a/crates/starknet_state_sync_types/Cargo.toml b/crates/starknet_state_sync_types/Cargo.toml index f9204e6338..edf8856f84 100644 --- a/crates/starknet_state_sync_types/Cargo.toml +++ b/crates/starknet_state_sync_types/Cargo.toml @@ -13,6 +13,7 @@ async-trait.workspace = true papyrus_proc_macros.workspace = true papyrus_storage.workspace = true serde = { workspace = true, features = ["derive"] } +starknet-types-core.workspace = true starknet_api.workspace = true starknet_sequencer_infra.workspace = true thiserror.workspace = true diff --git a/crates/starknet_state_sync_types/src/communication.rs b/crates/starknet_state_sync_types/src/communication.rs index cfc97cddee..62d017e790 100644 --- a/crates/starknet_state_sync_types/src/communication.rs +++ b/crates/starknet_state_sync_types/src/communication.rs @@ -4,6 +4,8 @@ use async_trait::async_trait; use papyrus_proc_macros::handle_response_variants; use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; +use starknet_api::core::ContractAddress; +use starknet_api::state::StorageKey; use starknet_sequencer_infra::component_client::{ ClientError, LocalComponentClient, @@ -13,6 +15,7 @@ use starknet_sequencer_infra::component_definitions::{ ComponentClient, ComponentRequestAndResponseSender, }; +use starknet_types_core::felt::Felt; use thiserror::Error; use crate::errors::StateSyncError; @@ -34,7 +37,13 @@ pub trait StateSyncClient: Send + Sync { sync_block: SyncBlock, ) -> StateSyncClientResult<()>; - // TODO: add get_storage_at for BlockifierStateReader trait + async fn get_storage_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + storage_key: StorageKey, + ) -> StateSyncClientResult>; + // TODO: add get_nonce_at for BlockifierStateReader trait // TODO: add get_compiled_class for BlockifierStateReader trait // TODO: add get_class_hash_at for BlockifierStateReader trait @@ -63,12 +72,14 @@ pub type StateSyncRequestAndResponseSender = pub enum StateSyncRequest { GetBlock(BlockNumber), AddNewBlock(BlockNumber, SyncBlock), + GetStorageAt(BlockNumber, ContractAddress, StorageKey), } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum StateSyncResponse { GetBlock(StateSyncResult>), AddNewBlock(StateSyncResult<()>), + GetStorageAt(StateSyncResult>), } #[async_trait] @@ -96,6 +107,22 @@ impl StateSyncClient for LocalStateSyncClient { StateSyncError ) } + + async fn get_storage_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + storage_key: StorageKey, + ) -> StateSyncClientResult> { + let request = StateSyncRequest::GetStorageAt(block_number, contract_address, storage_key); + let response = self.send(request).await; + handle_response_variants!( + StateSyncResponse, + GetStorageAt, + StateSyncClientError, + StateSyncError + ) + } } #[async_trait] @@ -123,4 +150,20 @@ impl StateSyncClient for RemoteStateSyncClient { StateSyncError ) } + + async fn get_storage_at( + &self, + block_number: BlockNumber, + contract_address: ContractAddress, + storage_key: StorageKey, + ) -> StateSyncClientResult> { + let request = StateSyncRequest::GetStorageAt(block_number, contract_address, storage_key); + let response = self.send(request).await; + handle_response_variants!( + StateSyncResponse, + GetStorageAt, + StateSyncClientError, + StateSyncError + ) + } }