From 51fa6bbe910854f508f32db2832007504f92f374 Mon Sep 17 00:00:00 2001 From: frisitano Date: Sat, 16 Nov 2024 19:10:50 +0800 Subject: [PATCH 1/2] feat: introduce StateCommitment in StateProviders --- .../commands/debug_cmd/in_memory_merkle.rs | 8 +- bin/reth/src/commands/debug_cmd/merkle.rs | 11 +- crates/exex/exex/src/backfill/test_utils.rs | 6 +- crates/stages/stages/src/stages/execution.rs | 12 +- .../provider/src/providers/consistent.rs | 12 +- .../provider/src/providers/database/mod.rs | 4 +- .../src/providers/database/provider.rs | 41 +++--- .../src/providers/state/historical.rs | 122 +++++++++++------- .../provider/src/providers/state/latest.rs | 49 ++++--- crates/storage/storage-api/src/state.rs | 7 + 10 files changed, 162 insertions(+), 110 deletions(-) diff --git a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs index d5bb8a87b22e..ef186ca050e1 100644 --- a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs @@ -22,9 +22,9 @@ use reth_network_api::NetworkInfo; use reth_node_api::{NodeTypesWithDB, NodeTypesWithEngine}; use reth_node_ethereum::EthExecutorProvider; use reth_provider::{ - writer::UnifiedStorageWriter, AccountExtReader, ChainSpecProvider, HashingWriter, - HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderFactory, - StageCheckpointReader, StateWriter, StorageReader, + writer::UnifiedStorageWriter, AccountExtReader, AsLatestStateProviderRef, ChainSpecProvider, + HashingWriter, HeaderProvider, OriginalValuesKnown, ProviderFactory, StageCheckpointReader, + StateWriter, StorageReader, }; use reth_revm::database::StateProviderDatabase; use reth_stages::StageId; @@ -133,7 +133,7 @@ impl> Command { ) .await?; - let db = StateProviderDatabase::new(LatestStateProviderRef::new(&provider)); + let db = StateProviderDatabase::new(provider.latest()); let executor = EthExecutorProvider::ethereum(provider_factory.chain_spec()).executor(db); diff --git a/bin/reth/src/commands/debug_cmd/merkle.rs b/bin/reth/src/commands/debug_cmd/merkle.rs index 9c77c70abc74..4128b982ca24 100644 --- a/bin/reth/src/commands/debug_cmd/merkle.rs +++ b/bin/reth/src/commands/debug_cmd/merkle.rs @@ -20,9 +20,9 @@ use reth_network_p2p::full_block::FullBlockClient; use reth_node_api::{NodeTypesWithDB, NodeTypesWithEngine}; use reth_node_ethereum::EthExecutorProvider; use reth_provider::{ - writer::UnifiedStorageWriter, BlockNumReader, BlockWriter, ChainSpecProvider, - DatabaseProviderFactory, HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, - ProviderError, ProviderFactory, StateWriter, + writer::UnifiedStorageWriter, AsLatestStateProviderRef, BlockNumReader, BlockWriter, + ChainSpecProvider, DatabaseProviderFactory, HeaderProvider, OriginalValuesKnown, ProviderError, + ProviderFactory, StateWriter, }; use reth_revm::database::StateProviderDatabase; use reth_stages::{ @@ -152,9 +152,8 @@ impl> Command { provider_rw.insert_block(sealed_block.clone())?; td += sealed_block.difficulty; - let mut executor = executor_provider.batch_executor(StateProviderDatabase::new( - LatestStateProviderRef::new(&provider_rw), - )); + let mut executor = + executor_provider.batch_executor(StateProviderDatabase::new(provider_rw.latest())); executor.execute_and_verify_one((&sealed_block.clone().unseal(), td).into())?; let execution_outcome = executor.finalize(); diff --git a/crates/exex/exex/src/backfill/test_utils.rs b/crates/exex/exex/src/backfill/test_utils.rs index 80af408c5c8f..222f9dc1d0d2 100644 --- a/crates/exex/exex/src/backfill/test_utils.rs +++ b/crates/exex/exex/src/backfill/test_utils.rs @@ -13,7 +13,7 @@ use reth_primitives::{ Block, BlockBody, BlockWithSenders, Receipt, SealedBlockWithSenders, Transaction, }; use reth_provider::{ - providers::ProviderNodeTypes, BlockWriter as _, ExecutionOutcome, LatestStateProviderRef, + providers::ProviderNodeTypes, AsLatestStateProviderRef, BlockWriter as _, ExecutionOutcome, ProviderFactory, }; use reth_revm::database::StateProviderDatabase; @@ -63,7 +63,7 @@ where // Execute the block to produce a block execution output let mut block_execution_output = EthExecutorProvider::ethereum(chain_spec) - .executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider))) + .executor(StateProviderDatabase::new(provider.latest())) .execute(BlockExecutionInput { block, total_difficulty: U256::ZERO })?; block_execution_output.state.reverts.sort(); @@ -189,7 +189,7 @@ where let provider = provider_factory.provider()?; let executor = EthExecutorProvider::ethereum(chain_spec) - .batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider))); + .batch_executor(StateProviderDatabase::new(provider.latest())); let mut execution_outcome = executor.execute_and_verify_batch(vec![ (&block1, U256::ZERO).into(), diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index 16234ad483f7..7c6d41bd536f 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -16,7 +16,7 @@ use reth_primitives_traits::{format_gas_throughput, NodePrimitives}; use reth_provider::{ providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter}, writer::UnifiedStorageWriter, - BlockHashReader, BlockReader, DBProvider, HeaderProvider, LatestStateProviderRef, + AsLatestStateProviderRef, BlockHashReader, BlockReader, DBProvider, HeaderProvider, OriginalValuesKnown, ProviderError, StateChangeWriter, StateWriter, StaticFileProviderFactory, StatsReader, TransactionVariant, }; @@ -46,8 +46,9 @@ use tracing::*; /// - [`tables::BlockBodyIndices`] to get tx number /// - [`tables::Transactions`] to execute /// -/// For state access [`LatestStateProviderRef`] provides us latest state and history state -/// For latest most recent state [`LatestStateProviderRef`] would need (Used for execution Stage): +/// For state access [`reth_provider::LatestStateProviderRef`] provides us latest state and history +/// state For latest most recent state [`reth_provider::LatestStateProviderRef`] would need (Used +/// for execution Stage): /// - [`tables::PlainAccountState`] /// - [`tables::Bytecodes`] /// - [`tables::PlainStorageState`] @@ -180,7 +181,8 @@ where + StaticFileProviderFactory + StatsReader + StateChangeWriter - + BlockHashReader, + + BlockHashReader + + AsLatestStateProviderRef, for<'a> UnifiedStorageWriter<'a, Provider, StaticFileProviderRWRefMut<'a, Provider::Primitives>>: StateWriter, { @@ -225,7 +227,7 @@ where None }; - let db = StateProviderDatabase(LatestStateProviderRef::new(provider)); + let db = StateProviderDatabase(provider.latest()); let mut executor = self.executor_provider.batch_executor(db); executor.set_tip(max_block); executor.set_prune_modes(prune_modes); diff --git a/crates/storage/provider/src/providers/consistent.rs b/crates/storage/provider/src/providers/consistent.rs index 3b2599f49991..a5980bcd7d48 100644 --- a/crates/storage/provider/src/providers/consistent.rs +++ b/crates/storage/provider/src/providers/consistent.rs @@ -1,10 +1,10 @@ use super::{DatabaseProviderRO, ProviderFactory, ProviderNodeTypes}; use crate::{ - providers::StaticFileProvider, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, - BlockReader, BlockReaderIdExt, BlockSource, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, - HeaderProvider, ProviderError, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, - StageCheckpointReader, StateReader, StaticFileProviderFactory, TransactionVariant, - TransactionsProvider, WithdrawalsProvider, + providers::StaticFileProvider, AccountReader, AsLatestStateProviderRef, BlockHashReader, + BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, ChainSpecProvider, + ChangeSetReader, EvmEnvProvider, HeaderProvider, ProviderError, PruneCheckpointReader, + ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateReader, + StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; use alloy_consensus::Header; use alloy_eips::{ @@ -109,7 +109,7 @@ impl ConsistentProvider { Ok(self.block_state_provider_ref(state)?.boxed()) } else { trace!(target: "providers::blockchain", "Using database state for latest state provider"); - self.storage_provider.latest() + Ok(self.storage_provider.latest()) } } diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 94c83bbb4422..14fc6f765f63 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -160,7 +160,9 @@ impl ProviderFactory { #[track_caller] pub fn latest(&self) -> ProviderResult { trace!(target: "providers::db", "Returning latest state provider"); - Ok(Box::new(LatestStateProvider::new(self.database_provider_ro()?))) + Ok(Box::new(LatestStateProvider::<_, N::StateCommitment>::new( + self.database_provider_ro()?, + ))) } /// Storage provider for state at that given block diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index b93112e70843..94b57c2113e4 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -6,14 +6,15 @@ use crate::{ AccountExtReader, BlockSource, ChangeSetReader, ReceiptProvider, StageCheckpointWriter, }, writer::UnifiedStorageWriter, - AccountReader, BlockExecutionWriter, BlockHashReader, BlockNumReader, BlockReader, BlockWriter, - BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter, DBProvider, EvmEnvProvider, - HashingWriter, HeaderProvider, HeaderSyncGap, HeaderSyncGapProvider, HistoricalStateProvider, - HistoricalStateProviderRef, HistoryWriter, LatestStateProvider, LatestStateProviderRef, - OriginalValuesKnown, ProviderError, PruneCheckpointReader, PruneCheckpointWriter, RevertsInit, - StageCheckpointReader, StateChangeWriter, StateProviderBox, StateReader, StateWriter, - StaticFileProviderFactory, StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, - TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider, + AccountReader, AsLatestStateProviderRef, BlockExecutionWriter, BlockHashReader, BlockNumReader, + BlockReader, BlockWriter, BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter, + DBProvider, EvmEnvProvider, HashingWriter, HeaderProvider, HeaderSyncGap, + HeaderSyncGapProvider, HistoricalStateProvider, HistoricalStateProviderRef, HistoryWriter, + LatestStateProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, + PruneCheckpointReader, PruneCheckpointWriter, RevertsInit, StageCheckpointReader, + StateChangeWriter, StateProviderBox, StateReader, StateWriter, StaticFileProviderFactory, + StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, TransactionsProvider, + TransactionsProviderExt, TrieWriter, WithdrawalsProvider, }; use alloy_consensus::Header; use alloy_eips::{ @@ -148,12 +149,6 @@ impl DatabaseProvider { } impl DatabaseProvider { - /// State provider for latest block - pub fn latest<'a>(&'a self) -> ProviderResult> { - trace!(target: "providers::db", "Returning latest state provider"); - Ok(Box::new(LatestStateProviderRef::new(self))) - } - /// Storage provider for state at that given block hash pub fn history_by_block_hash<'a>( &'a self, @@ -164,7 +159,7 @@ impl DatabaseProvider { if block_number == self.best_block_number().unwrap_or_default() && block_number == self.last_block_number().unwrap_or_default() { - return Ok(Box::new(LatestStateProviderRef::new(self))) + return Ok(Box::new(LatestStateProviderRef::<'_, _, N::StateCommitment>::new(self))) } // +1 as the changeset that we want is the one that was applied after this block. @@ -175,7 +170,8 @@ impl DatabaseProvider { let storage_history_prune_checkpoint = self.get_prune_checkpoint(PruneSegment::StorageHistory)?; - let mut state_provider = HistoricalStateProviderRef::new(self, block_number); + let mut state_provider = + HistoricalStateProviderRef::<'_, _, N::StateCommitment>::new(self, block_number); // If we pruned account or storage history, we can't return state on every historical block. // Instead, we should cap it at the latest prune checkpoint for corresponding prune segment. @@ -243,7 +239,7 @@ impl TryIntoHistoricalStateProvider for Databa if block_number == self.best_block_number().unwrap_or_default() && block_number == self.last_block_number().unwrap_or_default() { - return Ok(Box::new(LatestStateProvider::new(self))) + return Ok(Box::new(LatestStateProvider::<_, N::StateCommitment>::new(self))) } // +1 as the changeset that we want is the one that was applied after this block. @@ -254,7 +250,8 @@ impl TryIntoHistoricalStateProvider for Databa let storage_history_prune_checkpoint = self.get_prune_checkpoint(PruneSegment::StorageHistory)?; - let mut state_provider = HistoricalStateProvider::new(self, block_number); + let mut state_provider = + HistoricalStateProvider::<_, N::StateCommitment>::new(self, block_number); // If we pruned account or storage history, we can't return state on every historical block. // Instead, we should cap it at the latest prune checkpoint for corresponding prune segment. @@ -277,6 +274,14 @@ impl TryIntoHistoricalStateProvider for Databa } } +impl AsLatestStateProviderRef for DatabaseProvider { + /// State provider for latest state + fn latest<'a>(&'a self) -> Box { + trace!(target: "providers::db", "Returning latest state provider"); + Box::new(LatestStateProviderRef::<'_, _, N::StateCommitment>::new(self)) + } +} + impl + 'static> DatabaseProvider { diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index 29ba70e2049e..2cc912af9791 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -27,7 +27,7 @@ use reth_trie_db::{ DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot, DatabaseTrieWitness, }; -use std::fmt::Debug; +use std::{fmt::Debug, marker::PhantomData}; /// State provider for a given block number which takes a tx reference. /// @@ -41,13 +41,15 @@ use std::fmt::Debug; /// - [`tables::AccountChangeSets`] /// - [`tables::StorageChangeSets`] #[derive(Debug)] -pub struct HistoricalStateProviderRef<'b, Provider> { +pub struct HistoricalStateProviderRef<'b, Provider, SC> { /// Database provider provider: &'b Provider, /// Block number is main index for the history state of accounts and storages. block_number: BlockNumber, /// Lowest blocks at which different parts of the state are available. lowest_available_blocks: LowestAvailableBlocks, + /// Marker to associate the `StateCommitment` type with this provider. + _marker: PhantomData, } #[derive(Debug, Eq, PartialEq)] @@ -58,10 +60,15 @@ pub enum HistoryInfo { MaybeInPlainState, } -impl<'b, Provider: DBProvider + BlockNumReader> HistoricalStateProviderRef<'b, Provider> { +impl<'b, Provider: DBProvider + BlockNumReader, SC> HistoricalStateProviderRef<'b, Provider, SC> { /// Create new `StateProvider` for historical block number pub fn new(provider: &'b Provider, block_number: BlockNumber) -> Self { - Self { provider, block_number, lowest_available_blocks: Default::default() } + Self { + provider, + block_number, + lowest_available_blocks: Default::default(), + _marker: PhantomData, + } } /// Create new `StateProvider` for historical block number and lowest block numbers at which @@ -71,7 +78,7 @@ impl<'b, Provider: DBProvider + BlockNumReader> HistoricalStateProviderRef<'b, P block_number: BlockNumber, lowest_available_blocks: LowestAvailableBlocks, ) -> Self { - Self { provider, block_number, lowest_available_blocks } + Self { provider, block_number, lowest_available_blocks, _marker: PhantomData } } /// Lookup an account in the `AccountsHistory` table @@ -233,14 +240,14 @@ impl<'b, Provider: DBProvider + BlockNumReader> HistoricalStateProviderRef<'b, P } } -impl HistoricalStateProviderRef<'_, Provider> { +impl HistoricalStateProviderRef<'_, Provider, SC> { fn tx(&self) -> &Provider::Tx { self.provider.tx_ref() } } -impl AccountReader - for HistoricalStateProviderRef<'_, Provider> +impl AccountReader + for HistoricalStateProviderRef<'_, Provider, SC> { /// Get basic account information. fn basic_account(&self, address: Address) -> ProviderResult> { @@ -263,8 +270,8 @@ impl AccountReader } } -impl BlockHashReader - for HistoricalStateProviderRef<'_, Provider> +impl BlockHashReader + for HistoricalStateProviderRef<'_, Provider, SC> { /// Get block hash by number. fn block_hash(&self, number: u64) -> ProviderResult> { @@ -280,8 +287,8 @@ impl BlockHashReader } } -impl StateRootProvider - for HistoricalStateProviderRef<'_, Provider> +impl StateRootProvider + for HistoricalStateProviderRef<'_, Provider, SC> { fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult { let mut revert_state = self.revert_state()?; @@ -316,8 +323,8 @@ impl StateRootProvider } } -impl StorageRootProvider - for HistoricalStateProviderRef<'_, Provider> +impl StorageRootProvider + for HistoricalStateProviderRef<'_, Provider, SC> { fn storage_root( &self, @@ -343,8 +350,8 @@ impl StorageRootProvider } } -impl StateProofProvider - for HistoricalStateProviderRef<'_, Provider> +impl StateProofProvider + for HistoricalStateProviderRef<'_, Provider, SC> { /// Get account and storage proofs. fn proof( @@ -377,8 +384,8 @@ impl StateProofProvider } } -impl StateProvider - for HistoricalStateProviderRef<'_, Provider> +impl StateProvider + for HistoricalStateProviderRef<'_, Provider, SC> { /// Get storage. fn storage( @@ -419,19 +426,26 @@ impl StateProvider /// State provider for a given block number. /// For more detailed description, see [`HistoricalStateProviderRef`]. #[derive(Debug)] -pub struct HistoricalStateProvider { +pub struct HistoricalStateProvider { /// Database provider. provider: Provider, /// State at the block number is the main indexer of the state. block_number: BlockNumber, /// Lowest blocks at which different parts of the state are available. lowest_available_blocks: LowestAvailableBlocks, + /// Marker to associate the `StateCommitment` type with this provider. + _marker: PhantomData, } -impl HistoricalStateProvider { +impl HistoricalStateProvider { /// Create new `StateProvider` for historical block number pub fn new(provider: Provider, block_number: BlockNumber) -> Self { - Self { provider, block_number, lowest_available_blocks: Default::default() } + Self { + provider, + block_number, + lowest_available_blocks: Default::default(), + _marker: PhantomData, + } } /// Set the lowest block number at which the account history is available. @@ -454,7 +468,7 @@ impl HistoricalStateProvider { /// Returns a new provider that takes the `TX` as reference #[inline(always)] - const fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> { + const fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider, SC> { HistoricalStateProviderRef::new_with_lowest_available_blocks( &self.provider, self.block_number, @@ -464,7 +478,7 @@ impl HistoricalStateProvider { } // Delegates all provider impls to [HistoricalStateProviderRef] -delegate_provider_impls!(HistoricalStateProvider where [Provider: DBProvider + BlockNumReader + BlockHashReader]); +delegate_provider_impls!(HistoricalStateProvider where [Provider: DBProvider + BlockNumReader + BlockHashReader, SC: Send + Sync]); /// Lowest blocks at which different parts of the state are available. /// They may be [Some] if pruning is enabled. @@ -510,6 +524,10 @@ mod tests { use reth_primitives::{Account, StorageEntry}; use reth_storage_api::{BlockHashReader, BlockNumReader, DBProvider, DatabaseProviderFactory}; use reth_storage_errors::provider::ProviderError; + use reth_trie_db::MerklePatriciaTrie; + + type TestHistoricalStateProviderRef<'a, TX> = + HistoricalStateProviderRef<'a, TX, MerklePatriciaTrie>; const ADDRESS: Address = address!("0000000000000000000000000000000000000001"); const HIGHER_ADDRESS: Address = address!("0000000000000000000000000000000000000005"); @@ -517,8 +535,11 @@ mod tests { const fn assert_state_provider() {} #[allow(dead_code)] - const fn assert_historical_state_provider() { - assert_state_provider::>(); + const fn assert_historical_state_provider< + T: DBProvider + BlockNumReader + BlockHashReader, + SC: Send + Sync, + >() { + assert_state_provider::>(); } #[test] @@ -587,43 +608,46 @@ mod tests { let db = factory.provider().unwrap(); // run - assert_eq!(HistoricalStateProviderRef::new(&db, 1).basic_account(ADDRESS), Ok(None)); + assert_eq!(TestHistoricalStateProviderRef::new(&db, 1).basic_account(ADDRESS), Ok(None)); assert_eq!( - HistoricalStateProviderRef::new(&db, 2).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 2).basic_account(ADDRESS), Ok(Some(acc_at3)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 3).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 3).basic_account(ADDRESS), Ok(Some(acc_at3)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 4).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 4).basic_account(ADDRESS), Ok(Some(acc_at7)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 7).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 7).basic_account(ADDRESS), Ok(Some(acc_at7)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 9).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 9).basic_account(ADDRESS), Ok(Some(acc_at10)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 10).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 10).basic_account(ADDRESS), Ok(Some(acc_at10)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 11).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 11).basic_account(ADDRESS), Ok(Some(acc_at15)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 16).basic_account(ADDRESS), + TestHistoricalStateProviderRef::new(&db, 16).basic_account(ADDRESS), Ok(Some(acc_plain)) ); - assert_eq!(HistoricalStateProviderRef::new(&db, 1).basic_account(HIGHER_ADDRESS), Ok(None)); assert_eq!( - HistoricalStateProviderRef::new(&db, 1000).basic_account(HIGHER_ADDRESS), + TestHistoricalStateProviderRef::new(&db, 1).basic_account(HIGHER_ADDRESS), + Ok(None) + ); + assert_eq!( + TestHistoricalStateProviderRef::new(&db, 1000).basic_account(HIGHER_ADDRESS), Ok(Some(higher_acc_plain)) ); } @@ -681,41 +705,41 @@ mod tests { let db = factory.provider().unwrap(); // run - assert_eq!(HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE), Ok(None)); + assert_eq!(TestHistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE), Ok(None)); assert_eq!( - HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE), Ok(Some(U256::ZERO)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE), Ok(Some(entry_at7.value)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE), Ok(Some(entry_at7.value)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE), Ok(Some(entry_at10.value)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE), Ok(Some(entry_at10.value)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE), Ok(Some(entry_at15.value)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE), Ok(Some(entry_plain.value)) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE), Ok(None) ); assert_eq!( - HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE), + TestHistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE), Ok(Some(higher_entry_plain.value)) ); } @@ -727,7 +751,7 @@ mod tests { // provider block_number < lowest available block number, // i.e. state at provider block is pruned - let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks( + let provider = TestHistoricalStateProviderRef::new_with_lowest_available_blocks( &db, 2, LowestAvailableBlocks { @@ -746,7 +770,7 @@ mod tests { // provider block_number == lowest available block number, // i.e. state at provider block is available - let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks( + let provider = TestHistoricalStateProviderRef::new_with_lowest_available_blocks( &db, 2, LowestAvailableBlocks { @@ -762,7 +786,7 @@ mod tests { // provider block_number == lowest available block number, // i.e. state at provider block is available - let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks( + let provider = TestHistoricalStateProviderRef::new_with_lowest_available_blocks( &db, 2, LowestAvailableBlocks { diff --git a/crates/storage/provider/src/providers/state/latest.rs b/crates/storage/provider/src/providers/state/latest.rs index 297217acece7..bec5aa5e3ac6 100644 --- a/crates/storage/provider/src/providers/state/latest.rs +++ b/crates/storage/provider/src/providers/state/latest.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use crate::{ providers::state::macros::delegate_provider_impls, AccountReader, BlockHashReader, StateProvider, StateRootProvider, @@ -24,14 +26,15 @@ use reth_trie_db::{ /// State provider over latest state that takes tx reference. /// -/// Wraps a [`DBProvider`] to get access to database. +/// Wraps a [`DBProvider`] to get access to database and [`reth_trie_db::StateCommitment`] +/// (`PhantomData`) to get access to state commitment operations. #[derive(Debug)] -pub struct LatestStateProviderRef<'b, Provider>(&'b Provider); +pub struct LatestStateProviderRef<'b, Provider, SC>(&'b Provider, PhantomData); -impl<'b, Provider: DBProvider> LatestStateProviderRef<'b, Provider> { +impl<'b, Provider: DBProvider, SC> LatestStateProviderRef<'b, Provider, SC> { /// Create new state provider pub const fn new(provider: &'b Provider) -> Self { - Self(provider) + Self(provider, PhantomData) } fn tx(&self) -> &Provider::Tx { @@ -39,14 +42,18 @@ impl<'b, Provider: DBProvider> LatestStateProviderRef<'b, Provider> { } } -impl AccountReader for LatestStateProviderRef<'_, Provider> { +impl AccountReader + for LatestStateProviderRef<'_, Provider, SC> +{ /// Get basic account information. fn basic_account(&self, address: Address) -> ProviderResult> { self.tx().get::(address).map_err(Into::into) } } -impl BlockHashReader for LatestStateProviderRef<'_, Provider> { +impl BlockHashReader + for LatestStateProviderRef<'_, Provider, SC> +{ /// Get block hash by number. fn block_hash(&self, number: u64) -> ProviderResult> { self.0.block_hash(number) @@ -61,7 +68,9 @@ impl BlockHashReader for LatestStateProviderRef<'_, P } } -impl StateRootProvider for LatestStateProviderRef<'_, Provider> { +impl StateRootProvider + for LatestStateProviderRef<'_, Provider, SC> +{ fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult { StateRoot::overlay_root(self.tx(), hashed_state) .map_err(|err| ProviderError::Database(err.into())) @@ -89,7 +98,9 @@ impl StateRootProvider for LatestStateProviderRef<'_, Prov } } -impl StorageRootProvider for LatestStateProviderRef<'_, Provider> { +impl StorageRootProvider + for LatestStateProviderRef<'_, Provider, SC> +{ fn storage_root( &self, address: Address, @@ -110,7 +121,9 @@ impl StorageRootProvider for LatestStateProviderRef<'_, Pr } } -impl StateProofProvider for LatestStateProviderRef<'_, Provider> { +impl StateProofProvider + for LatestStateProviderRef<'_, Provider, SC> +{ fn proof( &self, input: TrieInput, @@ -138,8 +151,8 @@ impl StateProofProvider for LatestStateProviderRef<'_, Pro } } -impl StateProvider - for LatestStateProviderRef<'_, Provider> +impl StateProvider + for LatestStateProviderRef<'_, Provider, SC> { /// Get storage. fn storage( @@ -164,23 +177,23 @@ impl StateProvider /// State provider for the latest state. #[derive(Debug)] -pub struct LatestStateProvider(Provider); +pub struct LatestStateProvider(Provider, PhantomData); -impl LatestStateProvider { +impl LatestStateProvider { /// Create new state provider pub const fn new(db: Provider) -> Self { - Self(db) + Self(db, PhantomData) } /// Returns a new provider that takes the `TX` as reference #[inline(always)] - const fn as_ref(&self) -> LatestStateProviderRef<'_, Provider> { + const fn as_ref(&self) -> LatestStateProviderRef<'_, Provider, SC> { LatestStateProviderRef::new(&self.0) } } // Delegates all provider impls to [LatestStateProviderRef] -delegate_provider_impls!(LatestStateProvider where [Provider: DBProvider + BlockHashReader]); +delegate_provider_impls!(LatestStateProvider where [Provider: DBProvider + BlockHashReader, SC: Send + Sync]); #[cfg(test)] mod tests { @@ -188,7 +201,7 @@ mod tests { const fn assert_state_provider() {} #[allow(dead_code)] - const fn assert_latest_state_provider() { - assert_state_provider::>(); + const fn assert_latest_state_provider() { + assert_state_provider::>(); } } diff --git a/crates/storage/storage-api/src/state.rs b/crates/storage/storage-api/src/state.rs index d37940f04787..6c9e82cfba3b 100644 --- a/crates/storage/storage-api/src/state.rs +++ b/crates/storage/storage-api/src/state.rs @@ -91,6 +91,13 @@ pub trait TryIntoHistoricalStateProvider { ) -> ProviderResult; } +/// Trait implemented for database providers that can be converted into a latest state provider +/// reference. +pub trait AsLatestStateProviderRef { + /// Returns a [`StateProvider`] for the latest state. + fn latest<'a>(&'a self) -> Box; +} + /// Light wrapper that returns `StateProvider` implementations that correspond to the given /// `BlockNumber`, the latest state, or the pending state. /// From 52426dbce689ea4595881023834c32166a17959f Mon Sep 17 00:00:00 2001 From: frisitano Date: Wed, 20 Nov 2024 12:57:08 +0800 Subject: [PATCH 2/2] refactor: introduce StateCommimentProvider --- Cargo.lock | 1 + .../commands/debug_cmd/in_memory_merkle.rs | 8 +- bin/reth/src/commands/debug_cmd/merkle.rs | 11 +- crates/exex/exex/src/backfill/test_utils.rs | 6 +- crates/stages/stages/src/stages/execution.rs | 15 +- .../provider/src/providers/consistent.rs | 10 +- .../provider/src/providers/database/mod.rs | 4 +- .../src/providers/database/provider.rs | 42 +++--- .../src/providers/state/historical.rs | 133 ++++++++---------- .../provider/src/providers/state/latest.rs | 55 ++++---- crates/storage/storage-api/Cargo.toml | 1 + crates/storage/storage-api/src/state.rs | 14 +- 12 files changed, 142 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 973ad4718720..f1fb2f89eeaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9183,6 +9183,7 @@ dependencies = [ "reth-stages-types", "reth-storage-errors", "reth-trie", + "reth-trie-db", ] [[package]] diff --git a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs index ef186ca050e1..d5bb8a87b22e 100644 --- a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs @@ -22,9 +22,9 @@ use reth_network_api::NetworkInfo; use reth_node_api::{NodeTypesWithDB, NodeTypesWithEngine}; use reth_node_ethereum::EthExecutorProvider; use reth_provider::{ - writer::UnifiedStorageWriter, AccountExtReader, AsLatestStateProviderRef, ChainSpecProvider, - HashingWriter, HeaderProvider, OriginalValuesKnown, ProviderFactory, StageCheckpointReader, - StateWriter, StorageReader, + writer::UnifiedStorageWriter, AccountExtReader, ChainSpecProvider, HashingWriter, + HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderFactory, + StageCheckpointReader, StateWriter, StorageReader, }; use reth_revm::database::StateProviderDatabase; use reth_stages::StageId; @@ -133,7 +133,7 @@ impl> Command { ) .await?; - let db = StateProviderDatabase::new(provider.latest()); + let db = StateProviderDatabase::new(LatestStateProviderRef::new(&provider)); let executor = EthExecutorProvider::ethereum(provider_factory.chain_spec()).executor(db); diff --git a/bin/reth/src/commands/debug_cmd/merkle.rs b/bin/reth/src/commands/debug_cmd/merkle.rs index 4128b982ca24..9c77c70abc74 100644 --- a/bin/reth/src/commands/debug_cmd/merkle.rs +++ b/bin/reth/src/commands/debug_cmd/merkle.rs @@ -20,9 +20,9 @@ use reth_network_p2p::full_block::FullBlockClient; use reth_node_api::{NodeTypesWithDB, NodeTypesWithEngine}; use reth_node_ethereum::EthExecutorProvider; use reth_provider::{ - writer::UnifiedStorageWriter, AsLatestStateProviderRef, BlockNumReader, BlockWriter, - ChainSpecProvider, DatabaseProviderFactory, HeaderProvider, OriginalValuesKnown, ProviderError, - ProviderFactory, StateWriter, + writer::UnifiedStorageWriter, BlockNumReader, BlockWriter, ChainSpecProvider, + DatabaseProviderFactory, HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, + ProviderError, ProviderFactory, StateWriter, }; use reth_revm::database::StateProviderDatabase; use reth_stages::{ @@ -152,8 +152,9 @@ impl> Command { provider_rw.insert_block(sealed_block.clone())?; td += sealed_block.difficulty; - let mut executor = - executor_provider.batch_executor(StateProviderDatabase::new(provider_rw.latest())); + let mut executor = executor_provider.batch_executor(StateProviderDatabase::new( + LatestStateProviderRef::new(&provider_rw), + )); executor.execute_and_verify_one((&sealed_block.clone().unseal(), td).into())?; let execution_outcome = executor.finalize(); diff --git a/crates/exex/exex/src/backfill/test_utils.rs b/crates/exex/exex/src/backfill/test_utils.rs index 222f9dc1d0d2..80af408c5c8f 100644 --- a/crates/exex/exex/src/backfill/test_utils.rs +++ b/crates/exex/exex/src/backfill/test_utils.rs @@ -13,7 +13,7 @@ use reth_primitives::{ Block, BlockBody, BlockWithSenders, Receipt, SealedBlockWithSenders, Transaction, }; use reth_provider::{ - providers::ProviderNodeTypes, AsLatestStateProviderRef, BlockWriter as _, ExecutionOutcome, + providers::ProviderNodeTypes, BlockWriter as _, ExecutionOutcome, LatestStateProviderRef, ProviderFactory, }; use reth_revm::database::StateProviderDatabase; @@ -63,7 +63,7 @@ where // Execute the block to produce a block execution output let mut block_execution_output = EthExecutorProvider::ethereum(chain_spec) - .executor(StateProviderDatabase::new(provider.latest())) + .executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider))) .execute(BlockExecutionInput { block, total_difficulty: U256::ZERO })?; block_execution_output.state.reverts.sort(); @@ -189,7 +189,7 @@ where let provider = provider_factory.provider()?; let executor = EthExecutorProvider::ethereum(chain_spec) - .batch_executor(StateProviderDatabase::new(provider.latest())); + .batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider))); let mut execution_outcome = executor.execute_and_verify_batch(vec![ (&block1, U256::ZERO).into(), diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index 7c6d41bd536f..c8bcc8ae389a 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -16,9 +16,9 @@ use reth_primitives_traits::{format_gas_throughput, NodePrimitives}; use reth_provider::{ providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter}, writer::UnifiedStorageWriter, - AsLatestStateProviderRef, BlockHashReader, BlockReader, DBProvider, HeaderProvider, - OriginalValuesKnown, ProviderError, StateChangeWriter, StateWriter, StaticFileProviderFactory, - StatsReader, TransactionVariant, + BlockHashReader, BlockReader, DBProvider, HeaderProvider, LatestStateProviderRef, + OriginalValuesKnown, ProviderError, StateChangeWriter, StateCommitmentProvider, StateWriter, + StaticFileProviderFactory, StatsReader, TransactionVariant, }; use reth_prune_types::PruneModes; use reth_revm::database::StateProviderDatabase; @@ -46,9 +46,8 @@ use tracing::*; /// - [`tables::BlockBodyIndices`] to get tx number /// - [`tables::Transactions`] to execute /// -/// For state access [`reth_provider::LatestStateProviderRef`] provides us latest state and history -/// state For latest most recent state [`reth_provider::LatestStateProviderRef`] would need (Used -/// for execution Stage): +/// For state access [`LatestStateProviderRef`] provides us latest state and history state +/// For latest most recent state [`LatestStateProviderRef`] would need (Used for execution Stage): /// - [`tables::PlainAccountState`] /// - [`tables::Bytecodes`] /// - [`tables::PlainStorageState`] @@ -182,7 +181,7 @@ where + StatsReader + StateChangeWriter + BlockHashReader - + AsLatestStateProviderRef, + + StateCommitmentProvider, for<'a> UnifiedStorageWriter<'a, Provider, StaticFileProviderRWRefMut<'a, Provider::Primitives>>: StateWriter, { @@ -227,7 +226,7 @@ where None }; - let db = StateProviderDatabase(provider.latest()); + let db = StateProviderDatabase(LatestStateProviderRef::new(provider)); let mut executor = self.executor_provider.batch_executor(db); executor.set_tip(max_block); executor.set_prune_modes(prune_modes); diff --git a/crates/storage/provider/src/providers/consistent.rs b/crates/storage/provider/src/providers/consistent.rs index a5980bcd7d48..7702504ced4a 100644 --- a/crates/storage/provider/src/providers/consistent.rs +++ b/crates/storage/provider/src/providers/consistent.rs @@ -1,10 +1,10 @@ use super::{DatabaseProviderRO, ProviderFactory, ProviderNodeTypes}; use crate::{ - providers::StaticFileProvider, AccountReader, AsLatestStateProviderRef, BlockHashReader, - BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, ChainSpecProvider, - ChangeSetReader, EvmEnvProvider, HeaderProvider, ProviderError, PruneCheckpointReader, - ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateReader, - StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, + providers::StaticFileProvider, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, + BlockReader, BlockReaderIdExt, BlockSource, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, + HeaderProvider, ProviderError, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, + StageCheckpointReader, StateReader, StaticFileProviderFactory, TransactionVariant, + TransactionsProvider, WithdrawalsProvider, }; use alloy_consensus::Header; use alloy_eips::{ diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 14fc6f765f63..94c83bbb4422 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -160,9 +160,7 @@ impl ProviderFactory { #[track_caller] pub fn latest(&self) -> ProviderResult { trace!(target: "providers::db", "Returning latest state provider"); - Ok(Box::new(LatestStateProvider::<_, N::StateCommitment>::new( - self.database_provider_ro()?, - ))) + Ok(Box::new(LatestStateProvider::new(self.database_provider_ro()?))) } /// Storage provider for state at that given block diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 94b57c2113e4..ab5ed783e898 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -6,15 +6,15 @@ use crate::{ AccountExtReader, BlockSource, ChangeSetReader, ReceiptProvider, StageCheckpointWriter, }, writer::UnifiedStorageWriter, - AccountReader, AsLatestStateProviderRef, BlockExecutionWriter, BlockHashReader, BlockNumReader, - BlockReader, BlockWriter, BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter, - DBProvider, EvmEnvProvider, HashingWriter, HeaderProvider, HeaderSyncGap, - HeaderSyncGapProvider, HistoricalStateProvider, HistoricalStateProviderRef, HistoryWriter, - LatestStateProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, - PruneCheckpointReader, PruneCheckpointWriter, RevertsInit, StageCheckpointReader, - StateChangeWriter, StateProviderBox, StateReader, StateWriter, StaticFileProviderFactory, - StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, TransactionsProvider, - TransactionsProviderExt, TrieWriter, WithdrawalsProvider, + AccountReader, BlockExecutionWriter, BlockHashReader, BlockNumReader, BlockReader, BlockWriter, + BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter, DBProvider, EvmEnvProvider, + HashingWriter, HeaderProvider, HeaderSyncGap, HeaderSyncGapProvider, HistoricalStateProvider, + HistoricalStateProviderRef, HistoryWriter, LatestStateProvider, LatestStateProviderRef, + OriginalValuesKnown, ProviderError, PruneCheckpointReader, PruneCheckpointWriter, RevertsInit, + StageCheckpointReader, StateChangeWriter, StateCommitmentProvider, StateProviderBox, + StateReader, StateWriter, StaticFileProviderFactory, StatsReader, StorageReader, + StorageTrieWriter, TransactionVariant, TransactionsProvider, TransactionsProviderExt, + TrieWriter, WithdrawalsProvider, }; use alloy_consensus::Header; use alloy_eips::{ @@ -149,6 +149,12 @@ impl DatabaseProvider { } impl DatabaseProvider { + /// State provider for latest state + pub fn latest<'a>(&'a self) -> Box { + trace!(target: "providers::db", "Returning latest state provider"); + Box::new(LatestStateProviderRef::new(self)) + } + /// Storage provider for state at that given block hash pub fn history_by_block_hash<'a>( &'a self, @@ -159,7 +165,7 @@ impl DatabaseProvider { if block_number == self.best_block_number().unwrap_or_default() && block_number == self.last_block_number().unwrap_or_default() { - return Ok(Box::new(LatestStateProviderRef::<'_, _, N::StateCommitment>::new(self))) + return Ok(Box::new(LatestStateProviderRef::new(self))) } // +1 as the changeset that we want is the one that was applied after this block. @@ -170,8 +176,7 @@ impl DatabaseProvider { let storage_history_prune_checkpoint = self.get_prune_checkpoint(PruneSegment::StorageHistory)?; - let mut state_provider = - HistoricalStateProviderRef::<'_, _, N::StateCommitment>::new(self, block_number); + let mut state_provider = HistoricalStateProviderRef::new(self, block_number); // If we pruned account or storage history, we can't return state on every historical block. // Instead, we should cap it at the latest prune checkpoint for corresponding prune segment. @@ -239,7 +244,7 @@ impl TryIntoHistoricalStateProvider for Databa if block_number == self.best_block_number().unwrap_or_default() && block_number == self.last_block_number().unwrap_or_default() { - return Ok(Box::new(LatestStateProvider::<_, N::StateCommitment>::new(self))) + return Ok(Box::new(LatestStateProvider::new(self))) } // +1 as the changeset that we want is the one that was applied after this block. @@ -250,8 +255,7 @@ impl TryIntoHistoricalStateProvider for Databa let storage_history_prune_checkpoint = self.get_prune_checkpoint(PruneSegment::StorageHistory)?; - let mut state_provider = - HistoricalStateProvider::<_, N::StateCommitment>::new(self, block_number); + let mut state_provider = HistoricalStateProvider::new(self, block_number); // If we pruned account or storage history, we can't return state on every historical block. // Instead, we should cap it at the latest prune checkpoint for corresponding prune segment. @@ -274,12 +278,8 @@ impl TryIntoHistoricalStateProvider for Databa } } -impl AsLatestStateProviderRef for DatabaseProvider { - /// State provider for latest state - fn latest<'a>(&'a self) -> Box { - trace!(target: "providers::db", "Returning latest state provider"); - Box::new(LatestStateProviderRef::<'_, _, N::StateCommitment>::new(self)) - } +impl StateCommitmentProvider for DatabaseProvider { + type StateCommitment = N::StateCommitment; } impl + 'static> diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index 2cc912af9791..a70fe9ac203b 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -15,7 +15,9 @@ use reth_db_api::{ transaction::DbTx, }; use reth_primitives::{Account, Bytecode}; -use reth_storage_api::{BlockNumReader, DBProvider, StateProofProvider, StorageRootProvider}; +use reth_storage_api::{ + BlockNumReader, DBProvider, StateCommitmentProvider, StateProofProvider, StorageRootProvider, +}; use reth_storage_errors::provider::ProviderResult; use reth_trie::{ proof::{Proof, StorageProof}, @@ -27,7 +29,7 @@ use reth_trie_db::{ DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot, DatabaseTrieWitness, }; -use std::{fmt::Debug, marker::PhantomData}; +use std::fmt::Debug; /// State provider for a given block number which takes a tx reference. /// @@ -41,15 +43,13 @@ use std::{fmt::Debug, marker::PhantomData}; /// - [`tables::AccountChangeSets`] /// - [`tables::StorageChangeSets`] #[derive(Debug)] -pub struct HistoricalStateProviderRef<'b, Provider, SC> { +pub struct HistoricalStateProviderRef<'b, Provider> { /// Database provider provider: &'b Provider, /// Block number is main index for the history state of accounts and storages. block_number: BlockNumber, /// Lowest blocks at which different parts of the state are available. lowest_available_blocks: LowestAvailableBlocks, - /// Marker to associate the `StateCommitment` type with this provider. - _marker: PhantomData, } #[derive(Debug, Eq, PartialEq)] @@ -60,15 +60,12 @@ pub enum HistoryInfo { MaybeInPlainState, } -impl<'b, Provider: DBProvider + BlockNumReader, SC> HistoricalStateProviderRef<'b, Provider, SC> { +impl<'b, Provider: DBProvider + BlockNumReader + StateCommitmentProvider> + HistoricalStateProviderRef<'b, Provider> +{ /// Create new `StateProvider` for historical block number pub fn new(provider: &'b Provider, block_number: BlockNumber) -> Self { - Self { - provider, - block_number, - lowest_available_blocks: Default::default(), - _marker: PhantomData, - } + Self { provider, block_number, lowest_available_blocks: Default::default() } } /// Create new `StateProvider` for historical block number and lowest block numbers at which @@ -78,7 +75,7 @@ impl<'b, Provider: DBProvider + BlockNumReader, SC> HistoricalStateProviderRef<' block_number: BlockNumber, lowest_available_blocks: LowestAvailableBlocks, ) -> Self { - Self { provider, block_number, lowest_available_blocks, _marker: PhantomData } + Self { provider, block_number, lowest_available_blocks } } /// Lookup an account in the `AccountsHistory` table @@ -240,14 +237,14 @@ impl<'b, Provider: DBProvider + BlockNumReader, SC> HistoricalStateProviderRef<' } } -impl HistoricalStateProviderRef<'_, Provider, SC> { +impl HistoricalStateProviderRef<'_, Provider> { fn tx(&self) -> &Provider::Tx { self.provider.tx_ref() } } -impl AccountReader - for HistoricalStateProviderRef<'_, Provider, SC> +impl AccountReader + for HistoricalStateProviderRef<'_, Provider> { /// Get basic account information. fn basic_account(&self, address: Address) -> ProviderResult> { @@ -270,8 +267,8 @@ impl AccountReader } } -impl BlockHashReader - for HistoricalStateProviderRef<'_, Provider, SC> +impl BlockHashReader + for HistoricalStateProviderRef<'_, Provider> { /// Get block hash by number. fn block_hash(&self, number: u64) -> ProviderResult> { @@ -287,8 +284,8 @@ impl B } } -impl StateRootProvider - for HistoricalStateProviderRef<'_, Provider, SC> +impl StateRootProvider + for HistoricalStateProviderRef<'_, Provider> { fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult { let mut revert_state = self.revert_state()?; @@ -323,8 +320,8 @@ impl StateRootProvider } } -impl StorageRootProvider - for HistoricalStateProviderRef<'_, Provider, SC> +impl StorageRootProvider + for HistoricalStateProviderRef<'_, Provider> { fn storage_root( &self, @@ -350,8 +347,8 @@ impl StorageRootProvider } } -impl StateProofProvider - for HistoricalStateProviderRef<'_, Provider, SC> +impl StateProofProvider + for HistoricalStateProviderRef<'_, Provider> { /// Get account and storage proofs. fn proof( @@ -384,8 +381,8 @@ impl StateProofProvider } } -impl StateProvider - for HistoricalStateProviderRef<'_, Provider, SC> +impl + StateProvider for HistoricalStateProviderRef<'_, Provider> { /// Get storage. fn storage( @@ -426,26 +423,21 @@ impl S /// State provider for a given block number. /// For more detailed description, see [`HistoricalStateProviderRef`]. #[derive(Debug)] -pub struct HistoricalStateProvider { +pub struct HistoricalStateProvider { /// Database provider. provider: Provider, /// State at the block number is the main indexer of the state. block_number: BlockNumber, /// Lowest blocks at which different parts of the state are available. lowest_available_blocks: LowestAvailableBlocks, - /// Marker to associate the `StateCommitment` type with this provider. - _marker: PhantomData, } -impl HistoricalStateProvider { +impl + HistoricalStateProvider +{ /// Create new `StateProvider` for historical block number pub fn new(provider: Provider, block_number: BlockNumber) -> Self { - Self { - provider, - block_number, - lowest_available_blocks: Default::default(), - _marker: PhantomData, - } + Self { provider, block_number, lowest_available_blocks: Default::default() } } /// Set the lowest block number at which the account history is available. @@ -468,7 +460,7 @@ impl HistoricalStateProvider HistoricalStateProviderRef<'_, Provider, SC> { + const fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> { HistoricalStateProviderRef::new_with_lowest_available_blocks( &self.provider, self.block_number, @@ -478,7 +470,7 @@ impl HistoricalStateProvider where [Provider: DBProvider + BlockNumReader + BlockHashReader, SC: Send + Sync]); +delegate_provider_impls!(HistoricalStateProvider where [Provider: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider]); /// Lowest blocks at which different parts of the state are available. /// They may be [Some] if pruning is enabled. @@ -522,12 +514,11 @@ mod tests { transaction::{DbTx, DbTxMut}, }; use reth_primitives::{Account, StorageEntry}; - use reth_storage_api::{BlockHashReader, BlockNumReader, DBProvider, DatabaseProviderFactory}; + use reth_storage_api::{ + BlockHashReader, BlockNumReader, DBProvider, DatabaseProviderFactory, + StateCommitmentProvider, + }; use reth_storage_errors::provider::ProviderError; - use reth_trie_db::MerklePatriciaTrie; - - type TestHistoricalStateProviderRef<'a, TX> = - HistoricalStateProviderRef<'a, TX, MerklePatriciaTrie>; const ADDRESS: Address = address!("0000000000000000000000000000000000000001"); const HIGHER_ADDRESS: Address = address!("0000000000000000000000000000000000000005"); @@ -536,10 +527,9 @@ mod tests { const fn assert_state_provider() {} #[allow(dead_code)] const fn assert_historical_state_provider< - T: DBProvider + BlockNumReader + BlockHashReader, - SC: Send + Sync, + T: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider, >() { - assert_state_provider::>(); + assert_state_provider::>(); } #[test] @@ -608,46 +598,43 @@ mod tests { let db = factory.provider().unwrap(); // run - assert_eq!(TestHistoricalStateProviderRef::new(&db, 1).basic_account(ADDRESS), Ok(None)); + assert_eq!(HistoricalStateProviderRef::new(&db, 1).basic_account(ADDRESS), Ok(None)); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 2).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 2).basic_account(ADDRESS), Ok(Some(acc_at3)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 3).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 3).basic_account(ADDRESS), Ok(Some(acc_at3)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 4).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 4).basic_account(ADDRESS), Ok(Some(acc_at7)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 7).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 7).basic_account(ADDRESS), Ok(Some(acc_at7)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 9).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 9).basic_account(ADDRESS), Ok(Some(acc_at10)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 10).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 10).basic_account(ADDRESS), Ok(Some(acc_at10)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 11).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 11).basic_account(ADDRESS), Ok(Some(acc_at15)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 16).basic_account(ADDRESS), + HistoricalStateProviderRef::new(&db, 16).basic_account(ADDRESS), Ok(Some(acc_plain)) ); + assert_eq!(HistoricalStateProviderRef::new(&db, 1).basic_account(HIGHER_ADDRESS), Ok(None)); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 1).basic_account(HIGHER_ADDRESS), - Ok(None) - ); - assert_eq!( - TestHistoricalStateProviderRef::new(&db, 1000).basic_account(HIGHER_ADDRESS), + HistoricalStateProviderRef::new(&db, 1000).basic_account(HIGHER_ADDRESS), Ok(Some(higher_acc_plain)) ); } @@ -705,41 +692,41 @@ mod tests { let db = factory.provider().unwrap(); // run - assert_eq!(TestHistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE), Ok(None)); + assert_eq!(HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE), Ok(None)); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE), Ok(Some(U256::ZERO)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE), Ok(Some(entry_at7.value)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE), Ok(Some(entry_at7.value)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE), Ok(Some(entry_at10.value)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE), Ok(Some(entry_at10.value)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE), Ok(Some(entry_at15.value)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE), Ok(Some(entry_plain.value)) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE), Ok(None) ); assert_eq!( - TestHistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE), + HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE), Ok(Some(higher_entry_plain.value)) ); } @@ -751,7 +738,7 @@ mod tests { // provider block_number < lowest available block number, // i.e. state at provider block is pruned - let provider = TestHistoricalStateProviderRef::new_with_lowest_available_blocks( + let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks( &db, 2, LowestAvailableBlocks { @@ -770,7 +757,7 @@ mod tests { // provider block_number == lowest available block number, // i.e. state at provider block is available - let provider = TestHistoricalStateProviderRef::new_with_lowest_available_blocks( + let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks( &db, 2, LowestAvailableBlocks { @@ -786,7 +773,7 @@ mod tests { // provider block_number == lowest available block number, // i.e. state at provider block is available - let provider = TestHistoricalStateProviderRef::new_with_lowest_available_blocks( + let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks( &db, 2, LowestAvailableBlocks { diff --git a/crates/storage/provider/src/providers/state/latest.rs b/crates/storage/provider/src/providers/state/latest.rs index bec5aa5e3ac6..ab70d759b992 100644 --- a/crates/storage/provider/src/providers/state/latest.rs +++ b/crates/storage/provider/src/providers/state/latest.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use crate::{ providers::state::macros::delegate_provider_impls, AccountReader, BlockHashReader, StateProvider, StateRootProvider, @@ -11,7 +9,9 @@ use alloy_primitives::{ use reth_db::tables; use reth_db_api::{cursor::DbDupCursorRO, transaction::DbTx}; use reth_primitives::{Account, Bytecode}; -use reth_storage_api::{DBProvider, StateProofProvider, StorageRootProvider}; +use reth_storage_api::{ + DBProvider, StateCommitmentProvider, StateProofProvider, StorageRootProvider, +}; use reth_storage_errors::provider::{ProviderError, ProviderResult}; use reth_trie::{ proof::{Proof, StorageProof}, @@ -26,15 +26,14 @@ use reth_trie_db::{ /// State provider over latest state that takes tx reference. /// -/// Wraps a [`DBProvider`] to get access to database and [`reth_trie_db::StateCommitment`] -/// (`PhantomData`) to get access to state commitment operations. +/// Wraps a [`DBProvider`] to get access to database. #[derive(Debug)] -pub struct LatestStateProviderRef<'b, Provider, SC>(&'b Provider, PhantomData); +pub struct LatestStateProviderRef<'b, Provider>(&'b Provider); -impl<'b, Provider: DBProvider, SC> LatestStateProviderRef<'b, Provider, SC> { +impl<'b, Provider: DBProvider> LatestStateProviderRef<'b, Provider> { /// Create new state provider pub const fn new(provider: &'b Provider) -> Self { - Self(provider, PhantomData) + Self(provider) } fn tx(&self) -> &Provider::Tx { @@ -42,18 +41,14 @@ impl<'b, Provider: DBProvider, SC> LatestStateProviderRef<'b, Provider, SC> { } } -impl AccountReader - for LatestStateProviderRef<'_, Provider, SC> -{ +impl AccountReader for LatestStateProviderRef<'_, Provider> { /// Get basic account information. fn basic_account(&self, address: Address) -> ProviderResult> { self.tx().get::(address).map_err(Into::into) } } -impl BlockHashReader - for LatestStateProviderRef<'_, Provider, SC> -{ +impl BlockHashReader for LatestStateProviderRef<'_, Provider> { /// Get block hash by number. fn block_hash(&self, number: u64) -> ProviderResult> { self.0.block_hash(number) @@ -68,8 +63,8 @@ impl BlockHashReader } } -impl StateRootProvider - for LatestStateProviderRef<'_, Provider, SC> +impl StateRootProvider + for LatestStateProviderRef<'_, Provider> { fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult { StateRoot::overlay_root(self.tx(), hashed_state) @@ -98,8 +93,8 @@ impl StateRootProvider } } -impl StorageRootProvider - for LatestStateProviderRef<'_, Provider, SC> +impl StorageRootProvider + for LatestStateProviderRef<'_, Provider> { fn storage_root( &self, @@ -121,8 +116,8 @@ impl StorageRootProvider } } -impl StateProofProvider - for LatestStateProviderRef<'_, Provider, SC> +impl StateProofProvider + for LatestStateProviderRef<'_, Provider> { fn proof( &self, @@ -151,8 +146,8 @@ impl StateProofProvider } } -impl StateProvider - for LatestStateProviderRef<'_, Provider, SC> +impl StateProvider + for LatestStateProviderRef<'_, Provider> { /// Get storage. fn storage( @@ -177,23 +172,23 @@ impl StateProvider /// State provider for the latest state. #[derive(Debug)] -pub struct LatestStateProvider(Provider, PhantomData); +pub struct LatestStateProvider(Provider); -impl LatestStateProvider { +impl LatestStateProvider { /// Create new state provider pub const fn new(db: Provider) -> Self { - Self(db, PhantomData) + Self(db) } /// Returns a new provider that takes the `TX` as reference #[inline(always)] - const fn as_ref(&self) -> LatestStateProviderRef<'_, Provider, SC> { + const fn as_ref(&self) -> LatestStateProviderRef<'_, Provider> { LatestStateProviderRef::new(&self.0) } } // Delegates all provider impls to [LatestStateProviderRef] -delegate_provider_impls!(LatestStateProvider where [Provider: DBProvider + BlockHashReader, SC: Send + Sync]); +delegate_provider_impls!(LatestStateProvider where [Provider: DBProvider + BlockHashReader + StateCommitmentProvider]); #[cfg(test)] mod tests { @@ -201,7 +196,9 @@ mod tests { const fn assert_state_provider() {} #[allow(dead_code)] - const fn assert_latest_state_provider() { - assert_state_provider::>(); + const fn assert_latest_state_provider< + T: DBProvider + BlockHashReader + StateCommitmentProvider, + >() { + assert_state_provider::>(); } } diff --git a/crates/storage/storage-api/Cargo.toml b/crates/storage/storage-api/Cargo.toml index 2b13f6332f87..88e35c18f8c6 100644 --- a/crates/storage/storage-api/Cargo.toml +++ b/crates/storage/storage-api/Cargo.toml @@ -22,6 +22,7 @@ reth-prune-types.workspace = true reth-stages-types.workspace = true reth-storage-errors.workspace = true reth-trie.workspace = true +reth-trie-db.workspace = true reth-db.workspace = true # ethereum diff --git a/crates/storage/storage-api/src/state.rs b/crates/storage/storage-api/src/state.rs index 6c9e82cfba3b..49db24a9bb93 100644 --- a/crates/storage/storage-api/src/state.rs +++ b/crates/storage/storage-api/src/state.rs @@ -9,6 +9,7 @@ use auto_impl::auto_impl; use reth_execution_types::ExecutionOutcome; use reth_primitives::Bytecode; use reth_storage_errors::provider::{ProviderError, ProviderResult}; +use reth_trie_db::StateCommitment; /// Type alias of boxed [`StateProvider`]. pub type StateProviderBox = Box; @@ -82,6 +83,12 @@ pub trait StateProvider: } } +/// Trait implemented for database providers that can provide the [`StateCommitment`] type. +pub trait StateCommitmentProvider { + /// The [`StateCommitment`] type that can be used to perform state commitment operations. + type StateCommitment: StateCommitment; +} + /// Trait implemented for database providers that can be converted into a historical state provider. pub trait TryIntoHistoricalStateProvider { /// Returns a historical [`StateProvider`] indexed by the given historic block number. @@ -91,13 +98,6 @@ pub trait TryIntoHistoricalStateProvider { ) -> ProviderResult; } -/// Trait implemented for database providers that can be converted into a latest state provider -/// reference. -pub trait AsLatestStateProviderRef { - /// Returns a [`StateProvider`] for the latest state. - fn latest<'a>(&'a self) -> Box; -} - /// Light wrapper that returns `StateProvider` implementations that correspond to the given /// `BlockNumber`, the latest state, or the pending state. ///