diff --git a/Cargo.lock b/Cargo.lock index e1ff53c07064..a94595a20d6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7416,7 +7416,6 @@ dependencies = [ "reth-provider", "reth-prune", "reth-prune-types", - "reth-revm", "reth-rpc-types-compat", "reth-stages", "reth-stages-api", @@ -7711,6 +7710,7 @@ dependencies = [ "reth-execution-types", "reth-primitives", "reth-revm", + "reth-storage-api", "reth-testing-utils", "revm-primitives", "secp256k1", @@ -9319,7 +9319,6 @@ dependencies = [ "reth-provider", "reth-prune", "reth-prune-types", - "reth-revm", "reth-stages-api", "reth-static-file", "reth-storage-errors", diff --git a/bin/reth/src/commands/debug_cmd/build_block.rs b/bin/reth/src/commands/debug_cmd/build_block.rs index ce1a2cf6d8e2..6873bab12426 100644 --- a/bin/reth/src/commands/debug_cmd/build_block.rs +++ b/bin/reth/src/commands/debug_cmd/build_block.rs @@ -36,7 +36,7 @@ use reth_provider::{ BlockHashReader, BlockReader, BlockWriter, ChainSpecProvider, ProviderFactory, StageCheckpointReader, StateProviderFactory, }; -use reth_revm::{cached::CachedReads, database::StateProviderDatabase, primitives::KzgSettings}; +use reth_revm::{cached::CachedReads, primitives::KzgSettings}; use reth_stages::StageId; use reth_transaction_pool::{ blobstore::InMemoryBlobStore, BlobStore, EthPooledTransaction, PoolConfig, TransactionOrigin, @@ -260,7 +260,7 @@ impl> Command { SealedBlockWithSenders::>::new(block.clone(), senders).unwrap(); let state_provider = blockchain_db.latest()?; - let db = StateProviderDatabase::new(&state_provider); + let db = &state_provider; let executor = EthExecutorProvider::ethereum(provider_factory.chain_spec()).executor(db); 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 58b86648b901..b5df409dc027 100644 --- a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs @@ -28,7 +28,6 @@ use reth_provider::{ OriginalValuesKnown, ProviderFactory, StageCheckpointReader, StateWriter, StorageLocation, StorageReader, }; -use reth_revm::database::StateProviderDatabase; use reth_stages::StageId; use reth_tasks::TaskExecutor; use reth_trie::StateRoot; @@ -145,7 +144,7 @@ impl> Command { .await?; let state_provider = LatestStateProviderRef::new(&provider); - let db = StateProviderDatabase::new(&state_provider); + let db = &state_provider; let executor = EthExecutorProvider::ethereum(provider_factory.chain_spec()).executor(db); diff --git a/bin/reth/src/commands/debug_cmd/merkle.rs b/bin/reth/src/commands/debug_cmd/merkle.rs index 16a1f1112726..7fafc6e4c3d9 100644 --- a/bin/reth/src/commands/debug_cmd/merkle.rs +++ b/bin/reth/src/commands/debug_cmd/merkle.rs @@ -24,7 +24,6 @@ use reth_provider::{ DatabaseProviderFactory, HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, ProviderFactory, StateWriter, StorageLocation, }; -use reth_revm::database::StateProviderDatabase; use reth_stages::{ stages::{AccountHashingStage, MerkleStage, StorageHashingStage}, ExecInput, Stage, StageCheckpoint, @@ -161,9 +160,8 @@ impl> Command { provider_rw.insert_block(sealed_block.clone(), StorageLocation::Database)?; td += sealed_block.difficulty; - let mut executor = executor_provider.batch_executor(StateProviderDatabase::new( - LatestStateProviderRef::new(&provider_rw), - )); + let mut executor = + executor_provider.batch_executor(LatestStateProviderRef::new(&provider_rw)); executor.execute_and_verify_one((&sealed_block.clone().unseal(), td).into())?; let execution_outcome = executor.finalize(); diff --git a/crates/blockchain-tree/Cargo.toml b/crates/blockchain-tree/Cargo.toml index 1c42a292aea7..f932024fc6e0 100644 --- a/crates/blockchain-tree/Cargo.toml +++ b/crates/blockchain-tree/Cargo.toml @@ -19,7 +19,6 @@ reth-execution-errors.workspace = true reth-db.workspace = true reth-db-api.workspace = true reth-evm.workspace = true -reth-revm.workspace = true reth-provider.workspace = true reth-execution-types.workspace = true reth-stages-api.workspace = true diff --git a/crates/blockchain-tree/src/chain.rs b/crates/blockchain-tree/src/chain.rs index b6792bfeb754..68f5cd2fe33a 100644 --- a/crates/blockchain-tree/src/chain.rs +++ b/crates/blockchain-tree/src/chain.rs @@ -21,7 +21,6 @@ use reth_provider::{ DBProvider, FullExecutionDataProvider, HashedPostStateProvider, ProviderError, StateRootProvider, TryIntoHistoricalStateProvider, }; -use reth_revm::database::StateProviderDatabase; use reth_trie::{updates::TrieUpdates, TrieInput}; use reth_trie_parallel::root::ParallelStateRoot; use std::{ @@ -204,7 +203,7 @@ impl AppendableChain { let provider = BundleStateProvider::new(state_provider, bundle_state_data_provider); - let db = StateProviderDatabase::new(&provider); + let db = &provider; let executor = externals.executor_factory.executor(db); let block_hash = block.hash(); let block = block.unseal(); diff --git a/crates/engine/invalid-block-hooks/src/witness.rs b/crates/engine/invalid-block-hooks/src/witness.rs index 01fdb7cf3b14..bd77ba0a1413 100644 --- a/crates/engine/invalid-block-hooks/src/witness.rs +++ b/crates/engine/invalid-block-hooks/src/witness.rs @@ -13,8 +13,8 @@ use reth_primitives::{NodePrimitives, SealedBlockWithSenders, SealedHeader}; use reth_primitives_traits::SignedTransaction; use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory}; use reth_revm::{ - database::StateProviderDatabase, db::states::bundle_state::BundleRetention, - primitives::EnvWithHandlerCfg, DatabaseCommit, StateBuilder, + db::states::bundle_state::BundleRetention, primitives::EnvWithHandlerCfg, DatabaseCommit, + StateBuilder, StateProviderDatabase, }; use reth_rpc_api::DebugApiClient; use reth_tracing::tracing::warn; @@ -71,7 +71,7 @@ where // Setup database. let mut db = StateBuilder::new() - .with_database(StateProviderDatabase::new( + .with_database(StateProviderDatabase( self.provider.state_by_block_hash(parent_header.hash())?, )) .with_bundle_update() diff --git a/crates/engine/tree/Cargo.toml b/crates/engine/tree/Cargo.toml index 84ca3291a33f..eed4a0d4286b 100644 --- a/crates/engine/tree/Cargo.toml +++ b/crates/engine/tree/Cargo.toml @@ -29,7 +29,6 @@ reth-primitives.workspace = true reth-primitives-traits.workspace = true reth-provider.workspace = true reth-prune.workspace = true -reth-revm.workspace = true reth-stages-api.workspace = true reth-tasks.workspace = true reth-trie-parallel.workspace = true @@ -114,7 +113,6 @@ test-utils = [ "reth-provider/test-utils", "reth-prune-types", "reth-prune-types?/test-utils", - "reth-revm/test-utils", "reth-stages-api/test-utils", "reth-stages/test-utils", "reth-static-file", diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index 84430a559333..eba955c448e5 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -45,7 +45,6 @@ use reth_provider::{ HashedPostStateProvider, ProviderError, StateCommitmentProvider, StateProviderBox, StateProviderFactory, StateReader, StateRootProvider, TransactionVariant, }; -use reth_revm::database::StateProviderDatabase; use reth_stages_api::ControlFlow; use reth_trie::{updates::TrieUpdates, HashedPostState, TrieInput}; use reth_trie_parallel::root::{ParallelStateRoot, ParallelStateRootError}; @@ -2215,7 +2214,7 @@ where } trace!(target: "engine::tree", block=?block.num_hash(), "Executing block"); - let executor = self.executor_provider.executor(StateProviderDatabase::new(&state_provider)); + let executor = self.executor_provider.executor(&state_provider); let block_number = block.number(); let block_hash = block.hash(); diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index 4ee072599188..618d8dfc4230 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -19,6 +19,7 @@ reth-primitives = { workspace = true, features = ["reth-codec"] } reth-revm.workspace = true reth-ethereum-consensus.workspace = true reth-consensus.workspace = true +reth-storage-api.workspace = true # Ethereum revm-primitives.workspace = true diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 2955fdabc7b2..13668e3cf374 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -7,7 +7,6 @@ use crate::{ use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::Transaction as _; use alloy_eips::{eip6110, eip7685::Requests}; -use core::fmt::Display; use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET}; use reth_consensus::ConsensusError; use reth_ethereum_consensus::validate_block_post_execution; @@ -16,18 +15,15 @@ use reth_evm::{ execute::{ balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError, ExecuteOutput, - ProviderError, }, state_change::post_block_balance_increments, system_calls::{OnStateHook, SystemCaller}, ConfigureEvm, TxEnvOverrides, }; use reth_primitives::{BlockWithSenders, EthPrimitives, Receipt}; -use reth_revm::db::State; -use revm_primitives::{ - db::{Database, DatabaseCommit}, - EnvWithHandlerCfg, ResultAndState, U256, -}; +use reth_revm::{db::State, DatabaseCommit, StateProviderDatabase}; +use reth_storage_api::StateProvider; +use revm_primitives::{EnvWithHandlerCfg, ResultAndState, U256}; /// Factory for [`EthExecutionStrategy`]. #[derive(Debug, Clone)] @@ -71,15 +67,17 @@ where { type Primitives = EthPrimitives; - type Strategy + Display>> = - EthExecutionStrategy; + type Strategy = EthExecutionStrategy; fn create_strategy(&self, db: DB) -> Self::Strategy where - DB: Database + Display>, + DB: StateProvider, { - let state = - State::builder().with_database(db).with_bundle_update().without_state_clear().build(); + let state = State::builder() + .with_database(StateProviderDatabase(db)) + .with_bundle_update() + .without_state_clear() + .build(); EthExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) } } @@ -97,7 +95,7 @@ where /// Optional overrides for the transactions environment. tx_env_overrides: Option>, /// Current state for block execution. - state: State, + state: State>, /// Utility to call system smart contracts. system_caller: SystemCaller, } @@ -107,7 +105,11 @@ where EvmConfig: Clone, { /// Creates a new [`EthExecutionStrategy`] - pub fn new(state: State, chain_spec: Arc, evm_config: EvmConfig) -> Self { + pub fn new( + state: State>, + chain_spec: Arc, + evm_config: EvmConfig, + ) -> Self { let system_caller = SystemCaller::new(evm_config.clone(), chain_spec.clone()); Self { state, chain_spec, evm_config, system_caller, tx_env_overrides: None } } @@ -115,7 +117,7 @@ where impl EthExecutionStrategy where - DB: Database + Display>, + DB: StateProvider, EvmConfig: ConfigureEvm
, { /// Configures a new evm configuration and block environment for the given block. @@ -136,7 +138,7 @@ where impl BlockExecutionStrategy for EthExecutionStrategy where - DB: Database + Display>, + DB: StateProvider, EvmConfig: ConfigureEvm< Header = alloy_consensus::Header, Transaction = reth_primitives::TransactionSigned, @@ -199,11 +201,10 @@ where // Execute transaction. let result_and_state = evm.transact().map_err(move |err| { - let new_err = err.map_db_err(|e| e.into()); // Ensure hash is calculated for error log, if not already done BlockValidationError::EVM { hash: transaction.recalculate_hash(), - error: Box::new(new_err), + error: Box::new(err), } })?; self.system_caller.on_state(&result_and_state.state); @@ -285,11 +286,11 @@ where Ok(requests) } - fn state_ref(&self) -> &State { + fn state_ref(&self) -> &State> { &self.state } - fn state_mut(&mut self) -> &mut State { + fn state_mut(&mut self) -> &mut State> { &mut self.state } @@ -346,9 +347,7 @@ mod tests { use reth_primitives::{ public_key_to_address, Account, Block, BlockBody, BlockExt, Transaction, }; - use reth_revm::{ - database::StateProviderDatabase, test_utils::StateProviderTest, TransitionState, - }; + use reth_revm::{test_utils::StateProviderTest, Database, TransitionState}; use reth_testing_utils::generators::{self, sign_tx_with_key_pair}; use revm_primitives::{address, EvmState, BLOCKHASH_SERVE_WINDOW}; use secp256k1::{Keypair, Secp256k1}; @@ -417,7 +416,7 @@ mod tests { let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // attempt to execute a block without parent beacon block root, expect err let err = executor @@ -521,7 +520,7 @@ mod tests { // attempt to execute an empty block with parent beacon block root, this should not fail provider - .batch_executor(StateProviderDatabase::new(&db)) + .batch_executor(&db) .execute_and_verify_one( ( &BlockWithSenders::new_unchecked( @@ -572,7 +571,7 @@ mod tests { ..Header::default() }; - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // attempt to execute an empty block with parent beacon block root, this should not fail executor @@ -617,7 +616,7 @@ mod tests { let mut header = chain_spec.genesis_header().clone(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // attempt to execute the genesis block with non-zero parent beacon block root, expect err header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); @@ -693,7 +692,7 @@ mod tests { let provider = executor_provider(chain_spec); // execute header - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // Now execute a block with the fixed header, ensure that it does not fail executor @@ -766,7 +765,7 @@ mod tests { ); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // construct the header for block one let header = Header { timestamp: 1, number: 1, ..Header::default() }; @@ -812,7 +811,7 @@ mod tests { let header = chain_spec.genesis_header().clone(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // attempt to execute genesis block, this should not fail executor @@ -862,7 +861,7 @@ mod tests { ..Header::default() }; let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // attempt to execute the fork activation block, this should not fail executor @@ -910,7 +909,7 @@ mod tests { ); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); let header = Header { parent_hash: B256::random(), @@ -966,7 +965,7 @@ mod tests { let header_hash = header.hash_slow(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // attempt to execute the genesis block, this should not fail executor @@ -1129,7 +1128,7 @@ mod tests { let provider = executor_provider(chain_spec); - let executor = provider.executor(StateProviderDatabase::new(&db)); + let executor = provider.executor(&db); let BlockExecutionOutput { receipts, requests, .. } = executor .execute( @@ -1212,7 +1211,7 @@ mod tests { ); // Create an executor from the state provider - let executor = executor_provider(chain_spec).executor(StateProviderDatabase::new(&db)); + let executor = executor_provider(chain_spec).executor(&db); // Execute the block and capture the result let exec_result = executor.execute( @@ -1276,7 +1275,7 @@ mod tests { ); let provider = executor_provider(chain_spec); - let executor = provider.executor(StateProviderDatabase::new(&db)); + let executor = provider.executor(&db); let (tx, rx) = mpsc::channel(); let tx_clone = tx.clone(); diff --git a/crates/evm/Cargo.toml b/crates/evm/Cargo.toml index 39add9396cd2..a0a94e788e20 100644 --- a/crates/evm/Cargo.toml +++ b/crates/evm/Cargo.toml @@ -23,8 +23,7 @@ reth-primitives-traits.workspace = true reth-prune-types.workspace = true reth-revm.workspace = true reth-storage-errors.workspace = true - -reth-storage-api = { workspace = true, optional = true } +reth-storage-api.workspace = true revm.workspace = true revm-primitives.workspace = true @@ -68,7 +67,6 @@ test-utils = [ "reth-primitives/test-utils", "reth-primitives-traits/test-utils", "reth-revm/test-utils", - "dep:reth-storage-api", "revm/test-utils", "reth-prune-types/test-utils" ] diff --git a/crates/evm/src/either.rs b/crates/evm/src/either.rs index 4faeb1a72030..a1acb64cee0e 100644 --- a/crates/evm/src/either.rs +++ b/crates/evm/src/either.rs @@ -1,7 +1,5 @@ //! Helper type that represents one of two possible executor types -use core::fmt::Display; - use crate::{ execute::{BatchExecutor, BlockExecutorProvider, Executor}, system_calls::OnStateHook, @@ -9,8 +7,8 @@ use crate::{ use alloc::boxed::Box; use alloy_primitives::BlockNumber; use reth_prune_types::PruneModes; -use reth_storage_errors::provider::ProviderError; -use revm_primitives::db::Database; +use reth_revm::database::StateProviderDatabase; +use reth_storage_api::StateProvider; // re-export Either pub use futures_util::future::Either; @@ -23,15 +21,13 @@ where { type Primitives = A::Primitives; - type Executor + Display>> = - Either, B::Executor>; + type Executor = Either, B::Executor>; - type BatchExecutor + Display>> = - Either, B::BatchExecutor>; + type BatchExecutor = Either, B::BatchExecutor>; fn executor(&self, db: DB) -> Self::Executor where - DB: Database + Display>, + DB: StateProvider, { match self { Self::Left(a) => Either::Left(a.executor(db)), @@ -41,7 +37,7 @@ where fn batch_executor(&self, db: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: StateProvider, { match self { Self::Left(a) => Either::Left(a.batch_executor(db)), @@ -54,7 +50,7 @@ impl Executor for Either where A: Executor, B: for<'a> Executor = A::Input<'a>, Output = A::Output, Error = A::Error>, - DB: Database + Display>, + DB: StateProvider, { type Input<'a> = A::Input<'a>; type Output = A::Output; @@ -80,7 +76,7 @@ where witness: F, ) -> Result where - F: FnMut(&State), + F: FnMut(&State>), { match self { Self::Left(a) => a.execute_with_state_closure(input, witness), @@ -107,7 +103,7 @@ impl BatchExecutor for Either where A: BatchExecutor, B: for<'a> BatchExecutor = A::Input<'a>, Output = A::Output, Error = A::Error>, - DB: Database + Display>, + DB: StateProvider, { type Input<'a> = A::Input<'a>; type Output = A::Output; diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index 8c3e0108fcc3..0025624e8774 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -16,16 +16,16 @@ use alloy_primitives::{ map::{DefaultHashBuilder, HashMap}, Address, BlockNumber, }; -use core::fmt::Display; use reth_consensus::ConsensusError; use reth_primitives::{BlockWithSenders, NodePrimitives, Receipt}; use reth_prune_types::PruneModes; -use reth_revm::batch::BlockBatchRecord; +use reth_revm::{batch::BlockBatchRecord, StateProviderDatabase}; +use reth_storage_api::StateProvider; use revm::{ db::{states::bundle_state::BundleRetention, BundleState}, State, }; -use revm_primitives::{db::Database, Account, AccountStatus, EvmState, U256}; +use revm_primitives::{Account, AccountStatus, EvmState, U256}; /// A general purpose executor trait that executes an input (e.g. block) and produces an output /// (e.g. state changes and receipts). @@ -60,7 +60,7 @@ pub trait Executor { state: F, ) -> Result where - F: FnMut(&State); + F: FnMut(&State>); /// Executes the EVM with the given input and accepts a state hook closure that is invoked with /// the EVM state after execution. @@ -149,7 +149,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// /// It is not expected to validate the state trie root, this must be done by the caller using /// the returned state. - type Executor + Display>>: for<'a> Executor< + type Executor: for<'a> Executor< DB, Input<'a> = BlockExecutionInput< 'a, @@ -160,7 +160,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { >; /// An executor that can execute a batch of blocks given a database. - type BatchExecutor + Display>>: for<'a> BatchExecutor< + type BatchExecutor: for<'a> BatchExecutor< DB, Input<'a> = BlockExecutionInput< 'a, @@ -175,7 +175,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// This is used to execute a single block and get the changed state. fn executor(&self, db: DB) -> Self::Executor where - DB: Database + Display>; + DB: StateProvider; /// Creates a new batch executor with the given database and pruning modes. /// @@ -183,7 +183,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// during historical sync which involves executing multiple blocks in sequence. fn batch_executor(&self, db: DB) -> Self::BatchExecutor where - DB: Database + Display>; + DB: StateProvider; } /// Helper type for the output of executing a block. @@ -198,7 +198,7 @@ pub struct ExecuteOutput { /// Defines the strategy for executing a single block. pub trait BlockExecutionStrategy { /// Database this strategy operates on. - type DB: Database; + type DB: StateProvider; /// Primitive types used by the strategy. type Primitives: NodePrimitives; @@ -232,10 +232,10 @@ pub trait BlockExecutionStrategy { ) -> Result; /// Returns a reference to the current state. - fn state_ref(&self) -> &State; + fn state_ref(&self) -> &State>; /// Returns a mutable reference to the current state. - fn state_mut(&mut self) -> &mut State; + fn state_mut(&mut self) -> &mut State>; /// Sets a hook to be called after each state change during execution. fn with_state_hook(&mut self, _hook: Option>) {} @@ -263,7 +263,7 @@ pub trait BlockExecutionStrategyFactory: Send + Sync + Clone + Unpin + 'static { type Primitives: NodePrimitives; /// Associated strategy type. - type Strategy + Display>>: BlockExecutionStrategy< + type Strategy: BlockExecutionStrategy< DB = DB, Primitives = Self::Primitives, Error = BlockExecutionError, @@ -272,7 +272,7 @@ pub trait BlockExecutionStrategyFactory: Send + Sync + Clone + Unpin + 'static { /// Creates a strategy using the give database. fn create_strategy(&self, db: DB) -> Self::Strategy where - DB: Database + Display>; + DB: StateProvider; } impl Clone for BasicBlockExecutorProvider @@ -303,15 +303,13 @@ where { type Primitives = F::Primitives; - type Executor + Display>> = - BasicBlockExecutor>; + type Executor = BasicBlockExecutor>; - type BatchExecutor + Display>> = - BasicBatchExecutor>; + type BatchExecutor = BasicBatchExecutor>; fn executor(&self, db: DB) -> Self::Executor where - DB: Database + Display>, + DB: StateProvider, { let strategy = self.strategy_factory.create_strategy(db); BasicBlockExecutor::new(strategy) @@ -319,7 +317,7 @@ where fn batch_executor(&self, db: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: StateProvider, { let strategy = self.strategy_factory.create_strategy(db); let batch_record = BlockBatchRecord::default(); @@ -345,7 +343,7 @@ impl BasicBlockExecutor { impl Executor for BasicBlockExecutor where S: BlockExecutionStrategy, - DB: Database + Display>, + DB: StateProvider, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders<::Block>>; @@ -375,7 +373,7 @@ where mut state: F, ) -> Result where - F: FnMut(&State), + F: FnMut(&State>), { let BlockExecutionInput { block, total_difficulty } = input; @@ -445,7 +443,7 @@ where impl BatchExecutor for BasicBatchExecutor where S: BlockExecutionStrategy, - DB: Database + Display>, + DB: StateProvider, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders<::Block>>; @@ -507,10 +505,10 @@ where /// Zero balance increments are ignored and won't create state entries. pub fn balance_increment_state( balance_increments: &HashMap, - state: &mut State, + state: &mut State>, ) -> Result where - DB: Database, + DB: StateProvider, { let mut load_account = |address: &Address| -> Result<(Address, Account), BlockExecutionError> { let cache_account = state.load_cache_account(*address).map_err(|_| { @@ -545,7 +543,7 @@ mod tests { use core::marker::PhantomData; use reth_chainspec::{ChainSpec, MAINNET}; use reth_primitives::EthPrimitives; - use revm::db::{CacheDB, EmptyDBTyped}; + use reth_storage_api::noop::NoopProvider; use revm_primitives::{address, bytes, AccountInfo, TxEnv, KECCAK_EMPTY}; use std::sync::Arc; @@ -554,19 +552,19 @@ mod tests { impl BlockExecutorProvider for TestExecutorProvider { type Primitives = EthPrimitives; - type Executor + Display>> = TestExecutor; - type BatchExecutor + Display>> = TestExecutor; + type Executor = TestExecutor; + type BatchExecutor = TestExecutor; fn executor(&self, _db: DB) -> Self::Executor where - DB: Database + Display>, + DB: StateProvider, { TestExecutor(PhantomData) } fn batch_executor(&self, _db: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: StateProvider, { TestExecutor(PhantomData) } @@ -589,7 +587,7 @@ mod tests { _: F, ) -> Result where - F: FnMut(&State), + F: FnMut(&State>), { Err(BlockExecutionError::msg("execution unavailable for tests")) } @@ -637,7 +635,7 @@ mod tests { // factory can use them in a real use case. _chain_spec: Arc, _evm_config: EvmConfig, - state: State, + state: State>, execute_transactions_result: ExecuteOutput, apply_post_execution_changes_result: Requests, finish_result: BundleState, @@ -652,15 +650,14 @@ mod tests { impl BlockExecutionStrategyFactory for TestExecutorStrategyFactory { type Primitives = EthPrimitives; - type Strategy + Display>> = - TestExecutorStrategy; + type Strategy = TestExecutorStrategy; fn create_strategy(&self, db: DB) -> Self::Strategy where - DB: Database + Display>, + DB: StateProvider, { let state = State::builder() - .with_database(db) + .with_database(StateProviderDatabase(db)) .with_bundle_update() .without_state_clear() .build(); @@ -680,7 +677,7 @@ mod tests { impl BlockExecutionStrategy for TestExecutorStrategy where - DB: Database, + DB: StateProvider, { type DB = DB; type Primitives = EthPrimitives; @@ -711,11 +708,11 @@ mod tests { Ok(self.apply_post_execution_changes_result.clone()) } - fn state_ref(&self) -> &State { + fn state_ref(&self) -> &State> { &self.state } - fn state_mut(&mut self) -> &mut State { + fn state_mut(&mut self) -> &mut State> { &mut self.state } @@ -741,7 +738,7 @@ mod tests { #[test] fn test_provider() { let provider = TestExecutorProvider; - let db = CacheDB::>::default(); + let db = NoopProvider::default(); let executor = provider.executor(db); let _ = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO)); } @@ -764,7 +761,7 @@ mod tests { finish_result: expected_finish_result.clone(), }; let provider = BasicBlockExecutorProvider::new(strategy_factory); - let db = CacheDB::>::default(); + let db = NoopProvider::default(); let executor = provider.executor(db); let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO)); @@ -787,7 +784,7 @@ mod tests { finish_result: BundleState::default(), }; let provider = BasicBlockExecutorProvider::new(strategy_factory); - let db = CacheDB::>::default(); + let db = NoopProvider::default(); // if we want to apply tx env overrides the executor must be mut. let mut executor = provider.executor(db); @@ -804,9 +801,10 @@ mod tests { addr: Address, balance: u128, nonce: u64, - ) -> State>> { - let db = CacheDB::>::default(); - let mut state = State::builder().with_database(db).with_bundle_update().build(); + ) -> State> { + let db = NoopProvider::default(); + let mut state = + State::builder().with_database(StateProviderDatabase(db)).with_bundle_update().build(); let account_info = AccountInfo { balance: U256::from(balance), @@ -833,7 +831,7 @@ mod tests { #[test] fn test_balance_increment_state_empty_increments_map() { let mut state = State::builder() - .with_database(CacheDB::>::default()) + .with_database(StateProviderDatabase(NoopProvider::default())) .with_bundle_update() .build(); diff --git a/crates/evm/src/metrics.rs b/crates/evm/src/metrics.rs index 1f21cb4d3a41..bc5dc634a5d8 100644 --- a/crates/evm/src/metrics.rs +++ b/crates/evm/src/metrics.rs @@ -150,8 +150,10 @@ impl ExecutorMetrics { #[cfg(test)] mod tests { use super::*; + use alloy_eips::eip7685::Requests; use metrics_util::debugging::{DebugValue, DebuggingRecorder, Snapshotter}; + use reth_revm::StateProviderDatabase; use revm::db::BundleState; use revm_primitives::{ Account, AccountInfo, AccountStatus, EvmState, EvmStorage, EvmStorageSlot, B256, U256, @@ -185,7 +187,7 @@ mod tests { _state: F, ) -> Result where - F: FnMut(&revm::State<()>), + F: FnMut(&revm::State>), { Ok(BlockExecutionOutput { state: BundleState::default(), diff --git a/crates/evm/src/noop.rs b/crates/evm/src/noop.rs index 816a4c835644..cf6b9a6288eb 100644 --- a/crates/evm/src/noop.rs +++ b/crates/evm/src/noop.rs @@ -1,14 +1,13 @@ //! A no operation block executor implementation. use alloy_primitives::BlockNumber; -use core::fmt::Display; use reth_execution_errors::BlockExecutionError; use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome}; use reth_primitives::{BlockWithSenders, NodePrimitives}; use reth_prune_types::PruneModes; -use reth_storage_errors::provider::ProviderError; +use reth_revm::database::StateProviderDatabase; +use reth_storage_api::StateProvider; use revm::State; -use revm_primitives::db::Database; use crate::{ execute::{BatchExecutor, BlockExecutorProvider, Executor}, @@ -25,20 +24,20 @@ pub struct NoopBlockExecutorProvider

(core::marker::PhantomData

); impl BlockExecutorProvider for NoopBlockExecutorProvider

{ type Primitives = P; - type Executor + Display>> = Self; + type Executor = Self; - type BatchExecutor + Display>> = Self; + type BatchExecutor = Self; fn executor(&self, _: DB) -> Self::Executor where - DB: Database + Display>, + DB: StateProvider, { Self::default() } fn batch_executor(&self, _: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: StateProvider, { Self::default() } @@ -59,7 +58,7 @@ impl Executor for NoopBlockExecutorProvider

{ _: F, ) -> Result where - F: FnMut(&State), + F: FnMut(&State>), { Err(BlockExecutionError::msg(UNAVAILABLE_FOR_NOOP)) } diff --git a/crates/evm/src/test_utils.rs b/crates/evm/src/test_utils.rs index 1fb9fd7075de..72ae8534cc79 100644 --- a/crates/evm/src/test_utils.rs +++ b/crates/evm/src/test_utils.rs @@ -17,10 +17,11 @@ use reth_execution_errors::BlockExecutionError; use reth_execution_types::ExecutionOutcome; use reth_primitives::{BlockWithSenders, EthPrimitives, NodePrimitives, Receipt, Receipts}; use reth_prune_types::PruneModes; -use reth_storage_errors::provider::{ProviderError, ProviderResult}; +use reth_revm::database::StateProviderDatabase; +use reth_storage_api::StateProvider; +use reth_storage_errors::provider::ProviderResult; use revm::State; -use revm_primitives::db::Database; -use std::{fmt::Display, sync::Arc}; +use std::sync::Arc; impl EvmEnvProvider for reth_storage_api::noop::NoopProvider @@ -53,20 +54,20 @@ impl MockExecutorProvider { impl BlockExecutorProvider for MockExecutorProvider { type Primitives = EthPrimitives; - type Executor + Display>> = Self; + type Executor = Self; - type BatchExecutor + Display>> = Self; + type BatchExecutor = Self; fn executor(&self, _: DB) -> Self::Executor where - DB: Database + Display>, + DB: StateProvider, { self.clone() } fn batch_executor(&self, _: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: StateProvider, { self.clone() } @@ -97,7 +98,7 @@ impl Executor for MockExecutorProvider { _: F, ) -> Result where - F: FnMut(&State), + F: FnMut(&State>), { >::execute(self, input) } @@ -143,7 +144,7 @@ where /// Provides safe read access to the state pub fn with_state(&self, f: F) -> R where - F: FnOnce(&State) -> R, + F: FnOnce(&State>) -> R, { f(self.strategy.state_ref()) } @@ -151,7 +152,7 @@ where /// Provides safe write access to the state pub fn with_state_mut(&mut self, f: F) -> R where - F: FnOnce(&mut State) -> R, + F: FnOnce(&mut State>) -> R, { f(self.strategy.state_mut()) } @@ -164,7 +165,7 @@ where /// Provides safe read access to the state pub fn with_state(&self, f: F) -> R where - F: FnOnce(&State) -> R, + F: FnOnce(&State>) -> R, { f(self.strategy.state_ref()) } @@ -172,7 +173,7 @@ where /// Provides safe write access to the state pub fn with_state_mut(&mut self, f: F) -> R where - F: FnOnce(&mut State) -> R, + F: FnOnce(&mut State>) -> R, { f(self.strategy.state_mut()) } diff --git a/crates/exex/exex/Cargo.toml b/crates/exex/exex/Cargo.toml index b70fb921599e..6062a4808e70 100644 --- a/crates/exex/exex/Cargo.toml +++ b/crates/exex/exex/Cargo.toml @@ -29,7 +29,6 @@ reth-primitives = { workspace = true, features = ["secp256k1"] } reth-primitives-traits.workspace = true reth-provider.workspace = true reth-prune-types.workspace = true -reth-revm.workspace = true reth-stages-api.workspace = true reth-tasks.workspace = true reth-tracing.workspace = true @@ -60,6 +59,7 @@ reth-node-api.workspace = true reth-primitives-traits = { workspace = true, features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-testing-utils.workspace = true +reth-revm.workspace = true alloy-genesis.workspace = true alloy-consensus.workspace = true @@ -73,7 +73,6 @@ default = [] serde = [ "reth-provider/serde", "reth-exex-types/serde", - "reth-revm/serde", "alloy-consensus/serde", "alloy-eips/serde", "alloy-primitives/serde", diff --git a/crates/exex/exex/src/backfill/job.rs b/crates/exex/exex/src/backfill/job.rs index 0a2be83d6f61..11ab9881c5d8 100644 --- a/crates/exex/exex/src/backfill/job.rs +++ b/crates/exex/exex/src/backfill/job.rs @@ -16,7 +16,6 @@ use reth_provider::{ BlockReader, Chain, HeaderProvider, ProviderError, StateProviderFactory, TransactionVariant, }; use reth_prune_types::PruneModes; -use reth_revm::database::StateProviderDatabase; use reth_stages_api::ExecutionStageThresholds; use reth_tracing::tracing::{debug, trace}; @@ -75,9 +74,9 @@ where "Executing block range" ); - let mut executor = self.executor.batch_executor(StateProviderDatabase::new( + let mut executor = self.executor.batch_executor( self.provider.history_by_block_number(self.range.start().saturating_sub(1))?, - )); + ); executor.set_prune_modes(self.prune_modes.clone()); let mut fetch_block_duration = Duration::default(); @@ -211,9 +210,9 @@ where .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; // Configure the executor to use the previous block's state. - let executor = self.executor.executor(StateProviderDatabase::new( - self.provider.history_by_block_number(block_number.saturating_sub(1))?, - )); + let executor = self + .executor + .executor(self.provider.history_by_block_number(block_number.saturating_sub(1))?); trace!(target: "exex::backfill", number = block_number, txs = block_with_senders.block.body().transactions().len(), "Executing block"); diff --git a/crates/exex/exex/src/backfill/test_utils.rs b/crates/exex/exex/src/backfill/test_utils.rs index 6d93314e22bd..c99beb50264d 100644 --- a/crates/exex/exex/src/backfill/test_utils.rs +++ b/crates/exex/exex/src/backfill/test_utils.rs @@ -17,7 +17,6 @@ use reth_provider::{ providers::ProviderNodeTypes, BlockWriter as _, ExecutionOutcome, LatestStateProviderRef, ProviderFactory, }; -use reth_revm::database::StateProviderDatabase; use reth_testing_utils::generators::sign_tx_with_key_pair; use secp256k1::Keypair; @@ -70,7 +69,7 @@ where // Execute the block to produce a block execution output let mut block_execution_output = EthExecutorProvider::ethereum(chain_spec) - .executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider))) + .executor(LatestStateProviderRef::new(&provider)) .execute(BlockExecutionInput { block, total_difficulty: U256::ZERO })?; block_execution_output.state.reverts.sort(); @@ -204,7 +203,7 @@ where let provider = provider_factory.provider()?; let executor = EthExecutorProvider::ethereum(chain_spec) - .batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider))); + .batch_executor(LatestStateProviderRef::new(&provider)); let mut execution_outcome = executor.execute_and_verify_batch(vec![ (&block1, U256::ZERO).into(), diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index eeb56990b36d..891529e2b1fa 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -4,7 +4,6 @@ use crate::{l1::ensure_create2_deployer, OpBlockExecutionError, OpEvmConfig}; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::{Header, Transaction as _}; use alloy_eips::eip7685::Requests; -use core::fmt::Display; use op_alloy_consensus::DepositTransaction; use reth_chainspec::EthereumHardforks; use reth_consensus::ConsensusError; @@ -13,7 +12,6 @@ use reth_evm::{ execute::{ balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError, ExecuteOutput, - ProviderError, }, state_change::post_block_balance_increments, system_calls::{OnStateHook, SystemCaller}, @@ -24,8 +22,8 @@ use reth_optimism_consensus::validate_block_post_execution; use reth_optimism_forks::OpHardfork; use reth_optimism_primitives::OpPrimitives; use reth_primitives::{BlockWithSenders, Receipt, TransactionSigned, TxType}; -use reth_revm::{Database, State}; -use reth_storage_api::noop::NoopProvider; +use reth_revm::{State, StateProviderDatabase}; +use reth_storage_api::{noop::NoopProvider, StateProvider}; use revm_primitives::{db::DatabaseCommit, EnvWithHandlerCfg, ResultAndState, U256}; use tracing::trace; @@ -62,15 +60,17 @@ where + ConfigureEvm

, { type Primitives = OpPrimitives; - type Strategy + Display>> = - OpExecutionStrategy; + type Strategy = OpExecutionStrategy; fn create_strategy(&self, db: DB) -> Self::Strategy where - DB: Database + Display>, + DB: StateProvider, { - let state = - State::builder().with_database(db).with_bundle_update().without_state_clear().build(); + let state = State::builder() + .with_database(StateProviderDatabase(db)) + .with_bundle_update() + .without_state_clear() + .build(); OpExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) } } @@ -88,7 +88,7 @@ where /// Optional overrides for the transactions environment. tx_env_overrides: Option>, /// Current state for block execution. - state: State, + state: State>, /// Utility to call system smart contracts. system_caller: SystemCaller, } @@ -98,7 +98,11 @@ where EvmConfig: Clone, { /// Creates a new [`OpExecutionStrategy`] - pub fn new(state: State, chain_spec: Arc, evm_config: EvmConfig) -> Self { + pub fn new( + state: State>, + chain_spec: Arc, + evm_config: EvmConfig, + ) -> Self { let system_caller = SystemCaller::new(evm_config.clone(), chain_spec.clone()); Self { state, chain_spec, evm_config, system_caller, tx_env_overrides: None } } @@ -106,7 +110,7 @@ where impl OpExecutionStrategy where - DB: Database + Display>, + DB: StateProvider, EvmConfig: ConfigureEvm
, { /// Configures a new evm configuration and block environment for the given block. @@ -121,7 +125,7 @@ where impl BlockExecutionStrategy for OpExecutionStrategy where - DB: Database + Display>, + DB: StateProvider, EvmConfig: ConfigureEvm
, { type DB = DB; @@ -216,11 +220,10 @@ where // Execute transaction. let result_and_state = evm.transact().map_err(move |err| { - let new_err = err.map_db_err(|e| e.into()); // Ensure hash is calculated for error log, if not already done BlockValidationError::EVM { hash: transaction.recalculate_hash(), - error: Box::new(new_err), + error: Box::new(err), } })?; @@ -277,11 +280,11 @@ where Ok(Requests::default()) } - fn state_ref(&self) -> &State { + fn state_ref(&self) -> &State> { &self.state } - fn state_mut(&mut self) -> &mut State { + fn state_mut(&mut self) -> &mut State> { &mut self.state } @@ -331,9 +334,7 @@ mod tests { use reth_evm::execute::{BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider}; use reth_optimism_chainspec::OpChainSpecBuilder; use reth_primitives::{Account, Block, BlockBody, Transaction, TransactionSigned}; - use reth_revm::{ - database::StateProviderDatabase, test_utils::StateProviderTest, L1_BLOCK_CONTRACT, - }; + use reth_revm::{test_utils::StateProviderTest, L1_BLOCK_CONTRACT}; use std::{collections::HashMap, str::FromStr}; fn create_op_state_provider() -> StateProviderTest { @@ -415,7 +416,7 @@ mod tests { ); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // make sure the L1 block contract state is preloaded. executor.with_state_mut(|state| { @@ -499,7 +500,7 @@ mod tests { ); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(&db); // make sure the L1 block contract state is preloaded. executor.with_state_mut(|state| { diff --git a/crates/primitives-traits/src/account.rs b/crates/primitives-traits/src/account.rs index 64ce209e7f5e..bb963b948b78 100644 --- a/crates/primitives-traits/src/account.rs +++ b/crates/primitives-traits/src/account.rs @@ -2,7 +2,7 @@ use alloy_consensus::constants::KECCAK_EMPTY; use alloy_genesis::GenesisAccount; use alloy_primitives::{keccak256, Bytes, B256, U256}; use alloy_trie::TrieAccount; -use derive_more::Deref; +use derive_more::{Deref, From, Into}; use revm_primitives::{AccountInfo, Bytecode as RevmBytecode, BytecodeDecodeError}; #[cfg(any(test, feature = "reth-codec"))] @@ -75,7 +75,7 @@ impl Account { /// /// A wrapper around [`revm::primitives::Bytecode`][RevmBytecode] with encoding/decoding support. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, Default, PartialEq, Eq, Deref)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Deref, From, Into)] pub struct Bytecode(pub RevmBytecode); impl Bytecode { diff --git a/crates/revm/src/cached.rs b/crates/revm/src/cached.rs index 5d5262adc5b3..ce14671ab2d8 100644 --- a/crates/revm/src/cached.rs +++ b/crates/revm/src/cached.rs @@ -1,12 +1,25 @@ //! Database adapters for payload building. use alloy_primitives::{ - map::{Entry, HashMap}, - Address, B256, U256, + map::{B256HashMap, Entry, HashMap}, + Address, BlockNumber, Bytes, StorageKey, StorageValue, B256, U256, }; use core::cell::RefCell; -use revm::primitives::{ - db::{Database, DatabaseRef}, - AccountInfo, Bytecode, +use reth_primitives::Account; +use reth_storage_api::{ + AccountReader, BlockHashReader, HashedPostStateProvider, StateProofProvider, StateProvider, + StateRootProvider, StorageRootProvider, +}; +use reth_storage_errors::provider::ProviderResult; +use reth_trie::{ + updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, + MultiProofTargets, StorageMultiProof, StorageProof, TrieInput, +}; +use revm::{ + db::BundleState, + primitives::{ + db::{Database, DatabaseRef}, + AccountInfo, Bytecode, + }, }; /// A container type that caches reads from an underlying [`DatabaseRef`]. @@ -152,6 +165,221 @@ impl Database for CachedReadsDbMut<'_, DB> { } } +impl AccountReader for CachedReadsDbMut<'_, DB> { + fn basic_account(&self, address: Address) -> ProviderResult> { + if let Some(hit) = self.cached.accounts.get(&address) { + if let Some(acc) = &hit.info { + return Ok(Some(acc.into())) + } + } + + let db_read = self.db.basic_account(address)?; + if db_read.is_some() { + let acc = db_read.map(|info| info.into()); + let cache = &self.cached; + // safe because CachedReadsDbMut ensure exclusive write access to cache + unsafe { + let cache_entry = (*(*cache as *const CachedReads as *mut CachedReads)) + .accounts + .entry(address) + .or_default(); + cache_entry.info = acc; + } + } + + Ok(db_read) + } +} + +impl BlockHashReader for CachedReadsDbMut<'_, DB> { + fn block_hash(&self, number: BlockNumber) -> ProviderResult> { + let hit = self.cached.block_hashes.get(&number); + if hit.is_some() { + return Ok(hit.copied()) + } + + let db_read = self.db.block_hash(number)?; + if let Some(hash) = db_read { + let cache = &self.cached; + // safe because CachedReadsDbMut ensure exclusive write access to cache + unsafe { + _ = (*(*cache as *const CachedReads as *mut CachedReads)) + .block_hashes + .insert(number, hash) + } + } + + Ok(db_read) + } + + fn canonical_hashes_range( + &self, + start: BlockNumber, + end: BlockNumber, + ) -> ProviderResult> { + let range = start..end; + if range.is_empty() { + return Ok(vec![]) + } + + if self.block_hash(start)?.is_some() && self.block_hash(end)?.is_some() { + // optimistically collect hashes + let hashes = range + .into_iter() + .map_while(|block_num| self.block_hash(block_num).ok().flatten()) + .collect::>(); + // safe subtraction, already checked end is higher than start with call to + // `ops::Range::is_empty` + if hashes.len() as u64 == end - start { + return Ok(hashes) + } + } + + Ok(vec![]) + } +} + +impl StateRootProvider for CachedReadsDbMut<'_, DB> { + fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult { + self.db.state_root(hashed_state) + } + + fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult { + self.db.state_root_from_nodes(input) + } + + fn state_root_with_updates( + &self, + hashed_state: HashedPostState, + ) -> ProviderResult<(B256, TrieUpdates)> { + self.db.state_root_with_updates(hashed_state) + } + + fn state_root_from_nodes_with_updates( + &self, + input: TrieInput, + ) -> ProviderResult<(B256, TrieUpdates)> { + self.db.state_root_from_nodes_with_updates(input) + } +} + +impl StorageRootProvider for CachedReadsDbMut<'_, DB> { + fn storage_root( + &self, + address: Address, + hashed_storage: HashedStorage, + ) -> ProviderResult { + self.db.storage_root(address, hashed_storage) + } + + fn storage_proof( + &self, + address: Address, + slot: B256, + hashed_storage: HashedStorage, + ) -> ProviderResult { + self.db.storage_proof(address, slot, hashed_storage) + } + + fn storage_multiproof( + &self, + address: Address, + slots: &[B256], + hashed_storage: HashedStorage, + ) -> ProviderResult { + self.db.storage_multiproof(address, slots, hashed_storage) + } +} + +impl StateProofProvider for CachedReadsDbMut<'_, DB> { + fn proof( + &self, + input: TrieInput, + address: Address, + slots: &[B256], + ) -> ProviderResult { + self.db.proof(input, address, slots) + } + + fn multiproof( + &self, + input: TrieInput, + targets: MultiProofTargets, + ) -> ProviderResult { + self.db.multiproof(input, targets) + } + + fn witness( + &self, + input: TrieInput, + target: HashedPostState, + ) -> ProviderResult> { + self.db.witness(input, target) + } +} + +impl HashedPostStateProvider for CachedReadsDbMut<'_, DB> { + fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState { + self.db.hashed_post_state(bundle_state) + } +} + +impl StateProvider for CachedReadsDbMut<'_, DB> { + fn storage( + &self, + account: Address, + storage_key: StorageKey, + ) -> ProviderResult> { + if let Some(hit) = self.cached.accounts.get(&account) { + let val = hit.storage.get(&storage_key.into()); + if val.is_some() { + return Ok(val.copied()) + } + } + + let db_read = self.db.storage(account, storage_key)?; + if let Some(val) = db_read { + let cache = &self.cached; + // safe because CachedReadsDbMut ensure exclusive write access to cache + unsafe { + let cache_entry = (*(*cache as *const CachedReads as *mut CachedReads)) + .accounts + .entry(account) + .or_default(); + cache_entry.storage.insert(storage_key.into(), val); + } + } + + Ok(db_read) + } + + fn bytecode_by_hash( + &self, + code_hash: B256, + ) -> ProviderResult> { + let hit = self.cached.contracts.get(&code_hash); + if hit.is_some() { + return Ok(hit.map(|bytecode| bytecode.clone().into())) + } + + let db_read = self.db.bytecode_by_hash(code_hash)?; + if let Some(ref bytecode) = db_read { + let bytecode = bytecode.clone().into(); + let cache = &self.cached; + // safe because CachedReadsDbMut ensure exclusive write access to cache + unsafe { + let cache_entry = (*(*cache as *const CachedReads as *mut CachedReads)) + .contracts + .entry(code_hash) + .or_default(); + *cache_entry = bytecode; + } + } + + Ok(db_read) + } +} + /// A [`DatabaseRef`] that caches reads inside [`CachedReads`]. /// /// This is intended to be used as the [`DatabaseRef`] for @@ -182,7 +410,7 @@ impl DatabaseRef for CachedReadsDBRef<'_, DB> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] struct CachedAccount { info: Option, storage: HashMap, diff --git a/crates/revm/src/database.rs b/crates/revm/src/database.rs index 682aca6cf379..28b390246306 100644 --- a/crates/revm/src/database.rs +++ b/crates/revm/src/database.rs @@ -63,7 +63,8 @@ impl EvmStateProvider for T { } /// A [Database] and [`DatabaseRef`] implementation that uses [`EvmStateProvider`] as the underlying -/// data source. +/// data source. All [`StateProvider`](reth_storage_api::StateProvider) types also implement +/// [`EvmStateProvider`]. #[derive(Debug, Clone)] pub struct StateProviderDatabase(pub DB); diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 5f18a0fe6166..69380dff3ae0 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -33,3 +33,5 @@ pub mod either; /// Helper types for execution witness generation. #[cfg(feature = "witness")] pub mod witness; + +pub use database::StateProviderDatabase; diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 5a431699b33a..1745a1ea7292 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -26,7 +26,7 @@ use reth_provider::{ BlockIdReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, HeaderProvider, ProviderBlock, ReceiptProviderIdExt, StateProofProvider, TransactionVariant, }; -use reth_revm::{database::StateProviderDatabase, witness::ExecutionWitnessRecord}; +use reth_revm::{witness::ExecutionWitnessRecord, StateProviderDatabase}; use reth_rpc_api::DebugApiServer; use reth_rpc_eth_api::{ helpers::{EthTransactions, TraceExt}, @@ -104,7 +104,7 @@ where self.eth_api() .spawn_with_state_at_block(block.parent_hash().into(), move |state| { let mut results = Vec::with_capacity(block.body.transactions().len()); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(StateProviderDatabase(state)); this.eth_api().apply_pre_execution_changes(&block, &mut db, &cfg, &block_env)?; @@ -254,7 +254,7 @@ where // configure env for the target transaction let tx = transaction.into_recovered(); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(StateProviderDatabase(state)); this.eth_api().apply_pre_execution_changes( &block, @@ -545,7 +545,7 @@ where .spawn_with_state_at_block(at.into(), move |state| { // the outer vec for the bundles let mut all_bundles = Vec::with_capacity(bundles.len()); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(StateProviderDatabase(state)); if replay_block_txs { // only need to replay the transactions in the block if not all transactions are @@ -635,7 +635,7 @@ where self.eth_api() .spawn_with_state_at_block(block.parent_hash().into(), move |state_provider| { - let db = StateProviderDatabase::new(&state_provider); + let db = &state_provider; let block_executor = this.inner.block_executor.executor(db); let mut witness_record = ExecutionWitnessRecord::default(); diff --git a/crates/rpc/rpc/src/validation.rs b/crates/rpc/rpc/src/validation.rs index 94e06c6b2486..35caed4463b6 100644 --- a/crates/rpc/rpc/src/validation.rs +++ b/crates/rpc/rpc/src/validation.rs @@ -22,7 +22,7 @@ use reth_primitives_traits::{constants::GAS_LIMIT_BOUND_DIVISOR, Block as _, Blo use reth_provider::{ BlockExecutionInput, BlockExecutionOutput, BlockReaderIdExt, StateProviderFactory, }; -use reth_revm::{cached::CachedReads, database::StateProviderDatabase}; +use reth_revm::cached::CachedReads; use reth_rpc_api::BlockSubmissionValidationApiServer; use reth_rpc_server_types::result::internal_rpc_err; use reth_tasks::TaskSpawner; @@ -147,7 +147,7 @@ where let mut request_cache = self.cached_reads(latest_header_hash).await; - let cached_db = request_cache.as_db_mut(StateProviderDatabase::new(&state_provider)); + let cached_db = request_cache.as_db_mut(&state_provider); let executor = self.executor_provider.executor(cached_db); let block = block.unseal(); diff --git a/crates/stages/stages/Cargo.toml b/crates/stages/stages/Cargo.toml index e7114eeb16ac..af45c098d11c 100644 --- a/crates/stages/stages/Cargo.toml +++ b/crates/stages/stages/Cargo.toml @@ -32,7 +32,6 @@ reth-execution-types.workspace = true reth-prune.workspace = true reth-prune-types.workspace = true reth-storage-errors.workspace = true -reth-revm.workspace = true reth-stages-api.workspace = true reth-trie = { workspace = true, features = ["metrics"] } reth-trie-db = { workspace = true, features = ["metrics"] } @@ -68,7 +67,6 @@ reth-execution-errors.workspace = true reth-consensus = { workspace = true, features = ["test-utils"] } reth-network-p2p = { workspace = true, features = ["test-utils"] } reth-downloaders.workspace = true -reth-revm.workspace = true reth-static-file.workspace = true reth-stages-api = { workspace = true, features = ["test-utils"] } reth-testing-utils.workspace = true @@ -109,7 +107,6 @@ test-utils = [ "reth-downloaders/test-utils", "reth-primitives/test-utils", "reth-primitives-traits/test-utils", - "reth-revm/test-utils", "reth-codecs/test-utils", "reth-db-api/test-utils", "reth-trie-db/test-utils", diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index 444874e8e4a2..13fa39090c02 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -21,7 +21,6 @@ use reth_provider::{ StaticFileProviderFactory, StatsReader, StorageLocation, TransactionVariant, }; use reth_prune_types::PruneModes; -use reth_revm::database::StateProviderDatabase; use reth_stages_api::{ BlockErrorKind, CheckpointBlockRange, EntitiesCheckpoint, ExecInput, ExecOutput, ExecutionCheckpoint, ExecutionStageThresholds, Stage, StageCheckpoint, StageError, StageId, @@ -303,7 +302,7 @@ where self.ensure_consistency(provider, input.checkpoint().block_number, None)?; - let db = StateProviderDatabase(LatestStateProviderRef::new(provider)); + let db = LatestStateProviderRef::new(provider); let mut executor = self.executor_provider.batch_executor(db); executor.set_tip(max_block); executor.set_prune_modes(prune_modes); diff --git a/examples/custom-beacon-withdrawals/src/main.rs b/examples/custom-beacon-withdrawals/src/main.rs index c4b8676bd0c3..52f29fe9da32 100644 --- a/examples/custom-beacon-withdrawals/src/main.rs +++ b/examples/custom-beacon-withdrawals/src/main.rs @@ -12,11 +12,11 @@ use reth::{ api::{ConfigureEvm, ConfigureEvmEnv, NodeTypesWithEngine}, builder::{components::ExecutorBuilder, BuilderContext, FullNodeTypes}, cli::Cli, - providers::ProviderError, + providers::StateProvider, revm::{ interpreter::Host, primitives::{address, Address, Bytes, Env, EnvWithHandlerCfg, TransactTo, TxEnv, U256}, - Database, DatabaseCommit, Evm, State, + Database, DatabaseCommit, Evm, State, StateProviderDatabase, }, }; use reth_chainspec::{ChainSpec, EthereumHardforks}; @@ -30,7 +30,7 @@ use reth_evm::{ use reth_evm_ethereum::EthEvmConfig; use reth_node_ethereum::{node::EthereumAddOns, BasicBlockExecutorProvider, EthereumNode}; use reth_primitives::{BlockWithSenders, EthPrimitives, Receipt}; -use std::{fmt::Display, sync::Arc}; +use std::sync::Arc; pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe"); pub const WITHDRAWALS_ADDRESS: Address = address!("4200000000000000000000000000000000000000"); @@ -92,14 +92,17 @@ pub struct CustomExecutorStrategyFactory { impl BlockExecutionStrategyFactory for CustomExecutorStrategyFactory { type Primitives = EthPrimitives; - type Strategy + Display>> = CustomExecutorStrategy; + type Strategy = CustomExecutorStrategy; fn create_strategy(&self, db: DB) -> Self::Strategy where - DB: Database + Display>, + DB: StateProvider, { - let state = - State::builder().with_database(db).with_bundle_update().without_state_clear().build(); + let state = State::builder() + .with_database(StateProviderDatabase(db)) + .with_bundle_update() + .without_state_clear() + .build(); CustomExecutorStrategy { state, chain_spec: self.chain_spec.clone(), @@ -110,19 +113,19 @@ impl BlockExecutionStrategyFactory for CustomExecutorStrategyFactory { pub struct CustomExecutorStrategy where - DB: Database + Display>, + DB: StateProvider, { /// The chainspec chain_spec: Arc, /// How to create an EVM. evm_config: EthEvmConfig, /// Current state for block execution. - state: State, + state: State>, } impl CustomExecutorStrategy where - DB: Database + Display>, + DB: StateProvider, { /// Configures a new evm configuration and block environment for the given block. /// @@ -142,7 +145,7 @@ where impl BlockExecutionStrategy for CustomExecutorStrategy where - DB: Database + Display>, + DB: StateProvider, { type DB = DB; type Primitives = EthPrimitives; @@ -185,11 +188,11 @@ where Ok(Requests::default()) } - fn state_ref(&self) -> &State { + fn state_ref(&self) -> &State> { &self.state } - fn state_mut(&mut self) -> &mut State { + fn state_mut(&mut self) -> &mut State> { &mut self.state } }