From d3e4bca5134a477fa85a075ff6df39851f9f7ecd Mon Sep 17 00:00:00 2001 From: Noam Spiegelstein Date: Wed, 25 Dec 2024 15:31:21 +0200 Subject: [PATCH] feat(starknet_state_sync): implement state sync get latest block number --- .../starknet_gateway/src/rpc_state_reader.rs | 7 +++-- crates/starknet_gateway/src/state_reader.rs | 5 +++- .../src/state_reader_test_utils.rs | 7 +++-- .../src/stateful_transaction_validator.rs | 5 +++- .../starknet_gateway/src/sync_state_reader.rs | 21 ++++++++++++--- crates/starknet_state_sync/src/lib.rs | 9 +++++++ .../src/communication.rs | 26 +++++++++++++++++++ .../starknet_state_sync_types/src/errors.rs | 2 ++ 8 files changed, 72 insertions(+), 10 deletions(-) diff --git a/crates/starknet_gateway/src/rpc_state_reader.rs b/crates/starknet_gateway/src/rpc_state_reader.rs index e6abf8cd0a1..f9b9da49c97 100644 --- a/crates/starknet_gateway/src/rpc_state_reader.rs +++ b/crates/starknet_gateway/src/rpc_state_reader.rs @@ -13,6 +13,7 @@ use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; +use starknet_state_sync_types::communication::StateSyncClientResult; use starknet_types_core::felt::Felt; use crate::config::RpcStateReaderConfig; @@ -185,8 +186,10 @@ pub struct RpcStateReaderFactory { } impl StateReaderFactory for RpcStateReaderFactory { - fn get_state_reader_from_latest_block(&self) -> Box { - Box::new(RpcStateReader::from_latest(&self.config)) + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult> { + Ok(Box::new(RpcStateReader::from_latest(&self.config))) } fn get_state_reader(&self, block_number: BlockNumber) -> Box { diff --git a/crates/starknet_gateway/src/state_reader.rs b/crates/starknet_gateway/src/state_reader.rs index b026bbe6ef0..11a5acac299 100644 --- a/crates/starknet_gateway/src/state_reader.rs +++ b/crates/starknet_gateway/src/state_reader.rs @@ -6,6 +6,7 @@ use mockall::automock; use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; +use starknet_state_sync_types::communication::StateSyncClientResult; use starknet_types_core::felt::Felt; pub trait MempoolStateReader: BlockifierStateReader + Send + Sync { @@ -14,7 +15,9 @@ pub trait MempoolStateReader: BlockifierStateReader + Send + Sync { #[cfg_attr(test, automock)] pub trait StateReaderFactory: Send + Sync { - fn get_state_reader_from_latest_block(&self) -> Box; + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult>; fn get_state_reader(&self, block_number: BlockNumber) -> Box; } diff --git a/crates/starknet_gateway/src/state_reader_test_utils.rs b/crates/starknet_gateway/src/state_reader_test_utils.rs index 80c8fc8b516..9b505af103e 100644 --- a/crates/starknet_gateway/src/state_reader_test_utils.rs +++ b/crates/starknet_gateway/src/state_reader_test_utils.rs @@ -10,6 +10,7 @@ use starknet_api::block::{BlockInfo, BlockNumber}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::Fee; +use starknet_state_sync_types::communication::StateSyncClientResult; use starknet_types_core::felt::Felt; use crate::state_reader::{MempoolStateReader, StateReaderFactory}; @@ -57,8 +58,10 @@ pub struct TestStateReaderFactory { } impl StateReaderFactory for TestStateReaderFactory { - fn get_state_reader_from_latest_block(&self) -> Box { - Box::new(self.state_reader.clone()) + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult> { + Ok(Box::new(self.state_reader.clone())) } fn get_state_reader(&self, _block_number: BlockNumber) -> Box { diff --git a/crates/starknet_gateway/src/stateful_transaction_validator.rs b/crates/starknet_gateway/src/stateful_transaction_validator.rs index b08e6cf0f36..00c4d3c1e4b 100644 --- a/crates/starknet_gateway/src/stateful_transaction_validator.rs +++ b/crates/starknet_gateway/src/stateful_transaction_validator.rs @@ -121,7 +121,10 @@ fn skip_stateful_validations(tx: &ExecutableTransaction, account_nonce: Nonce) - pub fn get_latest_block_info( state_reader_factory: &dyn StateReaderFactory, ) -> StatefulTransactionValidatorResult { - let state_reader = state_reader_factory.get_state_reader_from_latest_block(); + let state_reader = state_reader_factory.get_state_reader_from_latest_block().map_err(|e| { + error!("Failed to get state reader from latest block: {}", e); + GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } + })?; state_reader.get_block_info().map_err(|e| { error!("Failed to get latest block info: {}", e); GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } diff --git a/crates/starknet_gateway/src/sync_state_reader.rs b/crates/starknet_gateway/src/sync_state_reader.rs index 05fbffbe0e6..313a6caaf84 100644 --- a/crates/starknet_gateway/src/sync_state_reader.rs +++ b/crates/starknet_gateway/src/sync_state_reader.rs @@ -7,7 +7,12 @@ use starknet_api::contract_class::ContractClass; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::state::StorageKey; -use starknet_state_sync_types::communication::SharedStateSyncClient; +use starknet_state_sync_types::communication::{ + SharedStateSyncClient, + StateSyncClientError, + StateSyncClientResult, +}; +use starknet_state_sync_types::errors::StateSyncError; use starknet_types_core::felt::Felt; use crate::state_reader::{MempoolStateReader, StateReaderFactory}; @@ -118,9 +123,17 @@ pub struct SyncStateReaderFactory { } impl StateReaderFactory for SyncStateReaderFactory { - // TODO(noamsp): Decide if we need this - fn get_state_reader_from_latest_block(&self) -> Box { - todo!() + fn get_state_reader_from_latest_block( + &self, + ) -> StateSyncClientResult> { + let latest_block_number = + block_on(self.shared_state_sync_client.get_latest_block_number())? + .ok_or(StateSyncClientError::StateSyncError(StateSyncError::EmptyState))?; + + Ok(Box::new(SyncStateReader::from_number( + self.shared_state_sync_client.clone(), + latest_block_number, + ))) } fn get_state_reader(&self, block_number: BlockNumber) -> Box { diff --git a/crates/starknet_state_sync/src/lib.rs b/crates/starknet_state_sync/src/lib.rs index 25941748825..504682973ed 100644 --- a/crates/starknet_state_sync/src/lib.rs +++ b/crates/starknet_state_sync/src/lib.rs @@ -76,6 +76,9 @@ impl ComponentRequestHandler for StateSync self.get_compiled_class_deprecated(block_number, class_hash), ) } + StateSyncRequest::GetLatestBlockNumber() => { + StateSyncResponse::GetLatestBlockNumber(self.get_latest_block_number()) + } } } } @@ -190,6 +193,12 @@ impl StateSync { .ok_or(StateSyncError::ClassNotFound(class_hash))?; Ok(ContractClass::V0(deprecated_compiled_contract_class)) } + + fn get_latest_block_number(&self) -> StateSyncResult> { + let txn = self.storage_reader.begin_ro_txn()?; + let latest_block_number = txn.get_state_marker()?.prev(); + Ok(latest_block_number) + } } 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 013d5d26479..0a1e5478638 100644 --- a/crates/starknet_state_sync_types/src/communication.rs +++ b/crates/starknet_state_sync_types/src/communication.rs @@ -68,6 +68,8 @@ pub trait StateSyncClient: Send + Sync { class_hash: ClassHash, ) -> StateSyncClientResult; + async fn get_latest_block_number(&self) -> StateSyncClientResult>; + // TODO: Add get_compiled_class_hash for StateSyncReader } @@ -95,6 +97,7 @@ pub enum StateSyncRequest { GetNonceAt(BlockNumber, ContractAddress), GetClassHashAt(BlockNumber, ContractAddress), GetCompiledClassDeprecated(BlockNumber, ClassHash), + GetLatestBlockNumber(), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -106,6 +109,7 @@ pub enum StateSyncResponse { GetNonceAt(StateSyncResult), GetClassHashAt(StateSyncResult), GetCompiledClassDeprecated(StateSyncResult), + GetLatestBlockNumber(StateSyncResult>), } #[async_trait] @@ -194,6 +198,17 @@ impl StateSyncClient for LocalStateSyncClient { StateSyncError ) } + + async fn get_latest_block_number(&self) -> StateSyncClientResult> { + let request = StateSyncRequest::GetLatestBlockNumber(); + let response = self.send(request).await; + handle_response_variants!( + StateSyncResponse, + GetLatestBlockNumber, + StateSyncClientError, + StateSyncError + ) + } } #[async_trait] @@ -282,4 +297,15 @@ impl StateSyncClient for RemoteStateSyncClient { StateSyncError ) } + + async fn get_latest_block_number(&self) -> StateSyncClientResult> { + let request = StateSyncRequest::GetLatestBlockNumber(); + let response = self.send(request).await; + handle_response_variants!( + StateSyncResponse, + GetLatestBlockNumber, + StateSyncClientError, + StateSyncError + ) + } } diff --git a/crates/starknet_state_sync_types/src/errors.rs b/crates/starknet_state_sync_types/src/errors.rs index cd66c8606e1..767f2215194 100644 --- a/crates/starknet_state_sync_types/src/errors.rs +++ b/crates/starknet_state_sync_types/src/errors.rs @@ -26,6 +26,8 @@ pub enum StateSyncError { SendError(String), #[error("Unexpected starknet api error: {0}")] StarknetApiError(String), + #[error("State is empty, latest block returned None")] + EmptyState, } impl From for StateSyncError {