From dad6d7438403ab0a0024ff495e164e78350ec194 Mon Sep 17 00:00:00 2001 From: frisitano <35734660+frisitano@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:47:42 +0800 Subject: [PATCH] Introduce `StateRootProviderExt` and integrate `StateRootProvider*` with `StateCommitment` (#48) * feat: introduce StateCommitment in StateProviders * refactor: introduce StateCommimentProvider * feat: introduce HashedPostStateProvider * feat: HashedPostState from reverts * feat: introduce HashedStorageProvider * lint: revm/test-utils feature propogation * fix: add Send + Sync bound on introduced storage state api methods * feat: introduce KeyHasherProvider * feat: introduce StateRootProviderExt and integrate it (and StateRootProvider) with StateCommitment * fix: add merge files * fix lint * fix lint * fmt * add KeyHasher generic to DatabaseHashedStorage::from_reverts trait * add merge files * add merge files * fix: propagate feature * fix: merge conflicts * reduce diff with upstream * remove clone requirement in blockchain_tree state root calculation --- Cargo.lock | 3 - bin/reth/Cargo.toml | 2 - .../src/commands/debug_cmd/build_block.rs | 8 +- .../commands/debug_cmd/in_memory_merkle.rs | 20 ++-- crates/blockchain-tree/Cargo.toml | 2 +- crates/blockchain-tree/src/blockchain_tree.rs | 25 ++--- crates/blockchain-tree/src/chain.rs | 2 +- crates/chain-state/src/in_memory.rs | 4 +- crates/chain-state/src/memory_overlay.rs | 4 +- crates/cli/commands/Cargo.toml | 4 +- .../cli/commands/src/recover/storage_tries.rs | 9 +- .../engine/invalid-block-hooks/src/witness.rs | 2 +- crates/engine/tree/src/tree/mod.rs | 2 +- crates/engine/util/src/reorg.rs | 2 +- crates/ethereum/payload/src/lib.rs | 16 ++-- crates/optimism/payload/src/builder.rs | 16 ++-- crates/revm/src/test_utils.rs | 4 +- .../rpc-eth-api/src/helpers/pending_block.rs | 3 +- crates/rpc/rpc-eth-types/src/cache/db.rs | 8 +- crates/rpc/rpc/src/validation.rs | 4 +- crates/stages/stages/src/stages/merkle.rs | 21 ++--- .../src/providers/bundle_state_provider.rs | 8 +- .../src/providers/database/provider.rs | 24 ++--- .../src/providers/state/historical.rs | 33 ++++--- .../provider/src/providers/state/latest.rs | 93 ++++++++++++++++--- .../provider/src/providers/state/macros.rs | 4 +- .../storage/provider/src/test_utils/mock.rs | 4 +- crates/storage/provider/src/test_utils/mod.rs | 9 +- .../storage/provider/src/test_utils/noop.rs | 4 +- crates/storage/storage-api/src/trie.rs | 44 ++++++++- crates/trie/db/src/state.rs | 59 ++++++++++-- 31 files changed, 291 insertions(+), 152 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8180e83e4069..d65539b840a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6440,8 +6440,6 @@ dependencies = [ "reth-tasks", "reth-tracing", "reth-transaction-pool", - "reth-trie", - "reth-trie-db", "serde_json", "similar-asserts", "tempfile", @@ -6744,7 +6742,6 @@ dependencies = [ "reth-static-file-types", "reth-trie", "reth-trie-common", - "reth-trie-db", "secp256k1", "serde", "serde_json", diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 437d11b5ad02..f0944bbbc4a1 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -54,8 +54,6 @@ reth-payload-primitives.workspace = true reth-payload-validator.workspace = true reth-basic-payload-builder.workspace = true reth-static-file.workspace = true -reth-trie = { workspace = true, features = ["metrics"] } -reth-trie-db = { workspace = true, features = ["metrics"] } reth-node-api.workspace = true reth-node-core.workspace = true reth-ethereum-payload-builder.workspace = true diff --git a/bin/reth/src/commands/debug_cmd/build_block.rs b/bin/reth/src/commands/debug_cmd/build_block.rs index 8c17f8ab7a5e..43de00b693fd 100644 --- a/bin/reth/src/commands/debug_cmd/build_block.rs +++ b/bin/reth/src/commands/debug_cmd/build_block.rs @@ -43,8 +43,6 @@ use reth_transaction_pool::{ blobstore::InMemoryBlobStore, BlobStore, EthPooledTransaction, PoolConfig, TransactionOrigin, TransactionPool, TransactionValidationTaskExecutor, }; -use reth_trie::StateRoot; -use reth_trie_db::DatabaseStateRoot; use std::{path::PathBuf, str::FromStr, sync::Arc}; use tracing::*; @@ -273,10 +271,8 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> { debug!(target: "reth::cli", ?execution_outcome, "Executed block"); let hashed_post_state = state_provider.hashed_post_state(execution_outcome.state()); - let (state_root, trie_updates) = StateRoot::overlay_root_with_updates( - provider_factory.provider()?.tx_ref(), - hashed_post_state.clone(), - )?; + let (state_root, trie_updates) = + state_provider.state_root_from_state_with_updates(hashed_post_state.clone())?; if state_root != block_with_senders.state_root { eyre::bail!( 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 feaf960dc93a..9b07549bd76d 100644 --- a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs @@ -25,14 +25,12 @@ use reth_primitives::BlockExt; use reth_provider::{ providers::ProviderNodeTypes, AccountExtReader, ChainSpecProvider, DatabaseProviderFactory, HashedPostStateProvider, HashingWriter, HeaderProvider, LatestStateProviderRef, - OriginalValuesKnown, ProviderFactory, StageCheckpointReader, StateWriter, StorageLocation, - StorageReader, + OriginalValuesKnown, ProviderFactory, StageCheckpointReader, StateRootProvider, + StateRootProviderExt, StateWriter, StorageLocation, StorageReader, }; use reth_revm::database::StateProviderDatabase; use reth_stages::StageId; use reth_tasks::TaskExecutor; -use reth_trie::StateRoot; -use reth_trie_db::DatabaseStateRoot; use std::{path::PathBuf, sync::Arc}; use tracing::*; @@ -164,10 +162,10 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> { let execution_outcome = ExecutionOutcome::from((block_execution_output, block.number)); // Unpacked `BundleState::state_root_slow` function - let (in_memory_state_root, in_memory_updates) = StateRoot::overlay_root_with_updates( - provider.tx_ref(), - state_provider.hashed_post_state(execution_outcome.state()), - )?; + let (in_memory_state_root, in_memory_updates) = state_provider + .state_root_from_state_with_updates( + state_provider.hashed_post_state(execution_outcome.state()), + )?; if in_memory_state_root == block.state_root { info!(target: "reth::cli", state_root = ?in_memory_state_root, "Computed in-memory state root matches"); @@ -195,10 +193,8 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> { let accounts = provider_rw.basic_accounts(account_lists)?; provider_rw.insert_account_for_hashing(accounts)?; - let (state_root, incremental_trie_updates) = StateRoot::incremental_root_with_updates( - provider_rw.tx_ref(), - block.number..=block.number, - )?; + let (state_root, incremental_trie_updates) = + state_provider.incremental_state_root_with_updates(block.number..=block.number)?; if state_root != block.state_root { eyre::bail!( "Computed incremental state root mismatch. Expected: {:?}. Got: {:?}", diff --git a/crates/blockchain-tree/Cargo.toml b/crates/blockchain-tree/Cargo.toml index 1fa7854aee59..099add248009 100644 --- a/crates/blockchain-tree/Cargo.toml +++ b/crates/blockchain-tree/Cargo.toml @@ -24,7 +24,6 @@ reth-provider.workspace = true reth-execution-types.workspace = true reth-stages-api.workspace = true reth-trie = { workspace = true, features = ["metrics"] } -reth-trie-db = { workspace = true, features = ["metrics"] } reth-trie-parallel.workspace = true reth-network.workspace = true reth-consensus.workspace = true @@ -58,6 +57,7 @@ reth-provider = { workspace = true, features = ["test-utils"] } reth-evm = { workspace = true, features = ["test-utils"] } reth-consensus = { workspace = true, features = ["test-utils"] } reth-testing-utils.workspace = true +reth-trie-db = { workspace = true, features = ["test-utils"] } reth-revm.workspace = true reth-evm-ethereum.workspace = true reth-execution-types.workspace = true diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 3c0d332c81dc..83ac21ba434c 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -25,12 +25,11 @@ use reth_provider::{ BlockExecutionWriter, BlockNumReader, BlockWriter, CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications, ChainSpecProvider, ChainSplit, ChainSplitTarget, DBProvider, DisplayBlocksChain, HashedPostStateProvider, HeaderProvider, - ProviderError, StaticFileProviderFactory, StorageLocation, + LatestStateProviderRef, ProviderError, StateRootProviderExt, StaticFileProviderFactory, + StorageLocation, }; use reth_stages_api::{MetricEvent, MetricEventsSender}; use reth_storage_errors::provider::{ProviderResult, RootMismatch}; -use reth_trie::{hashed_cursor::HashedPostStateCursorFactory, StateRoot}; -use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseStateRoot}; use std::{ collections::{btree_map::Entry, BTreeMap, HashSet}, sync::Arc, @@ -1216,17 +1215,15 @@ where ) -> Result<(), CanonicalError> { let (blocks, state, chain_trie_updates) = chain.into_inner(); let hashed_state = self.externals.provider_factory.hashed_post_state(state.state()); - let prefix_sets = hashed_state.construct_prefix_sets().freeze(); - let hashed_state_sorted = hashed_state.into_sorted(); // Compute state root or retrieve cached trie updates before opening write transaction. let block_hash_numbers = blocks.iter().map(|(number, b)| (number, b.hash())).collect::<Vec<_>>(); - let trie_updates = match chain_trie_updates { + let (trie_updates, hashed_state_sorted) = match chain_trie_updates { Some(updates) => { debug!(target: "blockchain_tree", blocks = ?block_hash_numbers, "Using cached trie updates"); self.metrics.trie_updates_insert_cached.increment(1); - updates + (updates, hashed_state.into_sorted()) } None => { debug!(target: "blockchain_tree", blocks = ?block_hash_numbers, "Recomputing state root for insert"); @@ -1237,14 +1234,9 @@ where // State root calculation can take a while, and we're sure no write transaction // will be open in parallel. See https://github.com/paradigmxyz/reth/issues/6168. .disable_long_read_transaction_safety(); - let (state_root, trie_updates) = StateRoot::from_tx(provider.tx_ref()) - .with_hashed_cursor_factory(HashedPostStateCursorFactory::new( - DatabaseHashedCursorFactory::new(provider.tx_ref()), - &hashed_state_sorted, - )) - .with_prefix_sets(prefix_sets) - .root_with_updates() - .map_err(Into::<BlockValidationError>::into)?; + let (state_root, trie_updates, hashed_state_sorted) = + LatestStateProviderRef::new(&provider) + .state_root_from_state_with_updates_and_sorted_state(hashed_state)?; let tip = blocks.tip(); if state_root != tip.state_root { return Err(ProviderError::StateRootMismatch(Box::new(RootMismatch { @@ -1255,7 +1247,7 @@ where .into()) } self.metrics.trie_updates_insert_recomputed.increment(1); - trie_updates + (trie_updates, hashed_state_sorted) } }; recorder.record_relative(MakeCanonicalAction::RetrieveStateTrieUpdates); @@ -1402,6 +1394,7 @@ mod tests { }; use reth_stages_api::StageCheckpoint; use reth_trie::{root::state_root_unhashed, StateRoot}; + use reth_trie_db::DatabaseStateRoot; use revm::AccountInfo; use std::collections::HashMap; diff --git a/crates/blockchain-tree/src/chain.rs b/crates/blockchain-tree/src/chain.rs index b82ee0410344..80c42d8dbb11 100644 --- a/crates/blockchain-tree/src/chain.rs +++ b/crates/blockchain-tree/src/chain.rs @@ -237,7 +237,7 @@ impl AppendableChain { .map_err(ProviderError::from)? } else { let hashed_state = provider.hashed_post_state(initial_execution_outcome.state()); - let state_root = provider.state_root(hashed_state)?; + let state_root = provider.state_root_from_state(hashed_state)?; (state_root, None) }; if block.state_root != state_root { diff --git a/crates/chain-state/src/in_memory.rs b/crates/chain-state/src/in_memory.rs index 1453f8543a18..877b3c7ce375 100644 --- a/crates/chain-state/src/in_memory.rs +++ b/crates/chain-state/src/in_memory.rs @@ -1027,7 +1027,7 @@ mod tests { } impl StateRootProvider for MockStateProvider { - fn state_root(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> { + fn state_root_from_state(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> { Ok(B256::random()) } @@ -1035,7 +1035,7 @@ mod tests { Ok(B256::random()) } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, _hashed_state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { diff --git a/crates/chain-state/src/memory_overlay.rs b/crates/chain-state/src/memory_overlay.rs index b39c4e57b97d..7615f551fe5b 100644 --- a/crates/chain-state/src/memory_overlay.rs +++ b/crates/chain-state/src/memory_overlay.rs @@ -119,7 +119,7 @@ macro_rules! impl_state_provider { } impl $($tokens)* StateRootProvider for $type { - fn state_root(&self, state: HashedPostState) -> ProviderResult<B256> { + fn state_root_from_state(&self, state: HashedPostState) -> ProviderResult<B256> { self.state_root_from_nodes(TrieInput::from_state(state)) } @@ -129,7 +129,7 @@ macro_rules! impl_state_provider { self.historical.state_root_from_nodes(input) } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { diff --git a/crates/cli/commands/Cargo.toml b/crates/cli/commands/Cargo.toml index 90acb82d71d7..4c403c2d75a4 100644 --- a/crates/cli/commands/Cargo.toml +++ b/crates/cli/commands/Cargo.toml @@ -45,8 +45,7 @@ reth-stages.workspace = true reth-stages-types = { workspace = true, optional = true } reth-static-file-types = { workspace = true, features = ["clap"] } reth-static-file.workspace = true -reth-trie = { workspace = true, features = ["metrics"] } -reth-trie-db = { workspace = true, features = ["metrics"] } +reth-trie = { workspace = true, optional = true } reth-trie-common = { workspace = true, optional = true } # ethereum @@ -113,6 +112,7 @@ arbitrary = [ "reth-codecs?/arbitrary", "reth-prune-types?/arbitrary", "reth-stages-types?/arbitrary", + "reth-trie", "reth-trie-common?/arbitrary", "alloy-consensus/arbitrary", ] diff --git a/crates/cli/commands/src/recover/storage_tries.rs b/crates/cli/commands/src/recover/storage_tries.rs index f879c393c6b1..f9b65010fa32 100644 --- a/crates/cli/commands/src/recover/storage_tries.rs +++ b/crates/cli/commands/src/recover/storage_tries.rs @@ -8,9 +8,10 @@ use reth_db_api::{ cursor::{DbCursorRO, DbDupCursorRW}, transaction::DbTx, }; -use reth_provider::{BlockNumReader, HeaderProvider, ProviderError}; -use reth_trie::StateRoot; -use reth_trie_db::DatabaseStateRoot; +use reth_provider::{ + BlockNumReader, HeaderProvider, LatestStateProviderRef, ProviderError, StateRootProviderExt, +}; + use tracing::*; /// `reth recover storage-tries` command @@ -50,7 +51,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C> entry = storage_trie_cursor.next()?; } - let state_root = StateRoot::from_tx(tx_mut).root()?; + let state_root = LatestStateProviderRef::new(&provider.0).state_root()?; if state_root != best_header.state_root { eyre::bail!( "Recovery failed. Incorrect state root. Expected: {:?}. Received: {:?}", diff --git a/crates/engine/invalid-block-hooks/src/witness.rs b/crates/engine/invalid-block-hooks/src/witness.rs index e86d84fcbd6b..f14154250783 100644 --- a/crates/engine/invalid-block-hooks/src/witness.rs +++ b/crates/engine/invalid-block-hooks/src/witness.rs @@ -242,7 +242,7 @@ where // Calculate the state root and trie updates after re-execution. They should match // the original ones. let (re_executed_root, trie_output) = - state_provider.state_root_with_updates(hashed_state)?; + state_provider.state_root_from_state_with_updates(hashed_state)?; if let Some((original_updates, original_root)) = trie_updates { if re_executed_root != original_root { let filename = format!("{}_{}.state_root.diff", block.number, block.hash()); diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index d6466612156f..52cd008a95a8 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -2268,7 +2268,7 @@ where result } else { debug!(target: "engine::tree", block=?sealed_block.num_hash(), persistence_in_progress, "Failed to compute state root in parallel"); - state_provider.state_root_with_updates(hashed_state.clone())? + state_provider.state_root_from_state_with_updates(hashed_state.clone())? }; if state_root != block.state_root { diff --git a/crates/engine/util/src/reorg.rs b/crates/engine/util/src/reorg.rs index 367a3cb7c84d..3af332b83b08 100644 --- a/crates/engine/util/src/reorg.rs +++ b/crates/engine/util/src/reorg.rs @@ -419,7 +419,7 @@ where gas_used: cumulative_gas_used, blob_gas_used: blob_gas_used.map(Into::into), excess_blob_gas: excess_blob_gas.map(Into::into), - state_root: state_provider.state_root(hashed_state)?, + state_root: state_provider.state_root_from_state(hashed_state)?, }, body: BlockBody { transactions, diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index da1f47d66b0c..fc59f330e1af 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -393,13 +393,15 @@ where // calculate the state root let hashed_state = db.database.db.hashed_post_state(execution_outcome.state()); let (state_root, trie_output) = { - db.database.inner().state_root_with_updates(hashed_state.clone()).inspect_err(|err| { - warn!(target: "payload_builder", - parent_hash=%parent_header.hash(), - %err, - "failed to calculate state root for payload" - ); - })? + db.database.inner().state_root_from_state_with_updates(hashed_state.clone()).inspect_err( + |err| { + warn!(target: "payload_builder", + parent_hash=%parent_header.hash(), + %err, + "failed to calculate state root for payload" + ); + }, + )? }; // create the block header diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 8edd6d1c9e04..108bbca94fd6 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -371,13 +371,15 @@ where let state_provider = state.database.as_ref(); let hashed_state = state_provider.hashed_post_state(execution_outcome.state()); let (state_root, trie_output) = { - state_provider.state_root_with_updates(hashed_state.clone()).inspect_err(|err| { - warn!(target: "payload_builder", - parent_header=%ctx.parent().hash(), - %err, - "failed to calculate state root for payload" - ); - })? + state_provider.state_root_from_state_with_updates(hashed_state.clone()).inspect_err( + |err| { + warn!(target: "payload_builder", + parent_header=%ctx.parent().hash(), + %err, + "failed to calculate state root for payload" + ); + }, + )? }; // create the block header diff --git a/crates/revm/src/test_utils.rs b/crates/revm/src/test_utils.rs index d290421309f2..38ed20bed019 100644 --- a/crates/revm/src/test_utils.rs +++ b/crates/revm/src/test_utils.rs @@ -72,7 +72,7 @@ impl BlockHashReader for StateProviderTest { } impl StateRootProvider for StateProviderTest { - fn state_root(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> { + fn state_root_from_state(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> { unimplemented!("state root computation is not supported") } @@ -80,7 +80,7 @@ impl StateRootProvider for StateProviderTest { unimplemented!("state root computation is not supported") } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, _hashed_state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index 7c2dede800ad..f56a3d5b0ab6 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -432,7 +432,8 @@ pub trait LoadPendingBlock: execution_outcome.block_logs_bloom(block_number).expect("Block is present"); // calculate the state root - let state_root = db.database.state_root(hashed_state).map_err(Self::Error::from_eth_err)?; + let state_root = + db.database.state_root_from_state(hashed_state).map_err(Self::Error::from_eth_err)?; // create the block header let transactions_root = calculate_transaction_root(&executed_txs); diff --git a/crates/rpc/rpc-eth-types/src/cache/db.rs b/crates/rpc/rpc-eth-types/src/cache/db.rs index c5e322677fac..2307adf40298 100644 --- a/crates/rpc/rpc-eth-types/src/cache/db.rs +++ b/crates/rpc/rpc-eth-types/src/cache/db.rs @@ -23,11 +23,11 @@ pub type StateCacheDb<'a> = CacheDB<StateProviderDatabase<StateProviderTraitObjW pub struct StateProviderTraitObjWrapper<'a>(pub &'a dyn StateProvider); impl reth_storage_api::StateRootProvider for StateProviderTraitObjWrapper<'_> { - fn state_root( + fn state_root_from_state( &self, hashed_state: reth_trie::HashedPostState, ) -> reth_errors::ProviderResult<B256> { - self.0.state_root(hashed_state) + self.0.state_root_from_state(hashed_state) } fn state_root_from_nodes( @@ -37,11 +37,11 @@ impl reth_storage_api::StateRootProvider for StateProviderTraitObjWrapper<'_> { self.0.state_root_from_nodes(input) } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, hashed_state: reth_trie::HashedPostState, ) -> reth_errors::ProviderResult<(B256, reth_trie::updates::TrieUpdates)> { - self.0.state_root_with_updates(hashed_state) + self.0.state_root_from_state_with_updates(hashed_state) } fn state_root_from_nodes_with_updates( diff --git a/crates/rpc/rpc/src/validation.rs b/crates/rpc/rpc/src/validation.rs index 6754f1c1a4e9..c4799bbb1d61 100644 --- a/crates/rpc/rpc/src/validation.rs +++ b/crates/rpc/rpc/src/validation.rs @@ -178,8 +178,8 @@ where self.ensure_payment(&block, &output, &message)?; - let state_root = - state_provider.state_root(state_provider.hashed_post_state(&output.state))?; + let state_root = state_provider + .state_root_from_state(state_provider.hashed_post_state(&output.state))?; if state_root != block.state_root { return Err(ConsensusError::BodyStateRootDiff( diff --git a/crates/stages/stages/src/stages/merkle.rs b/crates/stages/stages/src/stages/merkle.rs index 2d2503b53919..72122dd838b7 100644 --- a/crates/stages/stages/src/stages/merkle.rs +++ b/crates/stages/stages/src/stages/merkle.rs @@ -5,15 +5,14 @@ use reth_db::tables; use reth_db_api::transaction::{DbTx, DbTxMut}; use reth_primitives::{GotExpected, SealedHeader}; use reth_provider::{ - DBProvider, HeaderProvider, ProviderError, StageCheckpointReader, StageCheckpointWriter, - StatsReader, TrieWriter, + DBProvider, HeaderProvider, LatestStateProviderRef, ProviderError, StageCheckpointReader, + StageCheckpointWriter, StateCommitmentProvider, StateRootProviderExt, StatsReader, TrieWriter, }; use reth_stages_api::{ BlockErrorKind, EntitiesCheckpoint, ExecInput, ExecOutput, MerkleCheckpoint, Stage, StageCheckpoint, StageError, StageId, UnwindInput, UnwindOutput, }; -use reth_trie::{IntermediateStateRootState, StateRoot, StateRootProgress, StoredSubNode}; -use reth_trie_db::DatabaseStateRoot; +use reth_trie::{IntermediateStateRootState, StateRootProgress, StoredSubNode}; use std::fmt::Debug; use tracing::*; @@ -137,7 +136,8 @@ where + StatsReader + HeaderProvider + StageCheckpointReader - + StageCheckpointWriter, + + StageCheckpointWriter + + StateCommitmentProvider, { /// Return the id of the stage fn id(&self) -> StageId { @@ -210,10 +210,8 @@ where as u64, }); - let tx = provider.tx_ref(); - let progress = StateRoot::from_tx(tx) - .with_intermediate_state(checkpoint.map(IntermediateStateRootState::from)) - .root_with_progress() + let progress = LatestStateProviderRef::new(provider).state_root_with_progress + (checkpoint.map(IntermediateStateRootState::from)) .map_err(|e| { error!(target: "sync::stages::merkle", %e, ?current_block_number, ?to_block, "State root with progress failed! {INVALID_STATE_ROOT_ERROR_MESSAGE}"); StageError::Fatal(Box::new(e)) @@ -250,7 +248,7 @@ where } else { debug!(target: "sync::stages::merkle::exec", current = ?current_block_number, target = ?to_block, "Updating trie"); let (root, updates) = - StateRoot::incremental_root_with_updates(provider.tx_ref(), range) + LatestStateProviderRef::new(provider).incremental_state_root_with_updates(range) .map_err(|e| { error!(target: "sync::stages::merkle", %e, ?current_block_number, ?to_block, "Incremental state root failed! {INVALID_STATE_ROOT_ERROR_MESSAGE}"); StageError::Fatal(Box::new(e)) @@ -321,7 +319,8 @@ where if range.is_empty() { info!(target: "sync::stages::merkle::unwind", "Nothing to unwind"); } else { - let (block_root, updates) = StateRoot::incremental_root_with_updates(tx, range) + let (block_root, updates) = LatestStateProviderRef::new(provider) + .incremental_state_root_with_updates(range) .map_err(|e| StageError::Fatal(Box::new(e)))?; // Validate the calculated state root diff --git a/crates/storage/provider/src/providers/bundle_state_provider.rs b/crates/storage/provider/src/providers/bundle_state_provider.rs index 3bbef6aaf744..8536ccfbaa7d 100644 --- a/crates/storage/provider/src/providers/bundle_state_provider.rs +++ b/crates/storage/provider/src/providers/bundle_state_provider.rs @@ -83,25 +83,25 @@ impl<SP: StateProvider, EDP: ExecutionDataProvider> AccountReader for BundleStat impl<SP: StateProvider, EDP: ExecutionDataProvider> StateRootProvider for BundleStateProvider<SP, EDP> { - fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> { + fn state_root_from_state(&self, hashed_state: HashedPostState) -> ProviderResult<B256> { let bundle_state = self.block_execution_data_provider.execution_outcome().state(); let mut state = self.hashed_post_state(bundle_state); state.extend(hashed_state); - self.state_provider.state_root(state) + self.state_provider.state_root_from_state(state) } fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> { unimplemented!() } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, hashed_state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { let bundle_state = self.block_execution_data_provider.execution_outcome().state(); let mut state = self.hashed_post_state(bundle_state); state.extend(hashed_state); - self.state_provider.state_root_with_updates(state) + self.state_provider.state_root_from_state_with_updates(state) } fn state_root_from_nodes_with_updates( diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 8a081eb16bcc..a81242eb0223 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -15,10 +15,10 @@ use crate::{ HeaderSyncGapProvider, HistoricalStateProvider, HistoricalStateProviderRef, HistoryWriter, KeyHasherProvider, LatestStateProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, PruneCheckpointReader, PruneCheckpointWriter, RevertsInit, - StageCheckpointReader, StateCommitmentProvider, StateProviderBox, StateWriter, - StaticFileProviderFactory, StatsReader, StorageLocation, StorageReader, StorageTrieWriter, - TransactionVariant, TransactionsProvider, TransactionsProviderExt, TrieWriter, - WithdrawalsProvider, + StageCheckpointReader, StateCommitmentProvider, StateProviderBox, StateRootProviderExt, + StateWriter, StaticFileProviderFactory, StatsReader, StorageLocation, StorageReader, + StorageTrieWriter, TransactionVariant, TransactionsProvider, TransactionsProviderExt, + TrieWriter, WithdrawalsProvider, }; use alloy_consensus::Header; use alloy_eips::{ @@ -67,9 +67,9 @@ use reth_storage_errors::provider::{ProviderResult, RootMismatch}; use reth_trie::{ prefix_set::{PrefixSet, PrefixSetMut, TriePrefixSets}, updates::{StorageTrieUpdates, TrieUpdates}, - HashedPostStateSorted, KeyHasher, Nibbles, StateRoot, StoredNibbles, + HashedPostStateSorted, KeyHasher, Nibbles, StoredNibbles, }; -use reth_trie_db::{DatabaseStateRoot, DatabaseStorageTrieCursor, StateCommitment}; +use reth_trie_db::{DatabaseStorageTrieCursor, StateCommitment}; use revm::{ db::states::{PlainStateReverts, PlainStorageChangeset, PlainStorageRevert, StateChangeset}, primitives::{BlockEnv, CfgEnvWithHandlerCfg}, @@ -318,10 +318,8 @@ impl<TX: DbTx + DbTxMut + 'static, N: NodeTypesForProvider> DatabaseProvider<TX, storage_prefix_sets, destroyed_accounts, }; - let (new_state_root, trie_updates) = StateRoot::from_tx(&self.tx) - .with_prefix_sets(prefix_sets) - .root_with_updates() - .map_err(Into::<reth_db::DatabaseError>::into)?; + let (new_state_root, trie_updates) = LatestStateProviderRef::new(self) + .state_root_from_prefix_sets_with_updates(prefix_sets)?; let parent_number = range.start().saturating_sub(1); let parent_state_root = self @@ -2590,10 +2588,8 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes> HashingWriter for DatabaseProvi .collect(), destroyed_accounts, }; - let (state_root, trie_updates) = StateRoot::from_tx(&self.tx) - .with_prefix_sets(prefix_sets) - .root_with_updates() - .map_err(Into::<reth_db::DatabaseError>::into)?; + let (state_root, trie_updates) = LatestStateProviderRef::new(self) + .state_root_from_prefix_sets_with_updates(prefix_sets)?; if state_root != expected_state_root { return Err(ProviderError::StateRootMismatch(Box::new(RootMismatch { root: GotExpected { got: state_root, expected: expected_state_root }, diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index b2b63ef4a4f6..dfc7aed71662 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -24,8 +24,8 @@ use reth_trie::{ proof::{Proof, StorageProof}, updates::TrieUpdates, witness::TrieWitness, - AccountProof, HashedPostState, HashedStorage, KeyHasher, MultiProof, StateRoot, - StorageMultiProof, StorageRoot, TrieInput, + AccountProof, HashedPostState, HashedStorage, KeyHasher, MultiProof, StorageMultiProof, + StorageRoot, TrieInput, }; use reth_trie_db::{ DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot, @@ -297,27 +297,38 @@ impl<Provider: DBProvider + BlockNumReader + BlockHashReader> BlockHashReader impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StateRootProvider for HistoricalStateProviderRef<'_, Provider> { - fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> { + fn state_root_from_state(&self, hashed_state: HashedPostState) -> ProviderResult<B256> { let mut revert_state = self.revert_state()?; revert_state.extend(hashed_state); - StateRoot::overlay_root(self.tx(), revert_state) - .map_err(|err| ProviderError::Database(err.into())) + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root( + self.tx(), + revert_state, + ) + .map_err(|err| ProviderError::Database(err.into())) } fn state_root_from_nodes(&self, mut input: TrieInput) -> ProviderResult<B256> { input.prepend(self.revert_state()?); - StateRoot::overlay_root_from_nodes(self.tx(), input) - .map_err(|err| ProviderError::Database(err.into())) + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root_from_nodes( + self.tx(), + input, + ) + .map_err(|err| ProviderError::Database(err.into())) } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, hashed_state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { let mut revert_state = self.revert_state()?; revert_state.extend(hashed_state); - StateRoot::overlay_root_with_updates(self.tx(), revert_state) - .map_err(|err| ProviderError::Database(err.into())) + let (root, updates, _state_sorted) = + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root_with_updates( + self.tx(), + revert_state, + ) + .map_err(|err| ProviderError::Database(err.into()))?; + Ok((root, updates)) } fn state_root_from_nodes_with_updates( @@ -325,7 +336,7 @@ impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StateRootP mut input: TrieInput, ) -> ProviderResult<(B256, TrieUpdates)> { input.prepend(self.revert_state()?); - StateRoot::overlay_root_from_nodes_with_updates(self.tx(), input) + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root_from_nodes_with_updates(self.tx(), input) .map_err(|err| ProviderError::Database(err.into())) } } diff --git a/crates/storage/provider/src/providers/state/latest.rs b/crates/storage/provider/src/providers/state/latest.rs index e9b844b0d2c3..e05313427c67 100644 --- a/crates/storage/provider/src/providers/state/latest.rs +++ b/crates/storage/provider/src/providers/state/latest.rs @@ -11,15 +11,15 @@ use reth_db_api::{cursor::DbDupCursorRO, transaction::DbTx}; use reth_primitives::{Account, Bytecode}; use reth_storage_api::{ DBProvider, HashedStorageProvider, KeyHasherProvider, StateCommitmentProvider, - StateProofProvider, StorageRootProvider, + StateProofProvider, StateRootProviderExt, StorageRootProvider, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; use reth_trie::{ proof::{Proof, StorageProof}, updates::TrieUpdates, witness::TrieWitness, - AccountProof, HashedPostState, HashedStorage, KeyHasher, MultiProof, StateRoot, - StorageMultiProof, StorageRoot, TrieInput, + AccountProof, HashedPostState, HashedStorage, KeyHasher, MultiProof, StorageMultiProof, + StorageRoot, TrieInput, }; use reth_trie_db::{ DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot, @@ -68,31 +68,100 @@ impl<Provider: BlockHashReader> BlockHashReader for LatestStateProviderRef<'_, P impl<Provider: DBProvider + StateCommitmentProvider> StateRootProvider for LatestStateProviderRef<'_, Provider> { - fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> { - StateRoot::overlay_root(self.tx(), hashed_state) - .map_err(|err| ProviderError::Database(err.into())) + fn state_root_from_state(&self, hashed_state: HashedPostState) -> ProviderResult<B256> { + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root( + self.tx(), + hashed_state, + ) + .map_err(|err| ProviderError::Database(err.into())) } fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> { - StateRoot::overlay_root_from_nodes(self.tx(), input) - .map_err(|err| ProviderError::Database(err.into())) + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root_from_nodes( + self.tx(), + input, + ) + .map_err(|err| ProviderError::Database(err.into())) } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, hashed_state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { - StateRoot::overlay_root_with_updates(self.tx(), hashed_state) - .map_err(|err| ProviderError::Database(err.into())) + let (root, updates, _state_sorted) = + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root_with_updates( + self.tx(), + hashed_state, + ) + .map_err(|err| ProviderError::Database(err.into()))?; + Ok((root, updates)) } fn state_root_from_nodes_with_updates( &self, input: TrieInput, ) -> ProviderResult<(B256, TrieUpdates)> { - StateRoot::overlay_root_from_nodes_with_updates(self.tx(), input) + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root_from_nodes_with_updates(self.tx(), input) + .map_err(|err| ProviderError::Database(err.into())) + } +} + +impl<Provider: DBProvider + StateCommitmentProvider> StateRootProviderExt + for LatestStateProviderRef<'_, Provider> +{ + fn state_root(&self) -> ProviderResult<B256> { + <Provider::StateCommitment as StateCommitment>::StateRoot::root(self.tx()) .map_err(|err| ProviderError::Database(err.into())) } + + fn state_root_with_updates(&self) -> ProviderResult<(B256, TrieUpdates)> { + <Provider::StateCommitment as StateCommitment>::StateRoot::root_with_updates(self.tx()) + .map_err(|err| ProviderError::Database(err.into())) + } + + fn incremental_state_root_with_updates( + &self, + range: std::ops::RangeInclusive<BlockNumber>, + ) -> ProviderResult<(B256, TrieUpdates)> { + <Provider::StateCommitment as StateCommitment>::StateRoot::incremental_root_with_updates( + self.tx(), + range, + ) + .map_err(|err| ProviderError::Database(err.into())) + } + + fn state_root_from_prefix_sets_with_updates( + &self, + prefix_set: reth_trie::prefix_set::TriePrefixSets, + ) -> ProviderResult<(B256, TrieUpdates)> { + <Provider::StateCommitment as StateCommitment>::StateRoot::root_from_prefix_sets_with_updates( + self.tx(), + prefix_set, + ) + .map_err(|err| ProviderError::Database(err.into())) + } + + fn state_root_with_progress( + &self, + state: Option<reth_trie::IntermediateStateRootState>, + ) -> ProviderResult<reth_trie::StateRootProgress> { + <Provider::StateCommitment as StateCommitment>::StateRoot::root_with_progress( + self.tx(), + state, + ) + .map_err(|err| ProviderError::Database(err.into())) + } + + fn state_root_from_state_with_updates_and_sorted_state( + &self, + hashed_state: HashedPostState, + ) -> ProviderResult<(B256, TrieUpdates, reth_trie::HashedPostStateSorted)> { + <Provider::StateCommitment as StateCommitment>::StateRoot::overlay_root_with_updates( + self.tx(), + hashed_state, + ) + .map_err(|err| ProviderError::Database(err.into())) + } } impl<Provider: DBProvider + StateCommitmentProvider> StorageRootProvider diff --git a/crates/storage/provider/src/providers/state/macros.rs b/crates/storage/provider/src/providers/state/macros.rs index 2646e6e05536..ba2f477efd26 100644 --- a/crates/storage/provider/src/providers/state/macros.rs +++ b/crates/storage/provider/src/providers/state/macros.rs @@ -42,9 +42,9 @@ macro_rules! delegate_provider_impls { fn bytecode_by_hash(&self, code_hash: alloy_primitives::B256) -> reth_storage_errors::provider::ProviderResult<Option<reth_primitives::Bytecode>>; } StateRootProvider $(where [$($generics)*])? { - fn state_root(&self, state: reth_trie::HashedPostState) -> reth_storage_errors::provider::ProviderResult<alloy_primitives::B256>; + fn state_root_from_state(&self, state: reth_trie::HashedPostState) -> reth_storage_errors::provider::ProviderResult<alloy_primitives::B256>; fn state_root_from_nodes(&self, input: reth_trie::TrieInput) -> reth_storage_errors::provider::ProviderResult<alloy_primitives::B256>; - fn state_root_with_updates(&self, state: reth_trie::HashedPostState) -> reth_storage_errors::provider::ProviderResult<(alloy_primitives::B256, reth_trie::updates::TrieUpdates)>; + fn state_root_from_state_with_updates(&self, state: reth_trie::HashedPostState) -> reth_storage_errors::provider::ProviderResult<(alloy_primitives::B256, reth_trie::updates::TrieUpdates)>; fn state_root_from_nodes_with_updates(&self, input: reth_trie::TrieInput) -> reth_storage_errors::provider::ProviderResult<(alloy_primitives::B256, reth_trie::updates::TrieUpdates)>; } StorageRootProvider $(where [$($generics)*])? { diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 06972099e8bc..81a8cd3ee684 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -616,7 +616,7 @@ impl StageCheckpointReader for MockEthProvider { } impl StateRootProvider for MockEthProvider { - fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> { + fn state_root_from_state(&self, _state: HashedPostState) -> ProviderResult<B256> { Ok(self.state_roots.lock().pop().unwrap_or_default()) } @@ -624,7 +624,7 @@ impl StateRootProvider for MockEthProvider { Ok(self.state_roots.lock().pop().unwrap_or_default()) } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, _state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { diff --git a/crates/storage/provider/src/test_utils/mod.rs b/crates/storage/provider/src/test_utils/mod.rs index 2c3795573c20..47551fa9db14 100644 --- a/crates/storage/provider/src/test_utils/mod.rs +++ b/crates/storage/provider/src/test_utils/mod.rs @@ -1,5 +1,5 @@ use crate::{ - providers::{ProviderNodeTypes, StaticFileProvider}, + providers::{LatestStateProviderRef, ProviderNodeTypes, StaticFileProvider}, HashingWriter, ProviderFactory, TrieWriter, }; use alloy_primitives::B256; @@ -11,8 +11,7 @@ use reth_db::{ use reth_errors::ProviderResult; use reth_node_types::NodeTypesWithDBAdapter; use reth_primitives::{Account, StorageEntry}; -use reth_trie::StateRoot; -use reth_trie_db::DatabaseStateRoot; +use reth_storage_api::StateRootProviderExt; use std::sync::Arc; pub mod blocks; @@ -78,9 +77,7 @@ pub fn insert_genesis<N: ProviderNodeTypes<ChainSpec = ChainSpec>>( }); provider.insert_storage_for_hashing(alloc_storage)?; - let (root, updates) = StateRoot::from_tx(provider.tx_ref()) - .root_with_updates() - .map_err(Into::<reth_db::DatabaseError>::into)?; + let (root, updates) = LatestStateProviderRef::new(&provider.0).state_root_with_updates()?; provider.write_trie_updates(&updates).unwrap(); provider.commit()?; diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 3833fdae44a8..3c95d1c050cc 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -336,7 +336,7 @@ impl ChangeSetReader for NoopProvider { } impl StateRootProvider for NoopProvider { - fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> { + fn state_root_from_state(&self, _state: HashedPostState) -> ProviderResult<B256> { Ok(B256::default()) } @@ -344,7 +344,7 @@ impl StateRootProvider for NoopProvider { Ok(B256::default()) } - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, _state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { diff --git a/crates/storage/storage-api/src/trie.rs b/crates/storage/storage-api/src/trie.rs index ee1ca1de1800..b8c28dd88d9d 100644 --- a/crates/storage/storage-api/src/trie.rs +++ b/crates/storage/storage-api/src/trie.rs @@ -1,11 +1,13 @@ use alloy_primitives::{ map::{HashMap, HashSet}, - Address, Bytes, B256, + Address, BlockNumber, Bytes, B256, }; use reth_storage_errors::provider::ProviderResult; use reth_trie::{ + prefix_set::TriePrefixSets, updates::{StorageTrieUpdates, TrieUpdates}, - AccountProof, HashedPostState, HashedStorage, MultiProof, StorageMultiProof, StorageProof, + AccountProof, HashedPostState, HashedPostStateSorted, HashedStorage, + IntermediateStateRootState, MultiProof, StateRootProgress, StorageMultiProof, StorageProof, TrieInput, }; @@ -19,7 +21,7 @@ pub trait StateRootProvider: Send + Sync { /// It is recommended to provide a different implementation from /// `state_root_with_updates` since it affects the memory usage during state root /// computation. - fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256>; + fn state_root_from_state(&self, hashed_state: HashedPostState) -> ProviderResult<B256>; /// Returns the state root of the `HashedPostState` on top of the current state but re-uses the /// intermediate nodes to speed up the computation. It's up to the caller to construct the @@ -28,7 +30,7 @@ pub trait StateRootProvider: Send + Sync { /// Returns the state root of the `HashedPostState` on top of the current state with trie /// updates to be committed to the database. - fn state_root_with_updates( + fn state_root_from_state_with_updates( &self, hashed_state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)>; @@ -41,6 +43,40 @@ pub trait StateRootProvider: Send + Sync { ) -> ProviderResult<(B256, TrieUpdates)>; } +/// A trait that is used to compute the state root of the latest state stored in the database. +pub trait StateRootProviderExt: Send + Sync { + /// Returns the state root of the current state. + fn state_root(&self) -> ProviderResult<B256>; + + /// Returns the state root of the current state and trie updates. + fn state_root_with_updates(&self) -> ProviderResult<(B256, TrieUpdates)>; + + /// Returns the state root with trie updates associated with the given block range. + fn incremental_state_root_with_updates( + &self, + range: std::ops::RangeInclusive<BlockNumber>, + ) -> ProviderResult<(B256, TrieUpdates)>; + + /// Returns the state root progress. + fn state_root_with_progress( + &self, + state: Option<IntermediateStateRootState>, + ) -> ProviderResult<StateRootProgress>; + + /// Returns the state root of the current state with the provided prefix sets updated. + fn state_root_from_prefix_sets_with_updates( + &self, + prefix_set: TriePrefixSets, + ) -> ProviderResult<(B256, TrieUpdates)>; + + /// Returns the state root of the [`HashedPostState`] on top of the current, the trie updates + /// and the sorted hashed post state ([`HashedPostStateSorted`]). + fn state_root_from_state_with_updates_and_sorted_state( + &self, + hashed_state: HashedPostState, + ) -> ProviderResult<(B256, TrieUpdates, HashedPostStateSorted)>; +} + /// A type that can compute the storage root for a given account. #[auto_impl::auto_impl(&, Box, Arc)] pub trait StorageRootProvider: Send + Sync { diff --git a/crates/trie/db/src/state.rs b/crates/trie/db/src/state.rs index a6356c104dac..1452fecbb48a 100644 --- a/crates/trie/db/src/state.rs +++ b/crates/trie/db/src/state.rs @@ -9,9 +9,10 @@ use reth_db_api::{ use reth_execution_errors::StateRootError; use reth_storage_errors::db::DatabaseError; use reth_trie::{ - hashed_cursor::HashedPostStateCursorFactory, trie_cursor::InMemoryTrieCursorFactory, - updates::TrieUpdates, HashedPostState, HashedStorage, KeccakKeyHasher, KeyHasher, StateRoot, - StateRootProgress, TrieInput, + hashed_cursor::HashedPostStateCursorFactory, prefix_set::TriePrefixSets, + trie_cursor::InMemoryTrieCursorFactory, updates::TrieUpdates, HashedPostState, + HashedPostStateSorted, HashedStorage, IntermediateStateRootState, KeccakKeyHasher, KeyHasher, + StateRoot, StateRootProgress, TrieInput, }; use std::{collections::HashMap, ops::RangeInclusive}; use tracing::debug; @@ -112,7 +113,7 @@ pub trait DatabaseStateRoot<'a, TX>: Sized { fn overlay_root_with_updates( tx: &'a TX, post_state: HashedPostState, - ) -> Result<(B256, TrieUpdates), StateRootError>; + ) -> Result<(B256, TrieUpdates, HashedPostStateSorted), StateRootError>; /// Calculates the state root for provided [`HashedPostState`] using cached intermediate nodes. fn overlay_root_from_nodes(tx: &'a TX, input: TrieInput) -> Result<B256, StateRootError>; @@ -123,6 +124,27 @@ pub trait DatabaseStateRoot<'a, TX>: Sized { tx: &'a TX, input: TrieInput, ) -> Result<(B256, TrieUpdates), StateRootError>; + + /// Calculates the state root for the current state stored in the database. + fn root(tx: &'a TX) -> Result<B256, StateRootError>; + + /// Calculates the state root for the current state stored in the database and returns + /// trie updates. + fn root_with_updates(tx: &'a TX) -> Result<(B256, TrieUpdates), StateRootError>; + + /// Calculates the state root for the current state stored in the database updating the paths + /// associated with the provided prefix sets and returns the trie updates. + fn root_from_prefix_sets_with_updates( + tx: &'a TX, + prefix_sets: TriePrefixSets, + ) -> Result<(B256, TrieUpdates), StateRootError>; + + /// Calculates the state root for the current state stored in the database and returns the + /// intermediate progress of the computation. + fn root_with_progress( + tx: &'a TX, + state: Option<IntermediateStateRootState>, + ) -> Result<StateRootProgress, StateRootError>; } /// Extends [`HashedPostState`] with operations specific for working with a database transaction. @@ -185,15 +207,16 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> fn overlay_root_with_updates( tx: &'a TX, post_state: HashedPostState, - ) -> Result<(B256, TrieUpdates), StateRootError> { + ) -> Result<(B256, TrieUpdates, HashedPostStateSorted), StateRootError> { let prefix_sets = post_state.construct_prefix_sets().freeze(); let state_sorted = post_state.into_sorted(); - StateRoot::new( + let (root, updates) = StateRoot::new( DatabaseTrieCursorFactory::new(tx), HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted), ) .with_prefix_sets(prefix_sets) - .root_with_updates() + .root_with_updates()?; + Ok((root, updates, state_sorted)) } fn overlay_root_from_nodes(tx: &'a TX, input: TrieInput) -> Result<B256, StateRootError> { @@ -220,6 +243,28 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> .with_prefix_sets(input.prefix_sets.freeze()) .root_with_updates() } + + fn root(tx: &'a TX) -> Result<B256, StateRootError> { + Self::from_tx(tx).root() + } + + fn root_with_updates(tx: &'a TX) -> Result<(B256, TrieUpdates), StateRootError> { + Self::from_tx(tx).root_with_updates() + } + + fn root_from_prefix_sets_with_updates( + tx: &'a TX, + prefix_sets: TriePrefixSets, + ) -> Result<(B256, TrieUpdates), StateRootError> { + Self::from_tx(tx).with_prefix_sets(prefix_sets).root_with_updates() + } + + fn root_with_progress( + tx: &'a TX, + state: Option<IntermediateStateRootState>, + ) -> Result<StateRootProgress, StateRootError> { + Self::from_tx(tx).with_intermediate_state(state).root_with_progress() + } } impl<TX: DbTx> DatabaseHashedPostState<TX> for HashedPostState {