From ca9277b566613b9aeb0a6379d2a25cb31cbc26a1 Mon Sep 17 00:00:00 2001 From: bexan Date: Wed, 18 Sep 2024 17:30:21 +0200 Subject: [PATCH] store nonce & message hash --- Cargo.lock | 1 + .../katana/core/src/service/block_producer.rs | 55 +++++++++++++++---- .../core/src/service/messaging/service.rs | 1 + .../core/src/service/messaging/starknet.rs | 16 ++++-- crates/katana/primitives/src/contract.rs | 3 + crates/katana/storage/db/Cargo.toml | 2 + crates/katana/storage/db/src/tables.rs | 27 +++++++-- crates/katana/storage/provider/src/lib.rs | 26 ++++++++- .../storage/provider/src/providers/db/mod.rs | 46 +++++++++++++++- .../provider/src/providers/fork/mod.rs | 27 ++++++++- .../provider/src/providers/in_memory/cache.rs | 7 +++ .../provider/src/providers/in_memory/mod.rs | 31 ++++++++++- .../storage/provider/src/traits/messaging.rs | 15 +++++ 13 files changed, 233 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb7394efc4..c0babbb6f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7920,6 +7920,7 @@ dependencies = [ name = "katana-db" version = "1.0.0-alpha.12" dependencies = [ + "alloy-primitives", "anyhow", "criterion", "dojo-metrics", diff --git a/crates/katana/core/src/service/block_producer.rs b/crates/katana/core/src/service/block_producer.rs index 618d0f2c03..02d386f14e 100644 --- a/crates/katana/core/src/service/block_producer.rs +++ b/crates/katana/core/src/service/block_producer.rs @@ -13,9 +13,11 @@ use katana_pool::validation::stateful::TxValidator; use katana_primitives::block::{BlockHashOrNumber, ExecutableBlock, PartialHeader}; use katana_primitives::receipt::Receipt; use katana_primitives::trace::TxExecInfo; -use katana_primitives::transaction::{ExecutableTxWithHash, TxHash, TxWithHash}; +use katana_primitives::transaction::{ExecutableTxWithHash, TxHash, TxWithHash, Tx}; use katana_primitives::version::CURRENT_STARKNET_VERSION; +use katana_primitives::FieldElement; use katana_provider::error::ProviderError; +use katana_provider::traits::messaging::MessagingProvider; use katana_provider::traits::block::{BlockHashProvider, BlockNumberProvider}; use katana_provider::traits::env::BlockEnvProvider; use katana_provider::traits::state::StateFactoryProvider; @@ -296,9 +298,11 @@ impl IntervalBlockProducer { fn execute_transactions( executor: PendingExecutor, transactions: Vec, + backend: Arc>, ) -> TxExecutionResult { - let executor = &mut executor.write(); + let provider = backend.blockchain.provider(); + let executor = &mut executor.write(); let new_txs_count = transactions.len(); executor.execute_transactions(transactions)?; @@ -309,13 +313,43 @@ impl IntervalBlockProducer { let results = txs .iter() .skip(total_txs - new_txs_count) - .filter_map(|(tx, res)| match res { - ExecutionResult::Failed { .. } => None, - ExecutionResult::Success { receipt, trace, .. } => Some(TxWithOutcome { - tx: tx.clone(), - receipt: receipt.clone(), - exec_info: trace.clone(), - }), + .filter_map(|(tx, res)| { + let tx_ref: &Tx = &tx.transaction; + + trace!(target: LOG_TARGET, "Executed transaction: {:?}", tx); + let _ = match tx_ref { + Tx::L1Handler(l1_tx) => { + // get stored nonce from message hash + let message_hash_bytes = l1_tx.message_hash; + let message_hash_bytes: [u8; 32] = *message_hash_bytes; + match FieldElement::from_bytes_be(&message_hash_bytes) { + Ok(message_hash) => { + match provider.get_nonce_from_message_hash(message_hash) { + Ok(Some(nonce)) => provider.set_gather_message_nonce(nonce), + Ok(None) => { + Ok(()) + }, + Err(_e) => { + Ok(()) + } + } + }, + Err(_e) => { + Ok(()) + } + } + }, + _ => Ok({}) + }; + + match res { + ExecutionResult::Failed { .. } => None, + ExecutionResult::Success { receipt, trace, .. } => Some(TxWithOutcome { + tx: tx.clone(), + receipt: receipt.clone(), + exec_info: trace.clone(), + }), + } }) .collect::>(); @@ -399,10 +433,11 @@ impl Stream for IntervalBlockProducer { let transactions: Vec = std::mem::take(&mut pin.queued).into_iter().flatten().collect(); + let backend = pin.backend.clone(); let fut = pin .blocking_task_spawner - .spawn(|| Self::execute_transactions(executor, transactions)); + .spawn(|| Self::execute_transactions(executor, transactions, backend)); pin.ongoing_execution = Some(Box::pin(fut)); } diff --git a/crates/katana/core/src/service/messaging/service.rs b/crates/katana/core/src/service/messaging/service.rs index 5d664227ca..86471a2d9d 100644 --- a/crates/katana/core/src/service/messaging/service.rs +++ b/crates/katana/core/src/service/messaging/service.rs @@ -213,6 +213,7 @@ impl Stream for MessagingService { pin.backend.clone(), pin.gather_from_block, pin.max_block, + pin.chunk_size, ))); } diff --git a/crates/katana/core/src/service/messaging/starknet.rs b/crates/katana/core/src/service/messaging/starknet.rs index 91a3a8b334..8ad7bc8926 100644 --- a/crates/katana/core/src/service/messaging/starknet.rs +++ b/crates/katana/core/src/service/messaging/starknet.rs @@ -204,10 +204,14 @@ impl Messenger for StarknetMessaging { event = ?e, "Converting event into L1HandlerTx." ); - - if let Ok(tx) = l1_handler_tx_from_event(e, chain_id) { - l1_handler_txs.push(tx) - } + block_events.iter().for_each(|e| { + if let Ok(tx) = l1_handler_tx_from_event(e, chain_id) { + let last_processed_nonce = self.provider.get_gather_message_nonce().unwrap_or(0.into()); + if tx.nonce > last_processed_nonce { + l1_handler_txs.push(tx) + } + } + }) }); Ok((to_block, l1_handler_txs)) @@ -236,6 +240,10 @@ impl Messenger for StarknetMessaging { } self.send_hashes(hashes.clone()).await?; + for (index, hash) in hashes.iter().enumerate() { + self.send_hashes(std::slice::from_ref(hash)).await?; + self.provider.set_send_from_index(*hash, index as u64).await?; + } Ok(hashes) } diff --git a/crates/katana/primitives/src/contract.rs b/crates/katana/primitives/src/contract.rs index 4473d4169b..cfc589cf13 100644 --- a/crates/katana/primitives/src/contract.rs +++ b/crates/katana/primitives/src/contract.rs @@ -14,6 +14,9 @@ pub type StorageValue = Felt; /// Represents the type for a contract nonce. pub type Nonce = Felt; +/// Represents the type for a message hash. +pub type MessageHash = FieldElement; + /// Represents a contract address. #[derive(Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug, Deref)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/katana/storage/db/Cargo.toml b/crates/katana/storage/db/Cargo.toml index ce6aaf883b..081afb1547 100644 --- a/crates/katana/storage/db/Cargo.toml +++ b/crates/katana/storage/db/Cargo.toml @@ -21,6 +21,8 @@ tempfile = { workspace = true, optional = true } thiserror.workspace = true tracing.workspace = true +alloy-primitives.workspace = true + # codecs [dependencies.postcard] default-features = false diff --git a/crates/katana/storage/db/src/tables.rs b/crates/katana/storage/db/src/tables.rs index 39ddcdb4fb..d99ee2ee59 100644 --- a/crates/katana/storage/db/src/tables.rs +++ b/crates/katana/storage/db/src/tables.rs @@ -1,6 +1,6 @@ use katana_primitives::block::{BlockHash, BlockNumber, FinalityStatus, Header}; use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; -use katana_primitives::contract::{ContractAddress, GenericContractInfo, StorageKey}; +use katana_primitives::contract::{ContractAddress, GenericContractInfo, Nonce, StorageKey}; use katana_primitives::receipt::Receipt; use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{Tx, TxHash, TxNumber}; @@ -44,7 +44,7 @@ pub enum TableType { DupSort, } -pub const NUM_TABLES: usize = 24; +pub const NUM_TABLES: usize = 27; /// Macro to declare `libmdbx` tables. #[macro_export] @@ -168,7 +168,10 @@ define_tables_enum! {[ (ClassChangeHistory, TableType::DupSort), (StorageChangeHistory, TableType::DupSort), (StorageChangeSet, TableType::Table), - (MessagingInfo, TableType::Table) + (MessagingInfo, TableType::Table), + (MessagingNonceInfo, TableType::Table), + (MessagingMessageNonceMapping, TableType::Table), + (MessagingIndexInfo, TableType::Table), ]} tables! { @@ -227,7 +230,17 @@ tables! { StorageChangeHistory: (BlockNumber, ContractStorageKey) => ContractStorageEntry, /// Stores the block number related to messaging service - MessagingInfo: (u64) => BlockNumber + MessagingInfo: (u64) => BlockNumber, + + /// Stores the nonce related to messaging service + MessagingNonceInfo: (u64) => Nonce, + + /// Map a message hash to a message nonce + MessagingMessageNonceMapping: (TxHash) => Nonce, + + /// Stores the index of the messaging service + MessagingIndexInfo: (u64) => u64, + } #[cfg(test)] @@ -262,6 +275,9 @@ mod tests { assert_eq!(Tables::ALL[21].name(), StorageChangeHistory::NAME); assert_eq!(Tables::ALL[22].name(), StorageChangeSet::NAME); assert_eq!(Tables::ALL[23].name(), MessagingInfo::NAME); + assert_eq!(Tables::ALL[24].name(), MessagingNonceInfo::NAME); + assert_eq!(Tables::ALL[25].name(), MessagingMessageNonceMapping::NAME); + assert_eq!(Tables::ALL[26].name(), MessagingMessageNonceMapping::NAME); assert_eq!(Tables::Headers.table_type(), TableType::Table); assert_eq!(Tables::BlockHashes.table_type(), TableType::Table); @@ -287,6 +303,9 @@ mod tests { assert_eq!(Tables::StorageChangeHistory.table_type(), TableType::DupSort); assert_eq!(Tables::StorageChangeSet.table_type(), TableType::Table); assert_eq!(Tables::MessagingInfo.table_type(), TableType::Table); + assert_eq!(Tables::MessagingNonceInfo.table_type(), TableType::Table); + assert_eq!(Tables::MessagingMessageNonMapping.table_type(), TableType::Table); + assert_eq!(Tables::MessagingIndexInfo.table_type(), TableType::Table); } use katana_primitives::block::{BlockHash, BlockNumber, FinalityStatus, Header}; diff --git a/crates/katana/storage/provider/src/lib.rs b/crates/katana/storage/provider/src/lib.rs index 07a5a3e295..a4273ba6d7 100644 --- a/crates/katana/storage/provider/src/lib.rs +++ b/crates/katana/storage/provider/src/lib.rs @@ -6,7 +6,7 @@ use katana_primitives::block::{ SealedBlockWithStatus, }; use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; -use katana_primitives::contract::{ContractAddress, StorageKey, StorageValue}; +use katana_primitives::contract::{ContractAddress, MessageHash, Nonce, StorageKey, StorageValue}; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; @@ -401,4 +401,28 @@ where fn set_gather_from_block(&self, gather_from_block: BlockNumber) -> ProviderResult<()> { self.provider.set_gather_from_block(gather_from_block) } + + fn get_gather_message_nonce(&self) -> ProviderResult> { + self.provider.get_gather_message_nonce() + } + + fn set_gather_message_nonce(&self, nonce: Nonce) -> ProviderResult<()> { + self.provider.set_gather_message_nonce(nonce) + } + + fn get_nonce_from_message_hash(&self, message_hash: MessageHash) -> ProviderResult> { + self.provider.get_nonce_from_message_hash(message_hash) + } + + fn set_nonce_from_message_hash(&self, message_hash: MessageHash, nonce: Nonce) -> ProviderResult<()> { + self.provider.set_nonce_from_message_hash(message_hash, nonce) + } + + fn get_send_from_index(&self) -> ProviderResult> { + self.provider.get_send_from_index() + } + + fn set_send_from_index(&self, _send_from_index: u64) -> ProviderResult<()> { + self.provider.get_send_from_index(send_from_index) + } } diff --git a/crates/katana/storage/provider/src/providers/db/mod.rs b/crates/katana/storage/provider/src/providers/db/mod.rs index b4ad13f190..bc3706995d 100644 --- a/crates/katana/storage/provider/src/providers/db/mod.rs +++ b/crates/katana/storage/provider/src/providers/db/mod.rs @@ -21,7 +21,7 @@ use katana_primitives::block::{ }; use katana_primitives::class::{ClassHash, CompiledClassHash}; use katana_primitives::contract::{ - ContractAddress, GenericContractInfo, Nonce, StorageKey, StorageValue, + ContractAddress, GenericContractInfo, MessageHash, Nonce, StorageKey, StorageValue, }; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; @@ -36,7 +36,7 @@ use crate::traits::block::{ HeaderProvider, }; use crate::traits::env::BlockEnvProvider; -use crate::traits::messaging::{MessagingProvider, GATHER_FROM_BLOCK_KEY, SEND_FROM_BLOCK_KEY}; +use crate::traits::messaging::{MessagingProvider, GATHER_FROM_BLOCK_KEY, SEND_FROM_BLOCK_KEY, GATHER_FROM_NONCE_KEY, SEND_FROM_INDEX_KEY}; use crate::traits::state::{StateFactoryProvider, StateProvider, StateRootProvider}; use crate::traits::state_update::StateUpdateProvider; use crate::traits::transaction::{ @@ -791,6 +791,48 @@ impl MessagingProvider for DbProvider { Ok(()) })? } + + fn get_gather_message_nonce(&self) -> ProviderResult> { + let db_tx = self.0.tx()?; + let nonce = db_tx.get::(GATHER_FROM_NONCE_KEY)?; + db_tx.commit()?; + Ok(nonce) + } + + fn set_gather_message_nonce(&self, nonce: Nonce) -> ProviderResult<()> { + self.0.update(|db_tx| { + db_tx.put::(GATHER_FROM_NONCE_KEY, nonce)?; + Ok(()) + })? + } + + fn get_nonce_from_message_hash(&self, message_hash: MessageHash) -> ProviderResult> { + let db_tx = self.0.tx()?; + let nonce = db_tx.get::(message_hash)?; + db_tx.commit()?; + Ok(nonce) + } + + fn set_nonce_from_message_hash(&self, message_hash: MessageHash, nonce: Nonce) -> ProviderResult<()> { + self.0.update(|db_tx| { + db_tx.put::(message_hash, nonce)?; + Ok(()) + })? + } + + fn get_send_from_index(&self) -> ProviderResult> { + let db_tx = self.0.tx()?; + let index = db_tx.get::(SEND_FROM_INDEX_KEY)?; + db_tx.commit()?; + Ok(index) + } + + fn set_send_from_index(&self, send_from_index: u64) -> ProviderResult<()> { + self.0.update(|db_tx| { + db_tx.put::(SEND_FROM_INDEX_KEY, send_from_index)?; + Ok(()) + })? + } } #[cfg(test)] diff --git a/crates/katana/storage/provider/src/providers/fork/mod.rs b/crates/katana/storage/provider/src/providers/fork/mod.rs index 2e81ea821b..62cb9700ab 100644 --- a/crates/katana/storage/provider/src/providers/fork/mod.rs +++ b/crates/katana/storage/provider/src/providers/fork/mod.rs @@ -10,7 +10,7 @@ use katana_primitives::block::{ SealedBlockWithStatus, }; use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; -use katana_primitives::contract::ContractAddress; +use katana_primitives::contract::{ContractAddress, MessageHash, Nonce}; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; @@ -599,4 +599,29 @@ impl MessagingProvider for ForkedProvider { fn set_gather_from_block(&self, _gather_from_block: BlockNumber) -> ProviderResult<()> { Ok(()) } + + fn get_gather_message_nonce(&self) -> ProviderResult> { + Ok(None) + } + + fn set_gather_message_nonce(&self, _nonce: Nonce) -> ProviderResult<()> { + Ok(()) + } + + fn get_nonce_from_message_hash(&self, _message_hash: MessageHash) -> ProviderResult> { + Ok(None) + } + + fn set_nonce_from_message_hash(&self, _message_hash: MessageHash, _nonce: Nonce) -> ProviderResult<()> { + Ok(()) + } + + fn get_send_from_index(&self) -> ProviderResult> { + Ok(None) + } + + fn set_send_from_index(&self, _send_from_index: u64) -> ProviderResult<()> { + Ok(()) + } + } diff --git a/crates/katana/storage/provider/src/providers/in_memory/cache.rs b/crates/katana/storage/provider/src/providers/in_memory/cache.rs index a2acfb9b59..c4728ceaaf 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/cache.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/cache.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use katana_db::models::block::StoredBlockBodyIndices; use katana_primitives::block::{BlockHash, BlockNumber, FinalityStatus, Header}; +use katana_primitives::contract::Nonce; use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; use katana_primitives::contract::{ContractAddress, GenericContractInfo, StorageKey, StorageValue}; use katana_primitives::receipt::Receipt; @@ -89,6 +90,9 @@ pub struct CacheDb { pub(crate) transaction_numbers: HashMap, pub(crate) transaction_block: HashMap, pub(crate) messaging_info: HashMap, + pub(crate) messaging_nonce_info: HashMap, + pub(crate) messaging_message_nonce_mapping: HashMap, + pub(crate) messaging_index_info: HashMap, } impl CacheStateDb { @@ -122,6 +126,9 @@ impl CacheDb { latest_block_hash: Default::default(), latest_block_number: Default::default(), messaging_info: Default::default(), + messaging_nonce_info: Default::default(), + messaging_message_nonce_mapping: Default::default(), + messaging_index_info: Default::default(), } } } diff --git a/crates/katana/storage/provider/src/providers/in_memory/mod.rs b/crates/katana/storage/provider/src/providers/in_memory/mod.rs index 55058400e7..4c912f60eb 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/mod.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/mod.rs @@ -10,7 +10,7 @@ use katana_primitives::block::{ SealedBlockWithStatus, }; use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; -use katana_primitives::contract::ContractAddress; +use katana_primitives::contract::{ContractAddress, MessageHash, Nonce}; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; @@ -26,7 +26,7 @@ use crate::traits::block::{ }; use crate::traits::contract::ContractClassWriter; use crate::traits::env::BlockEnvProvider; -use crate::traits::messaging::{MessagingProvider, GATHER_FROM_BLOCK_KEY, SEND_FROM_BLOCK_KEY}; +use crate::traits::messaging::{MessagingProvider, GATHER_FROM_BLOCK_KEY, SEND_FROM_BLOCK_KEY, GATHER_FROM_NONCE_KEY, SEND_FROM_INDEX_KEY}; use crate::traits::state::{StateFactoryProvider, StateProvider, StateRootProvider, StateWriter}; use crate::traits::state_update::StateUpdateProvider; use crate::traits::transaction::{ @@ -595,4 +595,31 @@ impl MessagingProvider for InMemoryProvider { self.storage.write().messaging_info.insert(GATHER_FROM_BLOCK_KEY, gather_from_block); Ok(()) } + + fn get_gather_message_nonce(&self) -> ProviderResult> { + Ok(self.storage.read().messaging_nonce_info.get(&GATHER_FROM_NONCE_KEY).cloned()) + } + + fn set_gather_message_nonce(&self, nonce: Nonce) -> ProviderResult<()> { + self.storage.write().messaging_nonce_info.insert(GATHER_FROM_NONCE_KEY, nonce); + Ok(()) + } + + fn get_nonce_from_message_hash(&self, message_hash: MessageHash) -> ProviderResult> { + Ok(self.storage.read().messaging_message_nonce_mapping.get(&message_hash).cloned()) + } + + fn set_nonce_from_message_hash(&self, message_hash: MessageHash, nonce: Nonce) -> ProviderResult<()> { + self.storage.write().messaging_message_nonce_mapping.insert(message_hash, nonce); + Ok(()) + } + + fn get_send_from_index(&self) -> ProviderResult> { + Ok(self.storage.read().messaging_index_info.get(&SEND_FROM_INDEX_KEY).cloned()) + } + + fn set_send_from_index(&self, index: u64) -> ProviderResult<()> { + self.storage.write().messaging_index_info.insert(SEND_FROM_INDEX_KEY, index); + Ok(()) + } } diff --git a/crates/katana/storage/provider/src/traits/messaging.rs b/crates/katana/storage/provider/src/traits/messaging.rs index 42d6dd22f6..a556a4b8f4 100644 --- a/crates/katana/storage/provider/src/traits/messaging.rs +++ b/crates/katana/storage/provider/src/traits/messaging.rs @@ -1,9 +1,12 @@ use katana_primitives::block::BlockNumber; +use katana_primitives::contract::{Nonce, MessageHash}; use crate::ProviderResult; pub const SEND_FROM_BLOCK_KEY: u64 = 1; pub const GATHER_FROM_BLOCK_KEY: u64 = 2; +pub const GATHER_FROM_NONCE_KEY: u64 = 3; +pub const SEND_FROM_INDEX_KEY: u64 = 4; #[auto_impl::auto_impl(&, Box, Arc)] pub trait MessagingProvider: Send + Sync { @@ -15,4 +18,16 @@ pub trait MessagingProvider: Send + Sync { fn set_gather_from_block(&self, gather_from_block: BlockNumber) -> ProviderResult<()>; /// Returns the gather from block. fn get_gather_from_block(&self) -> ProviderResult>; + /// Sets the gather from nonce. + fn set_gather_message_nonce(&self, nonce: Nonce) -> ProviderResult<()>; + /// Returns the gather from nonce. + fn get_gather_message_nonce(&self) -> ProviderResult>; + /// Sets the nonce by message_hash. + fn set_nonce_from_message_hash(&self, message_hash: MessageHash, nonce: Nonce) -> ProviderResult<()>; + /// Returns the nonce by message_hash. + fn get_nonce_from_message_hash(&self, message_hash: MessageHash) -> ProviderResult>; + /// Sets the send from index. + fn set_send_from_index(&self, index: u64) -> ProviderResult<()>; + /// Returns the send from index. + fn get_send_from_index(&self) -> ProviderResult>; }