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 {