Skip to main content

reth_rpc_eth_api/helpers/
call.rs

1//! Loads a pending block from database. Helper trait for `eth_` transaction, call and trace RPC
2//! methods.
3
4use core::fmt;
5
6use super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace};
7use crate::{
8    helpers::estimate::EstimateCall, FromEvmError, FullEthApiTypes, RpcBlock, RpcNodeCore,
9};
10use alloy_consensus::{transaction::TxHashRef, BlockHeader};
11use alloy_eips::eip2930::AccessListResult;
12use alloy_evm::overrides::{apply_block_overrides, apply_state_overrides, OverrideBlockHashes};
13use alloy_network::TransactionBuilder;
14use alloy_primitives::{Bytes, B256, U256};
15use alloy_rpc_types_eth::{
16    simulate::{SimBlock, SimulatePayload, SimulatedBlock},
17    state::{EvmOverrides, StateOverride},
18    BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo,
19};
20use futures::Future;
21use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
22use reth_errors::{ProviderError, RethError};
23use reth_evm::{
24    block::BlockExecutor, env::BlockEnvironment, execute::BlockBuilder, ConfigureEvm, Evm,
25    EvmEnvFor, EvmFor, HaltReasonFor, InspectorFor, TransactionEnvMut, TxEnvFor,
26};
27use reth_node_api::BlockBody;
28use reth_primitives_traits::Recovered;
29use reth_revm::{
30    cancelled::CancelOnDrop,
31    database::StateProviderDatabase,
32    db::{bal::EvmDatabaseError, State},
33};
34use reth_rpc_convert::{RpcConvert, RpcTxReq};
35use reth_rpc_eth_types::{
36    cache::db::StateProviderTraitObjWrapper,
37    error::{AsEthApiError, FromEthApiError},
38    simulate::{self, EthSimulateError},
39    EthApiError, StateCacheDb,
40};
41use reth_storage_api::{BlockIdReader, ProviderTx};
42use revm::{
43    context::Block,
44    context_interface::{result::ResultAndState, Cfg, Transaction},
45    Database, DatabaseCommit,
46};
47use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
48use std::collections::BTreeMap;
49use tracing::{trace, warn};
50
51/// Result type for `eth_simulateV1` RPC method.
52pub type SimulatedBlocksResult<N, E> = Result<Vec<SimulatedBlock<RpcBlock<N>>>, E>;
53
54/// Execution related functions for the [`EthApiServer`](crate::EthApiServer) trait in
55/// the `eth_` namespace.
56pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthApiTypes {
57    /// Estimate gas needed for execution of the `request` at the [`BlockId`].
58    fn estimate_gas_at(
59        &self,
60        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
61        at: BlockId,
62        overrides: EvmOverrides,
63    ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
64        EstimateCall::estimate_gas_at(self, request, at, overrides)
65    }
66
67    /// `eth_simulateV1` executes an arbitrary number of transactions on top of the requested state.
68    /// The transactions are packed into individual blocks. Overrides can be provided.
69    ///
70    /// See also: <https://github.com/ethereum/go-ethereum/pull/27720>
71    fn simulate_v1(
72        &self,
73        payload: SimulatePayload<RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>>,
74        block: Option<BlockId>,
75    ) -> impl Future<Output = SimulatedBlocksResult<Self::NetworkTypes, Self::Error>> + Send {
76        async move {
77            if payload.block_state_calls.len() > self.max_simulate_blocks() as usize {
78                return Err(EthApiError::other(EthSimulateError::TooManyBlocks).into())
79            }
80
81            let block = block.unwrap_or_default();
82
83            let SimulatePayload {
84                block_state_calls,
85                trace_transfers,
86                validation,
87                return_full_transactions,
88            } = payload;
89
90            if block_state_calls.is_empty() {
91                return Err(EthApiError::InvalidParams(String::from("calls are empty.")).into())
92            }
93
94            let _permit = self.acquire_owned_blocking_io().await;
95
96            let base_block = self
97                .recovered_block(block)
98                .await?
99                .ok_or_else(|| EthApiError::other(EthSimulateError::BlockNotFound { block }))?;
100            let parent = base_block.sealed_header().clone();
101            let max_simulate_blocks = self.max_simulate_blocks();
102
103            self.spawn_with_state_at_block(block, move |this, db| {
104                let state_provider = db.database.0 .0;
105                let mut db = State::builder()
106                    .with_database(StateProviderDatabase::new(&state_provider))
107                    .with_bundle_update()
108                    .build();
109                let mut parent = parent;
110
111                let chain_id = this.provider().chain_spec().chain_id();
112
113                // Validate block ordering and fill gaps with empty blocks so every entry has an
114                // explicit `number` and `time` override and the chain is contiguous (see the
115                // execution-apis spec note: "If the block number is increased more than 1 compared
116                // to the previous block, new empty blocks are generated in between.").
117                let block_state_calls = simulate::sanitize_chain(
118                    block_state_calls,
119                    &parent,
120                    chain_id,
121                    max_simulate_blocks,
122                )?;
123
124                let mut blocks: Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>> =
125                    Vec::with_capacity(block_state_calls.len());
126
127                let call_gas_limit = this.call_gas_limit();
128                let mut remaining_call_gas_limit = (call_gas_limit > 0).then_some(call_gas_limit);
129
130                for block in block_state_calls {
131                    let SimBlock { block_overrides, state_overrides, calls } = block;
132
133                    let attributes = this
134                        .pending_env_builder()
135                        .pending_env_attributes(&parent, block_overrides.as_ref())
136                        .map_err(Self::Error::from_eth_err)?;
137
138                    let mut evm_env = this
139                        .evm_config()
140                        .next_evm_env(&parent, &attributes)
141                        .map_err(RethError::other)
142                        .map_err(Self::Error::from_eth_err)?;
143
144                    // Always disable EIP-3607
145                    evm_env.cfg_env.disable_eip3607 = true;
146
147                    // EIP-7825's transaction gas cap is only active with Amsterdam's
148                    // regular/state-gas accounting.
149                    if !evm_env.cfg_env.is_amsterdam_eip8037_enabled() {
150                        evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
151                    }
152
153                    if !validation {
154                        // If not explicitly required, we disable nonce check <https://github.com/paradigmxyz/reth/issues/16108>
155                        evm_env.cfg_env.disable_nonce_check = true;
156                        evm_env.cfg_env.disable_base_fee = true;
157                        evm_env.block_env.inner_mut().basefee = 0;
158                    }
159
160                    // Set prevrandao to zero for simulated blocks by default,
161                    // matching spec behavior where MixDigest is zero-initialized.
162                    // If user provides an override, it will be applied by apply_block_overrides.
163                    evm_env.block_env.inner_mut().prevrandao = Some(B256::ZERO);
164                    if !this
165                        .provider()
166                        .chain_spec()
167                        .is_paris_active_at_block(evm_env.block_env.number().saturating_to())
168                    {
169                        evm_env.block_env.inner_mut().difficulty = parent.difficulty();
170                    }
171
172                    if let Some(block_overrides) = block_overrides {
173                        // ensure we don't allow uncapped gas limit per block
174                        if let Some(gas_limit_override) = block_overrides.gas_limit &&
175                            gas_limit_override > evm_env.block_env.gas_limit() &&
176                            gas_limit_override > this.call_gas_limit()
177                        {
178                            return Err(EthApiError::other(EthSimulateError::GasLimitReached).into())
179                        }
180                        apply_block_overrides(
181                            block_overrides,
182                            &mut db,
183                            evm_env.block_env.inner_mut(),
184                        );
185                    }
186                    if let Some(ref state_overrides) = state_overrides {
187                        apply_state_overrides(state_overrides.clone(), &mut db)
188                            .map_err(Self::Error::from_eth_err)?;
189                    }
190
191                    let chain_id = evm_env.cfg_env.chain_id;
192
193                    let ctx = this
194                        .evm_config()
195                        .context_for_next_block(&parent, attributes)
196                        .map_err(RethError::other)
197                        .map_err(Self::Error::from_eth_err)?;
198                    let map_err = |e: EthApiError| -> Self::Error {
199                        match e.as_simulate_error() {
200                            Some(sim_err) => Self::Error::from_eth_err(EthApiError::other(sim_err)),
201                            None => Self::Error::from_eth_err(e),
202                        }
203                    };
204
205                    let (result, results) = if trace_transfers {
206                        // prepare inspector to capture transfer inside the evm so they are recorded
207                        // and included in logs
208                        let inspector = TransferInspector::new(false).with_logs(true);
209                        let evm = this
210                            .evm_config()
211                            .evm_with_env_and_inspector(&mut db, evm_env, inspector);
212                        let mut builder = this.evm_config().create_block_builder(evm, &parent, ctx);
213
214                        if let Some(ref state_overrides) = state_overrides {
215                            simulate::apply_precompile_overrides(
216                                state_overrides,
217                                builder.evm_mut().precompiles_mut(),
218                            )
219                            .map_err(|e| Self::Error::from_eth_err(EthApiError::other(e)))?;
220                        }
221
222                        simulate::execute_transactions(
223                            builder,
224                            &state_provider,
225                            calls,
226                            &mut remaining_call_gas_limit,
227                            chain_id,
228                            this.compute_state_root_for_eth_simulate(),
229                            this.converter(),
230                        )
231                        .map_err(map_err)?
232                    } else {
233                        let evm = this.evm_config().evm_with_env(&mut db, evm_env);
234                        let mut builder = this.evm_config().create_block_builder(evm, &parent, ctx);
235
236                        if let Some(ref state_overrides) = state_overrides {
237                            simulate::apply_precompile_overrides(
238                                state_overrides,
239                                builder.evm_mut().precompiles_mut(),
240                            )
241                            .map_err(|e| Self::Error::from_eth_err(EthApiError::other(e)))?;
242                        }
243
244                        simulate::execute_transactions(
245                            builder,
246                            &state_provider,
247                            calls,
248                            &mut remaining_call_gas_limit,
249                            chain_id,
250                            this.compute_state_root_for_eth_simulate(),
251                            this.converter(),
252                        )
253                        .map_err(map_err)?
254                    };
255
256                    let simulated_header = result.block.clone_sealed_header();
257                    db.override_block_hashes(BTreeMap::from([(
258                        simulated_header.number(),
259                        simulated_header.hash(),
260                    )]));
261                    parent = simulated_header;
262
263                    let block = simulate::build_simulated_block::<Self::Error, _>(
264                        result.block,
265                        results,
266                        return_full_transactions.into(),
267                        this.converter(),
268                    )?;
269
270                    blocks.push(block);
271                }
272
273                Ok(blocks)
274            })
275            .await
276        }
277    }
278
279    /// Executes the call request (`eth_call`) and returns the output
280    fn call(
281        &self,
282        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
283        block_number: Option<BlockId>,
284        overrides: EvmOverrides,
285    ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
286        async move {
287            let _permit = self.acquire_owned_blocking_io().await;
288            let res =
289                self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
290
291            Self::Error::ensure_success(res.result)
292        }
293    }
294
295    /// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the
296    /// optionality of state overrides
297    fn call_many(
298        &self,
299        bundles: Vec<Bundle<RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>>>,
300        state_context: Option<StateContext>,
301        mut state_override: Option<StateOverride>,
302    ) -> impl Future<Output = Result<Vec<Vec<EthCallResponse>>, Self::Error>> + Send
303    where
304        Self: Trace,
305    {
306        async move {
307            // Check if the vector of bundles is empty
308            if bundles.is_empty() {
309                return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into());
310            }
311
312            let _permit = self.acquire_owned_blocking_io().await;
313
314            let StateContext { transaction_index, block_number } =
315                state_context.unwrap_or_default();
316            let transaction_index = transaction_index.unwrap_or_default();
317
318            let mut target_block = block_number.unwrap_or_default();
319            let is_block_target_pending = target_block.is_pending();
320
321            // if it's not pending, we should always use block_hash over block_number to ensure that
322            // different provider calls query data related to the same block.
323            if !is_block_target_pending {
324                let Some(block_hash) = self
325                    .provider()
326                    .block_hash_for_id(target_block)
327                    .map_err(Self::Error::from_eth_err::<ProviderError>)?
328                else {
329                    return Err(EthApiError::HeaderNotFound(target_block).into())
330                };
331                target_block = block_hash.into();
332            }
333
334            let block = self
335                .recovered_block(target_block)
336                .await?
337                .ok_or(EthApiError::HeaderNotFound(target_block))?;
338            let evm_env = self.evm_env_for_header(block.sealed_block().sealed_header())?;
339
340            // we're essentially replaying the transactions in the block here, hence we need the
341            // state that points to the beginning of the block, which is the state at
342            // the parent block
343            let mut at = block.parent_hash();
344            let mut replay_block_txs = true;
345
346            let num_txs =
347                transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
348            // but if all transactions are to be replayed, we can use the state at the block itself,
349            // however only if we're not targeting the pending block, because for pending we can't
350            // rely on the block's state being available
351            if !is_block_target_pending && num_txs == block.body().transactions().len() {
352                at = block.hash();
353                replay_block_txs = false;
354            }
355
356            self.spawn_with_state_at_block(at, move |this, mut db| {
357                let mut all_results = Vec::with_capacity(bundles.len());
358
359                if replay_block_txs {
360                    this.replay_block_until(&mut db, &block, num_txs)?;
361                }
362
363                // transact all bundles
364                for (bundle_index, bundle) in bundles.into_iter().enumerate() {
365                    let Bundle { transactions, block_override } = bundle;
366                    if transactions.is_empty() {
367                        // Skip empty bundles
368                        continue;
369                    }
370
371                    let mut bundle_results = Vec::with_capacity(transactions.len());
372                    let block_overrides = block_override.map(Box::new);
373
374                    // transact all transactions in the bundle
375                    for (tx_index, tx) in transactions.into_iter().enumerate() {
376                        // Apply overrides, state overrides are only applied for the first tx in the
377                        // request
378                        let overrides =
379                            EvmOverrides::new(state_override.take(), block_overrides.clone());
380
381                        let (current_evm_env, prepared_tx) = this
382                            .prepare_call_env(evm_env.clone(), tx, &mut db, overrides)
383                            .map_err(|err| {
384                                Self::Error::from_eth_err(EthApiError::call_many_error(
385                                    bundle_index,
386                                    tx_index,
387                                    err.into(),
388                                ))
389                            })?;
390                        let res = this.transact(&mut db, current_evm_env, prepared_tx).map_err(
391                            |err| {
392                                Self::Error::from_eth_err(EthApiError::call_many_error(
393                                    bundle_index,
394                                    tx_index,
395                                    err.into(),
396                                ))
397                            },
398                        )?;
399
400                        match Self::Error::ensure_success(res.result) {
401                            Ok(output) => {
402                                bundle_results
403                                    .push(EthCallResponse { value: Some(output), error: None });
404                            }
405                            Err(err) => {
406                                bundle_results.push(EthCallResponse {
407                                    value: None,
408                                    error: Some(err.to_string()),
409                                });
410                            }
411                        }
412
413                        // Commit state changes after each transaction to allow subsequent calls to
414                        // see the updates
415                        db.commit(res.state);
416                    }
417
418                    all_results.push(bundle_results);
419                }
420
421                Ok(all_results)
422            })
423            .await
424        }
425    }
426
427    /// Creates [`AccessListResult`] for the [`RpcTxReq`] at the given
428    /// [`BlockId`], or latest block.
429    fn create_access_list_at(
430        &self,
431        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
432        block_number: Option<BlockId>,
433        state_override: Option<StateOverride>,
434    ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
435    where
436        Self: Trace,
437    {
438        async move {
439            let block_id = block_number.unwrap_or_default();
440            let (evm_env, at) = self.evm_env_at(block_id).await?;
441
442            self.spawn_blocking_io_fut(async move |this| {
443                this.create_access_list_with(evm_env, at, request, state_override).await
444            })
445            .await
446        }
447    }
448
449    /// Creates [`AccessListResult`] for the [`RpcTxReq`] at the given
450    /// [`BlockId`].
451    fn create_access_list_with(
452        &self,
453        evm_env: EvmEnvFor<Self::Evm>,
454        at: BlockId,
455        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
456        state_override: Option<StateOverride>,
457    ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
458    where
459        Self: Trace,
460    {
461        self.spawn_with_state_at_block(at, |this, mut db| {
462            let initial = request.as_ref().access_list().cloned().unwrap_or_default();
463            let (evm_env, mut tx_env) = this.prepare_call_env(
464                evm_env,
465                request,
466                &mut db,
467                EvmOverrides::state(state_override),
468            )?;
469
470            let mut evm = this.evm_config().evm_with_env_and_inspector(
471                &mut db,
472                evm_env,
473                AccessListInspector::new(initial),
474            );
475
476            let result = evm.transact(tx_env.clone())?;
477            let access_list = core::mem::take(evm.inspector_mut()).into_access_list();
478            let gas_used = result.result.tx_gas_used();
479            tx_env.set_access_list(access_list.clone());
480            if let Err(err) = Self::Error::ensure_success(result.result) {
481                return Ok(AccessListResult {
482                    access_list,
483                    gas_used: U256::from(gas_used),
484                    error: Some(err.to_string()),
485                });
486            }
487
488            // transact again to get the exact gas used
489            evm.disable_inspector();
490            let result = evm.transact(tx_env)?;
491            let gas_used = result.result.tx_gas_used();
492            let error = Self::Error::ensure_success(result.result).err().map(|e| e.to_string());
493
494            Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
495        })
496    }
497}
498
499/// Executes code on state.
500pub trait Call:
501    LoadState<
502        RpcConvert: RpcConvert<Evm = Self::Evm>,
503        Error: FromEvmError<Self::Evm>
504                   + From<<Self::RpcConvert as RpcConvert>::Error>
505                   + From<ProviderError>,
506    > + SpawnBlocking
507{
508    /// Returns default gas limit to use for `eth_call` and tracing RPC methods.
509    ///
510    /// Data access in default trait method implementations.
511    fn call_gas_limit(&self) -> u64;
512
513    /// Returns the maximum number of blocks accepted for `eth_simulateV1`.
514    fn max_simulate_blocks(&self) -> u64;
515
516    /// Returns whether `eth_simulateV1` should compute state roots.
517    fn compute_state_root_for_eth_simulate(&self) -> bool;
518
519    /// Returns the maximum memory the EVM can allocate per RPC request.
520    fn evm_memory_limit(&self) -> u64;
521
522    /// Returns the max gas limit that the caller can afford given a transaction environment.
523    fn caller_gas_allowance(
524        &self,
525        mut db: impl Database<Error: Into<EthApiError>>,
526        _evm_env: &EvmEnvFor<Self::Evm>,
527        tx_env: &TxEnvFor<Self::Evm>,
528    ) -> Result<u64, Self::Error> {
529        alloy_evm::call::caller_gas_allowance(&mut db, tx_env).map_err(Self::Error::from_eth_err)
530    }
531
532    /// Executes the `TxEnv` against the given [Database] without committing state
533    /// changes.
534    fn transact<DB>(
535        &self,
536        db: DB,
537        evm_env: EvmEnvFor<Self::Evm>,
538        tx_env: TxEnvFor<Self::Evm>,
539    ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
540    where
541        DB: Database<Error = EvmDatabaseError<ProviderError>> + fmt::Debug,
542    {
543        let mut evm = self.evm_config().evm_with_env(db, evm_env);
544        let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
545
546        Ok(res)
547    }
548
549    /// Executes the [`reth_evm::EvmEnv`] against the given [Database] without committing state
550    /// changes.
551    fn transact_with_inspector<DB, I>(
552        &self,
553        db: DB,
554        evm_env: EvmEnvFor<Self::Evm>,
555        tx_env: TxEnvFor<Self::Evm>,
556        inspector: I,
557    ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
558    where
559        DB: Database<Error = EvmDatabaseError<ProviderError>> + fmt::Debug,
560        I: InspectorFor<Self::Evm, DB>,
561    {
562        let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, inspector);
563        let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
564
565        Ok(res)
566    }
567
568    /// Executes the call request at the given [`BlockId`].
569    ///
570    /// This spawns a new task that obtains the state for the given [`BlockId`] and then transacts
571    /// the call [`Self::transact`]. If the future is dropped before the (blocking) transact
572    /// call is invoked, then the task is cancelled early, (for example if the request is terminated
573    /// early client-side).
574    fn transact_call_at(
575        &self,
576        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
577        at: BlockId,
578        overrides: EvmOverrides,
579    ) -> impl Future<Output = Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>> + Send
580    where
581        Self: LoadPendingBlock,
582    {
583        async move {
584            let guard = CancelOnDrop::default();
585            let cancel = guard.clone();
586            let this = self.clone();
587
588            let res = self
589                .spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
590                    if cancel.is_cancelled() {
591                        // callsite dropped the guard
592                        return Err(EthApiError::InternalEthError.into())
593                    }
594                    this.transact(db, evm_env, tx_env)
595                })
596                .await;
597            drop(guard);
598            res
599        }
600    }
601
602    /// Executes the closure with the state that corresponds to the given [`BlockId`] on a new task
603    fn spawn_with_state_at_block<F, R>(
604        &self,
605        at: impl Into<BlockId>,
606        f: F,
607    ) -> impl Future<Output = Result<R, Self::Error>> + Send
608    where
609        F: FnOnce(Self, StateCacheDb) -> Result<R, Self::Error> + Send + 'static,
610        R: Send + 'static,
611    {
612        let at = at.into();
613        self.spawn_blocking_io_fut(async move |this| {
614            let state = this.state_at_block_id(at).await?;
615            let db = State::builder()
616                .with_database(StateProviderDatabase::new(StateProviderTraitObjWrapper(state)))
617                .build();
618            f(this, db)
619        })
620    }
621
622    /// Prepares the state and env for the given [`RpcTxReq`] at the given [`BlockId`] and
623    /// executes the closure on a new task returning the result of the closure.
624    ///
625    /// This returns the configured [`reth_evm::EvmEnv`] for the given [`RpcTxReq`] at
626    /// the given [`BlockId`] and with configured call settings: `prepare_call_env`.
627    ///
628    /// This is primarily used by `eth_call`.
629    ///
630    /// # Blocking behaviour
631    ///
632    /// This assumes executing the call is relatively more expensive on IO than CPU because it
633    /// transacts a single transaction on an empty in memory database. Because `eth_call`s are
634    /// usually allowed to consume a lot of gas, this also allows a lot of memory operations so
635    /// we assume this is not primarily CPU bound and instead spawn the call on a regular tokio task
636    /// instead, where blocking IO is less problematic.
637    fn spawn_with_call_at<F, R>(
638        &self,
639        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
640        at: BlockId,
641        overrides: EvmOverrides,
642        f: F,
643    ) -> impl Future<Output = Result<R, Self::Error>> + Send
644    where
645        Self: LoadPendingBlock,
646        F: FnOnce(
647                &mut StateCacheDb,
648                EvmEnvFor<Self::Evm>,
649                TxEnvFor<Self::Evm>,
650            ) -> Result<R, Self::Error>
651            + Send
652            + 'static,
653        R: Send + 'static,
654    {
655        async move {
656            let (evm_env, at) = self.evm_env_at(at).await?;
657            self.spawn_with_state_at_block(at, move |this, mut db| {
658                let (evm_env, tx_env) =
659                    this.prepare_call_env(evm_env, request, &mut db, overrides)?;
660
661                f(&mut db, evm_env, tx_env)
662            })
663            .await
664        }
665    }
666
667    /// Retrieves the transaction if it exists and executes it.
668    ///
669    /// Before the transaction is executed, all previous transaction in the block are applied to the
670    /// state by executing them first.
671    /// The callback `f` is invoked with the [`ResultAndState`] after the transaction was executed
672    /// and the database that points to the beginning of the transaction.
673    ///
674    /// Note: Implementers should use a threadpool where blocking is allowed, such as
675    /// [`BlockingTaskPool`](reth_tasks::pool::BlockingTaskPool).
676    fn spawn_replay_transaction<F, R>(
677        &self,
678        hash: B256,
679        f: F,
680    ) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
681    where
682        Self: LoadBlock + LoadTransaction,
683        F: FnOnce(
684                TransactionInfo,
685                ResultAndState<HaltReasonFor<Self::Evm>>,
686                StateCacheDb,
687            ) -> Result<R, Self::Error>
688            + Send
689            + 'static,
690        R: Send + 'static,
691    {
692        async move {
693            let (transaction, block) = match self.transaction_and_block(hash).await? {
694                None => return Ok(None),
695                Some(res) => res,
696            };
697            let (tx, tx_info) = transaction.split();
698
699            // we need to get the state of the parent block because we're essentially replaying the
700            // block the transaction is included in
701            let parent_block = block.parent_hash();
702
703            self.spawn_with_state_at_block(parent_block, move |this, mut db| {
704                let block_txs = block.transactions_recovered();
705
706                let mut executor = RpcNodeCore::evm_config(&this)
707                    .executor_for_block(&mut db, block.sealed_block())
708                    .map_err(RethError::other)
709                    .map_err(Self::Error::from_eth_err)?;
710                executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
711
712                // replay all transactions prior to the targeted transaction
713                for block_tx in block_txs {
714                    if block_tx.tx_hash() == tx.tx_hash() {
715                        break;
716                    }
717                    executor.execute_transaction(block_tx).map_err(Self::Error::from_eth_err)?;
718                }
719
720                let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
721
722                let res = executor.evm_mut().transact(tx_env).map_err(Self::Error::from_evm_err)?;
723                drop(executor);
724                f(tx_info, res, db)
725            })
726            .await
727            .map(Some)
728        }
729    }
730
731    /// Replays all transactions before the target transaction index on the given EVM.
732    ///
733    /// This executes on a caller provided EVM, so the target transaction can then be run on the
734    /// same EVM, keeping any block-scoped EVM state intact. The EVM's inspector configuration is
735    /// left untouched; see
736    /// [`Trace::inspect_transaction_in_block`] to replay without inspection and trace the target.
737    ///
738    /// If the target index is greater than or equal to the iterator length, all transactions are
739    /// replayed.
740    fn replay_transactions_until_with_evm<'a, DB, I, Txs>(
741        &self,
742        evm: &mut EvmFor<Self::Evm, DB, I>,
743        transactions: Txs,
744        target_tx_index: usize,
745    ) -> Result<(), Self::Error>
746    where
747        DB: Database<Error = EvmDatabaseError<ProviderError>> + DatabaseCommit + core::fmt::Debug,
748        I: InspectorFor<Self::Evm, DB>,
749        Txs: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
750    {
751        for (index, tx) in transactions.into_iter().enumerate() {
752            if index == target_tx_index {
753                // reached the target transaction
754                break
755            }
756
757            let tx_env = self.evm_config().tx_env(tx);
758            evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
759        }
760        Ok(())
761    }
762
763    ///
764    /// All `TxEnv` fields are derived from the given [`RpcTxReq`], if fields are
765    /// `None`, they fall back to the [`reth_evm::EvmEnv`]'s settings.
766    fn create_txn_env(
767        &self,
768        evm_env: &EvmEnvFor<Self::Evm>,
769        mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
770        mut db: impl Database<Error: Into<EthApiError>>,
771    ) -> Result<TxEnvFor<Self::Evm>, Self::Error> {
772        if request.as_ref().nonce().is_none() {
773            let nonce = db
774                .basic(request.as_ref().from().unwrap_or_default())
775                .map_err(Into::into)?
776                .map(|acc| acc.nonce)
777                .unwrap_or_default();
778            request.as_mut().set_nonce(nonce);
779        }
780
781        Ok(self.converter().tx_env(request, evm_env)?)
782    }
783
784    /// Prepares the [`reth_evm::EvmEnv`] for execution of calls.
785    ///
786    /// Does not commit any changes to the underlying database.
787    ///
788    /// ## EVM settings
789    ///
790    /// This modifies certain EVM settings to mirror geth's `SkipAccountChecks` when transacting requests, see also: <https://github.com/ethereum/go-ethereum/blob/380688c636a654becc8f114438c2a5d93d2db032/core/state_transition.go#L145-L148>:
791    ///
792    ///  - `disable_eip3607` is set to `true`
793    ///  - `disable_base_fee` is set to `true`
794    ///  - `nonce` is set to `None`
795    ///
796    /// In addition, this changes the block's gas limit to the configured [`Self::call_gas_limit`].
797    #[expect(clippy::type_complexity)]
798    fn prepare_call_env<DB>(
799        &self,
800        mut evm_env: EvmEnvFor<Self::Evm>,
801        mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
802        db: &mut DB,
803        overrides: EvmOverrides,
804    ) -> Result<(EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>), Self::Error>
805    where
806        DB: Database + DatabaseCommit + OverrideBlockHashes,
807        EthApiError: From<<DB as Database>::Error>,
808    {
809        // track whether the request has a gas limit set
810        let request_has_gas_limit = request.as_ref().gas_limit().is_some();
811
812        if let Some(requested_gas) = request.as_ref().gas_limit() {
813            let global_gas_cap = self.call_gas_limit();
814            if global_gas_cap != 0 && global_gas_cap < requested_gas {
815                warn!(target: "rpc::eth::call", ?request, ?global_gas_cap, "Capping gas limit to global gas cap");
816                request.as_mut().set_gas_limit(global_gas_cap);
817            }
818        } else {
819            // cap request's gas limit to call gas limit
820            request.as_mut().set_gas_limit(self.call_gas_limit());
821        }
822
823        // Disable block gas limit check to allow executing transactions with higher gas limit (call
824        // gas limit): https://github.com/paradigmxyz/reth/issues/18577
825        evm_env.cfg_env.disable_block_gas_limit = true;
826
827        // Disabled because eth_call is sometimes used with eoa senders
828        // See <https://github.com/paradigmxyz/reth/issues/1959>
829        evm_env.cfg_env.disable_eip3607 = true;
830
831        // The basefee should be ignored for eth_call
832        // See:
833        // <https://github.com/ethereum/go-ethereum/blob/ee8e83fa5f6cb261dad2ed0a7bbcde4930c41e6c/internal/ethapi/api.go#L985>
834        evm_env.cfg_env.disable_base_fee = true;
835
836        // Disable EIP-7825 transaction gas limit to support larger transactions
837        evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
838
839        // Disable additional fee charges, e.g. opstack operator fee charge
840        // See:
841        // <https://github.com/paradigmxyz/reth/issues/18470>
842        evm_env.cfg_env.disable_fee_charge = true;
843
844        evm_env.cfg_env.memory_limit = self.evm_memory_limit();
845
846        // set nonce to None so that the correct nonce is chosen by the EVM
847        request.as_mut().take_nonce();
848
849        if let Some(block_overrides) = overrides.block {
850            apply_block_overrides(*block_overrides, db, evm_env.block_env.inner_mut());
851        }
852        if let Some(state_overrides) = overrides.state {
853            apply_state_overrides(state_overrides, db)
854                .map_err(EthApiError::from_state_overrides_err)?;
855        }
856
857        let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
858
859        // lower the basefee to 0 to avoid breaking EVM invariants (basefee < gasprice): <https://github.com/ethereum/go-ethereum/blob/355228b011ef9a85ebc0f21e7196f892038d49f0/internal/ethapi/api.go#L700-L704>
860        if tx_env.gas_price() == 0 {
861            evm_env.block_env.inner_mut().basefee = 0;
862        }
863
864        if !request_has_gas_limit {
865            // No gas limit was provided in the request, so we need to cap the transaction gas limit
866            if tx_env.gas_price() > 0 {
867                // If gas price is specified, cap transaction gas limit with caller allowance
868                trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
869                let cap = self.caller_gas_allowance(db, &evm_env, &tx_env)?;
870                // ensure we cap gas_limit to the block's
871                tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit()));
872            }
873        }
874
875        Ok((evm_env, tx_env))
876    }
877}