Skip to main content

reth_evm_ethereum/
lib.rs

1//! EVM config for vanilla Ethereum.
2
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
5    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
6    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12extern crate alloc;
13
14use alloc::{borrow::Cow, sync::Arc};
15use alloy_consensus::{BlockHeader, Header};
16use alloy_eips::{eip4895::Withdrawal, eip7840::BlobParams, merge::SLOT_DURATION_SECS};
17use alloy_primitives::{Address, Bytes, B256};
18use convert::{block_env_with_blob_params, spec_id};
19use core::{any::TypeId, convert::Infallible, fmt::Debug};
20use reth_chainspec::{ChainSpec, EthChainSpec, EthereumHardforks, MAINNET};
21use reth_ethereum_forks::Hardforks;
22use reth_ethereum_primitives::{Block, EthPrimitives};
23use reth_evm::{ConfigureEvm, EvmEnv, EvmEnvFor, NextBlockEnvAttributes, SenderRecoveryCache};
24use reth_primitives_traits::{SealedBlock, SealedHeader};
25
26#[cfg(feature = "std")]
27use alloy_consensus::Transaction;
28#[cfg(feature = "std")]
29use alloy_eips::Decodable2718;
30#[cfg(feature = "std")]
31use alloy_rpc_types_engine::ExecutionData;
32#[cfg(feature = "std")]
33use convert::payload_block_env;
34#[cfg(feature = "std")]
35use evm2::evm::{Database, Db};
36#[cfg(feature = "std")]
37use reth_ethereum_primitives::TransactionSigned;
38#[cfg(feature = "std")]
39use reth_evm::{
40    precompile_cache::PrecompileCacheMap, ConfigureEngineEvm, EvmFor, ExecutableTxIterator,
41    ExecutionCtxFor, SpecFor,
42};
43#[cfg(feature = "std")]
44use reth_primitives_traits::SignedTransaction;
45#[cfg(feature = "std")]
46use reth_storage_errors::any::AnyError;
47
48#[cfg(feature = "jit")]
49use core::any::Any;
50
51pub use convert::spec_id_by_timestamp_and_block_number;
52
53/// Configured Ethereum EVM environment.
54pub struct EthEvmEnv<T = evm2::BaseEvmTypes>
55where
56    T: evm2::EvmTypesHost,
57{
58    /// Active EVM spec.
59    pub spec: T::SpecId,
60    /// Runtime configuration for the active EVM spec.
61    pub version: evm2::Version,
62    /// EVM block environment.
63    pub block: evm2::env::BlockEnv<T>,
64}
65
66impl<T: evm2::EvmTypesHost> Clone for EthEvmEnv<T> {
67    fn clone(&self) -> Self {
68        Self { spec: self.spec, version: self.version, block: self.block }
69    }
70}
71
72impl<T: evm2::EvmTypesHost> Debug for EthEvmEnv<T>
73where
74    T::SpecId: Debug,
75    T::BlockEnvExt: Debug,
76{
77    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78        f.debug_struct("EthEvmEnv")
79            .field("spec", &self.spec)
80            .field("version", &self.version)
81            .field("block", &self.block)
82            .finish()
83    }
84}
85
86impl<T: evm2::EvmTypesHost> EthEvmEnv<T> {
87    /// Creates a new Ethereum EVM environment.
88    pub fn new(spec: T::SpecId, block: evm2::env::BlockEnv<T>, chain_id: u64) -> Self {
89        let mut version = evm2::Version::new(spec.into());
90        version.chain_id = chain_id;
91        Self { spec, version, block }
92    }
93
94    /// Creates a new Ethereum EVM environment with a preconfigured runtime version.
95    pub const fn new_with_version(
96        spec: T::SpecId,
97        block: evm2::env::BlockEnv<T>,
98        version: evm2::Version,
99    ) -> Self {
100        Self { spec, version, block }
101    }
102}
103
104impl<T> Default for EthEvmEnv<T>
105where
106    T: evm2::EvmTypesHost,
107    T::SpecId: Default,
108{
109    fn default() -> Self {
110        let spec = T::SpecId::default();
111        Self { spec, version: evm2::Version::new(spec.into()), block: Default::default() }
112    }
113}
114
115impl<T: evm2::EvmTypesHost> AsRef<evm2::env::BlockEnv<T>> for EthEvmEnv<T> {
116    fn as_ref(&self) -> &evm2::env::BlockEnv<T> {
117        &self.block
118    }
119}
120
121impl<T: evm2::EvmTypes> EvmEnv for EthEvmEnv<T>
122where
123    T::SpecId: Debug + Send + Sync,
124    T::BlockEnvExt: Send + Sync,
125{
126    type EvmTypes = T;
127
128    fn spec_id(&self) -> T::SpecId {
129        self.spec
130    }
131
132    fn chain_id(&self) -> u64 {
133        self.version.chain_id
134    }
135
136    fn block_env(&self) -> &evm2::env::BlockEnv<T> {
137        &self.block
138    }
139
140    fn block_env_mut(&mut self) -> &mut evm2::env::BlockEnv<T> {
141        &mut self.block
142    }
143
144    fn version(&self) -> &evm2::Version {
145        &self.version
146    }
147
148    fn version_mut(&mut self) -> &mut evm2::Version {
149        &mut self.version
150    }
151
152    fn block_base_fee(&self) -> u64 {
153        self.block.basefee.saturating_to()
154    }
155
156    fn block_blob_base_fee(&self) -> u64 {
157        self.block.blob_basefee.saturating_to()
158    }
159
160    fn transaction_validation_limits(&self) -> reth_evm::EvmTransactionValidationLimits {
161        // `u64::MAX` means there is no cap, which the pool expects as `0`.
162        let tx_gas_limit_cap = match self.version.tx_gas_caps().0 {
163            u64::MAX => 0,
164            cap => cap,
165        };
166
167        reth_evm::EvmTransactionValidationLimits {
168            max_initcode_size: self.version.max_initcode_size,
169            tx_gas_limit_cap,
170        }
171    }
172
173    fn transaction_validation_gas_rules(&self) -> reth_evm::EvmTransactionValidationGasRules {
174        reth_evm::EvmTransactionValidationGasRules { version: self.version }
175    }
176
177    fn uses_separate_block_gas(&self) -> bool {
178        self.version.feature(evm2::EvmFeatures::EIP8037)
179    }
180
181    fn regular_gas_limit_cap(&self) -> u64 {
182        self.version.tx_gas_limit_cap
183    }
184
185    fn with_nonce_check_disabled(mut self) -> Self {
186        self.version.features.remove(evm2::EvmFeatures::NONCE_CHECK);
187        self
188    }
189
190    fn with_balance_check_disabled(mut self) -> Self {
191        self.version.features.remove(evm2::EvmFeatures::BALANCE_CHECK);
192        self
193    }
194}
195
196/// Ethereum block execution context.
197#[derive(Debug, Clone)]
198pub struct EthBlockExecutionCtx<'a> {
199    /// Optional transaction count hint.
200    pub tx_count_hint: Option<usize>,
201    /// Parent block hash.
202    pub parent_hash: B256,
203    /// Parent beacon block root.
204    pub parent_beacon_block_root: Option<B256>,
205    /// Ommer headers.
206    pub ommers: &'a [Header],
207    /// Withdrawals.
208    pub withdrawals: Option<Cow<'a, [Withdrawal]>>,
209    /// Extra data for the built block.
210    pub extra_data: Bytes,
211    /// Optional slot number for post-Amsterdam payloads.
212    pub slot_number: Option<u64>,
213}
214
215/// Helper type with backwards compatible methods to obtain Ethereum executor providers.
216#[doc(hidden)]
217pub mod execute {
218    use crate::EthEvmConfig;
219
220    #[deprecated(note = "Use `EthEvmConfig` instead")]
221    pub type EthExecutorProvider = EthEvmConfig;
222}
223
224mod build;
225pub use build::EthBlockAssembler;
226
227mod executor;
228pub use executor::{
229    EthBigBlockExecutor, EthBigBlockPlan, EthBigBlockSegment, EthBlockExecutor,
230    EthTransactionResultWithState,
231};
232
233/// Ethereum block executor and EVM factory implementations.
234pub mod factory;
235#[cfg(not(feature = "jit"))]
236pub use factory::RethEvmFactory;
237#[cfg(feature = "jit")]
238pub use factory::{
239    maybe_run_jit_helper, CompilationEvent, CompilationKind, CompileTimings, JitBackend,
240    JitMetrics, JitMode, RethEvmFactory, RuntimeConfig, RuntimeStatsSnapshot, RuntimeTuning,
241};
242pub use factory::{EthBigBlockExecutorFactory, EthBlockExecutorFactory, EvmFactory};
243
244mod convert;
245pub use convert::{recover_authorizations, ExecutableRecoveredTx};
246
247mod execution;
248
249#[cfg(test)]
250mod dao_fork;
251
252mod receipt;
253pub use receipt::RethReceiptBuilder;
254
255#[cfg(feature = "test-utils")]
256mod test_utils;
257#[cfg(feature = "test-utils")]
258pub use test_utils::*;
259
260/// Ethereum-related EVM configuration.
261#[derive(Debug, Clone)]
262pub struct EthEvmConfig<C = ChainSpec, F = RethEvmFactory>
263where
264    F: EvmFactory,
265{
266    /// Inner Ethereum block executor factory.
267    pub executor_factory: EthBlockExecutorFactory<RethReceiptBuilder, C, F>,
268    /// Ethereum block assembler.
269    pub block_assembler: EthBlockAssembler<C>,
270    /// Cache of recovered transaction senders, if enabled.
271    pub sender_recovery_cache: Option<SenderRecoveryCache>,
272}
273
274impl EthEvmConfig {
275    /// Creates a new Ethereum EVM configuration for Ethereum mainnet.
276    pub fn mainnet() -> Self {
277        Self::ethereum(MAINNET.clone())
278    }
279}
280
281impl<ChainSpec> EthEvmConfig<ChainSpec> {
282    /// Creates a new Ethereum EVM configuration with the given chain spec.
283    pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
284        Self::ethereum(chain_spec)
285    }
286
287    /// Creates a new Ethereum EVM configuration.
288    pub fn ethereum(chain_spec: Arc<ChainSpec>) -> Self {
289        Self::new_with_evm_factory(chain_spec, RethEvmFactory::default())
290    }
291}
292
293impl<ChainSpec, F: EvmFactory> EthEvmConfig<ChainSpec, F> {
294    /// Creates a new Ethereum EVM configuration with the given EVM factory configuration.
295    pub fn new_with_evm_factory(chain_spec: Arc<ChainSpec>, evm_factory: F) -> Self {
296        Self {
297            block_assembler: EthBlockAssembler::new(chain_spec.clone()),
298            sender_recovery_cache: None,
299            executor_factory: EthBlockExecutorFactory::new_with_evm_factory(
300                chain_spec,
301                evm_factory,
302            ),
303        }
304    }
305
306    /// Returns the chain spec associated with this configuration.
307    pub const fn chain_spec(&self) -> &Arc<ChainSpec> {
308        self.executor_factory.chain_spec()
309    }
310
311    fn evm_env_from_base_spec(
312        &self,
313        spec: evm2::SpecId,
314        block: evm2::env::BlockEnv,
315        blob_params: Option<BlobParams>,
316    ) -> EthEvmEnv<F::Types>
317    where
318        ChainSpec: EthChainSpec,
319    {
320        let factory = self.executor_factory.evm_factory();
321        let mut version = factory.version(spec, self.chain_spec().chain_id());
322        if let Some(blob_params) = blob_params {
323            version.max_blobs_per_tx = blob_params.max_blobs_per_tx as usize;
324        }
325        EthEvmEnv::new_with_version(factory.spec_id(spec), factory.block_env(block), version)
326    }
327
328    /// Uses the provided sender recovery cache.
329    pub fn with_sender_recovery_cache(mut self, cache: SenderRecoveryCache) -> Self {
330        self.sender_recovery_cache = Some(cache);
331        self
332    }
333}
334
335impl<ChainSpec, EvmF> ConfigureEvm for EthEvmConfig<ChainSpec, EvmF>
336where
337    ChainSpec: EthChainSpec<Header = Header> + EthereumHardforks + Hardforks + 'static,
338    EvmF: EvmFactory,
339    <EvmF::Types as evm2::EvmTypesHost>::Tx: alloy_eips::eip2718::Typed2718
340        + reth_evm::FromTxWithEncoded<reth_ethereum_primitives::TransactionSigned>
341        + reth_evm::TransactionEnvMut,
342{
343    type Primitives = EthPrimitives;
344    type Error = Infallible;
345    type NextBlockEnvCtx = NextBlockEnvAttributes;
346    type BlockExecutorFactory = EthBlockExecutorFactory<RethReceiptBuilder, ChainSpec, EvmF>;
347    #[cfg(feature = "std")]
348    type BlockAssembler = EthBlockAssembler<ChainSpec>;
349
350    #[cfg(feature = "std")]
351    fn block_executor_factory(&self) -> &Self::BlockExecutorFactory {
352        &self.executor_factory
353    }
354
355    #[cfg(feature = "std")]
356    fn block_assembler(&self) -> &Self::BlockAssembler {
357        &self.block_assembler
358    }
359
360    fn with_jit_support_enabled(self, enabled: bool) -> Self
361    where
362        Self: Sized,
363    {
364        #[cfg(feature = "jit")]
365        {
366            let mut this = self;
367            if let Some(factory) = (this.executor_factory.evm_factory_mut() as &mut dyn Any)
368                .downcast_mut::<factory::RethEvmFactory>()
369            {
370                factory.set_jit_support(enabled);
371            }
372            this
373        }
374
375        #[cfg(not(feature = "jit"))]
376        {
377            let _ = enabled;
378            self
379        }
380    }
381
382    #[cfg(feature = "std")]
383    fn evm_with_precompile_cache<'a, DB>(
384        &self,
385        db: DB,
386        evm_env: EvmEnvFor<Self>,
387        cache_map: PrecompileCacheMap<SpecFor<Self>>,
388        metrics_enabled: bool,
389    ) -> EvmFor<'a, Self>
390    where
391        DB: Database + 'a,
392    {
393        self.executor_factory.build_evm_with_precompile_cache(
394            Db::new(db),
395            evm_env,
396            cache_map,
397            metrics_enabled,
398        )
399    }
400
401    fn jit_backend(&self) -> Option<&dyn reth_evm::JitBackend> {
402        #[cfg(feature = "jit")]
403        if let Some(factory) = (self.executor_factory.evm_factory() as &dyn Any)
404            .downcast_ref::<factory::RethEvmFactory>()
405        {
406            return Some(factory);
407        }
408
409        None
410    }
411
412    fn evm_env(&self, header: &Header) -> Result<EvmEnvFor<Self>, Self::Error> {
413        let spec = spec_id(self.chain_spec().as_ref(), header);
414        let blob_params = self.chain_spec().as_ref().blob_params_at_timestamp(header.timestamp);
415        Ok(self.evm_env_from_base_spec(
416            spec,
417            block_env_with_blob_params(header, blob_params),
418            blob_params,
419        ))
420    }
421
422    fn next_evm_env(
423        &self,
424        parent: &Header,
425        attributes: &NextBlockEnvAttributes,
426    ) -> Result<EvmEnvFor<Self>, Self::Error> {
427        let base_fee = self
428            .chain_spec()
429            .as_ref()
430            .next_block_base_fee(parent, attributes.timestamp)
431            .unwrap_or_default();
432        let blob_params = self.chain_spec().as_ref().blob_params_at_timestamp(attributes.timestamp);
433        let header = Header {
434            beneficiary: attributes.suggested_fee_recipient,
435            timestamp: attributes.timestamp,
436            number: parent.number + 1,
437            gas_limit: attributes.gas_limit,
438            base_fee_per_gas: Some(base_fee),
439            mix_hash: attributes.prev_randao,
440            slot_number: attributes.slot_number,
441            excess_blob_gas: parent
442                .maybe_next_block_excess_blob_gas(blob_params)
443                .or_else(|| blob_params.map(|_| 0)),
444            ..Default::default()
445        };
446
447        let spec = spec_id(self.chain_spec().as_ref(), &header);
448        Ok(self.evm_env_from_base_spec(
449            spec,
450            block_env_with_blob_params(&header, blob_params),
451            blob_params,
452        ))
453    }
454
455    fn context_for_block<'a>(
456        &self,
457        block: &'a SealedBlock<Block>,
458    ) -> Result<EthBlockExecutionCtx<'a>, Self::Error>
459    where
460        Self: 'a,
461    {
462        Ok(EthBlockExecutionCtx {
463            tx_count_hint: Some(block.transaction_count()),
464            parent_hash: block.header().parent_hash,
465            parent_beacon_block_root: block.header().parent_beacon_block_root,
466            ommers: &block.body().ommers,
467            withdrawals: block.body().withdrawals.as_ref().map(|w| Cow::Borrowed(w.as_slice())),
468            extra_data: block.header().extra_data.clone(),
469            slot_number: block.header().slot_number,
470        })
471    }
472
473    fn context_for_next_block(
474        &self,
475        parent: &SealedHeader,
476        attributes: Self::NextBlockEnvCtx,
477    ) -> Result<EthBlockExecutionCtx<'_>, Self::Error> {
478        Ok(EthBlockExecutionCtx {
479            tx_count_hint: None,
480            parent_hash: parent.hash(),
481            parent_beacon_block_root: attributes.parent_beacon_block_root,
482            ommers: &[],
483            withdrawals: attributes.withdrawals.map(|w| Cow::Owned(w.into_inner())),
484            extra_data: attributes.extra_data,
485            slot_number: attributes.slot_number,
486        })
487    }
488
489    fn reuses_prewarm_results(&self) -> bool {
490        // Custom factories may change transaction validation or read state outside the database.
491        let factory = TypeId::of::<EvmF>();
492        factory == TypeId::of::<factory::RethEvmFactory>()
493    }
494
495    #[cfg(feature = "std")]
496    fn prewarm_tx_result<'a>(
497        &self,
498        tx: &TransactionSigned,
499        result: reth_evm::TxResultWithStateFor<Self>,
500    ) -> Option<reth_evm::TxExecutionResultFor<'a, Self>>
501    where
502        Self: 'a,
503    {
504        Some(EthTransactionResultWithState::new(
505            result,
506            tx.tx_type(),
507            tx.blob_gas_used().unwrap_or_default(),
508        ))
509    }
510
511    fn speculative_next_evm_env(
512        &self,
513        parent: &SealedHeader,
514        beneficiary: Address,
515    ) -> Option<EvmEnvFor<Self>> {
516        let Ok(evm_env) = self.next_evm_env(
517            parent,
518            &NextBlockEnvAttributes {
519                timestamp: parent.timestamp + SLOT_DURATION_SECS,
520                suggested_fee_recipient: beneficiary,
521                prev_randao: B256::ZERO,
522                gas_limit: parent.gas_limit,
523                parent_beacon_block_root: None,
524                withdrawals: None,
525                extra_data: Bytes::new(),
526                slot_number: None,
527            },
528        );
529        Some(evm_env)
530    }
531}
532
533#[cfg(feature = "std")]
534impl<ChainSpec, EvmF> ConfigureEngineEvm<ExecutionData> for EthEvmConfig<ChainSpec, EvmF>
535where
536    ChainSpec: EthChainSpec<Header = Header> + EthereumHardforks + Hardforks + 'static,
537    EvmF: EvmFactory,
538    EvmF::Types: evm2::EvmTypes<Tx = evm2::ethereum::TxEnvelope>,
539{
540    fn evm_env_for_payload(&self, payload: &ExecutionData) -> Result<EvmEnvFor<Self>, Self::Error> {
541        let spec = spec_id_by_timestamp_and_block_number(
542            self.chain_spec().as_ref(),
543            payload.payload.timestamp(),
544            payload.payload.block_number(),
545        );
546        let blob_params =
547            self.chain_spec().as_ref().blob_params_at_timestamp(payload.payload.timestamp());
548        Ok(self.evm_env_from_base_spec(
549            spec,
550            payload_block_env(payload, spec, blob_params),
551            blob_params,
552        ))
553    }
554
555    fn context_for_payload<'a>(
556        &self,
557        payload: &'a ExecutionData,
558    ) -> Result<ExecutionCtxFor<'a, Self>, Self::Error> {
559        Ok(EthBlockExecutionCtx {
560            tx_count_hint: Some(payload.payload.transactions().len()),
561            parent_hash: payload.parent_hash(),
562            parent_beacon_block_root: payload.sidecar.parent_beacon_block_root(),
563            ommers: &[],
564            withdrawals: payload.payload.withdrawals().map(|w| Cow::Borrowed(w.as_slice())),
565            extra_data: payload.payload.as_v1().extra_data.clone(),
566            slot_number: payload.payload.as_v4().map(|v4| v4.slot_number),
567        })
568    }
569
570    fn tx_iterator_for_payload(
571        &self,
572        payload: &ExecutionData,
573    ) -> Result<impl ExecutableTxIterator<Self>, Self::Error> {
574        let txs = payload.payload.transactions().clone();
575        let sender_recovery_cache = self.sender_recovery_cache.clone();
576        let convert = move |tx: Bytes| {
577            let tx = TransactionSigned::decode_2718_exact(tx.as_ref()).map_err(AnyError::new)?;
578            let signer = if let Some(cache) = &sender_recovery_cache {
579                cache.recover(&tx)
580            } else {
581                tx.try_recover()
582            }
583            .map_err(AnyError::new)?;
584            Ok::<_, AnyError>(ExecutableRecoveredTx::new(tx.with_signer(signer)))
585        };
586
587        Ok((txs, convert))
588    }
589}
590
591#[cfg(test)]
592mod tests {
593    use super::*;
594    use alloy_eips::eip7825::MAX_TX_GAS_LIMIT_OSAKA;
595    use alloy_genesis::Genesis;
596    use alloy_primitives::U256;
597    use reth_chainspec::{Chain, ChainSpec};
598
599    #[test]
600    fn test_evm_env_for_header_uses_chain_blob_params() {
601        for update_fraction in [BlobParams::cancun().update_fraction, u128::from(u64::MAX) + 1] {
602            let mut chain_spec = ChainSpec::builder()
603                .chain(Chain::mainnet())
604                .genesis(Genesis::default())
605                .cancun_activated()
606                .build();
607            chain_spec.blob_params.cancun.update_fraction = update_fraction;
608            let blob_params = chain_spec.blob_params_at_timestamp(1).expect("cancun blob params");
609            let excess_blob_gas = 1_000_000;
610            let header = Header {
611                timestamp: 1,
612                excess_blob_gas: Some(excess_blob_gas),
613                ..Default::default()
614            };
615
616            let env = EthEvmConfig::new(Arc::new(chain_spec)).evm_env(&header).unwrap().block;
617
618            assert_eq!(env.blob_basefee, U256::from(blob_params.calc_blob_fee(excess_blob_gas)));
619        }
620    }
621
622    #[test]
623    fn test_transaction_validation_limits_tx_gas_limit_cap() {
624        let cap = |spec| {
625            EthEvmEnv::<evm2::BaseEvmTypes>::new(spec, Default::default(), 1)
626                .transaction_validation_limits()
627                .tx_gas_limit_cap
628        };
629
630        assert_eq!(cap(evm2::SpecId::PRAGUE), 0);
631        assert_eq!(cap(evm2::SpecId::OSAKA), MAX_TX_GAS_LIMIT_OSAKA);
632        assert_eq!(cap(evm2::SpecId::AMSTERDAM), evm2::constants::MAX_TX_TOTAL_GAS_LIMIT_AMSTERDAM);
633    }
634
635    #[derive(Debug, Clone)]
636    struct CustomFactory;
637
638    impl EvmFactory for CustomFactory {
639        type Types = evm2::BaseEvmTypes;
640        type SpecId = evm2::SpecId;
641
642        fn spec_id(&self, spec: evm2::SpecId) -> Self::SpecId {
643            spec
644        }
645
646        fn tx_registry(
647            &self,
648            spec: Self::SpecId,
649        ) -> evm2::registry::TxRegistry<Self::Types, evm2::TxResult<Self::Types>> {
650            evm2::ethereum::ethereum_tx_registry(spec)
651        }
652    }
653
654    #[test]
655    fn test_reuses_prewarm_results_only_for_known_factories() {
656        assert!(EthEvmConfig::mainnet().reuses_prewarm_results());
657        assert!(EthEvmConfig::new_with_evm_factory(
658            MAINNET.clone(),
659            factory::RethEvmFactory::default()
660        )
661        .reuses_prewarm_results());
662
663        assert!(!EthEvmConfig::new_with_evm_factory(MAINNET.clone(), CustomFactory)
664            .reuses_prewarm_results());
665    }
666
667    #[cfg(feature = "jit")]
668    #[test]
669    fn test_jit_support_updates_reth_factory() {
670        let evm_config =
671            EthEvmConfig::new_with_evm_factory(MAINNET.clone(), RethEvmFactory::disabled());
672
673        assert!(evm_config.jit_backend().is_some());
674        assert!(!evm_config.executor_factory.evm_factory().jit_support_enabled());
675
676        let jit_evm_config = evm_config.clone().with_jit_support();
677        assert!(jit_evm_config.executor_factory.evm_factory().jit_support_enabled());
678        assert!(!evm_config.executor_factory.evm_factory().jit_support_enabled());
679
680        let jit_evm_config = jit_evm_config.with_jit_support_enabled(false);
681        assert!(!jit_evm_config.executor_factory.evm_factory().jit_support_enabled());
682    }
683
684    #[cfg(feature = "jit")]
685    #[test]
686    fn test_jit_support_ignores_plain_factory() {
687        let evm_config = EthEvmConfig::new_with_evm_factory(MAINNET.clone(), CustomFactory);
688
689        assert!(evm_config.jit_backend().is_none());
690
691        let evm_config = evm_config.with_jit_support();
692        assert!(evm_config.jit_backend().is_none());
693    }
694}