diff --git a/crates/interfaces/src/provider.rs b/crates/interfaces/src/provider.rs index fc6f8cbd63..c82116b2b1 100644 --- a/crates/interfaces/src/provider.rs +++ b/crates/interfaces/src/provider.rs @@ -91,4 +91,6 @@ pub enum ProviderError { /// Thrown when we failed to lookup a block for the pending state #[error("Unknown block hash: {0:}")] UnknownBlockHash(H256), + #[error("Unable to compute state root on top of historical block")] + StateRootNotAvailableForHistoricalBlock, } diff --git a/crates/revm/src/executor.rs b/crates/revm/src/executor.rs index a349786518..9b4a05d2de 100644 --- a/crates/revm/src/executor.rs +++ b/crates/revm/src/executor.rs @@ -600,7 +600,9 @@ mod tests { constants::ETH_TO_WEI, hex_literal::hex, keccak256, Account, Address, BlockNumber, Bytecode, Bytes, ChainSpecBuilder, ForkCondition, StorageKey, H256, MAINNET, U256, }; - use reth_provider::{post_state::Storage, AccountProvider, BlockHashProvider, StateProvider}; + use reth_provider::{ + post_state::Storage, AccountProvider, BlockHashProvider, StateProvider, StateRootProvider, + }; use reth_rlp::Decodable; use std::{collections::HashMap, str::FromStr}; @@ -655,6 +657,12 @@ mod tests { } } + impl StateRootProvider for StateProviderTest { + fn state_root(&self, _post_state: PostState) -> reth_interfaces::Result { + todo!() + } + } + impl StateProvider for StateProviderTest { fn storage( &self, diff --git a/crates/storage/provider/src/post_state.rs b/crates/storage/provider/src/post_state.rs index 651ae38f2c..93e3c8923f 100644 --- a/crates/storage/provider/src/post_state.rs +++ b/crates/storage/provider/src/post_state.rs @@ -1174,13 +1174,10 @@ mod tests { #[test] fn post_state_state_root() { let mut state: BTreeMap)> = (0..10) - .into_iter() .map(|key| { let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None }; - let storage = (0..10) - .into_iter() - .map(|key| (H256::from_low_u64_be(key), U256::from(key))) - .collect(); + let storage = + (0..10).map(|key| (H256::from_low_u64_be(key), U256::from(key))).collect(); (Address::from_low_u64_be(key), (account, storage)) }) .collect(); @@ -1190,7 +1187,7 @@ mod tests { // insert initial state to the database db.update(|tx| { for (address, (account, storage)) in state.iter() { - let hashed_address = keccak256(&address); + let hashed_address = keccak256(address); tx.put::(hashed_address, *account).unwrap(); for (slot, value) in storage { tx.put::( @@ -1240,7 +1237,7 @@ mod tests { let slot_2 = U256::from(2); let slot_2_key = H256(slot_2.to_be_bytes()); let address_2_slot_2_old_value = - state.get(&address_2).unwrap().1.get(&slot_2_key).unwrap().clone(); + *state.get(&address_2).unwrap().1.get(&slot_2_key).unwrap(); let address_2_slot_2_new_value = U256::from(100); state.get_mut(&address_2).unwrap().1.insert(slot_2_key, address_2_slot_2_new_value); post_state.change_storage( @@ -1261,8 +1258,7 @@ mod tests { // change balance of account 3 let address_3 = Address::from_low_u64_be(3); let address_3_account_old = state.get(&address_3).unwrap().0; - let address_3_account_new = - Account { balance: U256::from(24), ..address_3_account_old.clone() }; + let address_3_account_new = Account { balance: U256::from(24), ..address_3_account_old }; state.get_mut(&address_3).unwrap().0.balance = address_3_account_new.balance; post_state.change_account( block_number, @@ -1283,7 +1279,7 @@ mod tests { // change nonce of account 4 let address_4 = Address::from_low_u64_be(4); let address_4_account_old = state.get(&address_4).unwrap().0; - let address_4_account_new = Account { nonce: 128, ..address_4_account_old.clone() }; + let address_4_account_new = Account { nonce: 128, ..address_4_account_old }; state.get_mut(&address_4).unwrap().0.nonce = address_4_account_new.nonce; post_state.change_account( block_number, diff --git a/crates/storage/provider/src/providers/database.rs b/crates/storage/provider/src/providers/database.rs index 4a0d77d19e..04ff715060 100644 --- a/crates/storage/provider/src/providers/database.rs +++ b/crates/storage/provider/src/providers/database.rs @@ -1,11 +1,11 @@ use crate::{ providers::state::{historical::HistoricalStateProvider, latest::LatestStateProvider}, traits::ReceiptProvider, - BlockHashProvider, BlockIdProvider, BlockProvider, EvmEnvProvider, HeaderProvider, PostState, - ProviderError, StateProviderBox, StateRootProvider, TransactionsProvider, WithdrawalsProvider, + BlockHashProvider, BlockIdProvider, BlockProvider, EvmEnvProvider, HeaderProvider, + ProviderError, StateProviderBox, TransactionsProvider, WithdrawalsProvider, }; use reth_db::{cursor::DbCursorRO, database::Database, tables, transaction::DbTx}; -use reth_interfaces::{Error, Result}; +use reth_interfaces::Result; use reth_primitives::{ Block, BlockHash, BlockId, BlockNumber, ChainInfo, ChainSpec, Hardfork, Head, Header, Receipt, TransactionMeta, TransactionSigned, TxHash, TxNumber, Withdrawal, H256, U256, @@ -440,16 +440,6 @@ impl EvmEnvProvider for ShareableDatabase { } } -impl StateRootProvider for ShareableDatabase -where - DB: Database, -{ - fn state_root(&self, post_state: &PostState) -> Result { - let tx = self.db.tx()?; - post_state.state_root_slow(&tx).map_err(|err| Error::Database(err.into())) - } -} - #[cfg(test)] mod tests { use super::ShareableDatabase; diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 201bcfaa4a..c09faa1182 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -1,8 +1,8 @@ use crate::{ BlockHashProvider, BlockIdProvider, BlockProvider, BlockchainTreePendingStateProvider, - CanonStateNotifications, CanonStateSubscriptions, EvmEnvProvider, HeaderProvider, PostState, + CanonStateNotifications, CanonStateSubscriptions, EvmEnvProvider, HeaderProvider, PostStateDataProvider, ReceiptProvider, StateProviderBox, StateProviderFactory, - StateRootProvider, TransactionsProvider, WithdrawalsProvider, + TransactionsProvider, WithdrawalsProvider, }; use reth_db::database::Database; use reth_interfaces::{ @@ -290,16 +290,6 @@ where } } -impl StateRootProvider for BlockchainProvider -where - DB: Database, - Tree: Send + Sync, -{ - fn state_root(&self, post_state: &PostState) -> Result { - self.database.state_root(post_state) - } -} - impl BlockchainTreeEngine for BlockchainProvider where DB: Send + Sync, diff --git a/crates/storage/provider/src/providers/post_state_provider.rs b/crates/storage/provider/src/providers/post_state_provider.rs index 548047efac..d69617c79e 100644 --- a/crates/storage/provider/src/providers/post_state_provider.rs +++ b/crates/storage/provider/src/providers/post_state_provider.rs @@ -1,4 +1,7 @@ -use crate::{AccountProvider, BlockHashProvider, PostStateDataProvider, StateProvider}; +use crate::{ + AccountProvider, BlockHashProvider, PostState, PostStateDataProvider, StateProvider, + StateRootProvider, +}; use reth_interfaces::{provider::ProviderError, Result}; use reth_primitives::{Account, Address, BlockNumber, Bytecode, Bytes, H256, U256}; @@ -48,6 +51,16 @@ impl AccountProvider } } +impl StateRootProvider + for PostStateProvider +{ + fn state_root(&self, post_state: PostState) -> Result { + let mut state = self.post_state_data_provider.state().clone(); + state.extend(post_state); + self.state_provider.state_root(state) + } +} + impl StateProvider for PostStateProvider { fn storage( &self, diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index cdf2821412..9c40d76127 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -1,6 +1,6 @@ use crate::{ providers::state::macros::delegate_provider_impls, AccountProvider, BlockHashProvider, - ProviderError, StateProvider, + PostState, ProviderError, StateProvider, StateRootProvider, }; use reth_db::{ cursor::{DbCursorRO, DbDupCursorRO}, @@ -92,6 +92,12 @@ impl<'a, 'b, TX: DbTx<'a>> BlockHashProvider for HistoricalStateProviderRef<'a, } } +impl<'a, 'b, TX: DbTx<'a>> StateRootProvider for HistoricalStateProviderRef<'a, 'b, TX> { + fn state_root(&self, _post_state: PostState) -> Result { + Err(ProviderError::StateRootNotAvailableForHistoricalBlock.into()) + } +} + impl<'a, 'b, TX: DbTx<'a>> StateProvider for HistoricalStateProviderRef<'a, 'b, TX> { /// Get storage. fn storage(&self, address: Address, storage_key: StorageKey) -> Result> { diff --git a/crates/storage/provider/src/providers/state/latest.rs b/crates/storage/provider/src/providers/state/latest.rs index 6c99f59ab7..d9bda462b9 100644 --- a/crates/storage/provider/src/providers/state/latest.rs +++ b/crates/storage/provider/src/providers/state/latest.rs @@ -1,6 +1,6 @@ use crate::{ providers::state::macros::delegate_provider_impls, AccountProvider, BlockHashProvider, - StateProvider, + PostState, StateProvider, StateRootProvider, }; use reth_db::{ cursor::{DbCursorRO, DbDupCursorRO}, @@ -55,6 +55,14 @@ impl<'a, 'b, TX: DbTx<'a>> BlockHashProvider for LatestStateProviderRef<'a, 'b, } } +impl<'a, 'b, TX: DbTx<'a>> StateRootProvider for LatestStateProviderRef<'a, 'b, TX> { + fn state_root(&self, post_state: PostState) -> Result { + post_state + .state_root_slow(self.db) + .map_err(|err| reth_interfaces::Error::Database(err.into())) + } +} + impl<'a, 'b, TX: DbTx<'a>> StateProvider for LatestStateProviderRef<'a, 'b, TX> { /// Get storage. fn storage(&self, account: Address, storage_key: StorageKey) -> Result> { diff --git a/crates/storage/provider/src/providers/state/macros.rs b/crates/storage/provider/src/providers/state/macros.rs index d6d3f60ec8..83c9c756d1 100644 --- a/crates/storage/provider/src/providers/state/macros.rs +++ b/crates/storage/provider/src/providers/state/macros.rs @@ -30,6 +30,9 @@ macro_rules! delegate_provider_impls { ($target:ty $(where [$($generics:tt)*])?) => { $crate::providers::state::macros::delegate_impls_to_as_ref!( for $target => + StateRootProvider $(where [$($generics)*])? { + fn state_root(&self, state: crate::PostState) -> reth_interfaces::Result; + } AccountProvider $(where [$($generics)*])? { fn basic_account(&self, address: reth_primitives::Address) -> reth_interfaces::Result>; } diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 7cdf137f1d..afdafbfdac 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -1,7 +1,7 @@ use crate::{ traits::ReceiptProvider, AccountProvider, BlockHashProvider, BlockIdProvider, BlockProvider, - EvmEnvProvider, HeaderProvider, PostStateDataProvider, StateProvider, StateProviderBox, - StateProviderFactory, TransactionsProvider, + EvmEnvProvider, HeaderProvider, PostState, PostStateDataProvider, StateProvider, + StateProviderBox, StateProviderFactory, StateRootProvider, TransactionsProvider, }; use parking_lot::Mutex; use reth_interfaces::Result; @@ -267,6 +267,12 @@ impl AccountProvider for MockEthProvider { } } +impl StateRootProvider for MockEthProvider { + fn state_root(&self, _post_state: PostState) -> Result { + todo!() + } +} + impl StateProvider for MockEthProvider { fn storage(&self, account: Address, storage_key: StorageKey) -> Result> { let lock = self.accounts.lock(); diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 2379d44e9a..44e2747f47 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -1,7 +1,7 @@ use crate::{ traits::ReceiptProvider, AccountProvider, BlockHashProvider, BlockIdProvider, BlockProvider, - EvmEnvProvider, HeaderProvider, StateProvider, StateProviderBox, StateProviderFactory, - TransactionsProvider, + EvmEnvProvider, HeaderProvider, PostState, StateProvider, StateProviderBox, + StateProviderFactory, StateRootProvider, TransactionsProvider, }; use reth_interfaces::Result; use reth_primitives::{ @@ -126,6 +126,12 @@ impl AccountProvider for NoopProvider { } } +impl StateRootProvider for NoopProvider { + fn state_root(&self, _post_state: PostState) -> Result { + todo!() + } +} + impl StateProvider for NoopProvider { fn storage(&self, _account: Address, _storage_key: StorageKey) -> Result> { Ok(None) diff --git a/crates/storage/provider/src/traits/state.rs b/crates/storage/provider/src/traits/state.rs index 250ea8218c..dfdcd623b8 100644 --- a/crates/storage/provider/src/traits/state.rs +++ b/crates/storage/provider/src/traits/state.rs @@ -12,7 +12,9 @@ pub type StateProviderBox<'a> = Box; /// An abstraction for a type that provides state data. #[auto_impl(&, Arc, Box)] -pub trait StateProvider: BlockHashProvider + AccountProvider + Send + Sync { +pub trait StateProvider: + BlockHashProvider + AccountProvider + StateRootProvider + Send + Sync +{ /// Get storage of given account. fn storage(&self, account: Address, storage_key: StorageKey) -> Result>; @@ -154,8 +156,8 @@ pub trait PostStateDataProvider: Send + Sync { } /// A type that can compute the state root of a given post state. -#[auto_impl[Box,&]] +#[auto_impl[Box,&, Arc]] pub trait StateRootProvider: Send + Sync { - /// Returns the state root of the given block. - fn state_root(&self, post_state: &PostState) -> Result; + /// Returns the state root of the PostState on top of the current state. + fn state_root(&self, post_state: PostState) -> Result; }