From acccf1441e1c48939f1d2691f07667740ce921b7 Mon Sep 17 00:00:00 2001 From: Dan Cline <6798349+Rjected@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:40:12 -0500 Subject: [PATCH] feat: EvmEnvConfig trait (#6051) --- Cargo.lock | 10 + bin/reth/src/builder.rs | 17 +- .../src/commands/debug_cmd/build_block.rs | 14 +- bin/reth/src/commands/debug_cmd/execution.rs | 5 +- .../commands/debug_cmd/in_memory_merkle.rs | 4 +- bin/reth/src/commands/debug_cmd/merkle.rs | 5 +- .../src/commands/debug_cmd/replay_engine.rs | 12 +- bin/reth/src/commands/import.rs | 4 +- bin/reth/src/commands/stage/dump/execution.rs | 12 +- bin/reth/src/commands/stage/dump/merkle.rs | 3 +- bin/reth/src/commands/stage/run.rs | 7 +- crates/blockchain-tree/Cargo.toml | 1 + crates/blockchain-tree/src/blockchain_tree.rs | 4 +- crates/consensus/auto-seal/Cargo.toml | 1 + crates/consensus/auto-seal/src/lib.rs | 45 +++- crates/consensus/auto-seal/src/task.rs | 28 ++- .../consensus/beacon/src/engine/test_utils.rs | 5 +- crates/node-api/Cargo.toml | 1 + crates/node-api/src/evm/mod.rs | 35 +++ crates/node-api/src/lib.rs | 4 + crates/node-builder/src/engine.rs | 28 --- crates/node-builder/src/evm.rs | 70 ++++++ crates/node-builder/src/lib.rs | 10 +- crates/node-builder/src/optimism.rs | 72 ++++++ crates/node-core/src/args/rpc_server_args.rs | 14 +- crates/node-core/src/cli/components.rs | 36 ++- crates/node-core/src/node_config.rs | 20 +- crates/primitives/src/revm/env.rs | 101 ++------- crates/primitives/src/revm/mod.rs | 26 +-- crates/revm/Cargo.toml | 2 + crates/revm/src/factory.rs | 22 +- crates/revm/src/optimism/processor.rs | 6 +- crates/revm/src/processor.rs | 69 ++++-- crates/rpc/rpc-builder/Cargo.toml | 1 + crates/rpc/rpc-builder/src/auth.rs | 20 +- crates/rpc/rpc-builder/src/eth.rs | 4 +- crates/rpc/rpc-builder/src/lib.rs | 210 ++++++++++++------ crates/rpc/rpc-builder/tests/it/utils.rs | 4 +- crates/rpc/rpc/Cargo.toml | 4 +- crates/rpc/rpc/src/eth/api/block.rs | 9 +- crates/rpc/rpc/src/eth/api/call.rs | 4 +- crates/rpc/rpc/src/eth/api/fees.rs | 4 +- crates/rpc/rpc/src/eth/api/mod.rs | 36 ++- crates/rpc/rpc/src/eth/api/server.rs | 22 +- crates/rpc/rpc/src/eth/api/sign.rs | 2 +- crates/rpc/rpc/src/eth/api/state.rs | 12 +- crates/rpc/rpc/src/eth/api/transactions.rs | 18 +- crates/rpc/rpc/src/eth/cache/mod.rs | 38 +++- crates/rpc/rpc/src/eth/revm_utils.rs | 15 +- crates/stages/Cargo.toml | 1 + crates/stages/src/lib.rs | 3 +- crates/stages/src/sets.rs | 6 +- crates/stages/src/stages/execution.rs | 12 +- crates/stages/src/stages/mod.rs | 8 +- crates/storage/provider/Cargo.toml | 1 + .../provider/src/providers/database/mod.rs | 45 +++- .../src/providers/database/provider.rs | 56 +++-- crates/storage/provider/src/providers/mod.rs | 45 +++- .../storage/provider/src/test_utils/mock.rs | 37 ++- .../storage/provider/src/test_utils/noop.rs | 37 ++- crates/storage/provider/src/traits/evm_env.rs | 44 +++- testing/ef-tests/Cargo.toml | 1 + testing/ef-tests/src/cases/blockchain_test.rs | 2 + 63 files changed, 1003 insertions(+), 391 deletions(-) create mode 100644 crates/node-api/src/evm/mod.rs create mode 100644 crates/node-builder/src/evm.rs create mode 100644 crates/node-builder/src/optimism.rs diff --git a/Cargo.lock b/Cargo.lock index 2fbae2460..012cb0c9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2284,6 +2284,7 @@ dependencies = [ "alloy-rlp", "reth-db", "reth-interfaces", + "reth-node-builder", "reth-primitives", "reth-provider", "reth-revm", @@ -5804,6 +5805,7 @@ dependencies = [ "reth-beacon-consensus", "reth-interfaces", "reth-node-api", + "reth-node-builder", "reth-primitives", "reth-provider", "reth-revm", @@ -5896,6 +5898,7 @@ dependencies = [ "reth-db", "reth-interfaces", "reth-metrics", + "reth-node-builder", "reth-primitives", "reth-provider", "reth-revm", @@ -6373,6 +6376,7 @@ dependencies = [ "reth-payload-builder", "reth-primitives", "reth-rpc-types", + "revm-primitives", "serde", "thiserror", ] @@ -6579,6 +6583,7 @@ dependencies = [ "reth-interfaces", "reth-metrics", "reth-nippy-jar", + "reth-node-api", "reth-primitives", "reth-trie", "revm", @@ -6618,6 +6623,8 @@ version = "0.1.0-alpha.16" dependencies = [ "reth-consensus-common", "reth-interfaces", + "reth-node-api", + "reth-node-builder", "reth-primitives", "reth-provider", "reth-trie", @@ -6655,6 +6662,8 @@ dependencies = [ "reth-metrics", "reth-network", "reth-network-api", + "reth-node-api", + "reth-node-builder", "reth-primitives", "reth-provider", "reth-revm", @@ -6853,6 +6862,7 @@ dependencies = [ "reth-eth-wire", "reth-interfaces", "reth-metrics", + "reth-node-builder", "reth-primitives", "reth-provider", "reth-revm", diff --git a/bin/reth/src/builder.rs b/bin/reth/src/builder.rs index 669f73617..d55c27465 100644 --- a/bin/reth/src/builder.rs +++ b/bin/reth/src/builder.rs @@ -25,9 +25,9 @@ use reth_interfaces::p2p::either::EitherDownloader; use reth_network::NetworkEvents; use reth_network_api::{NetworkInfo, PeersInfo}; #[cfg(not(feature = "optimism"))] -use reth_node_builder::EthEngineTypes; +use reth_node_builder::{EthEngineTypes, EthEvmConfig}; #[cfg(feature = "optimism")] -use reth_node_builder::OptimismEngineTypes; +use reth_node_builder::{OptimismEngineTypes, OptimismEvmConfig}; use reth_node_core::{ cli::{ components::{RethNodeComponentsImpl, RethRpcServerHandles}, @@ -162,6 +162,14 @@ impl NodeBuilderWit .prune_config(Arc::clone(&self.config.chain))? .or(config.prune.clone()); + // TODO: stateful node builder should be able to remove cfgs here + #[cfg(feature = "optimism")] + let evm_config = OptimismEvmConfig::default(); + + // The default payload builder is implemented on the unit type. + #[cfg(not(feature = "optimism"))] + let evm_config = EthEvmConfig::default(); + // configure blockchain tree let tree_config = BlockchainTreeConfig::default(); let tree = self.config.build_blockchain_tree( @@ -170,6 +178,7 @@ impl NodeBuilderWit prune_config.clone(), sync_metrics_tx.clone(), tree_config, + evm_config, )?; let canon_state_notification_sender = tree.canon_state_notification_sender(); let blockchain_tree = ShareableBlockchainTree::new(tree); @@ -207,6 +216,7 @@ impl NodeBuilderWit network_builder.handle(), executor.clone(), blockchain_db.clone(), + evm_config, ); // allow network modifications @@ -272,6 +282,7 @@ impl NodeBuilderWit consensus_engine_tx.clone(), canon_state_notification_sender, mining_mode, + evm_config, ) .build(); @@ -286,6 +297,7 @@ impl NodeBuilderWit sync_metrics_tx, prune_config.clone(), max_block, + evm_config, ) .await?; @@ -307,6 +319,7 @@ impl NodeBuilderWit sync_metrics_tx, prune_config.clone(), max_block, + evm_config, ) .await?; diff --git a/bin/reth/src/commands/debug_cmd/build_block.rs b/bin/reth/src/commands/debug_cmd/build_block.rs index 0608c3570..1da61834d 100644 --- a/bin/reth/src/commands/debug_cmd/build_block.rs +++ b/bin/reth/src/commands/debug_cmd/build_block.rs @@ -14,6 +14,10 @@ use reth_blockchain_tree::{ use reth_db::{init_db, mdbx::DatabaseArguments, DatabaseEnv}; use reth_interfaces::{consensus::Consensus, RethResult}; use reth_node_api::PayloadBuilderAttributes; +#[cfg(not(feature = "optimism"))] +use reth_node_builder::EthEvmConfig; +#[cfg(feature = "optimism")] +use reth_node_builder::OptimismEvmConfig; use reth_payload_builder::database::CachedReads; #[cfg(feature = "optimism")] use reth_payload_builder::OptimismPayloadBuilderAttributes; @@ -156,11 +160,17 @@ impl Command { let consensus: Arc = Arc::new(BeaconConsensus::new(Arc::clone(&self.chain))); + #[cfg(feature = "optimism")] + let evm_config = OptimismEvmConfig::default(); + + #[cfg(not(feature = "optimism"))] + let evm_config = EthEvmConfig::default(); + // configure blockchain tree let tree_externals = TreeExternals::new( provider_factory.clone(), Arc::clone(&consensus), - EvmProcessorFactory::new(self.chain.clone()), + EvmProcessorFactory::new(self.chain.clone(), evm_config), ); let tree = BlockchainTree::new(tree_externals, BlockchainTreeConfig::default(), None)?; let blockchain_tree = ShareableBlockchainTree::new(tree); @@ -298,7 +308,7 @@ impl Command { let block_with_senders = SealedBlockWithSenders::new(block.clone(), senders).unwrap(); - let executor_factory = EvmProcessorFactory::new(self.chain.clone()); + let executor_factory = EvmProcessorFactory::new(self.chain.clone(), evm_config); let mut executor = executor_factory.with_state(blockchain_db.latest()?); executor .execute_and_verify_receipt(&block_with_senders.clone().unseal(), U256::MAX)?; diff --git a/bin/reth/src/commands/debug_cmd/execution.rs b/bin/reth/src/commands/debug_cmd/execution.rs index 6dd9e2d7e..4ecc6cba5 100644 --- a/bin/reth/src/commands/debug_cmd/execution.rs +++ b/bin/reth/src/commands/debug_cmd/execution.rs @@ -27,7 +27,7 @@ use reth_interfaces::{ }; use reth_network::{NetworkEvents, NetworkHandle}; use reth_network_api::NetworkInfo; - +use reth_node_builder::EthEvmConfig; use reth_primitives::{fs, stage::StageId, BlockHashOrNumber, BlockNumber, ChainSpec, B256}; use reth_provider::{BlockExecutionWriter, HeaderSyncMode, ProviderFactory, StageCheckpointReader}; use reth_stages::{ @@ -110,7 +110,8 @@ impl Command { let stage_conf = &config.stages; let (tip_tx, tip_rx) = watch::channel(B256::ZERO); - let factory = reth_revm::EvmProcessorFactory::new(self.chain.clone()); + let factory = + reth_revm::EvmProcessorFactory::new(self.chain.clone(), EthEvmConfig::default()); let header_mode = HeaderSyncMode::Tip(tip_rx); let pipeline = Pipeline::builder() 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 50dc6bbe3..4d280b7e4 100644 --- a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs @@ -17,6 +17,7 @@ use reth_db::{init_db, mdbx::DatabaseArguments, DatabaseEnv}; use reth_interfaces::executor::BlockValidationError; use reth_network::NetworkHandle; use reth_network_api::NetworkInfo; +use reth_node_builder::EthEvmConfig; use reth_primitives::{fs, stage::StageId, BlockHashOrNumber, ChainSpec}; use reth_provider::{ AccountExtReader, BlockWriter, ExecutorFactory, HashingWriter, HeaderProvider, @@ -162,7 +163,8 @@ impl Command { ) .await?; - let executor_factory = reth_revm::EvmProcessorFactory::new(self.chain.clone()); + let executor_factory = + reth_revm::EvmProcessorFactory::new(self.chain.clone(), EthEvmConfig::default()); let mut executor = executor_factory.with_state(LatestStateProviderRef::new(provider.tx_ref())); diff --git a/bin/reth/src/commands/debug_cmd/merkle.rs b/bin/reth/src/commands/debug_cmd/merkle.rs index 2abcf8fe8..25c0960ac 100644 --- a/bin/reth/src/commands/debug_cmd/merkle.rs +++ b/bin/reth/src/commands/debug_cmd/merkle.rs @@ -20,7 +20,7 @@ use reth_db::{ use reth_interfaces::{consensus::Consensus, p2p::full_block::FullBlockClient}; use reth_network::NetworkHandle; use reth_network_api::NetworkInfo; - +use reth_node_builder::EthEvmConfig; use reth_primitives::{ fs, stage::{StageCheckpoint, StageId}, @@ -202,7 +202,8 @@ impl Command { checkpoint.stage_checkpoint.is_some() }); - let factory = reth_revm::EvmProcessorFactory::new(self.chain.clone()); + let factory = + reth_revm::EvmProcessorFactory::new(self.chain.clone(), EthEvmConfig::default()); let mut execution_stage = ExecutionStage::new( factory, ExecutionStageThresholds { diff --git a/bin/reth/src/commands/debug_cmd/replay_engine.rs b/bin/reth/src/commands/debug_cmd/replay_engine.rs index aaf522fef..fd45630f4 100644 --- a/bin/reth/src/commands/debug_cmd/replay_engine.rs +++ b/bin/reth/src/commands/debug_cmd/replay_engine.rs @@ -21,9 +21,9 @@ use reth_interfaces::consensus::Consensus; use reth_network::NetworkHandle; use reth_network_api::NetworkInfo; #[cfg(not(feature = "optimism"))] -use reth_node_builder::EthEngineTypes; +use reth_node_builder::{EthEngineTypes, EthEvmConfig}; #[cfg(feature = "optimism")] -use reth_node_builder::OptimismEngineTypes; +use reth_node_builder::{OptimismEngineTypes, OptimismEvmConfig}; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_primitives::{fs, ChainSpec}; use reth_provider::{providers::BlockchainProvider, CanonStateSubscriptions, ProviderFactory}; @@ -125,11 +125,17 @@ impl Command { let consensus: Arc = Arc::new(BeaconConsensus::new(Arc::clone(&self.chain))); + #[cfg(not(feature = "optimism"))] + let evm_config = EthEvmConfig::default(); + + #[cfg(feature = "optimism")] + let evm_config = OptimismEvmConfig::default(); + // Configure blockchain tree let tree_externals = TreeExternals::new( provider_factory.clone(), Arc::clone(&consensus), - EvmProcessorFactory::new(self.chain.clone()), + EvmProcessorFactory::new(self.chain.clone(), evm_config), ); let tree = BlockchainTree::new(tree_externals, BlockchainTreeConfig::default(), None)?; let blockchain_tree = ShareableBlockchainTree::new(tree); diff --git a/bin/reth/src/commands/import.rs b/bin/reth/src/commands/import.rs index 7c57e6c0a..acd04e97d 100644 --- a/bin/reth/src/commands/import.rs +++ b/bin/reth/src/commands/import.rs @@ -16,6 +16,7 @@ use reth_downloaders::{ headers::reverse_headers::ReverseHeadersDownloaderBuilder, }; use reth_interfaces::consensus::Consensus; +use reth_node_builder::EthEvmConfig; use reth_primitives::{stage::StageId, ChainSpec, B256}; use reth_provider::{HeaderSyncMode, ProviderFactory, StageCheckpointReader}; use reth_stages::{ @@ -158,7 +159,8 @@ impl ImportCommand { .into_task(); let (tip_tx, tip_rx) = watch::channel(B256::ZERO); - let factory = reth_revm::EvmProcessorFactory::new(self.chain.clone()); + let factory = + reth_revm::EvmProcessorFactory::new(self.chain.clone(), EthEvmConfig::default()); let max_block = file_client.max_block().unwrap_or(0); let mut pipeline = Pipeline::builder() diff --git a/bin/reth/src/commands/stage/dump/execution.rs b/bin/reth/src/commands/stage/dump/execution.rs index d0ce96ce5..48bfc67df 100644 --- a/bin/reth/src/commands/stage/dump/execution.rs +++ b/bin/reth/src/commands/stage/dump/execution.rs @@ -5,6 +5,7 @@ use reth_db::{ cursor::DbCursorRO, database::Database, table::TableImporter, tables, transaction::DbTx, DatabaseEnv, }; +use reth_node_builder::EthEvmConfig; use reth_primitives::{stage::StageCheckpoint, ChainSpec}; use reth_provider::ProviderFactory; use reth_revm::EvmProcessorFactory; @@ -98,8 +99,10 @@ async fn unwind_and_copy( let factory = ProviderFactory::new(db_tool.db, db_tool.chain.clone()); let provider = factory.provider_rw()?; - let mut exec_stage = - ExecutionStage::new_with_factory(EvmProcessorFactory::new(db_tool.chain.clone())); + let mut exec_stage = ExecutionStage::new_with_factory(EvmProcessorFactory::new( + db_tool.chain.clone(), + EthEvmConfig::default(), + )); exec_stage.unwind( &provider, @@ -130,7 +133,10 @@ async fn dry_run( info!(target: "reth::cli", "Executing stage. [dry-run]"); let factory = ProviderFactory::new(&output_db, chain.clone()); - let mut exec_stage = ExecutionStage::new_with_factory(EvmProcessorFactory::new(chain.clone())); + let mut exec_stage = ExecutionStage::new_with_factory(EvmProcessorFactory::new( + chain.clone(), + EthEvmConfig::default(), + )); let input = reth_stages::ExecInput { target: Some(to), checkpoint: Some(StageCheckpoint::new(from)) }; diff --git a/bin/reth/src/commands/stage/dump/merkle.rs b/bin/reth/src/commands/stage/dump/merkle.rs index cba4afb96..3f7481be1 100644 --- a/bin/reth/src/commands/stage/dump/merkle.rs +++ b/bin/reth/src/commands/stage/dump/merkle.rs @@ -2,6 +2,7 @@ use super::setup; use crate::utils::DbTool; use eyre::Result; use reth_db::{database::Database, table::TableImporter, tables, DatabaseEnv}; +use reth_node_builder::EthEvmConfig; use reth_primitives::{stage::StageCheckpoint, BlockNumber, ChainSpec, PruneModes}; use reth_provider::ProviderFactory; use reth_stages::{ @@ -68,7 +69,7 @@ async fn unwind_and_copy( // Bring Plainstate to TO (hashing stage execution requires it) let mut exec_stage = ExecutionStage::new( - reth_revm::EvmProcessorFactory::new(db_tool.chain.clone()), + reth_revm::EvmProcessorFactory::new(db_tool.chain.clone(), EthEvmConfig::default()), ExecutionStageThresholds { max_blocks: Some(u64::MAX), max_changes: None, diff --git a/bin/reth/src/commands/stage/run.rs b/bin/reth/src/commands/stage/run.rs index f4a49c1ad..d32fe9ae7 100644 --- a/bin/reth/src/commands/stage/run.rs +++ b/bin/reth/src/commands/stage/run.rs @@ -17,7 +17,7 @@ use reth_beacon_consensus::BeaconConsensus; use reth_config::Config; use reth_db::{init_db, mdbx::DatabaseArguments}; use reth_downloaders::bodies::bodies::BodiesDownloaderBuilder; - +use reth_node_builder::EthEvmConfig; use reth_primitives::ChainSpec; use reth_provider::{ProviderFactory, StageCheckpointReader}; use reth_stages::{ @@ -198,7 +198,10 @@ impl Command { } StageEnum::Senders => (Box::new(SenderRecoveryStage::new(batch_size)), None), StageEnum::Execution => { - let factory = reth_revm::EvmProcessorFactory::new(self.chain.clone()); + let factory = reth_revm::EvmProcessorFactory::new( + self.chain.clone(), + EthEvmConfig::default(), + ); ( Box::new(ExecutionStage::new( factory, diff --git a/crates/blockchain-tree/Cargo.toml b/crates/blockchain-tree/Cargo.toml index 7565fe06d..56c45ab9f 100644 --- a/crates/blockchain-tree/Cargo.toml +++ b/crates/blockchain-tree/Cargo.toml @@ -45,6 +45,7 @@ reth-interfaces = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true , features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-revm.workspace = true +reth-node-builder.workspace = true parking_lot.workspace = true assert_matches.workspace = true diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index d2e93c6a0..9bb48e1f5 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1239,6 +1239,7 @@ mod tests { use linked_hash_set::LinkedHashSet; use reth_db::{tables, test_utils::TempDatabase, transaction::DbTxMut, DatabaseEnv}; use reth_interfaces::test_utils::TestConsensus; + use reth_node_builder::EthEvmConfig; use reth_primitives::{ constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH, ETHEREUM_BLOCK_GAS_LIMIT}, keccak256, @@ -1402,7 +1403,8 @@ mod tests { ); let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone()); let consensus = Arc::new(TestConsensus::default()); - let executor_factory = EvmProcessorFactory::new(chain_spec.clone()); + let executor_factory = + EvmProcessorFactory::new(chain_spec.clone(), EthEvmConfig::default()); { let provider_rw = provider_factory.provider_rw().unwrap(); diff --git a/crates/consensus/auto-seal/Cargo.toml b/crates/consensus/auto-seal/Cargo.toml index 4fa7ddfc1..25b5db192 100644 --- a/crates/consensus/auto-seal/Cargo.toml +++ b/crates/consensus/auto-seal/Cargo.toml @@ -21,6 +21,7 @@ reth-stages.workspace = true reth-revm.workspace = true reth-transaction-pool.workspace = true reth-node-api.workspace = true +reth-node-builder.workspace = true # async diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index cd70af97b..8e6fc27b1 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -19,7 +19,7 @@ use reth_interfaces::{ consensus::{Consensus, ConsensusError}, executor::{BlockExecutionError, BlockValidationError}, }; -use reth_node_api::EngineTypes; +use reth_node_api::{EngineTypes, EvmEnvConfig}; use reth_primitives::{ constants::{EMPTY_RECEIPTS, EMPTY_TRANSACTIONS, ETHEREUM_BLOCK_GAS_LIMIT}, proofs, Block, BlockBody, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithSenders, Bloom, @@ -94,7 +94,7 @@ impl Consensus for AutoSealConsensus { /// Builder type for configuring the setup #[derive(Debug)] -pub struct AutoSealBuilder { +pub struct AutoSealBuilder { client: Client, consensus: AutoSealConsensus, pool: Pool, @@ -102,11 +102,12 @@ pub struct AutoSealBuilder { storage: Storage, to_engine: UnboundedSender>, canon_state_notification: CanonStateNotificationSender, + evm_config: EvmConfig, } // === impl AutoSealBuilder === -impl AutoSealBuilder +impl AutoSealBuilder where Client: BlockReaderIdExt, Pool: TransactionPool, @@ -120,6 +121,7 @@ where to_engine: UnboundedSender>, canon_state_notification: CanonStateNotificationSender, mode: MiningMode, + evm_config: EvmConfig, ) -> Self { let latest_header = client .latest_header() @@ -135,6 +137,7 @@ where mode, to_engine, canon_state_notification, + evm_config, } } @@ -146,9 +149,19 @@ where /// Consumes the type and returns all components #[track_caller] - pub fn build(self) -> (AutoSealConsensus, AutoSealClient, MiningTask) { - let Self { client, consensus, pool, mode, storage, to_engine, canon_state_notification } = - self; + pub fn build( + self, + ) -> (AutoSealConsensus, AutoSealClient, MiningTask) { + let Self { + client, + consensus, + pool, + mode, + storage, + to_engine, + canon_state_notification, + evm_config, + } = self; let auto_client = AutoSealClient::new(storage.clone()); let task = MiningTask::new( Arc::clone(&consensus.chain_spec), @@ -158,6 +171,7 @@ where storage, client, pool, + evm_config, ); (consensus, auto_client, task) } @@ -298,11 +312,14 @@ impl StorageInner { /// Executes the block with the given block and senders, on the provided [EVMProcessor]. /// /// This returns the poststate from execution and post-block changes, as well as the gas used. - pub(crate) fn execute( + pub(crate) fn execute( &mut self, block: &BlockWithSenders, - executor: &mut EVMProcessor<'_>, - ) -> Result<(BundleStateWithReceipts, u64), BlockExecutionError> { + executor: &mut EVMProcessor<'_, EvmConfig>, + ) -> Result<(BundleStateWithReceipts, u64), BlockExecutionError> + where + EvmConfig: EvmEnvConfig, + { trace!(target: "consensus::auto", transactions=?&block.body, "executing transactions"); // TODO: there isn't really a parent beacon block root here, so not sure whether or not to // call the 4788 beacon contract @@ -370,12 +387,16 @@ impl StorageInner { /// Builds and executes a new block with the given transactions, on the provided [EVMProcessor]. /// /// This returns the header of the executed block, as well as the poststate from execution. - pub(crate) fn build_and_execute( + pub(crate) fn build_and_execute( &mut self, transactions: Vec, client: &impl StateProviderFactory, chain_spec: Arc, - ) -> Result<(SealedHeader, BundleStateWithReceipts), BlockExecutionError> { + evm_config: EvmConfig, + ) -> Result<(SealedHeader, BundleStateWithReceipts), BlockExecutionError> + where + EvmConfig: EvmEnvConfig, + { let header = self.build_header_template(&transactions, chain_spec.clone()); let block = Block { header, body: transactions, ommers: vec![], withdrawals: None } @@ -389,7 +410,7 @@ impl StorageInner { .with_database_boxed(Box::new(StateProviderDatabase::new(client.latest().unwrap()))) .with_bundle_update() .build(); - let mut executor = EVMProcessor::new_with_state(chain_spec.clone(), db); + let mut executor = EVMProcessor::new_with_state(chain_spec.clone(), db, evm_config); let (bundle_state, gas_used) = self.execute(&block, &mut executor)?; diff --git a/crates/consensus/auto-seal/src/task.rs b/crates/consensus/auto-seal/src/task.rs index 3e64e8bdb..5b1a48a33 100644 --- a/crates/consensus/auto-seal/src/task.rs +++ b/crates/consensus/auto-seal/src/task.rs @@ -2,7 +2,7 @@ use crate::{mode::MiningMode, Storage}; use futures_util::{future::BoxFuture, FutureExt}; use reth_beacon_consensus::{BeaconEngineMessage, ForkchoiceStatus}; use reth_interfaces::consensus::ForkchoiceState; -use reth_node_api::EngineTypes; +use reth_node_api::{EngineTypes, EvmEnvConfig}; use reth_primitives::{Block, ChainSpec, IntoRecoveredTransaction, SealedBlockWithSenders}; use reth_provider::{CanonChainTracker, CanonStateNotificationSender, Chain, StateProviderFactory}; use reth_stages::PipelineEvent; @@ -19,7 +19,7 @@ use tokio_stream::wrappers::UnboundedReceiverStream; use tracing::{debug, error, warn}; /// A Future that listens for new ready transactions and puts new blocks into storage -pub struct MiningTask { +pub struct MiningTask { /// The configured chain spec chain_spec: Arc, /// The client used to interact with the state @@ -40,12 +40,17 @@ pub struct MiningTask { canon_state_notification: CanonStateNotificationSender, /// The pipeline events to listen on pipe_line_events: Option>, + /// The type that defines how to configure the EVM. + evm_config: EvmConfig, } // === impl MiningTask === -impl MiningTask { +impl + MiningTask +{ /// Creates a new instance of the task + #[allow(clippy::too_many_arguments)] pub(crate) fn new( chain_spec: Arc, miner: MiningMode, @@ -54,6 +59,7 @@ impl MiningTask Self { Self { chain_spec, @@ -66,6 +72,7 @@ impl MiningTask MiningTask Future for MiningTask +impl Future for MiningTask where Client: StateProviderFactory + CanonChainTracker + Clone + Unpin + 'static, Pool: TransactionPool + Unpin + 'static, ::Transaction: IntoRecoveredTransaction, Engine: EngineTypes + 'static, + EvmConfig: EvmEnvConfig + Clone + Unpin + Send + Sync + 'static, { type Output = (); @@ -110,6 +118,7 @@ where let pool = this.pool.clone(); let events = this.pipe_line_events.take(); let canon_state_notification = this.canon_state_notification.clone(); + let evm_config = this.evm_config.clone(); // Create the mining future that creates a block, notifies the engine that drives // the pipeline @@ -125,7 +134,12 @@ where }) .unzip(); - match storage.build_and_execute(transactions.clone(), &client, chain_spec) { + match storage.build_and_execute( + transactions.clone(), + &client, + chain_spec, + evm_config, + ) { Ok((new_header, bundle_state)) => { // clear all transactions from pool pool.remove_transactions( @@ -230,8 +244,8 @@ where } } -impl std::fmt::Debug - for MiningTask +impl std::fmt::Debug + for MiningTask { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MiningTask").finish_non_exhaustive() diff --git a/crates/consensus/beacon/src/engine/test_utils.rs b/crates/consensus/beacon/src/engine/test_utils.rs index 35d34dfe0..bbe0f8492 100644 --- a/crates/consensus/beacon/src/engine/test_utils.rs +++ b/crates/consensus/beacon/src/engine/test_utils.rs @@ -22,7 +22,7 @@ use reth_interfaces::{ sync::NoopSyncStateUpdater, test_utils::{NoopFullBlockClient, TestConsensus}, }; -use reth_node_builder::EthEngineTypes; +use reth_node_builder::{EthEngineTypes, EthEvmConfig}; use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_primitives::{BlockNumber, ChainSpec, PruneModes, Receipt, B256, U256}; use reth_provider::{ @@ -46,7 +46,7 @@ type TestBeaconConsensusEngine = BeaconConsensusEngine< Arc, ShareableBlockchainTree< Arc, - EitherExecutorFactory, + EitherExecutorFactory>, >, >, Arc>, @@ -474,6 +474,7 @@ where } TestExecutorConfig::Real => EitherExecutorFactory::Right(EvmProcessorFactory::new( self.base_config.chain_spec.clone(), + EthEvmConfig::default(), )), }; diff --git a/crates/node-api/Cargo.toml b/crates/node-api/Cargo.toml index c0d7b8c50..097dde333 100644 --- a/crates/node-api/Cargo.toml +++ b/crates/node-api/Cargo.toml @@ -14,6 +14,7 @@ workspace = true # reth reth-primitives.workspace = true reth-rpc-types.workspace = true +revm-primitives.workspace = true thiserror.workspace = true # io diff --git a/crates/node-api/src/evm/mod.rs b/crates/node-api/src/evm/mod.rs new file mode 100644 index 000000000..b66126ebe --- /dev/null +++ b/crates/node-api/src/evm/mod.rs @@ -0,0 +1,35 @@ +use reth_primitives::{revm::env::fill_block_env, Address, ChainSpec, Header, Transaction, U256}; +use revm_primitives::{BlockEnv, CfgEnv, SpecId, TxEnv}; + +/// This represents the set of methods used to configure the EVM before execution. +pub trait EvmEnvConfig: Send + Sync + Unpin + Clone { + /// The type of the transaction metadata. + type TxMeta; + + /// Fill transaction environment from a [Transaction] and the given sender address. + fn fill_tx_env(tx_env: &mut TxEnv, transaction: T, sender: Address, meta: Self::TxMeta) + where + T: AsRef; + + /// Fill [CfgEnv] fields according to the chain spec and given header + fn fill_cfg_env( + cfg_env: &mut CfgEnv, + chain_spec: &ChainSpec, + header: &Header, + total_difficulty: U256, + ); + + /// Convenience function to call both [fill_cfg_env](EvmEnvConfig::fill_cfg_env) and + /// [fill_block_env]. + fn fill_cfg_and_block_env( + cfg: &mut CfgEnv, + block_env: &mut BlockEnv, + chain_spec: &ChainSpec, + header: &Header, + total_difficulty: U256, + ) { + Self::fill_cfg_env(cfg, chain_spec, header, total_difficulty); + let after_merge = cfg.spec_id >= SpecId::MERGE; + fill_block_env(block_env, chain_spec, header, after_merge); + } +} diff --git a/crates/node-api/src/lib.rs b/crates/node-api/src/lib.rs index 7f490698d..cf2aa568b 100644 --- a/crates/node-api/src/lib.rs +++ b/crates/node-api/src/lib.rs @@ -18,3 +18,7 @@ pub use engine::{ AttributesValidationError, BuiltPayload, EngineApiMessageVersion, EngineTypes, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes, }; + +/// Traits and helper types used to abstract over EVM methods and types. +pub mod evm; +pub use evm::EvmEnvConfig; diff --git a/crates/node-builder/src/engine.rs b/crates/node-builder/src/engine.rs index 05e3b7719..75a98dbd2 100644 --- a/crates/node-builder/src/engine.rs +++ b/crates/node-builder/src/engine.rs @@ -1,15 +1,9 @@ -#[cfg(feature = "optimism")] -use reth_node_api::optimism_validate_version_specific_fields; use reth_node_api::{ validate_version_specific_fields, AttributesValidationError, EngineApiMessageVersion, EngineTypes, PayloadOrAttributes, }; -#[cfg(feature = "optimism")] -use reth_payload_builder::OptimismPayloadBuilderAttributes; use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes}; use reth_primitives::ChainSpec; -#[cfg(feature = "optimism")] -use reth_rpc_types::engine::OptimismPayloadAttributes; use reth_rpc_types::engine::PayloadAttributes as EthPayloadAttributes; /// The types used in the default mainnet ethereum beacon consensus engine. @@ -30,25 +24,3 @@ impl EngineTypes for EthEngineTypes { validate_version_specific_fields(chain_spec, version, payload_or_attrs) } } - -#[cfg(feature = "optimism")] -/// The types used in the optimism beacon consensus engine. -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct OptimismEngineTypes; - -// TODO: remove cfg once Hardfork::Canyon can be used without the flag -#[cfg(feature = "optimism")] -impl EngineTypes for OptimismEngineTypes { - type PayloadAttributes = OptimismPayloadAttributes; - type PayloadBuilderAttributes = OptimismPayloadBuilderAttributes; - type BuiltPayload = EthBuiltPayload; - - fn validate_version_specific_fields( - chain_spec: &ChainSpec, - version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, OptimismPayloadAttributes>, - ) -> Result<(), AttributesValidationError> { - optimism_validate_version_specific_fields(chain_spec, version, payload_or_attrs) - } -} diff --git a/crates/node-builder/src/evm.rs b/crates/node-builder/src/evm.rs new file mode 100644 index 000000000..dd7867420 --- /dev/null +++ b/crates/node-builder/src/evm.rs @@ -0,0 +1,70 @@ +use reth_node_api::EvmEnvConfig; +use reth_primitives::{ + revm::{config::revm_spec, env::fill_tx_env}, + revm_primitives::{AnalysisKind, CfgEnv, TxEnv}, + Address, ChainSpec, Head, Header, Transaction, U256, +}; + +/// Ethereum-related EVM configuration. +#[derive(Debug, Clone, Copy, Default)] +#[non_exhaustive] +pub struct EthEvmConfig; + +impl EvmEnvConfig for EthEvmConfig { + type TxMeta = (); + + fn fill_tx_env(tx_env: &mut TxEnv, transaction: T, sender: Address, _meta: ()) + where + T: AsRef, + { + fill_tx_env(tx_env, transaction, sender) + } + + fn fill_cfg_env( + cfg_env: &mut CfgEnv, + chain_spec: &ChainSpec, + header: &Header, + total_difficulty: U256, + ) { + let spec_id = revm_spec( + chain_spec, + Head { + number: header.number, + timestamp: header.timestamp, + difficulty: header.difficulty, + total_difficulty, + hash: Default::default(), + }, + ); + + cfg_env.chain_id = chain_spec.chain().id(); + cfg_env.spec_id = spec_id; + cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; + } +} + +#[cfg(test)] +mod tests { + use super::*; + use reth_primitives::revm_primitives::BlockEnv; + + #[test] + #[ignore] + fn test_fill_cfg_and_block_env() { + let mut cfg_env = CfgEnv::default(); + let mut block_env = BlockEnv::default(); + let header = Header::default(); + let chain_spec = ChainSpec::default(); + let total_difficulty = U256::ZERO; + + EthEvmConfig::fill_cfg_and_block_env( + &mut cfg_env, + &mut block_env, + &chain_spec, + &header, + total_difficulty, + ); + + assert_eq!(cfg_env.chain_id, chain_spec.chain().id()); + } +} diff --git a/crates/node-builder/src/lib.rs b/crates/node-builder/src/lib.rs index c15e0132d..13050eb40 100644 --- a/crates/node-builder/src/lib.rs +++ b/crates/node-builder/src/lib.rs @@ -12,5 +12,13 @@ pub mod engine; pub use engine::EthEngineTypes; +/// Exports commonly used concrete instances of the [EvmEnvConfig](reth_node_api::EvmEnvConfig) +/// trait. +pub mod evm; +pub use evm::EthEvmConfig; + +/// Exports optimism-specific types that implement traits in [reth_node_api]. #[cfg(feature = "optimism")] -pub use engine::OptimismEngineTypes; +pub mod optimism; +#[cfg(feature = "optimism")] +pub use optimism::{OptimismEngineTypes, OptimismEvmConfig}; diff --git a/crates/node-builder/src/optimism.rs b/crates/node-builder/src/optimism.rs new file mode 100644 index 000000000..8385fb6f8 --- /dev/null +++ b/crates/node-builder/src/optimism.rs @@ -0,0 +1,72 @@ +#![cfg(feature = "optimism")] +use reth_node_api::{ + optimism_validate_version_specific_fields, AttributesValidationError, EngineApiMessageVersion, + EngineTypes, EvmEnvConfig, PayloadOrAttributes, +}; +use reth_payload_builder::{EthBuiltPayload, OptimismPayloadBuilderAttributes}; +use reth_primitives::{ + revm::{config::revm_spec, env::fill_op_tx_env}, + revm_primitives::{AnalysisKind, CfgEnv, TxEnv}, + Address, Bytes, ChainSpec, Head, Header, Transaction, U256, +}; +use reth_rpc_types::engine::OptimismPayloadAttributes; + +/// The types used in the optimism beacon consensus engine. +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct OptimismEngineTypes; + +impl EngineTypes for OptimismEngineTypes { + type PayloadAttributes = OptimismPayloadAttributes; + type PayloadBuilderAttributes = OptimismPayloadBuilderAttributes; + type BuiltPayload = EthBuiltPayload; + + fn validate_version_specific_fields( + chain_spec: &ChainSpec, + version: EngineApiMessageVersion, + payload_or_attrs: PayloadOrAttributes<'_, OptimismPayloadAttributes>, + ) -> Result<(), AttributesValidationError> { + optimism_validate_version_specific_fields(chain_spec, version, payload_or_attrs) + } +} + +/// Optimism-related EVM configuration. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct OptimismEvmConfig; + +impl EvmEnvConfig for OptimismEvmConfig { + type TxMeta = Bytes; + + fn fill_tx_env(tx_env: &mut TxEnv, transaction: T, sender: Address, meta: Bytes) + where + T: AsRef, + { + fill_op_tx_env(tx_env, transaction, sender, meta); + } + + fn fill_cfg_env( + cfg_env: &mut CfgEnv, + chain_spec: &ChainSpec, + header: &Header, + total_difficulty: U256, + ) { + let spec_id = revm_spec( + chain_spec, + Head { + number: header.number, + timestamp: header.timestamp, + difficulty: header.difficulty, + total_difficulty, + hash: Default::default(), + }, + ); + + cfg_env.chain_id = chain_spec.chain().id(); + cfg_env.spec_id = spec_id; + cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; + + // optimism-specific configuration + cfg_env.optimism = chain_spec.is_optimism(); + } +} diff --git a/crates/node-core/src/args/rpc_server_args.rs b/crates/node-core/src/args/rpc_server_args.rs index e0c6fcd8f..0de47e951 100644 --- a/crates/node-core/src/args/rpc_server_args.rs +++ b/crates/node-core/src/args/rpc_server_args.rs @@ -19,7 +19,7 @@ use clap::{ use futures::TryFutureExt; use rand::Rng; use reth_network_api::{NetworkInfo, Peers}; -use reth_node_api::EngineTypes; +use reth_node_api::{EngineTypes, EvmEnvConfig}; use reth_provider::{ AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, HeaderProvider, StateProviderFactory, @@ -292,6 +292,7 @@ impl RpcServerArgs { .with_network(components.network()) .with_events(components.events()) .with_executor(components.task_executor()) + .with_evm_config(components.evm_config()) .build_with_auth_server(module_config, engine_api); let rpc_components = RethRpcComponents { @@ -338,13 +339,14 @@ impl RpcServerArgs { } /// Convenience function for starting a rpc server with configs which extracted from cli args. - pub async fn start_rpc_server( + pub async fn start_rpc_server( &self, provider: Provider, pool: Pool, network: Network, executor: Tasks, events: Events, + evm_config: EvmConfig, ) -> Result where Provider: BlockReaderIdExt @@ -361,6 +363,7 @@ impl RpcServerArgs { Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { reth_rpc_builder::launch( provider, @@ -370,12 +373,14 @@ impl RpcServerArgs { self.rpc_server_config(), executor, events, + evm_config, ) .await } /// Create Engine API server. - pub async fn start_auth_server( + #[allow(clippy::too_many_arguments)] + pub async fn start_auth_server( &self, provider: Provider, pool: Pool, @@ -383,6 +388,7 @@ impl RpcServerArgs { executor: Tasks, engine_api: EngineApi, jwt_secret: JwtSecret, + evm_config: EvmConfig, ) -> Result where Provider: BlockReaderIdExt @@ -397,6 +403,7 @@ impl RpcServerArgs { Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, EngineT: EngineTypes + 'static, + EvmConfig: EvmEnvConfig + 'static, { let socket_address = SocketAddr::new(self.auth_addr, self.auth_port); @@ -408,6 +415,7 @@ impl RpcServerArgs { engine_api, socket_address, jwt_secret, + evm_config, ) .await } diff --git a/crates/node-core/src/cli/components.rs b/crates/node-core/src/cli/components.rs index 04168dbc4..28580a38a 100644 --- a/crates/node-core/src/cli/components.rs +++ b/crates/node-core/src/cli/components.rs @@ -3,6 +3,7 @@ use reth_db::database::Database; use reth_network::{NetworkEvents, NetworkProtocols}; use reth_network_api::{NetworkInfo, Peers}; +use reth_node_api::EvmEnvConfig; use reth_primitives::ChainSpec; use reth_provider::{ AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, @@ -59,6 +60,8 @@ pub trait RethNodeComponents: Clone + Send + Sync + 'static { type Events: CanonStateSubscriptions + Clone + 'static; /// The type that is used to spawn tasks. type Tasks: TaskSpawner + Clone + Unpin + 'static; + /// The type that defines how to configure the EVM before execution. + type EvmConfig: EvmEnvConfig + 'static; /// Returns the instance of the provider fn provider(&self) -> Self::Provider; @@ -75,6 +78,9 @@ pub trait RethNodeComponents: Clone + Send + Sync + 'static { /// Returns the instance of the events subscription handler. fn events(&self) -> Self::Events; + /// Returns the instance of the EVM config. + fn evm_config(&self) -> Self::EvmConfig; + /// Helper function to return the chain spec. fn chain_spec(&self) -> Arc { self.provider().chain_spec() @@ -98,6 +104,7 @@ pub struct RethRpcComponents<'a, Reth: RethNodeComponents> { Reth::Network, Reth::Tasks, Reth::Events, + Reth::EvmConfig, >, /// Holds installed modules per transport type. /// @@ -114,7 +121,7 @@ pub struct RethRpcComponents<'a, Reth: RethNodeComponents> { /// /// Represents components required for the Reth node. #[derive(Clone, Debug)] -pub struct RethNodeComponentsImpl { +pub struct RethNodeComponentsImpl { /// Represents underlying database type. __phantom: PhantomData, /// Represents the provider instance. @@ -127,10 +134,12 @@ pub struct RethNodeComponentsImpl { pub task_executor: Tasks, /// Represents the events subscription handler instance. pub events: Events, + /// Represents the type that is used to configure the EVM before execution. + pub evm_config: EvmConfig, } -impl - RethNodeComponentsImpl +impl + RethNodeComponentsImpl { /// Create new instance of the node components. pub fn new( @@ -139,13 +148,22 @@ impl network: Network, task_executor: Tasks, events: Events, + evm_config: EvmConfig, ) -> Self { - Self { provider, pool, network, task_executor, events, __phantom: std::marker::PhantomData } + Self { + provider, + pool, + network, + task_executor, + events, + evm_config, + __phantom: std::marker::PhantomData, + } } } -impl RethNodeComponents - for RethNodeComponentsImpl +impl RethNodeComponents + for RethNodeComponentsImpl where DB: Database + Clone + Unpin + 'static, Provider: FullProvider + Clone + 'static, @@ -153,6 +171,7 @@ where Pool: TransactionPool + Clone + Unpin + 'static, Network: NetworkInfo + Peers + NetworkProtocols + NetworkEvents + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { type DB = DB; type Provider = Provider; @@ -160,6 +179,7 @@ where type Network = Network; type Events = Events; type Tasks = Tasks; + type EvmConfig = EvmConfig; fn provider(&self) -> Self::Provider { self.provider.clone() @@ -180,6 +200,10 @@ where fn events(&self) -> Self::Events { self.events.clone() } + + fn evm_config(&self) -> Self::EvmConfig { + self.evm_config.clone() + } } /// Contains the handles to the spawned RPC servers. diff --git a/crates/node-core/src/node_config.rs b/crates/node-core/src/node_config.rs index d368cd531..c58cc4b9f 100644 --- a/crates/node-core/src/node_config.rs +++ b/crates/node-core/src/node_config.rs @@ -36,6 +36,7 @@ use reth_interfaces::{ RethResult, }; use reth_network::{NetworkBuilder, NetworkConfig, NetworkHandle, NetworkManager}; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ constants::eip4844::{LoadKzgSettingsError, MAINNET_KZG_TRUSTED_SETUP}, kzg::KzgSettings, @@ -412,22 +413,24 @@ impl NodeConfig { } /// Build the blockchain tree - pub fn build_blockchain_tree( + pub fn build_blockchain_tree( &self, provider_factory: ProviderFactory, consensus: Arc, prune_config: Option, sync_metrics_tx: UnboundedSender, tree_config: BlockchainTreeConfig, - ) -> eyre::Result> + evm_config: EvmConfig, + ) -> eyre::Result>> where DB: Database + Unpin + Clone + 'static, + EvmConfig: EvmEnvConfig + Clone + 'static, { // configure blockchain tree let tree_externals = TreeExternals::new( provider_factory.clone(), consensus.clone(), - EvmProcessorFactory::new(self.chain.clone()), + EvmProcessorFactory::new(self.chain.clone(), evm_config), ); let tree = BlockchainTree::new( tree_externals, @@ -517,7 +520,7 @@ impl NodeConfig { /// Constructs a [Pipeline] that's wired to the network #[allow(clippy::too_many_arguments)] - pub async fn build_networked_pipeline( + pub async fn build_networked_pipeline( &self, config: &StageConfig, client: Client, @@ -527,10 +530,12 @@ impl NodeConfig { metrics_tx: reth_stages::MetricEventsSender, prune_config: Option, max_block: Option, + evm_config: EvmConfig, ) -> eyre::Result> where DB: Database + Unpin + Clone + 'static, Client: HeadersClient + BodiesClient + Clone + 'static, + EvmConfig: EvmEnvConfig + Clone + 'static, { // building network downloaders using the fetch client let header_downloader = ReverseHeadersDownloaderBuilder::new(config.headers) @@ -552,6 +557,7 @@ impl NodeConfig { self.debug.continuous, metrics_tx, prune_config, + evm_config, ) .await?; @@ -750,7 +756,7 @@ impl NodeConfig { /// Builds the [Pipeline] with the given [ProviderFactory] and downloaders. #[allow(clippy::too_many_arguments)] - pub async fn build_pipeline( + pub async fn build_pipeline( &self, provider_factory: ProviderFactory, stage_config: &StageConfig, @@ -761,11 +767,13 @@ impl NodeConfig { continuous: bool, metrics_tx: reth_stages::MetricEventsSender, prune_config: Option, + evm_config: EvmConfig, ) -> eyre::Result> where DB: Database + Clone + 'static, H: HeaderDownloader + 'static, B: BodyDownloader + 'static, + EvmConfig: EvmEnvConfig + Clone + 'static, { let mut builder = Pipeline::builder(); @@ -776,7 +784,7 @@ impl NodeConfig { let (tip_tx, tip_rx) = watch::channel(B256::ZERO); use revm_inspectors::stack::InspectorStackConfig; - let factory = reth_revm::EvmProcessorFactory::new(self.chain.clone()); + let factory = reth_revm::EvmProcessorFactory::new(self.chain.clone(), evm_config); let stack_config = InspectorStackConfig { use_printer_tracer: self.debug.print_inspector, diff --git a/crates/primitives/src/revm/env.rs b/crates/primitives/src/revm/env.rs index 6741d191c..bcc819a23 100644 --- a/crates/primitives/src/revm/env.rs +++ b/crates/primitives/src/revm/env.rs @@ -1,56 +1,14 @@ use crate::{ constants::{BEACON_ROOTS_ADDRESS, SYSTEM_ADDRESS}, recover_signer_unchecked, - revm::config::revm_spec, - revm_primitives::{AnalysisKind, BlockEnv, CfgEnv, Env, SpecId, TransactTo, TxEnv}, - Address, Bytes, Chain, ChainSpec, Head, Header, Transaction, TransactionKind, + revm_primitives::{BlockEnv, Env, TransactTo, TxEnv}, + Address, Bytes, Chain, ChainSpec, Header, Transaction, TransactionKind, TransactionSignedEcRecovered, B256, U256, }; #[cfg(feature = "optimism")] use revm_primitives::OptimismFields; -/// Convenience function to call both [fill_cfg_env] and [fill_block_env] -pub fn fill_cfg_and_block_env( - cfg: &mut CfgEnv, - block_env: &mut BlockEnv, - chain_spec: &ChainSpec, - header: &Header, - total_difficulty: U256, -) { - fill_cfg_env(cfg, chain_spec, header, total_difficulty); - let after_merge = cfg.spec_id >= SpecId::MERGE; - fill_block_env(block_env, chain_spec, header, after_merge); -} - -/// Fill [CfgEnv] fields according to the chain spec and given header -pub fn fill_cfg_env( - cfg_env: &mut CfgEnv, - chain_spec: &ChainSpec, - header: &Header, - total_difficulty: U256, -) { - let spec_id = revm_spec( - chain_spec, - Head { - number: header.number, - timestamp: header.timestamp, - difficulty: header.difficulty, - total_difficulty, - hash: Default::default(), - }, - ); - - cfg_env.chain_id = chain_spec.chain().id(); - cfg_env.spec_id = spec_id; - cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; - - #[cfg(feature = "optimism")] - { - cfg_env.optimism = chain_spec.is_optimism(); - } -} - /// Fill block environment from Block. pub fn fill_block_env( block_env: &mut BlockEnv, @@ -146,7 +104,12 @@ pub fn tx_env_with_recovered(transaction: &TransactionSignedEcRecovered) -> TxEn { let mut envelope_buf = Vec::with_capacity(transaction.length_without_header()); transaction.encode_enveloped(&mut envelope_buf); - fill_tx_env(&mut tx_env, transaction.as_ref(), transaction.signer(), envelope_buf.into()); + fill_op_tx_env( + &mut tx_env, + transaction.as_ref(), + transaction.signer(), + envelope_buf.into(), + ); } tx_env @@ -175,7 +138,7 @@ pub fn fill_tx_env_with_beacon_root_contract_call(env: &mut Env, parent_beacon_b nonce: None, gas_limit: 30_000_000, value: U256::ZERO, - data: parent_beacon_block_root.0.to_vec().into(), + data: parent_beacon_block_root.0.into(), // Setting the gas price to zero enforces that no value is transferred as part of the call, // and that the call will not count against the block's gas limit gas_price: U256::ZERO, @@ -217,16 +180,12 @@ pub fn fill_tx_env_with_recovered( transaction: &TransactionSignedEcRecovered, envelope: Bytes, ) { - fill_tx_env(tx_env, transaction.as_ref(), transaction.signer(), envelope); + fill_op_tx_env(tx_env, transaction.as_ref(), transaction.signer(), envelope); } /// Fill transaction environment from a [Transaction] and the given sender address. -pub fn fill_tx_env( - tx_env: &mut TxEnv, - transaction: T, - sender: Address, - #[cfg(feature = "optimism")] envelope: Bytes, -) where +pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: T, sender: Address) +where T: AsRef, { tx_env.caller = sender; @@ -332,14 +291,18 @@ pub fn fill_tx_env( tx_env.nonce = None; } } - - #[cfg(feature = "optimism")] - fill_op_tx_env(tx_env, transaction, envelope); } +/// Fill transaction environment from a [Transaction], envelope, and the given sender address. #[cfg(feature = "optimism")] #[inline(always)] -fn fill_op_tx_env>(tx_env: &mut TxEnv, transaction: T, envelope: Bytes) { +pub fn fill_op_tx_env>( + tx_env: &mut TxEnv, + transaction: T, + sender: Address, + envelope: Bytes, +) { + fill_tx_env(tx_env, &transaction, sender); match transaction.as_ref() { Transaction::Deposit(tx) => { tx_env.optimism = OptimismFields { @@ -359,27 +322,3 @@ fn fill_op_tx_env>(tx_env: &mut TxEnv, transaction: T, env } } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[ignore] - fn test_fill_cfg_and_block_env() { - let mut cfg_env = CfgEnv::default(); - let mut block_env = BlockEnv::default(); - let header = Header::default(); - let chain_spec = ChainSpec::default(); - let total_difficulty = U256::ZERO; - - fill_cfg_and_block_env( - &mut cfg_env, - &mut block_env, - &chain_spec, - &header, - total_difficulty, - ); - - assert_eq!(cfg_env.chain_id, chain_spec.chain().id()); - } -} diff --git a/crates/primitives/src/revm/mod.rs b/crates/primitives/src/revm/mod.rs index 14bafa18e..311c5e2b5 100644 --- a/crates/primitives/src/revm/mod.rs +++ b/crates/primitives/src/revm/mod.rs @@ -1,20 +1,18 @@ -/// The `compat` module contains a set of utility functions that bridge the gap between Revm and -/// Reth Ethereum implementations. +/// The `compat` module contains utility functions that perform conversions between reth and revm, +/// compare analogous types from the two implementations, and calculate intrinsic gas usage. /// -/// These functions enable the conversion of data structures between the two implementations, such -/// as converting `Log` structures, `AccountInfo`, and `Account` objects. -/// -/// Additionally, it provides a function to calculate intrinsic gas usage for transactions beyond -/// the Merge hardfork, offering compatibility for both Shanghai and Merge Ethereum specifications. -/// -/// These utilities facilitate interoperability and data exchange between Revm and Reth -/// implementations. +/// The included conversion methods can be used to convert between: +/// * reth's [Log](crate::Log) type and revm's [Log](revm_primitives::Log) type. +/// * reth's [Account](crate::Account) type and revm's [AccountInfo](revm_primitives::AccountInfo) +/// type. pub mod compat; + /// Reth block execution/validation configuration and constants pub mod config; -/// The `env` module provides essential utilities for managing Ethereum transaction and block -/// environments. + +/// The `env` module provides utility methods for filling revm transaction and block environments. /// -/// It includes functions to fill transaction and block environments with relevant data, handle -/// system contract calls, and recover the signer of Ethereum headers. +/// It includes functions to fill transaction and block environments with relevant data, prepare +/// the block and transaction environments for system contract calls, and recover the signer from +/// Clique-formatted extra data in ethereum headers. pub mod env; diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index e717ee22e..2ca18b165 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -17,6 +17,7 @@ reth-primitives.workspace = true reth-interfaces.workspace = true reth-provider.workspace = true reth-consensus-common.workspace = true +reth-node-api.workspace = true # revm revm.workspace = true @@ -27,6 +28,7 @@ tracing.workspace = true [dev-dependencies] reth-trie.workspace = true +reth-node-builder.workspace = true [features] optimism = [ diff --git a/crates/revm/src/factory.rs b/crates/revm/src/factory.rs index c35b1ad11..a35e0dcd2 100644 --- a/crates/revm/src/factory.rs +++ b/crates/revm/src/factory.rs @@ -3,21 +3,24 @@ use crate::{ processor::EVMProcessor, stack::{InspectorStack, InspectorStackConfig}, }; +use reth_node_api::EvmEnvConfig; use reth_primitives::ChainSpec; use reth_provider::{ExecutorFactory, PrunableBlockExecutor, StateProvider}; use std::sync::Arc; /// Factory for creating [EVMProcessor]. #[derive(Clone, Debug)] -pub struct EvmProcessorFactory { +pub struct EvmProcessorFactory { chain_spec: Arc, stack: Option, + /// Type that defines how the produced EVM should be configured. + evm_config: EvmConfig, } -impl EvmProcessorFactory { +impl EvmProcessorFactory { /// Create new factory - pub fn new(chain_spec: Arc) -> Self { - Self { chain_spec, stack: None } + pub fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { + Self { chain_spec, stack: None, evm_config } } /// Sets the inspector stack for all generated executors. @@ -33,13 +36,20 @@ impl EvmProcessorFactory { } } -impl ExecutorFactory for EvmProcessorFactory { +impl ExecutorFactory for EvmProcessorFactory +where + EvmConfig: EvmEnvConfig + Send + Sync + Clone + 'static, +{ fn with_state<'a, SP: StateProvider + 'a>( &'a self, sp: SP, ) -> Box { let database_state = StateProviderDatabase::new(sp); - let mut evm = Box::new(EVMProcessor::new_with_db(self.chain_spec.clone(), database_state)); + let mut evm = Box::new(EVMProcessor::new_with_db( + self.chain_spec.clone(), + database_state, + self.evm_config.clone(), + )); if let Some(ref stack) = self.stack { evm.set_stack(stack.clone()); } diff --git a/crates/revm/src/optimism/processor.rs b/crates/revm/src/optimism/processor.rs index 40ff62f66..164725f03 100644 --- a/crates/revm/src/optimism/processor.rs +++ b/crates/revm/src/optimism/processor.rs @@ -2,6 +2,7 @@ use crate::processor::{verify_receipt, EVMProcessor}; use reth_interfaces::executor::{ BlockExecutionError, BlockValidationError, OptimismBlockExecutionError, }; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ revm::compat::into_reth_log, revm_primitives::ResultAndState, BlockWithSenders, Hardfork, Receipt, U256, @@ -11,7 +12,10 @@ use revm::DatabaseCommit; use std::time::Instant; use tracing::{debug, trace}; -impl<'a> BlockExecutor for EVMProcessor<'a> { +impl<'a, EvmConfig> BlockExecutor for EVMProcessor<'a, EvmConfig> +where + EvmConfig: EvmEnvConfig, +{ fn execute( &mut self, block: &BlockWithSenders, diff --git a/crates/revm/src/processor.rs b/crates/revm/src/processor.rs index f9290d866..c56b4ec84 100644 --- a/crates/revm/src/processor.rs +++ b/crates/revm/src/processor.rs @@ -5,8 +5,8 @@ use crate::{ state_change::{apply_beacon_root_contract_call, post_block_balance_increments}, }; use reth_interfaces::executor::{BlockExecutionError, BlockValidationError}; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ - revm::env::{fill_cfg_and_block_env, fill_tx_env}, Address, Block, BlockNumber, BlockWithSenders, Bloom, ChainSpec, GotExpected, Hardfork, Header, PruneMode, PruneModes, PruneSegmentError, Receipt, ReceiptWithBloom, Receipts, TransactionSigned, B256, MINIMUM_PRUNING_DISTANCE, U256, @@ -21,6 +21,11 @@ use revm::{ }; use std::{sync::Arc, time::Instant}; +#[cfg(feature = "optimism")] +use reth_primitives::revm::env::fill_op_tx_env; +#[cfg(not(feature = "optimism"))] +use reth_primitives::revm::env::fill_tx_env; + #[cfg(not(feature = "optimism"))] use reth_primitives::revm::compat::into_reth_log; #[cfg(not(feature = "optimism"))] @@ -48,7 +53,7 @@ use tracing::{debug, trace}; // TODO: https://github.com/bluealloy/revm/pull/745 // #[derive(Debug)] #[allow(missing_debug_implementations)] -pub struct EVMProcessor<'a> { +pub struct EVMProcessor<'a, EvmConfig> { /// The configured chain-spec pub(crate) chain_spec: Arc, /// revm instance that contains database and env environment. @@ -74,16 +79,21 @@ pub struct EVMProcessor<'a> { pruning_address_filter: Option<(u64, Vec
)>, /// Execution stats pub(crate) stats: BlockExecutorStats, + /// The type that is able to configure the EVM environment. + _evm_config: EvmConfig, } -impl<'a> EVMProcessor<'a> { +impl<'a, EvmConfig> EVMProcessor<'a, EvmConfig> +where + EvmConfig: EvmEnvConfig, +{ /// Return chain spec. pub fn chain_spec(&self) -> &Arc { &self.chain_spec } /// Create a new pocessor with the given chain spec. - pub fn new(chain_spec: Arc) -> Self { + pub fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { let evm = EVM::new(); EVMProcessor { chain_spec, @@ -95,6 +105,7 @@ impl<'a> EVMProcessor<'a> { prune_modes: PruneModes::none(), pruning_address_filter: None, stats: BlockExecutorStats::default(), + _evm_config: evm_config, } } @@ -102,19 +113,21 @@ impl<'a> EVMProcessor<'a> { pub fn new_with_db( chain_spec: Arc, db: StateProviderDatabase, + evm_config: EvmConfig, ) -> Self { let state = State::builder() .with_database_boxed(Box::new(db)) .with_bundle_update() .without_state_clear() .build(); - EVMProcessor::new_with_state(chain_spec, state) + EVMProcessor::new_with_state(chain_spec, state, evm_config) } /// Create a new EVM processor with the given revm state. pub fn new_with_state( chain_spec: Arc, revm_state: StateDBBox<'a, ProviderError>, + evm_config: EvmConfig, ) -> Self { let mut evm = EVM::new(); evm.database(revm_state); @@ -128,6 +141,7 @@ impl<'a> EVMProcessor<'a> { prune_modes: PruneModes::none(), pruning_address_filter: None, stats: BlockExecutorStats::default(), + _evm_config: evm_config, } } @@ -157,7 +171,7 @@ impl<'a> EVMProcessor<'a> { self.db_mut().set_state_clear_flag(state_clear_flag); - fill_cfg_and_block_env( + EvmConfig::fill_cfg_and_block_env( &mut self.evm.env.cfg, &mut self.evm.env.block, &self.chain_spec, @@ -240,7 +254,7 @@ impl<'a> EVMProcessor<'a> { { let mut envelope_buf = Vec::with_capacity(transaction.length_without_header()); transaction.encode_enveloped(&mut envelope_buf); - fill_tx_env(&mut self.evm.env.tx, transaction, sender, envelope_buf.into()); + fill_op_tx_env(&mut self.evm.env.tx, transaction, sender, envelope_buf.into()); } let hash = transaction.hash(); @@ -374,7 +388,10 @@ impl<'a> EVMProcessor<'a> { /// Default Ethereum implementation of the [BlockExecutor] trait for the [EVMProcessor]. #[cfg(not(feature = "optimism"))] -impl<'a> BlockExecutor for EVMProcessor<'a> { +impl<'a, EvmConfig> BlockExecutor for EVMProcessor<'a, EvmConfig> +where + EvmConfig: EvmEnvConfig, +{ fn execute( &mut self, block: &BlockWithSenders, @@ -486,7 +503,10 @@ impl<'a> BlockExecutor for EVMProcessor<'a> { } } -impl<'a> PrunableBlockExecutor for EVMProcessor<'a> { +impl<'a, EvmConfig> PrunableBlockExecutor for EVMProcessor<'a, EvmConfig> +where + EvmConfig: EvmEnvConfig, +{ fn set_tip(&mut self, tip: BlockNumber) { self.tip = Some(tip); } @@ -536,6 +556,7 @@ pub fn verify_receipt<'a>( mod tests { use super::*; use reth_interfaces::provider::ProviderResult; + use reth_node_builder::EthEvmConfig; use reth_primitives::{ bytes, constants::{BEACON_ROOTS_ADDRESS, SYSTEM_ADDRESS}, @@ -664,7 +685,11 @@ mod tests { ); // execute invalid header (no parent beacon block root) - let mut executor = EVMProcessor::new_with_db(chain_spec, StateProviderDatabase::new(db)); + let mut executor = EVMProcessor::new_with_db( + chain_spec, + StateProviderDatabase::new(db), + EthEvmConfig::default(), + ); // attempt to execute a block without parent beacon block root, expect err let err = executor @@ -752,7 +777,11 @@ mod tests { .build(), ); - let mut executor = EVMProcessor::new_with_db(chain_spec, StateProviderDatabase::new(db)); + let mut executor = EVMProcessor::new_with_db( + chain_spec, + StateProviderDatabase::new(db), + EthEvmConfig::default(), + ); executor.init_env(&header, U256::ZERO); // get the env @@ -809,7 +838,11 @@ mod tests { .build(), ); - let mut executor = EVMProcessor::new_with_db(chain_spec, StateProviderDatabase::new(db)); + let mut executor = EVMProcessor::new_with_db( + chain_spec, + StateProviderDatabase::new(db), + EthEvmConfig::default(), + ); // construct the header for block one let header = Header { @@ -872,7 +905,11 @@ mod tests { let mut header = chain_spec.genesis_header(); - let mut executor = EVMProcessor::new_with_db(chain_spec, StateProviderDatabase::new(db)); + let mut executor = EVMProcessor::new_with_db( + chain_spec, + StateProviderDatabase::new(db), + EthEvmConfig::default(), + ); executor.init_env(&header, U256::ZERO); // attempt to execute the genesis block with non-zero parent beacon block root, expect err @@ -962,7 +999,11 @@ mod tests { ); // execute header - let mut executor = EVMProcessor::new_with_db(chain_spec, StateProviderDatabase::new(db)); + let mut executor = EVMProcessor::new_with_db( + chain_spec, + StateProviderDatabase::new(db), + EthEvmConfig::default(), + ); executor.init_env(&header, U256::ZERO); // ensure that the env is configured with a base fee diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index 396dbe805..afea11c31 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -26,6 +26,7 @@ reth-tasks.workspace = true reth-transaction-pool.workspace = true reth-rpc-types-compat.workspace = true reth-node-api.workspace = true +reth-node-builder.workspace = true # rpc/net jsonrpsee = { workspace = true, features = ["server"] } diff --git a/crates/rpc/rpc-builder/src/auth.rs b/crates/rpc/rpc-builder/src/auth.rs index 6bf01a883..5649784e3 100644 --- a/crates/rpc/rpc-builder/src/auth.rs +++ b/crates/rpc/rpc-builder/src/auth.rs @@ -12,7 +12,7 @@ use jsonrpsee::{ Methods, }; use reth_network_api::{NetworkInfo, Peers}; -use reth_node_api::EngineTypes; +use reth_node_api::{EngineTypes, EvmEnvConfig}; use reth_provider::{ BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, HeaderProvider, ReceiptProviderIdExt, StateProviderFactory, @@ -35,7 +35,7 @@ use std::{ /// Configure and launch a _standalone_ auth server with `engine` and a _new_ `eth` namespace. #[allow(clippy::too_many_arguments)] -pub async fn launch( +pub async fn launch( provider: Provider, pool: Pool, network: Network, @@ -43,6 +43,7 @@ pub async fn launch( engine_api: EngineApi, socket_addr: SocketAddr, secret: JwtSecret, + evm_config: EvmConfig, ) -> Result where Provider: BlockReaderIdExt @@ -59,10 +60,15 @@ where Tasks: TaskSpawner + Clone + 'static, EngineT: EngineTypes, EngineApi: EngineApiServer, + EvmConfig: EvmEnvConfig + 'static, { // spawn a new cache task - let eth_cache = - EthStateCache::spawn_with(provider.clone(), Default::default(), executor.clone()); + let eth_cache = EthStateCache::spawn_with( + provider.clone(), + Default::default(), + executor.clone(), + evm_config.clone(), + ); let gas_oracle = GasPriceOracle::new(provider.clone(), Default::default(), eth_cache.clone()); @@ -78,6 +84,7 @@ where Box::new(executor.clone()), BlockingTaskPool::build().expect("failed to build tracing pool"), fee_history_cache, + evm_config, ); let config = EthFilterConfig::default() .max_logs_per_response(DEFAULT_MAX_LOGS_PER_RESPONSE) @@ -88,8 +95,8 @@ where } /// Configure and launch a _standalone_ auth server with existing EthApi implementation. -pub async fn launch_with_eth_api( - eth_api: EthApi, +pub async fn launch_with_eth_api( + eth_api: EthApi, eth_filter: EthFilter, engine_api: EngineApi, socket_addr: SocketAddr, @@ -108,6 +115,7 @@ where Network: NetworkInfo + Peers + Clone + 'static, EngineT: EngineTypes, EngineApi: EngineApiServer, + EvmConfig: EvmEnvConfig + 'static, { // Configure the module and start the server. let mut module = RpcModule::new(()); diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index 8da340536..d6fc98785 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -13,9 +13,9 @@ use serde::{Deserialize, Serialize}; /// All handlers for the `eth` namespace #[derive(Debug, Clone)] -pub struct EthHandlers { +pub struct EthHandlers { /// Main `eth_` request handler - pub api: EthApi, + pub api: EthApi, /// The async caching layer used by the eth handlers pub cache: EthStateCache, /// Polling based filter handler available on all transports diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index a85fce251..22c624c23 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -18,6 +18,7 @@ //! //! ``` //! use reth_network_api::{NetworkInfo, Peers}; +//! use reth_node_api::EvmEnvConfig; //! use reth_provider::{ //! AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, //! ChangeSetReader, EvmEnvProvider, StateProviderFactory, @@ -27,11 +28,12 @@ //! }; //! use reth_tasks::TokioTaskExecutor; //! use reth_transaction_pool::TransactionPool; -//! pub async fn launch( +//! pub async fn launch( //! provider: Provider, //! pool: Pool, //! network: Network, //! events: Events, +//! evm_config: EvmConfig, //! ) where //! Provider: AccountReader //! + BlockReaderIdExt @@ -45,6 +47,7 @@ //! Pool: TransactionPool + Clone + 'static, //! Network: NetworkInfo + Peers + Clone + 'static, //! Events: CanonStateSubscriptions + Clone + 'static, +//! EvmConfig: EvmEnvConfig + 'static, //! { //! // configure the rpc module per transport //! let transports = TransportRpcModuleConfig::default().with_http(vec![ @@ -53,9 +56,15 @@ //! RethRpcModule::Eth, //! RethRpcModule::Web3, //! ]); -//! let transport_modules = -//! RpcModuleBuilder::new(provider, pool, network, TokioTaskExecutor::default(), events) -//! .build(transports); +//! let transport_modules = RpcModuleBuilder::new( +//! provider, +//! pool, +//! network, +//! TokioTaskExecutor::default(), +//! events, +//! evm_config, +//! ) +//! .build(transports); //! let handle = RpcServerConfig::default() //! .with_http(ServerBuilder::default()) //! .start(transport_modules) @@ -69,7 +78,7 @@ //! //! ``` //! use reth_network_api::{NetworkInfo, Peers}; -//! use reth_node_api::EngineTypes; +//! use reth_node_api::{EngineTypes, EvmEnvConfig}; //! use reth_provider::{ //! AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, //! ChangeSetReader, EvmEnvProvider, StateProviderFactory, @@ -83,12 +92,13 @@ //! use reth_tasks::TokioTaskExecutor; //! use reth_transaction_pool::TransactionPool; //! use tokio::try_join; -//! pub async fn launch( +//! pub async fn launch( //! provider: Provider, //! pool: Pool, //! network: Network, //! events: Events, //! engine_api: EngineApi, +//! evm_config: EvmConfig, //! ) where //! Provider: AccountReader //! + BlockReaderIdExt @@ -104,6 +114,7 @@ //! Events: CanonStateSubscriptions + Clone + 'static, //! EngineApi: EngineApiServer, //! EngineT: EngineTypes, +//! EvmConfig: EvmEnvConfig + 'static, //! { //! // configure the rpc module per transport //! let transports = TransportRpcModuleConfig::default().with_http(vec![ @@ -112,8 +123,14 @@ //! RethRpcModule::Eth, //! RethRpcModule::Web3, //! ]); -//! let builder = -//! RpcModuleBuilder::new(provider, pool, network, TokioTaskExecutor::default(), events); +//! let builder = RpcModuleBuilder::new( +//! provider, +//! pool, +//! network, +//! TokioTaskExecutor::default(), +//! events, +//! evm_config, +//! ); //! //! // configure the server modules //! let (modules, auth_module, _registry) = @@ -150,7 +167,8 @@ use jsonrpsee::{ server::{IdProvider, Server, ServerHandle}, Methods, RpcModule, }; -use reth_node_api::EngineTypes; +use reth_node_api::{EngineTypes, EvmEnvConfig}; +use reth_node_builder::EthEvmConfig; use serde::{Deserialize, Serialize, Serializer}; use strum::{AsRefStr, EnumIter, EnumVariantNames, IntoStaticStr, ParseError, VariantNames}; use tower::layer::util::{Identity, Stack}; @@ -207,7 +225,8 @@ pub mod constants; mod metrics; /// Convenience function for starting a server in one step. -pub async fn launch( +#[allow(clippy::too_many_arguments)] +pub async fn launch( provider: Provider, pool: Pool, network: Network, @@ -215,6 +234,7 @@ pub async fn launch( server_config: impl Into, executor: Tasks, events: Events, + evm_config: EvmConfig, ) -> Result where Provider: BlockReaderIdExt @@ -230,10 +250,11 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { let module_config = module_config.into(); let server_config = server_config.into(); - RpcModuleBuilder::new(provider, pool, network, executor, events) + RpcModuleBuilder::new(provider, pool, network, executor, events, evm_config) .build(module_config) .start_server(server_config) .await @@ -243,7 +264,7 @@ where /// /// This is the main entrypoint and the easiest way to configure an RPC server. #[derive(Debug, Clone)] -pub struct RpcModuleBuilder { +pub struct RpcModuleBuilder { /// The Provider type to when creating all rpc handlers provider: Provider, /// The Pool type to when creating all rpc handlers @@ -254,12 +275,14 @@ pub struct RpcModuleBuilder { executor: Tasks, /// Provides access to chain events, such as new blocks, required by pubsub. events: Events, + /// Defines how the EVM should be configured before execution. + evm_config: EvmConfig, } // === impl RpcBuilder === -impl - RpcModuleBuilder +impl + RpcModuleBuilder { /// Create a new instance of the builder pub fn new( @@ -268,26 +291,33 @@ impl network: Network, executor: Tasks, events: Events, + evm_config: EvmConfig, ) -> Self { - Self { provider, pool, network, executor, events } + Self { provider, pool, network, executor, events, evm_config } } /// Configure the provider instance. - pub fn with_provider

(self, provider: P) -> RpcModuleBuilder + pub fn with_provider

( + self, + provider: P, + ) -> RpcModuleBuilder where P: BlockReader + StateProviderFactory + EvmEnvProvider + 'static, { - let Self { pool, network, executor, events, .. } = self; - RpcModuleBuilder { provider, network, pool, executor, events } + let Self { pool, network, executor, events, evm_config, .. } = self; + RpcModuleBuilder { provider, network, pool, executor, events, evm_config } } /// Configure the transaction pool instance. - pub fn with_pool

(self, pool: P) -> RpcModuleBuilder + pub fn with_pool

( + self, + pool: P, + ) -> RpcModuleBuilder where P: TransactionPool + 'static, { - let Self { provider, network, executor, events, .. } = self; - RpcModuleBuilder { provider, network, pool, executor, events } + let Self { provider, network, executor, events, evm_config, .. } = self; + RpcModuleBuilder { provider, network, pool, executor, events, evm_config } } /// Configure a [NoopTransactionPool] instance. @@ -297,24 +327,28 @@ impl /// requires a [TransactionPool] implementation. pub fn with_noop_pool( self, - ) -> RpcModuleBuilder { - let Self { provider, executor, events, network, .. } = self; + ) -> RpcModuleBuilder { + let Self { provider, executor, events, network, evm_config, .. } = self; RpcModuleBuilder { provider, executor, events, network, + evm_config, pool: NoopTransactionPool::default(), } } /// Configure the network instance. - pub fn with_network(self, network: N) -> RpcModuleBuilder + pub fn with_network( + self, + network: N, + ) -> RpcModuleBuilder where N: NetworkInfo + Peers + 'static, { - let Self { provider, pool, executor, events, .. } = self; - RpcModuleBuilder { provider, network, pool, executor, events } + let Self { provider, pool, executor, events, evm_config, .. } = self; + RpcModuleBuilder { provider, network, pool, executor, events, evm_config } } /// Configure a [NoopNetwork] instance. @@ -322,21 +356,30 @@ impl /// Caution: This will configure a network API that does abosultely nothing. /// This is only intended for allow easier setup of namespaces that depend on the [EthApi] which /// requires a [NetworkInfo] implementation. - pub fn with_noop_network(self) -> RpcModuleBuilder { - let Self { provider, pool, executor, events, .. } = self; - RpcModuleBuilder { provider, pool, executor, events, network: NoopNetwork::default() } + pub fn with_noop_network( + self, + ) -> RpcModuleBuilder { + let Self { provider, pool, executor, events, evm_config, .. } = self; + RpcModuleBuilder { + provider, + pool, + executor, + events, + network: NoopNetwork::default(), + evm_config, + } } /// Configure the task executor to use for additional tasks. pub fn with_executor( self, executor: T, - ) -> RpcModuleBuilder + ) -> RpcModuleBuilder where T: TaskSpawner + 'static, { - let Self { pool, network, provider, events, .. } = self; - RpcModuleBuilder { provider, network, pool, executor, events } + let Self { pool, network, provider, events, evm_config, .. } = self; + RpcModuleBuilder { provider, network, pool, executor, events, evm_config } } /// Configure [TokioTaskExecutor] as the task executor to use for additional tasks. @@ -345,23 +388,45 @@ impl /// [TokioTaskExecutor]. pub fn with_tokio_executor( self, - ) -> RpcModuleBuilder { - let Self { pool, network, provider, events, .. } = self; - RpcModuleBuilder { provider, network, pool, events, executor: TokioTaskExecutor::default() } + ) -> RpcModuleBuilder { + let Self { pool, network, provider, events, evm_config, .. } = self; + RpcModuleBuilder { + provider, + network, + pool, + events, + executor: TokioTaskExecutor::default(), + evm_config, + } } /// Configure the event subscriber instance - pub fn with_events(self, events: E) -> RpcModuleBuilder + pub fn with_events( + self, + events: E, + ) -> RpcModuleBuilder where E: CanonStateSubscriptions + 'static, { - let Self { provider, pool, executor, network, .. } = self; - RpcModuleBuilder { provider, network, pool, executor, events } + let Self { provider, pool, executor, network, evm_config, .. } = self; + RpcModuleBuilder { provider, network, pool, executor, events, evm_config } + } + + /// Configure the evm configuration type + pub fn with_evm_config( + self, + evm_config: E, + ) -> RpcModuleBuilder + where + E: EvmEnvConfig + 'static, + { + let Self { provider, pool, executor, network, events, .. } = self; + RpcModuleBuilder { provider, network, pool, executor, events, evm_config } } } -impl - RpcModuleBuilder +impl + RpcModuleBuilder where Provider: BlockReaderIdExt + AccountReader @@ -376,6 +441,7 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Configures all [RpcModule]s specific to the given [TransportRpcModuleConfig] which can be /// used to start the transport server(s). @@ -389,14 +455,14 @@ where ) -> ( TransportRpcModules, AuthRpcModule, - RethModuleRegistry, + RethModuleRegistry, ) where EngineApi: EngineApiServer, { let mut modules = TransportRpcModules::default(); - let Self { provider, pool, network, executor, events } = self; + let Self { provider, pool, network, executor, events, evm_config } = self; let TransportRpcModuleConfig { http, ws, ipc, config } = module_config.clone(); @@ -407,6 +473,7 @@ where executor, events, config.unwrap_or_default(), + evm_config, ); modules.config = module_config; @@ -445,9 +512,9 @@ where pub fn into_registry( self, config: RpcModuleConfig, - ) -> RethModuleRegistry { - let Self { provider, pool, network, executor, events } = self; - RethModuleRegistry::new(provider, pool, network, executor, events, config) + ) -> RethModuleRegistry { + let Self { provider, pool, network, executor, events, evm_config } = self; + RethModuleRegistry::new(provider, pool, network, executor, events, config, evm_config) } /// Configures all [RpcModule]s specific to the given [TransportRpcModuleConfig] which can be @@ -457,7 +524,7 @@ where pub fn build(self, module_config: TransportRpcModuleConfig) -> TransportRpcModules<()> { let mut modules = TransportRpcModules::default(); - let Self { provider, pool, network, executor, events } = self; + let Self { provider, pool, network, executor, events, evm_config } = self; if !module_config.is_empty() { let TransportRpcModuleConfig { http, ws, ipc, config } = module_config.clone(); @@ -469,6 +536,7 @@ where executor, events, config.unwrap_or_default(), + evm_config, ); modules.config = module_config; @@ -481,9 +549,9 @@ where } } -impl Default for RpcModuleBuilder<(), (), (), (), ()> { +impl Default for RpcModuleBuilder<(), (), (), (), (), EthEvmConfig> { fn default() -> Self { - RpcModuleBuilder::new((), (), (), (), ()) + RpcModuleBuilder::new((), (), (), (), (), EthEvmConfig::default()) } } @@ -639,7 +707,8 @@ impl RpcModuleSelection { /// Note: This will always create new instance of the module handlers and is therefor only /// recommended for launching standalone transports. If multiple transports need to be /// configured it's recommended to use the [RpcModuleBuilder]. - pub fn standalone_module( + #[allow(clippy::too_many_arguments)] + pub fn standalone_module( &self, provider: Provider, pool: Pool, @@ -647,6 +716,7 @@ impl RpcModuleSelection { executor: Tasks, events: Events, config: RpcModuleConfig, + evm_config: EvmConfig, ) -> RpcModule<()> where Provider: BlockReaderIdExt @@ -662,9 +732,10 @@ impl RpcModuleSelection { Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { let mut registry = - RethModuleRegistry::new(provider, pool, network, executor, events, config); + RethModuleRegistry::new(provider, pool, network, executor, events, config, evm_config); registry.module_for(self) } @@ -849,16 +920,18 @@ impl Serialize for RethRpcModule { /// A Helper type the holds instances of the configured modules. #[derive(Debug)] -pub struct RethModuleRegistry { +pub struct RethModuleRegistry { provider: Provider, pool: Pool, network: Network, executor: Tasks, events: Events, + /// Defines how to configure the EVM before execution. + evm_config: EvmConfig, /// Additional settings for handlers. config: RpcModuleConfig, /// Holds a clone of all the eth namespace handlers - eth: Option>, + eth: Option>, /// to put trace calls behind semaphore blocking_pool_guard: BlockingTaskGuard, /// Contains the [Methods] of a module @@ -867,8 +940,8 @@ pub struct RethModuleRegistry { // === impl RethModuleRegistry === -impl - RethModuleRegistry +impl + RethModuleRegistry { /// Creates a new, empty instance. pub fn new( @@ -878,11 +951,13 @@ impl executor: Tasks, events: Events, config: RpcModuleConfig, + evm_config: EvmConfig, ) -> Self { Self { provider, pool, network, + evm_config, eth: None, executor, modules: Default::default(), @@ -927,8 +1002,8 @@ impl } } -impl - RethModuleRegistry +impl + RethModuleRegistry where Network: NetworkInfo + Peers + Clone + 'static, { @@ -957,8 +1032,8 @@ where } } -impl - RethModuleRegistry +impl + RethModuleRegistry where Provider: BlockReaderIdExt + AccountReader @@ -973,6 +1048,7 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Register Eth Namespace /// @@ -1185,13 +1261,14 @@ where /// - [FeeHistoryCache] fn with_eth(&mut self, f: F) -> R where - F: FnOnce(&EthHandlers) -> R, + F: FnOnce(&EthHandlers) -> R, { if self.eth.is_none() { let cache = EthStateCache::spawn_with( self.provider.clone(), self.config.eth.cache.clone(), self.executor.clone(), + self.evm_config.clone(), ); let gas_oracle = GasPriceOracle::new( self.provider.clone(), @@ -1234,6 +1311,7 @@ where executor.clone(), blocking_task_pool.clone(), fee_history_cache, + self.evm_config.clone(), ); let filter = EthFilter::new( self.provider.clone(), @@ -1262,7 +1340,7 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [Self::eth_api] - pub fn eth_handlers(&mut self) -> EthHandlers { + pub fn eth_handlers(&mut self) -> EthHandlers { self.with_eth(|handlers| handlers.clone()) } @@ -1273,7 +1351,7 @@ where /// # Panics /// /// If called outside of the tokio runtime. - pub fn eth_api(&mut self) -> EthApi { + pub fn eth_api(&mut self) -> EthApi { self.with_eth(|handlers| handlers.api.clone()) } @@ -1282,7 +1360,7 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [Self::eth_api] - pub fn trace_api(&mut self) -> TraceApi> { + pub fn trace_api(&mut self) -> TraceApi> { let eth = self.eth_handlers(); TraceApi::new(self.provider.clone(), eth.api, self.blocking_pool_guard.clone()) } @@ -1292,7 +1370,7 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [Self::eth_api] - pub fn bundle_api(&mut self) -> EthBundle> { + pub fn bundle_api(&mut self) -> EthBundle> { let eth_api = self.eth_api(); EthBundle::new(eth_api, self.blocking_pool_guard.clone()) } @@ -1302,7 +1380,7 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [Self::eth_api] - pub fn otterscan_api(&mut self) -> OtterscanApi> { + pub fn otterscan_api(&mut self) -> OtterscanApi> { let eth_api = self.eth_api(); OtterscanApi::new(eth_api) } @@ -1312,7 +1390,7 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [Self::eth_api] - pub fn debug_api(&mut self) -> DebugApi> { + pub fn debug_api(&mut self) -> DebugApi> { let eth_api = self.eth_api(); DebugApi::new(self.provider.clone(), eth_api, self.blocking_pool_guard.clone()) } @@ -1322,7 +1400,7 @@ where /// # Panics /// /// If called outside of the tokio runtime. See also [Self::eth_api] - pub fn net_api(&mut self) -> NetApi> { + pub fn net_api(&mut self) -> NetApi> { let eth_api = self.eth_api(); NetApi::new(self.network.clone(), eth_api) } diff --git a/crates/rpc/rpc-builder/tests/it/utils.rs b/crates/rpc/rpc-builder/tests/it/utils.rs index 239900fd3..a16b8dbb1 100644 --- a/crates/rpc/rpc-builder/tests/it/utils.rs +++ b/crates/rpc/rpc-builder/tests/it/utils.rs @@ -1,6 +1,6 @@ use reth_beacon_consensus::BeaconConsensusEngineHandle; use reth_network_api::noop::NoopNetwork; -use reth_node_builder::EthEngineTypes; +use reth_node_builder::{EthEngineTypes, EthEvmConfig}; use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_primitives::MAINNET; use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; @@ -99,6 +99,7 @@ pub fn test_rpc_builder() -> RpcModuleBuilder< NoopNetwork, TokioTaskExecutor, TestCanonStateSubscriptions, + EthEvmConfig, > { RpcModuleBuilder::default() .with_provider(NoopProvider::default()) @@ -106,4 +107,5 @@ pub fn test_rpc_builder() -> RpcModuleBuilder< .with_network(NoopNetwork::default()) .with_executor(TokioTaskExecutor::default()) .with_events(TestCanonStateSubscriptions::default()) + .with_evm_config(EthEvmConfig::default()) } diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 9f95d7fa3..532e0005d 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -26,8 +26,8 @@ reth-revm = { workspace = true, features = ["js-tracer"] } reth-tasks.workspace = true reth-consensus-common.workspace = true reth-rpc-types-compat.workspace = true -lazy_static = "*" revm-inspectors.workspace = true +reth-node-api.workspace = true # eth alloy-rlp.workspace = true @@ -76,12 +76,14 @@ tracing-futures = "0.2" schnellru.workspace = true futures.workspace = true derive_more = "0.99" +lazy_static = "*" [dev-dependencies] jsonrpsee = { workspace = true, features = ["client"] } assert_matches.workspace = true tempfile.workspace = true reth-interfaces = { workspace = true, features = ["test-utils"] } +reth-node-builder.workspace = true [features] optimism = [ diff --git a/crates/rpc/rpc/src/eth/api/block.rs b/crates/rpc/rpc/src/eth/api/block.rs index e619d210a..e3c962c47 100644 --- a/crates/rpc/rpc/src/eth/api/block.rs +++ b/crates/rpc/rpc/src/eth/api/block.rs @@ -1,7 +1,5 @@ //! Contains RPC handler implementations specific to blocks. -use std::sync::Arc; - use crate::{ eth::{ api::transactions::build_transaction_receipt_with_block_receipts, @@ -10,20 +8,21 @@ use crate::{ EthApi, }; use reth_network_api::NetworkInfo; +use reth_node_api::EvmEnvConfig; use reth_primitives::{BlockId, TransactionMeta}; - use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_rpc_types::{Index, RichBlock, TransactionReceipt}; - use reth_rpc_types_compat::block::{from_block, uncle_block_from_header}; use reth_transaction_pool::TransactionPool; +use std::sync::Arc; -impl EthApi +impl EthApi where Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Returns the uncle headers of the given block /// diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index 661d14d4c..c11b7d202 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -13,6 +13,7 @@ use crate::{ EthApi, }; use reth_network_api::NetworkInfo; +use reth_node_api::EvmEnvConfig; use reth_primitives::{revm::env::tx_env_with_recovered, BlockId, BlockNumberOrTag, Bytes, U256}; use reth_provider::{ BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProvider, StateProviderFactory, @@ -33,12 +34,13 @@ use tracing::trace; const MIN_TRANSACTION_GAS: u64 = 21_000u64; const MIN_CREATE_GAS: u64 = 53_000u64; -impl EthApi +impl EthApi where Pool: TransactionPool + Clone + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Estimate gas needed for execution of the `request` at the [BlockId]. pub async fn estimate_gas_at( diff --git a/crates/rpc/rpc/src/eth/api/fees.rs b/crates/rpc/rpc/src/eth/api/fees.rs index f8d435871..de62a3d46 100644 --- a/crates/rpc/rpc/src/eth/api/fees.rs +++ b/crates/rpc/rpc/src/eth/api/fees.rs @@ -8,18 +8,20 @@ use crate::{ EthApi, }; use reth_network_api::NetworkInfo; +use reth_node_api::EvmEnvConfig; use reth_primitives::{basefee::calculate_next_block_base_fee, BlockNumberOrTag, U256}; use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_rpc_types::FeeHistory; use reth_transaction_pool::TransactionPool; use tracing::debug; -impl EthApi +impl EthApi where Pool: TransactionPool + Clone + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Returns a suggestion for a gas price for legacy transactions. /// diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 7a64a1930..124411da1 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -15,6 +15,7 @@ use crate::eth::{ use async_trait::async_trait; use reth_interfaces::RethResult; use reth_network_api::NetworkInfo; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ revm_primitives::{BlockEnv, CfgEnv}, Address, BlockId, BlockNumberOrTag, ChainInfo, SealedBlockWithSenders, B256, U256, U64, @@ -82,12 +83,12 @@ pub trait EthApiSpec: EthTransactions + Send + Sync { /// are implemented separately in submodules. The rpc handler implementation can then delegate to /// the main impls. This way [`EthApi`] is not limited to [`jsonrpsee`] and can be used standalone /// or in other network handlers (for example ipc). -pub struct EthApi { +pub struct EthApi { /// All nested fields bundled together. - inner: Arc>, + inner: Arc>, } -impl EthApi +impl EthApi where Provider: BlockReaderIdExt + ChainSpecProvider, { @@ -102,6 +103,7 @@ where gas_cap: impl Into, blocking_task_pool: BlockingTaskPool, fee_history_cache: FeeHistoryCache, + evm_config: EvmConfig, ) -> Self { Self::with_spawner( provider, @@ -113,6 +115,7 @@ where Box::::default(), blocking_task_pool, fee_history_cache, + evm_config, ) } @@ -128,6 +131,7 @@ where task_spawner: Box, blocking_task_pool: BlockingTaskPool, fee_history_cache: FeeHistoryCache, + evm_config: EvmConfig, ) -> Self { // get the block number of the latest block let latest_block = provider @@ -150,6 +154,7 @@ where pending_block: Default::default(), blocking_task_pool, fee_history_cache, + evm_config, #[cfg(feature = "optimism")] http_client: reqwest::Client::builder().use_rustls_tls().build().unwrap(), }; @@ -215,7 +220,7 @@ where // === State access helpers === -impl EthApi +impl EthApi where Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, @@ -252,12 +257,13 @@ where } } -impl EthApi +impl EthApi where Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + Clone + 'static, { /// Configures the [CfgEnv] and [BlockEnv] for the pending block /// @@ -293,7 +299,12 @@ where let mut block_env = BlockEnv::default(); // Note: for the PENDING block we assume it is past the known merge block and thus this will // not fail when looking up the total difficulty value for the blockenv. - self.provider().fill_env_with_header(&mut cfg, &mut block_env, origin.header())?; + self.provider().fill_env_with_header( + &mut cfg, + &mut block_env, + origin.header(), + self.inner.evm_config.clone(), + )?; Ok(PendingBlockEnv { cfg, block_env, origin }) } @@ -347,25 +358,28 @@ where } } -impl std::fmt::Debug for EthApi { +impl std::fmt::Debug + for EthApi +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EthApi").finish_non_exhaustive() } } -impl Clone for EthApi { +impl Clone for EthApi { fn clone(&self) -> Self { Self { inner: Arc::clone(&self.inner) } } } #[async_trait] -impl EthApiSpec for EthApi +impl EthApiSpec for EthApi where Pool: TransactionPool + Clone + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Network: NetworkInfo + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Returns the current ethereum protocol version. /// @@ -443,7 +457,7 @@ impl From for u64 { } /// Container type `EthApi` -struct EthApiInner { +struct EthApiInner { /// The transaction pool. pool: Pool, /// The provider that can interact with the chain. @@ -468,6 +482,8 @@ struct EthApiInner { blocking_task_pool: BlockingTaskPool, /// Cache for block fees history fee_history_cache: FeeHistoryCache, + /// The type that defines how to configure the EVM + evm_config: EvmConfig, /// An http client for communicating with sequencers. #[cfg(feature = "optimism")] http_client: reqwest::Client, diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 6d20f7912..6e97eaa57 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -12,6 +12,7 @@ use crate::{ }; use jsonrpsee::core::RpcResult as Result; use reth_network_api::NetworkInfo; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ serde_helper::{num::U64HexOrNumber, JsonStorageKey}, Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64, @@ -31,7 +32,7 @@ use serde_json::Value; use tracing::trace; #[async_trait::async_trait] -impl EthApiServer for EthApi +impl EthApiServer for EthApi where Self: EthApiSpec + EthTransactions, Pool: TransactionPool + 'static, @@ -44,6 +45,7 @@ where + EvmEnvProvider + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Handler for: `eth_protocolVersion` async fn protocol_version(&self) -> Result { @@ -402,6 +404,7 @@ mod tests { use jsonrpsee::types::error::INVALID_PARAMS_CODE; use reth_interfaces::test_utils::{generators, generators::Rng}; use reth_network_api::noop::NoopNetwork; + use reth_node_builder::EthEvmConfig; use reth_primitives::{ basefee::calculate_next_block_base_fee, constants::ETHEREUM_BLOCK_GAS_LIMIT, BaseFeeParams, Block, BlockNumberOrTag, Header, TransactionSigned, B256, U256, @@ -425,9 +428,9 @@ mod tests { + 'static, >( provider: P, - ) -> EthApi { - let cache = EthStateCache::spawn(provider.clone(), Default::default()); - + ) -> EthApi { + let evm_config = EthEvmConfig::default(); + let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config); let fee_history_cache = FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); @@ -440,6 +443,7 @@ mod tests { ETHEREUM_BLOCK_GAS_LIMIT, BlockingTaskPool::build().expect("failed to build tracing pool"), fee_history_cache, + evm_config, ) } @@ -449,7 +453,7 @@ mod tests { mut oldest_block: Option, block_count: u64, mock_provider: MockEthProvider, - ) -> (EthApi, Vec, Vec) { + ) -> (EthApi, Vec, Vec) { let mut rng = generators::rng(); // Build mock data @@ -534,7 +538,7 @@ mod tests { /// Invalid block range #[tokio::test] async fn test_fee_history_empty() { - let response = as EthApiServer>::fee_history( + let response = as EthApiServer>::fee_history( &build_test_eth_api(NoopProvider::default()), 1.into(), BlockNumberOrTag::Latest, @@ -556,7 +560,7 @@ mod tests { let (eth_api, _, _) = prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - let response = as EthApiServer>::fee_history( + let response = as EthApiServer>::fee_history( ð_api, (newest_block + 1).into(), newest_block.into(), @@ -579,7 +583,7 @@ mod tests { let (eth_api, _, _) = prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - let response = as EthApiServer>::fee_history( + let response = as EthApiServer>::fee_history( ð_api, (1).into(), (newest_block + 1000).into(), @@ -602,7 +606,7 @@ mod tests { let (eth_api, _, _) = prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - let response = as EthApiServer>::fee_history( + let response = as EthApiServer>::fee_history( ð_api, (0).into(), (newest_block).into(), diff --git a/crates/rpc/rpc/src/eth/api/sign.rs b/crates/rpc/rpc/src/eth/api/sign.rs index 4d1e9bda0..97d9255c4 100644 --- a/crates/rpc/rpc/src/eth/api/sign.rs +++ b/crates/rpc/rpc/src/eth/api/sign.rs @@ -12,7 +12,7 @@ use reth_primitives::{Address, Bytes}; use serde_json::Value; use std::ops::Deref; -impl EthApi { +impl EthApi { pub(crate) async fn sign(&self, account: Address, message: Bytes) -> EthResult { let signer = self.find_signer(&account)?; let signature = signer.sign(account, &message).await?; diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs index a63e08126..9bd219b7b 100644 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ b/crates/rpc/rpc/src/eth/api/state.rs @@ -4,6 +4,7 @@ use crate::{ eth::error::{EthApiError, EthResult, RpcInvalidTransactionError}, EthApi, }; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ serde_helper::JsonStorageKey, Address, BlockId, BlockNumberOrTag, Bytes, B256, U256, }; @@ -14,12 +15,13 @@ use reth_rpc_types::EIP1186AccountProofResponse; use reth_rpc_types_compat::proof::from_primitive_account_proof; use reth_transaction_pool::{PoolTransaction, TransactionPool}; -impl EthApi +impl EthApi where Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Pool: TransactionPool + Clone + 'static, Network: Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { pub(crate) fn get_code(&self, address: Address, block_id: Option) -> EthResult { let state = self.state_at_block_id_or_latest(block_id)?; @@ -131,6 +133,7 @@ mod tests { }, BlockingTaskPool, }; + use reth_node_builder::EthEvmConfig; use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, StorageKey, StorageValue}; use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider}; use reth_transaction_pool::test_utils::testing_pool; @@ -140,8 +143,9 @@ mod tests { async fn test_storage() { // === Noop === let pool = testing_pool(); + let evm_config = EthEvmConfig::default(); - let cache = EthStateCache::spawn(NoopProvider::default(), Default::default()); + let cache = EthStateCache::spawn(NoopProvider::default(), Default::default(), evm_config); let eth_api = EthApi::new( NoopProvider::default(), pool.clone(), @@ -151,6 +155,7 @@ mod tests { ETHEREUM_BLOCK_GAS_LIMIT, BlockingTaskPool::build().expect("failed to build tracing pool"), FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()), + evm_config, ); let address = Address::random(); let storage = eth_api.storage_at(address, U256::ZERO.into(), None).unwrap(); @@ -164,7 +169,7 @@ mod tests { let account = ExtendedAccount::new(0, U256::ZERO).extend_storage(storage); mock_provider.add_account(address, account); - let cache = EthStateCache::spawn(mock_provider.clone(), Default::default()); + let cache = EthStateCache::spawn(mock_provider.clone(), Default::default(), evm_config); let eth_api = EthApi::new( mock_provider.clone(), pool, @@ -174,6 +179,7 @@ mod tests { ETHEREUM_BLOCK_GAS_LIMIT, BlockingTaskPool::build().expect("failed to build tracing pool"), FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()), + evm_config, ); let storage_key: U256 = storage_key.into(); diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index db91ad806..659c70328 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -14,6 +14,7 @@ use crate::{ }; use async_trait::async_trait; use reth_network_api::NetworkInfo; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ eip4844::calc_blob_gasprice, revm::env::{fill_block_env_with_coinbase, tx_env_with_recovered}, @@ -307,12 +308,14 @@ pub trait EthTransactions: Send + Sync { } #[async_trait] -impl EthTransactions for EthApi +impl EthTransactions + for EthApi where Pool: TransactionPool + Clone + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { fn call_gas_limit(&self) -> u64 { self.inner.gas_cap @@ -869,12 +872,13 @@ where // === impl EthApi === -impl EthApi +impl EthApi where Pool: TransactionPool + Clone + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { /// Spawns the given closure on a new blocking tracing task async fn spawn_tracing_task_with(&self, f: F) -> EthResult @@ -891,7 +895,7 @@ where } } -impl EthApi +impl EthApi where Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, @@ -1017,12 +1021,13 @@ where } } -impl EthApi +impl EthApi where Pool: TransactionPool + 'static, Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, Network: NetworkInfo + Send + Sync + 'static, + EvmConfig: EvmEnvConfig + 'static, { pub(crate) fn sign_request( &self, @@ -1271,6 +1276,7 @@ mod tests { BlockingTaskPool, EthApi, }; use reth_network_api::noop::NoopNetwork; + use reth_node_builder::EthEvmConfig; use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, hex_literal::hex, Bytes}; use reth_provider::test_utils::NoopProvider; use reth_transaction_pool::{test_utils::testing_pool, TransactionPool}; @@ -1282,7 +1288,8 @@ mod tests { let pool = testing_pool(); - let cache = EthStateCache::spawn(noop_provider, Default::default()); + let evm_config = EthEvmConfig::default(); + let cache = EthStateCache::spawn(noop_provider, Default::default(), evm_config); let fee_history_cache = FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); let eth_api = EthApi::new( @@ -1294,6 +1301,7 @@ mod tests { ETHEREUM_BLOCK_GAS_LIMIT, BlockingTaskPool::build().expect("failed to build tracing pool"), fee_history_cache, + evm_config, ); // https://etherscan.io/tx/0xa694b71e6c128a2ed8e2e0f6770bddbe52e3bb8f10e8472f9a79ab81497a8b5d diff --git a/crates/rpc/rpc/src/eth/cache/mod.rs b/crates/rpc/rpc/src/eth/cache/mod.rs index 05c168682..c2e7be58b 100644 --- a/crates/rpc/rpc/src/eth/cache/mod.rs +++ b/crates/rpc/rpc/src/eth/cache/mod.rs @@ -2,6 +2,7 @@ use futures::{future::Either, Stream, StreamExt}; use reth_interfaces::provider::{ProviderError, ProviderResult}; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ Block, BlockHashOrNumber, BlockWithSenders, Receipt, SealedBlock, SealedBlockWithSenders, TransactionSigned, TransactionSignedEcRecovered, B256, @@ -68,14 +69,15 @@ pub struct EthStateCache { impl EthStateCache { /// Creates and returns both [EthStateCache] frontend and the memory bound service. - fn create( + fn create( provider: Provider, action_task_spawner: Tasks, + evm_config: EvmConfig, max_blocks: u32, max_receipts: u32, max_envs: u32, max_concurrent_db_operations: usize, - ) -> (Self, EthStateCacheService) { + ) -> (Self, EthStateCacheService) { let (to_service, rx) = unbounded_channel(); let service = EthStateCacheService { provider, @@ -86,6 +88,7 @@ impl EthStateCache { action_rx: UnboundedReceiverStream::new(rx), action_task_spawner, rate_limiter: Arc::new(Semaphore::new(max_concurrent_db_operations)), + evm_config, }; let cache = EthStateCache { to_service }; (cache, service) @@ -95,31 +98,39 @@ impl EthStateCache { /// [tokio::spawn]. /// /// See also [Self::spawn_with] - pub fn spawn(provider: Provider, config: EthStateCacheConfig) -> Self + pub fn spawn( + provider: Provider, + config: EthStateCacheConfig, + evm_config: EvmConfig, + ) -> Self where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, + EvmConfig: EvmEnvConfig + 'static, { - Self::spawn_with(provider, config, TokioTaskExecutor::default()) + Self::spawn_with(provider, config, TokioTaskExecutor::default(), evm_config) } /// Creates a new async LRU backed cache service task and spawns it to a new task via the given /// spawner. /// /// The cache is memory limited by the given max bytes values. - pub fn spawn_with( + pub fn spawn_with( provider: Provider, config: EthStateCacheConfig, executor: Tasks, + evm_config: EvmConfig, ) -> Self where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Tasks: TaskSpawner + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { let EthStateCacheConfig { max_blocks, max_receipts, max_envs, max_concurrent_db_requests } = config; let (this, service) = Self::create( provider, executor.clone(), + evm_config, max_blocks, max_receipts, max_envs, @@ -267,6 +278,7 @@ impl EthStateCache { pub(crate) struct EthStateCacheService< Provider, Tasks, + EvmConfig, LimitBlocks = ByLength, LimitReceipts = ByLength, LimitEnvs = ByLength, @@ -291,12 +303,15 @@ pub(crate) struct EthStateCacheService< action_task_spawner: Tasks, /// Rate limiter rate_limiter: Arc, + /// The type that determines how to configure the EVM. + evm_config: EvmConfig, } -impl EthStateCacheService +impl EthStateCacheService where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Tasks: TaskSpawner + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { fn on_new_block(&mut self, block_hash: B256, res: ProviderResult>) { if let Some(queued) = self.full_block_cache.remove(&block_hash) { @@ -347,10 +362,11 @@ where } } -impl Future for EthStateCacheService +impl Future for EthStateCacheService where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Tasks: TaskSpawner + Clone + 'static, + EvmConfig: EvmEnvConfig + 'static, { type Output = (); @@ -456,13 +472,19 @@ where let provider = this.provider.clone(); let action_tx = this.action_tx.clone(); let rate_limiter = this.rate_limiter.clone(); + let evm_config = this.evm_config.clone(); this.action_task_spawner.spawn_blocking(Box::pin(async move { // Acquire permit let _permit = rate_limiter.acquire().await; let mut cfg = CfgEnv::default(); let mut block_env = BlockEnv::default(); let res = provider - .fill_env_at(&mut cfg, &mut block_env, block_hash.into()) + .fill_env_at( + &mut cfg, + &mut block_env, + block_hash.into(), + evm_config, + ) .map(|_| (cfg, block_env)); let _ = action_tx.send(CacheAction::EnvResult { block_hash, diff --git a/crates/rpc/rpc/src/eth/revm_utils.rs b/crates/rpc/rpc/src/eth/revm_utils.rs index 7524f0662..931240a3e 100644 --- a/crates/rpc/rpc/src/eth/revm_utils.rs +++ b/crates/rpc/rpc/src/eth/revm_utils.rs @@ -1,14 +1,20 @@ //! utilities for working with revm use crate::eth::error::{EthApiError, EthResult, RpcInvalidTransactionError}; +#[cfg(feature = "optimism")] +use reth_primitives::revm::env::fill_op_tx_env; +#[cfg(not(feature = "optimism"))] +use reth_primitives::revm::env::fill_tx_env; use reth_primitives::{ - revm::env::{fill_tx_env, fill_tx_env_with_recovered}, - Address, TransactionSigned, TransactionSignedEcRecovered, TxHash, B256, U256, + revm::env::fill_tx_env_with_recovered, Address, TransactionSigned, + TransactionSignedEcRecovered, TxHash, B256, U256, }; use reth_rpc_types::{ state::{AccountOverride, StateOverride}, BlockOverrides, CallRequest, }; +#[cfg(feature = "optimism")] +use revm::primitives::{Bytes, OptimismFields}; use revm::{ db::CacheDB, precompile::{Precompiles, SpecId as PrecompilesSpecId}, @@ -21,9 +27,6 @@ use revm_primitives::{ }; use tracing::trace; -#[cfg(feature = "optimism")] -use revm::primitives::{Bytes, OptimismFields}; - /// Helper type that bundles various overrides for EVM Execution. /// /// By `Default`, no overrides are included. @@ -104,7 +107,7 @@ impl FillableTransaction for TransactionSigned { { let mut envelope_buf = Vec::with_capacity(self.length_without_header()); self.encode_enveloped(&mut envelope_buf); - fill_tx_env(tx_env, self, signer, envelope_buf.into()); + fill_op_tx_env(tx_env, self, signer, envelope_buf.into()); } Ok(()) } diff --git a/crates/stages/Cargo.toml b/crates/stages/Cargo.toml index d3ddca5be..20a73e87c 100644 --- a/crates/stages/Cargo.toml +++ b/crates/stages/Cargo.toml @@ -62,6 +62,7 @@ reth-db = { workspace = true, features = ["test-utils", "mdbx"] } reth-interfaces = { workspace = true, features = ["test-utils"] } reth-downloaders.workspace = true reth-eth-wire.workspace = true # TODO(onbjerg): We only need this for [BlockBody] +reth-node-builder.workspace = true reth-blockchain-tree.workspace = true reth-revm.workspace = true reth-trie = { workspace = true, features = ["test-utils"] } diff --git a/crates/stages/src/lib.rs b/crates/stages/src/lib.rs index 7c8ed234b..23254e4ab 100644 --- a/crates/stages/src/lib.rs +++ b/crates/stages/src/lib.rs @@ -22,6 +22,7 @@ //! # use reth_stages::Pipeline; //! # use reth_stages::sets::DefaultStages; //! # use tokio::sync::watch; +//! # use reth_node_builder::EthEvmConfig; //! # use reth_provider::ProviderFactory; //! # use reth_provider::HeaderSyncMode; //! # use reth_provider::test_utils::create_test_provider_factory; @@ -39,7 +40,7 @@ //! # provider_factory.clone() //! # ); //! # let (tip_tx, tip_rx) = watch::channel(B256::default()); -//! # let executor_factory = EvmProcessorFactory::new(chain_spec.clone()); +//! # let executor_factory = EvmProcessorFactory::new(chain_spec.clone(), EthEvmConfig::default()); //! // Create a pipeline that can fully sync //! # let pipeline = //! Pipeline::builder() diff --git a/crates/stages/src/sets.rs b/crates/stages/src/sets.rs index 1f3d49e39..d4b7a8c61 100644 --- a/crates/stages/src/sets.rs +++ b/crates/stages/src/sets.rs @@ -14,9 +14,10 @@ //! # use reth_stages::sets::{OfflineStages}; //! # use reth_revm::EvmProcessorFactory; //! # use reth_primitives::MAINNET; +//! # use reth_node_builder::EthEvmConfig; //! # use reth_provider::test_utils::create_test_provider_factory; //! -//! # let executor_factory = EvmProcessorFactory::new(MAINNET.clone()); +//! # let executor_factory = EvmProcessorFactory::new(MAINNET.clone(), EthEvmConfig::default()); //! # let provider_factory = create_test_provider_factory(); //! // Build a pipeline with all offline stages. //! # let pipeline = Pipeline::builder().add_stages(OfflineStages::new(executor_factory)).build(provider_factory); @@ -26,9 +27,10 @@ //! # use reth_stages::Pipeline; //! # use reth_stages::{StageSet, sets::OfflineStages}; //! # use reth_revm::EvmProcessorFactory; +//! # use reth_node_builder::EthEvmConfig; //! # use reth_primitives::MAINNET; //! // Build a pipeline with all offline stages and a custom stage at the end. -//! # let executor_factory = EvmProcessorFactory::new(MAINNET.clone()); +//! # let executor_factory = EvmProcessorFactory::new(MAINNET.clone(), EthEvmConfig::default()); //! Pipeline::builder() //! .add_stages( //! OfflineStages::new(executor_factory).builder().add_stage(MyCustomStage) diff --git a/crates/stages/src/stages/execution.rs b/crates/stages/src/stages/execution.rs index 42225b1a0..84ecacb68 100644 --- a/crates/stages/src/stages/execution.rs +++ b/crates/stages/src/stages/execution.rs @@ -502,6 +502,7 @@ mod tests { use assert_matches::assert_matches; use reth_db::{models::AccountBeforeTx, test_utils::create_test_rw_db}; use reth_interfaces::executor::BlockValidationError; + use reth_node_builder::EthEvmConfig; use reth_primitives::{ address, hex_literal::hex, keccak256, stage::StageUnitCheckpoint, Account, Bytecode, ChainSpecBuilder, PruneModes, SealedBlock, StorageEntry, B256, MAINNET, U256, @@ -510,10 +511,11 @@ mod tests { use reth_revm::EvmProcessorFactory; use std::sync::Arc; - fn stage() -> ExecutionStage { - let executor_factory = EvmProcessorFactory::new(Arc::new( - ChainSpecBuilder::mainnet().berlin_activated().build(), - )); + fn stage() -> ExecutionStage> { + let executor_factory = EvmProcessorFactory::new( + Arc::new(ChainSpecBuilder::mainnet().berlin_activated().build()), + EthEvmConfig::default(), + ); ExecutionStage::new( executor_factory, ExecutionStageThresholds { @@ -701,7 +703,7 @@ mod tests { provider.commit().unwrap(); let provider = factory.provider_rw().unwrap(); - let mut execution_stage: ExecutionStage = stage(); + let mut execution_stage: ExecutionStage> = stage(); let output = execution_stage.execute(&provider, input).unwrap(); provider.commit().unwrap(); assert_matches!(output, ExecOutput { diff --git a/crates/stages/src/stages/mod.rs b/crates/stages/src/stages/mod.rs index 29e6a1c63..cf6f5480b 100644 --- a/crates/stages/src/stages/mod.rs +++ b/crates/stages/src/stages/mod.rs @@ -55,6 +55,7 @@ mod tests { AccountHistory, DatabaseEnv, }; use reth_interfaces::test_utils::generators::{self, random_block}; + use reth_node_builder::EthEvmConfig; use reth_primitives::{ address, hex_literal::hex, keccak256, Account, Bytecode, ChainSpecBuilder, PruneMode, PruneModes, SealedBlock, U256, @@ -128,9 +129,10 @@ mod tests { // Check execution and create receipts and changesets according to the pruning // configuration let mut execution_stage = ExecutionStage::new( - EvmProcessorFactory::new(Arc::new( - ChainSpecBuilder::mainnet().berlin_activated().build(), - )), + EvmProcessorFactory::new( + Arc::new(ChainSpecBuilder::mainnet().berlin_activated().build()), + EthEvmConfig::default(), + ), ExecutionStageThresholds { max_blocks: Some(100), max_changes: None, diff --git a/crates/storage/provider/Cargo.toml b/crates/storage/provider/Cargo.toml index 64ff9742a..7e87f7fa3 100644 --- a/crates/storage/provider/Cargo.toml +++ b/crates/storage/provider/Cargo.toml @@ -18,6 +18,7 @@ reth-interfaces.workspace = true reth-db.workspace = true reth-trie.workspace = true reth-nippy-jar.workspace = true +reth-node-api.workspace = true revm.workspace = true diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index fbe9b0ebd..4c5358e2e 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -11,6 +11,7 @@ use crate::{ }; use reth_db::{database::Database, init_db, models::StoredBlockBodyIndices, DatabaseEnv}; use reth_interfaces::{provider::ProviderResult, RethError, RethResult}; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ snapshot::HighestSnapshots, stage::{StageCheckpoint, StageId}, @@ -437,22 +438,30 @@ impl StageCheckpointReader for ProviderFactory { } impl EvmEnvProvider for ProviderFactory { - fn fill_env_at( + fn fill_env_at( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, at: BlockHashOrNumber, - ) -> ProviderResult<()> { - self.provider()?.fill_env_at(cfg, block_env, at) + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.provider()?.fill_env_at(cfg, block_env, at, evm_config) } - fn fill_env_with_header( + fn fill_env_with_header( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, header: &Header, - ) -> ProviderResult<()> { - self.provider()?.fill_env_with_header(cfg, block_env, header) + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.provider()?.fill_env_with_header(cfg, block_env, header, evm_config) } fn fill_block_env_at( @@ -471,12 +480,28 @@ impl EvmEnvProvider for ProviderFactory { self.provider()?.fill_block_env_with_header(block_env, header) } - fn fill_cfg_env_at(&self, cfg: &mut CfgEnv, at: BlockHashOrNumber) -> ProviderResult<()> { - self.provider()?.fill_cfg_env_at(cfg, at) + fn fill_cfg_env_at( + &self, + cfg: &mut CfgEnv, + at: BlockHashOrNumber, + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.provider()?.fill_cfg_env_at(cfg, at, evm_config) } - fn fill_cfg_env_with_header(&self, cfg: &mut CfgEnv, header: &Header) -> ProviderResult<()> { - self.provider()?.fill_cfg_env_with_header(cfg, header) + fn fill_cfg_env_with_header( + &self, + cfg: &mut CfgEnv, + header: &Header, + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.provider()?.fill_cfg_env_with_header(cfg, header, evm_config) } } diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 4ff3e48c6..eef70b2b8 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -31,12 +31,10 @@ use reth_interfaces::{ provider::{ProviderResult, RootMismatch}, RethError, RethResult, }; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ keccak256, - revm::{ - config::revm_spec, - env::{fill_block_env, fill_cfg_and_block_env, fill_cfg_env}, - }, + revm::{config::revm_spec, env::fill_block_env}, stage::{StageCheckpoint, StageId}, trie::Nibbles, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithSenders, @@ -1729,27 +1727,41 @@ impl WithdrawalsProvider for DatabaseProvider { } impl EvmEnvProvider for DatabaseProvider { - fn fill_env_at( + fn fill_env_at( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, at: BlockHashOrNumber, - ) -> ProviderResult<()> { + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { let hash = self.convert_number(at)?.ok_or(ProviderError::HeaderNotFound(at))?; let header = self.header(&hash)?.ok_or(ProviderError::HeaderNotFound(at))?; - self.fill_env_with_header(cfg, block_env, &header) + self.fill_env_with_header(cfg, block_env, &header, evm_config) } - fn fill_env_with_header( + fn fill_env_with_header( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, header: &Header, - ) -> ProviderResult<()> { + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { let total_difficulty = self .header_td_by_number(header.number)? .ok_or_else(|| ProviderError::HeaderNotFound(header.number.into()))?; - fill_cfg_and_block_env(cfg, block_env, &self.chain_spec, header, total_difficulty); + EvmConfig::fill_cfg_and_block_env( + cfg, + block_env, + &self.chain_spec, + header, + total_difficulty, + ); Ok(()) } @@ -1788,17 +1800,33 @@ impl EvmEnvProvider for DatabaseProvider { Ok(()) } - fn fill_cfg_env_at(&self, cfg: &mut CfgEnv, at: BlockHashOrNumber) -> ProviderResult<()> { + fn fill_cfg_env_at( + &self, + cfg: &mut CfgEnv, + at: BlockHashOrNumber, + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { let hash = self.convert_number(at)?.ok_or(ProviderError::HeaderNotFound(at))?; let header = self.header(&hash)?.ok_or(ProviderError::HeaderNotFound(at))?; - self.fill_cfg_env_with_header(cfg, &header) + self.fill_cfg_env_with_header(cfg, &header, evm_config) } - fn fill_cfg_env_with_header(&self, cfg: &mut CfgEnv, header: &Header) -> ProviderResult<()> { + fn fill_cfg_env_with_header( + &self, + cfg: &mut CfgEnv, + header: &Header, + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { let total_difficulty = self .header_td_by_number(header.number)? .ok_or_else(|| ProviderError::HeaderNotFound(header.number.into()))?; - fill_cfg_env(cfg, &self.chain_spec, header, total_difficulty); + EvmConfig::fill_cfg_env(cfg, &self.chain_spec, header, total_difficulty); Ok(()) } } diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 2d0aac23d..a3696f37f 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -13,6 +13,7 @@ use reth_interfaces::{ provider::ProviderResult, RethError, RethResult, }; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ stage::{StageCheckpoint, StageId}, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumber, @@ -456,22 +457,30 @@ where DB: Database, Tree: Send + Sync, { - fn fill_env_at( + fn fill_env_at( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, at: BlockHashOrNumber, - ) -> ProviderResult<()> { - self.database.provider()?.fill_env_at(cfg, block_env, at) + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.database.provider()?.fill_env_at(cfg, block_env, at, evm_config) } - fn fill_env_with_header( + fn fill_env_with_header( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, header: &Header, - ) -> ProviderResult<()> { - self.database.provider()?.fill_env_with_header(cfg, block_env, header) + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.database.provider()?.fill_env_with_header(cfg, block_env, header, evm_config) } fn fill_block_env_at( @@ -490,12 +499,28 @@ where self.database.provider()?.fill_block_env_with_header(block_env, header) } - fn fill_cfg_env_at(&self, cfg: &mut CfgEnv, at: BlockHashOrNumber) -> ProviderResult<()> { - self.database.provider()?.fill_cfg_env_at(cfg, at) + fn fill_cfg_env_at( + &self, + cfg: &mut CfgEnv, + at: BlockHashOrNumber, + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.database.provider()?.fill_cfg_env_at(cfg, at, evm_config) } - fn fill_cfg_env_with_header(&self, cfg: &mut CfgEnv, header: &Header) -> ProviderResult<()> { - self.database.provider()?.fill_cfg_env_with_header(cfg, header) + fn fill_cfg_env_with_header( + &self, + cfg: &mut CfgEnv, + header: &Header, + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { + self.database.provider()?.fill_cfg_env_with_header(cfg, header, evm_config) } } diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 0c862a1da..3f4a4b20a 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -9,6 +9,7 @@ use crate::{ use parking_lot::Mutex; use reth_db::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_interfaces::provider::{ProviderError, ProviderResult}; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ keccak256, trie::AccountProof, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, BlockWithSenders, Bytecode, Bytes, ChainInfo, ChainSpec, Header, Receipt, @@ -554,21 +555,29 @@ impl StateProvider for MockEthProvider { } impl EvmEnvProvider for MockEthProvider { - fn fill_env_at( + fn fill_env_at( &self, _cfg: &mut CfgEnv, _block_env: &mut BlockEnv, _at: BlockHashOrNumber, - ) -> ProviderResult<()> { + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } - fn fill_env_with_header( + fn fill_env_with_header( &self, _cfg: &mut CfgEnv, _block_env: &mut BlockEnv, _header: &Header, - ) -> ProviderResult<()> { + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } @@ -588,11 +597,27 @@ impl EvmEnvProvider for MockEthProvider { Ok(()) } - fn fill_cfg_env_at(&self, _cfg: &mut CfgEnv, _at: BlockHashOrNumber) -> ProviderResult<()> { + fn fill_cfg_env_at( + &self, + _cfg: &mut CfgEnv, + _at: BlockHashOrNumber, + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } - fn fill_cfg_env_with_header(&self, _cfg: &mut CfgEnv, _header: &Header) -> ProviderResult<()> { + fn fill_cfg_env_with_header( + &self, + _cfg: &mut CfgEnv, + _header: &Header, + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } } diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 4036ca99f..cdd3e93b9 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -9,6 +9,7 @@ use crate::{ }; use reth_db::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_interfaces::provider::ProviderResult; +use reth_node_api::EvmEnvConfig; use reth_primitives::{ stage::{StageCheckpoint, StageId}, trie::AccountProof, @@ -314,21 +315,29 @@ impl StateProvider for NoopProvider { } impl EvmEnvProvider for NoopProvider { - fn fill_env_at( + fn fill_env_at( &self, _cfg: &mut CfgEnv, _block_env: &mut BlockEnv, _at: BlockHashOrNumber, - ) -> ProviderResult<()> { + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } - fn fill_env_with_header( + fn fill_env_with_header( &self, _cfg: &mut CfgEnv, _block_env: &mut BlockEnv, _header: &Header, - ) -> ProviderResult<()> { + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } @@ -348,11 +357,27 @@ impl EvmEnvProvider for NoopProvider { Ok(()) } - fn fill_cfg_env_at(&self, _cfg: &mut CfgEnv, _at: BlockHashOrNumber) -> ProviderResult<()> { + fn fill_cfg_env_at( + &self, + _cfg: &mut CfgEnv, + _at: BlockHashOrNumber, + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } - fn fill_cfg_env_with_header(&self, _cfg: &mut CfgEnv, _header: &Header) -> ProviderResult<()> { + fn fill_cfg_env_with_header( + &self, + _cfg: &mut CfgEnv, + _header: &Header, + _evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig, + { Ok(()) } } diff --git a/crates/storage/provider/src/traits/evm_env.rs b/crates/storage/provider/src/traits/evm_env.rs index 4aa540078..1358c207c 100644 --- a/crates/storage/provider/src/traits/evm_env.rs +++ b/crates/storage/provider/src/traits/evm_env.rs @@ -1,4 +1,5 @@ use reth_interfaces::provider::ProviderResult; +use reth_node_api::EvmEnvConfig; use reth_primitives::{BlockHashOrNumber, Header}; use revm::primitives::{BlockEnv, CfgEnv}; @@ -10,28 +11,41 @@ use revm::primitives::{BlockEnv, CfgEnv}; pub trait EvmEnvProvider: Send + Sync { /// Fills the [CfgEnv] and [BlockEnv] fields with values specific to the given /// [BlockHashOrNumber]. - fn fill_env_at( + fn fill_env_at( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, at: BlockHashOrNumber, - ) -> ProviderResult<()>; + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig; /// Fills the default [CfgEnv] and [BlockEnv] fields with values specific to the given [Header]. - fn env_with_header(&self, header: &Header) -> ProviderResult<(CfgEnv, BlockEnv)> { + fn env_with_header( + &self, + header: &Header, + evm_config: EvmConfig, + ) -> ProviderResult<(CfgEnv, BlockEnv)> + where + EvmConfig: EvmEnvConfig, + { let mut cfg = CfgEnv::default(); let mut block_env = BlockEnv::default(); - self.fill_env_with_header(&mut cfg, &mut block_env, header)?; + self.fill_env_with_header::(&mut cfg, &mut block_env, header, evm_config)?; Ok((cfg, block_env)) } /// Fills the [CfgEnv] and [BlockEnv] fields with values specific to the given [Header]. - fn fill_env_with_header( + fn fill_env_with_header( &self, cfg: &mut CfgEnv, block_env: &mut BlockEnv, header: &Header, - ) -> ProviderResult<()>; + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig; /// Fills the [BlockEnv] fields with values specific to the given [BlockHashOrNumber]. fn fill_block_env_at( @@ -48,8 +62,22 @@ pub trait EvmEnvProvider: Send + Sync { ) -> ProviderResult<()>; /// Fills the [CfgEnv] fields with values specific to the given [BlockHashOrNumber]. - fn fill_cfg_env_at(&self, cfg: &mut CfgEnv, at: BlockHashOrNumber) -> ProviderResult<()>; + fn fill_cfg_env_at( + &self, + cfg: &mut CfgEnv, + at: BlockHashOrNumber, + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig; /// Fills the [CfgEnv] fields with values specific to the given [Header]. - fn fill_cfg_env_with_header(&self, cfg: &mut CfgEnv, header: &Header) -> ProviderResult<()>; + fn fill_cfg_env_with_header( + &self, + cfg: &mut CfgEnv, + header: &Header, + evm_config: EvmConfig, + ) -> ProviderResult<()> + where + EvmConfig: EvmEnvConfig; } diff --git a/testing/ef-tests/Cargo.toml b/testing/ef-tests/Cargo.toml index 6f1d776d1..c5eabaf17 100644 --- a/testing/ef-tests/Cargo.toml +++ b/testing/ef-tests/Cargo.toml @@ -21,6 +21,7 @@ reth-provider.workspace = true reth-stages.workspace = true reth-interfaces.workspace = true reth-revm.workspace = true +reth-node-builder.workspace = true alloy-rlp.workspace = true tokio = "1.28.1" diff --git a/testing/ef-tests/src/cases/blockchain_test.rs b/testing/ef-tests/src/cases/blockchain_test.rs index 3ff4ebbab..dece7eb82 100644 --- a/testing/ef-tests/src/cases/blockchain_test.rs +++ b/testing/ef-tests/src/cases/blockchain_test.rs @@ -6,6 +6,7 @@ use crate::{ }; use alloy_rlp::Decodable; use reth_db::test_utils::create_test_rw_db; +use reth_node_builder::EthEvmConfig; use reth_primitives::{BlockBody, SealedBlock}; use reth_provider::{BlockWriter, HashingWriter, ProviderFactory}; use reth_stages::{stages::ExecutionStage, ExecInput, Stage}; @@ -108,6 +109,7 @@ impl Case for BlockchainTestCase { // network. let _ = ExecutionStage::new_with_factory(reth_revm::EvmProcessorFactory::new( Arc::new(case.network.clone().into()), + EthEvmConfig::default(), )) .execute( &provider,