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, 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, StateProviderBox};
42use revm::{
43    context::Block,
44    context_interface::{result::ResultAndState, 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                    if !validation {
148                        // If not explicitly required, we disable nonce check <https://github.com/paradigmxyz/reth/issues/16108>
149                        evm_env.cfg_env.disable_nonce_check = true;
150                        evm_env.cfg_env.disable_base_fee = true;
151                        evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
152                        evm_env.block_env.inner_mut().basefee = 0;
153                    }
154
155                    // Set prevrandao to zero for simulated blocks by default,
156                    // matching spec behavior where MixDigest is zero-initialized.
157                    // If user provides an override, it will be applied by apply_block_overrides.
158                    evm_env.block_env.inner_mut().prevrandao = Some(B256::ZERO);
159                    if !this
160                        .provider()
161                        .chain_spec()
162                        .is_paris_active_at_block(evm_env.block_env.number().saturating_to())
163                    {
164                        evm_env.block_env.inner_mut().difficulty = parent.difficulty();
165                    }
166
167                    if let Some(block_overrides) = block_overrides {
168                        // ensure we don't allow uncapped gas limit per block
169                        if let Some(gas_limit_override) = block_overrides.gas_limit &&
170                            gas_limit_override > evm_env.block_env.gas_limit() &&
171                            gas_limit_override > this.call_gas_limit()
172                        {
173                            return Err(EthApiError::other(EthSimulateError::GasLimitReached).into())
174                        }
175                        apply_block_overrides(
176                            block_overrides,
177                            &mut db,
178                            evm_env.block_env.inner_mut(),
179                        );
180                    }
181                    if let Some(ref state_overrides) = state_overrides {
182                        apply_state_overrides(state_overrides.clone(), &mut db)
183                            .map_err(Self::Error::from_eth_err)?;
184                    }
185
186                    let chain_id = evm_env.cfg_env.chain_id;
187
188                    let ctx = this
189                        .evm_config()
190                        .context_for_next_block(&parent, attributes)
191                        .map_err(RethError::other)
192                        .map_err(Self::Error::from_eth_err)?;
193                    let map_err = |e: EthApiError| -> Self::Error {
194                        match e.as_simulate_error() {
195                            Some(sim_err) => Self::Error::from_eth_err(EthApiError::other(sim_err)),
196                            None => Self::Error::from_eth_err(e),
197                        }
198                    };
199
200                    let (result, results) = if trace_transfers {
201                        // prepare inspector to capture transfer inside the evm so they are recorded
202                        // and included in logs
203                        let inspector = TransferInspector::new(false).with_logs(true);
204                        let evm = this
205                            .evm_config()
206                            .evm_with_env_and_inspector(&mut db, evm_env, inspector);
207                        let mut builder = this.evm_config().create_block_builder(evm, &parent, ctx);
208
209                        if let Some(ref state_overrides) = state_overrides {
210                            simulate::apply_precompile_overrides(
211                                state_overrides,
212                                builder.evm_mut().precompiles_mut(),
213                            )
214                            .map_err(|e| Self::Error::from_eth_err(EthApiError::other(e)))?;
215                        }
216
217                        simulate::execute_transactions(
218                            builder,
219                            &state_provider,
220                            calls,
221                            &mut remaining_call_gas_limit,
222                            chain_id,
223                            this.compute_state_root_for_eth_simulate(),
224                            this.converter(),
225                        )
226                        .map_err(map_err)?
227                    } else {
228                        let evm = this.evm_config().evm_with_env(&mut db, evm_env);
229                        let mut builder = this.evm_config().create_block_builder(evm, &parent, ctx);
230
231                        if let Some(ref state_overrides) = state_overrides {
232                            simulate::apply_precompile_overrides(
233                                state_overrides,
234                                builder.evm_mut().precompiles_mut(),
235                            )
236                            .map_err(|e| Self::Error::from_eth_err(EthApiError::other(e)))?;
237                        }
238
239                        simulate::execute_transactions(
240                            builder,
241                            &state_provider,
242                            calls,
243                            &mut remaining_call_gas_limit,
244                            chain_id,
245                            this.compute_state_root_for_eth_simulate(),
246                            this.converter(),
247                        )
248                        .map_err(map_err)?
249                    };
250
251                    let simulated_header = result.block.clone_sealed_header();
252                    db.override_block_hashes(BTreeMap::from([(
253                        simulated_header.number(),
254                        simulated_header.hash(),
255                    )]));
256                    parent = simulated_header;
257
258                    let block = simulate::build_simulated_block::<Self::Error, _>(
259                        result.block,
260                        results,
261                        return_full_transactions.into(),
262                        this.converter(),
263                    )?;
264
265                    blocks.push(block);
266                }
267
268                Ok(blocks)
269            })
270            .await
271        }
272    }
273
274    /// Executes the call request (`eth_call`) and returns the output
275    fn call(
276        &self,
277        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
278        block_number: Option<BlockId>,
279        overrides: EvmOverrides,
280    ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
281        async move {
282            let _permit = self.acquire_owned_blocking_io().await;
283            let res =
284                self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
285
286            Self::Error::ensure_success(res.result)
287        }
288    }
289
290    /// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the
291    /// optionality of state overrides
292    fn call_many(
293        &self,
294        bundles: Vec<Bundle<RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>>>,
295        state_context: Option<StateContext>,
296        mut state_override: Option<StateOverride>,
297    ) -> impl Future<Output = Result<Vec<Vec<EthCallResponse>>, Self::Error>> + Send {
298        async move {
299            // Check if the vector of bundles is empty
300            if bundles.is_empty() {
301                return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into());
302            }
303
304            let _permit = self.acquire_owned_blocking_io().await;
305
306            let StateContext { transaction_index, block_number } =
307                state_context.unwrap_or_default();
308            let transaction_index = transaction_index.unwrap_or_default();
309
310            let mut target_block = block_number.unwrap_or_default();
311            let is_block_target_pending = target_block.is_pending();
312
313            // if it's not pending, we should always use block_hash over block_number to ensure that
314            // different provider calls query data related to the same block.
315            if !is_block_target_pending {
316                let Some(block_hash) = self
317                    .provider()
318                    .block_hash_for_id(target_block)
319                    .map_err(Self::Error::from_eth_err::<ProviderError>)?
320                else {
321                    return Err(EthApiError::HeaderNotFound(target_block).into())
322                };
323                target_block = block_hash.into();
324            }
325
326            let block = self
327                .recovered_block(target_block)
328                .await?
329                .ok_or(EthApiError::HeaderNotFound(target_block))?;
330            let evm_env = self.evm_env_for_header(block.sealed_block().sealed_header())?;
331
332            // we're essentially replaying the transactions in the block here, hence we need the
333            // state that points to the beginning of the block, which is the state at
334            // the parent block
335            let mut at = block.parent_hash();
336            let mut replay_block_txs = true;
337
338            let num_txs =
339                transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
340            // but if all transactions are to be replayed, we can use the state at the block itself,
341            // however only if we're not targeting the pending block, because for pending we can't
342            // rely on the block's state being available
343            if !is_block_target_pending && num_txs == block.body().transactions().len() {
344                at = block.hash();
345                replay_block_txs = false;
346            }
347
348            self.spawn_with_state_at_block(at, move |this, mut db| {
349                let mut all_results = Vec::with_capacity(bundles.len());
350
351                if replay_block_txs {
352                    let mut executor = RpcNodeCore::evm_config(&this)
353                        .executor_for_block(&mut db, block.sealed_block())
354                        .map_err(RethError::other)
355                        .map_err(Self::Error::from_eth_err)?;
356                    executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
357                    for tx in block.transactions_recovered().take(num_txs) {
358                        executor.execute_transaction(tx).map_err(Self::Error::from_eth_err)?;
359                    }
360                }
361
362                // transact all bundles
363                for (bundle_index, bundle) in bundles.into_iter().enumerate() {
364                    let Bundle { transactions, block_override } = bundle;
365                    if transactions.is_empty() {
366                        // Skip empty bundles
367                        continue;
368                    }
369
370                    let mut bundle_results = Vec::with_capacity(transactions.len());
371                    let block_overrides = block_override.map(Box::new);
372
373                    // transact all transactions in the bundle
374                    for (tx_index, tx) in transactions.into_iter().enumerate() {
375                        // Apply overrides, state overrides are only applied for the first tx in the
376                        // request
377                        let overrides =
378                            EvmOverrides::new(state_override.take(), block_overrides.clone());
379
380                        let (current_evm_env, prepared_tx) = this
381                            .prepare_call_env(evm_env.clone(), tx, &mut db, overrides)
382                            .map_err(|err| {
383                                Self::Error::from_eth_err(EthApiError::call_many_error(
384                                    bundle_index,
385                                    tx_index,
386                                    err.into(),
387                                ))
388                            })?;
389                        let res = this.transact(&mut db, current_evm_env, prepared_tx).map_err(
390                            |err| {
391                                Self::Error::from_eth_err(EthApiError::call_many_error(
392                                    bundle_index,
393                                    tx_index,
394                                    err.into(),
395                                ))
396                            },
397                        )?;
398
399                        match Self::Error::ensure_success(res.result) {
400                            Ok(output) => {
401                                bundle_results
402                                    .push(EthCallResponse { value: Some(output), error: None });
403                            }
404                            Err(err) => {
405                                bundle_results.push(EthCallResponse {
406                                    value: None,
407                                    error: Some(err.to_string()),
408                                });
409                            }
410                        }
411
412                        // Commit state changes after each transaction to allow subsequent calls to
413                        // see the updates
414                        db.commit(res.state);
415                    }
416
417                    all_results.push(bundle_results);
418                }
419
420                Ok(all_results)
421            })
422            .await
423        }
424    }
425
426    /// Creates [`AccessListResult`] for the [`RpcTxReq`] at the given
427    /// [`BlockId`], or latest block.
428    fn create_access_list_at(
429        &self,
430        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
431        block_number: Option<BlockId>,
432        state_override: Option<StateOverride>,
433    ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
434    where
435        Self: Trace,
436    {
437        async move {
438            let block_id = block_number.unwrap_or_default();
439            let (evm_env, at) = self.evm_env_at(block_id).await?;
440
441            self.spawn_blocking_io_fut(async move |this| {
442                this.create_access_list_with(evm_env, at, request, state_override).await
443            })
444            .await
445        }
446    }
447
448    /// Creates [`AccessListResult`] for the [`RpcTxReq`] at the given
449    /// [`BlockId`].
450    fn create_access_list_with(
451        &self,
452        mut evm_env: EvmEnvFor<Self::Evm>,
453        at: BlockId,
454        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
455        state_override: Option<StateOverride>,
456    ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
457    where
458        Self: Trace,
459    {
460        self.spawn_blocking_io_fut(async move |this| {
461            let state = this.state_at_block_id(at).await?;
462            let mut db = State::builder().with_database(StateProviderDatabase::new(state)).build();
463
464            if let Some(state_overrides) = state_override {
465                apply_state_overrides(state_overrides, &mut db)
466                    .map_err(Self::Error::from_eth_err)?;
467            }
468
469            // Read fields from request before consuming it in create_txn_env
470            let request_has_gas_limit = request.as_ref().gas_limit().is_some();
471            let initial = request.as_ref().access_list().cloned().unwrap_or_default();
472
473            let mut tx_env = this.create_txn_env(&evm_env, request, &mut db)?;
474
475            // we want to disable this in eth_createAccessList, since this is common practice used
476            // by other node impls and providers <https://github.com/foundry-rs/foundry/issues/4388>
477            evm_env.cfg_env.disable_block_gas_limit = true;
478
479            // The basefee should be ignored for eth_createAccessList
480            // See:
481            // <https://github.com/ethereum/go-ethereum/blob/8990c92aea01ca07801597b00c0d83d4e2d9b811/internal/ethapi/api.go#L1476-L1476>
482            evm_env.cfg_env.disable_base_fee = true;
483
484            // Disabled because eth_createAccessList is sometimes used with non-eoa senders
485            evm_env.cfg_env.disable_eip3607 = true;
486
487            // Disable additional fee charges (e.g. L2 operator fees),
488            // consistent with prepare_call_env and estimate_gas_with.
489            evm_env.cfg_env.disable_fee_charge = true;
490
491            // Disable EIP-7825 transaction gas limit cap so that the gas limit
492            // fallback (block gas limit) is not rejected when it exceeds the
493            // per-tx cap (2^24 ≈ 16.7M post-Osaka).
494            evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
495
496            if !request_has_gas_limit && tx_env.gas_price() > 0 {
497                let cap = this.caller_gas_allowance(&mut db, &evm_env, &tx_env)?;
498                // no gas limit was provided in the request, so we need to cap the request's gas
499                // limit
500                tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit()));
501            }
502
503            let mut inspector = AccessListInspector::new(initial);
504
505            let result = this.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
506            let access_list = inspector.into_access_list();
507            let gas_used = result.result.tx_gas_used();
508            tx_env.set_access_list(access_list.clone());
509            if let Err(err) = Self::Error::ensure_success(result.result) {
510                return Ok(AccessListResult {
511                    access_list,
512                    gas_used: U256::from(gas_used),
513                    error: Some(err.to_string()),
514                });
515            }
516
517            // transact again to get the exact gas used
518            let result = this.transact(&mut db, evm_env, tx_env)?;
519            let gas_used = result.result.tx_gas_used();
520            let error = Self::Error::ensure_success(result.result).err().map(|e| e.to_string());
521
522            Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
523        })
524    }
525}
526
527/// Executes code on state.
528pub trait Call:
529    LoadState<
530        RpcConvert: RpcConvert<Evm = Self::Evm>,
531        Error: FromEvmError<Self::Evm>
532                   + From<<Self::RpcConvert as RpcConvert>::Error>
533                   + From<ProviderError>,
534    > + SpawnBlocking
535{
536    /// Returns default gas limit to use for `eth_call` and tracing RPC methods.
537    ///
538    /// Data access in default trait method implementations.
539    fn call_gas_limit(&self) -> u64;
540
541    /// Returns the maximum number of blocks accepted for `eth_simulateV1`.
542    fn max_simulate_blocks(&self) -> u64;
543
544    /// Returns whether `eth_simulateV1` should compute state roots.
545    fn compute_state_root_for_eth_simulate(&self) -> bool;
546
547    /// Returns the maximum memory the EVM can allocate per RPC request.
548    fn evm_memory_limit(&self) -> u64;
549
550    /// Returns the max gas limit that the caller can afford given a transaction environment.
551    fn caller_gas_allowance(
552        &self,
553        mut db: impl Database<Error: Into<EthApiError>>,
554        _evm_env: &EvmEnvFor<Self::Evm>,
555        tx_env: &TxEnvFor<Self::Evm>,
556    ) -> Result<u64, Self::Error> {
557        alloy_evm::call::caller_gas_allowance(&mut db, tx_env).map_err(Self::Error::from_eth_err)
558    }
559
560    /// Executes the closure with the state that corresponds to the given [`BlockId`].
561    fn with_state_at_block<F, R>(
562        &self,
563        at: BlockId,
564        f: F,
565    ) -> impl Future<Output = Result<R, Self::Error>> + Send
566    where
567        R: Send + 'static,
568        F: FnOnce(Self, StateProviderBox) -> Result<R, Self::Error> + Send + 'static,
569    {
570        self.spawn_blocking_io_fut(async move |this| {
571            let state = this.state_at_block_id(at).await?;
572            f(this, state)
573        })
574    }
575
576    /// Executes the `TxEnv` against the given [Database] without committing state
577    /// changes.
578    fn transact<DB>(
579        &self,
580        db: DB,
581        evm_env: EvmEnvFor<Self::Evm>,
582        tx_env: TxEnvFor<Self::Evm>,
583    ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
584    where
585        DB: Database<Error = EvmDatabaseError<ProviderError>> + fmt::Debug,
586    {
587        let mut evm = self.evm_config().evm_with_env(db, evm_env);
588        let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
589
590        Ok(res)
591    }
592
593    /// Executes the [`reth_evm::EvmEnv`] against the given [Database] without committing state
594    /// changes.
595    fn transact_with_inspector<DB, I>(
596        &self,
597        db: DB,
598        evm_env: EvmEnvFor<Self::Evm>,
599        tx_env: TxEnvFor<Self::Evm>,
600        inspector: I,
601    ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
602    where
603        DB: Database<Error = EvmDatabaseError<ProviderError>> + fmt::Debug,
604        I: InspectorFor<Self::Evm, DB>,
605    {
606        let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, inspector);
607        let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
608
609        Ok(res)
610    }
611
612    /// Executes the call request at the given [`BlockId`].
613    ///
614    /// This spawns a new task that obtains the state for the given [`BlockId`] and then transacts
615    /// the call [`Self::transact`]. If the future is dropped before the (blocking) transact
616    /// call is invoked, then the task is cancelled early, (for example if the request is terminated
617    /// early client-side).
618    fn transact_call_at(
619        &self,
620        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
621        at: BlockId,
622        overrides: EvmOverrides,
623    ) -> impl Future<Output = Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>> + Send
624    where
625        Self: LoadPendingBlock,
626    {
627        async move {
628            let guard = CancelOnDrop::default();
629            let cancel = guard.clone();
630            let this = self.clone();
631
632            let res = self
633                .spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
634                    if cancel.is_cancelled() {
635                        // callsite dropped the guard
636                        return Err(EthApiError::InternalEthError.into())
637                    }
638                    this.transact(db, evm_env, tx_env)
639                })
640                .await;
641            drop(guard);
642            res
643        }
644    }
645
646    /// Executes the closure with the state that corresponds to the given [`BlockId`] on a new task
647    fn spawn_with_state_at_block<F, R>(
648        &self,
649        at: impl Into<BlockId>,
650        f: F,
651    ) -> impl Future<Output = Result<R, Self::Error>> + Send
652    where
653        F: FnOnce(Self, StateCacheDb) -> Result<R, Self::Error> + Send + 'static,
654        R: Send + 'static,
655    {
656        let at = at.into();
657        self.spawn_blocking_io_fut(async move |this| {
658            let state = this.state_at_block_id(at).await?;
659            let db = State::builder()
660                .with_database(StateProviderDatabase::new(StateProviderTraitObjWrapper(state)))
661                .build();
662            f(this, db)
663        })
664    }
665
666    /// Prepares the state and env for the given [`RpcTxReq`] at the given [`BlockId`] and
667    /// executes the closure on a new task returning the result of the closure.
668    ///
669    /// This returns the configured [`reth_evm::EvmEnv`] for the given [`RpcTxReq`] at
670    /// the given [`BlockId`] and with configured call settings: `prepare_call_env`.
671    ///
672    /// This is primarily used by `eth_call`.
673    ///
674    /// # Blocking behaviour
675    ///
676    /// This assumes executing the call is relatively more expensive on IO than CPU because it
677    /// transacts a single transaction on an empty in memory database. Because `eth_call`s are
678    /// usually allowed to consume a lot of gas, this also allows a lot of memory operations so
679    /// we assume this is not primarily CPU bound and instead spawn the call on a regular tokio task
680    /// instead, where blocking IO is less problematic.
681    fn spawn_with_call_at<F, R>(
682        &self,
683        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
684        at: BlockId,
685        overrides: EvmOverrides,
686        f: F,
687    ) -> impl Future<Output = Result<R, Self::Error>> + Send
688    where
689        Self: LoadPendingBlock,
690        F: FnOnce(
691                &mut StateCacheDb,
692                EvmEnvFor<Self::Evm>,
693                TxEnvFor<Self::Evm>,
694            ) -> Result<R, Self::Error>
695            + Send
696            + 'static,
697        R: Send + 'static,
698    {
699        async move {
700            let (evm_env, at) = self.evm_env_at(at).await?;
701            self.spawn_with_state_at_block(at, move |this, mut db| {
702                let (evm_env, tx_env) =
703                    this.prepare_call_env(evm_env, request, &mut db, overrides)?;
704
705                f(&mut db, evm_env, tx_env)
706            })
707            .await
708        }
709    }
710
711    /// Retrieves the transaction if it exists and executes it.
712    ///
713    /// Before the transaction is executed, all previous transaction in the block are applied to the
714    /// state by executing them first.
715    /// The callback `f` is invoked with the [`ResultAndState`] after the transaction was executed
716    /// and the database that points to the beginning of the transaction.
717    ///
718    /// Note: Implementers should use a threadpool where blocking is allowed, such as
719    /// [`BlockingTaskPool`](reth_tasks::pool::BlockingTaskPool).
720    fn spawn_replay_transaction<F, R>(
721        &self,
722        hash: B256,
723        f: F,
724    ) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
725    where
726        Self: LoadBlock + LoadTransaction,
727        F: FnOnce(
728                TransactionInfo,
729                ResultAndState<HaltReasonFor<Self::Evm>>,
730                StateCacheDb,
731            ) -> Result<R, Self::Error>
732            + Send
733            + 'static,
734        R: Send + 'static,
735    {
736        async move {
737            let (transaction, block) = match self.transaction_and_block(hash).await? {
738                None => return Ok(None),
739                Some(res) => res,
740            };
741            let (tx, tx_info) = transaction.split();
742
743            // we need to get the state of the parent block because we're essentially replaying the
744            // block the transaction is included in
745            let parent_block = block.parent_hash();
746
747            self.spawn_with_state_at_block(parent_block, move |this, mut db| {
748                let block_txs = block.transactions_recovered();
749
750                let mut executor = RpcNodeCore::evm_config(&this)
751                    .executor_for_block(&mut db, block.sealed_block())
752                    .map_err(RethError::other)
753                    .map_err(Self::Error::from_eth_err)?;
754                executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
755
756                // replay all transactions prior to the targeted transaction
757                for block_tx in block_txs {
758                    if block_tx.tx_hash() == tx.tx_hash() {
759                        break;
760                    }
761                    executor.execute_transaction(block_tx).map_err(Self::Error::from_eth_err)?;
762                }
763
764                let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
765
766                let res = executor.evm_mut().transact(tx_env).map_err(Self::Error::from_evm_err)?;
767                drop(executor);
768                f(tx_info, res, db)
769            })
770            .await
771            .map(Some)
772        }
773    }
774
775    /// Replays all the transactions until the target transaction is found.
776    ///
777    /// All transactions before the target transaction are executed and their changes are written to
778    /// the _runtime_ db ([`State`]).
779    ///
780    /// Note: This assumes the target transaction is in the given iterator.
781    /// Returns the index of the target transaction in the given iterator.
782    fn replay_transactions_until<'a, DB, I>(
783        &self,
784        db: &mut DB,
785        evm_env: EvmEnvFor<Self::Evm>,
786        transactions: I,
787        target_tx_hash: B256,
788    ) -> Result<usize, Self::Error>
789    where
790        DB: Database<Error = EvmDatabaseError<ProviderError>> + DatabaseCommit + core::fmt::Debug,
791        I: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
792    {
793        let mut evm = self.evm_config().evm_with_env(db, evm_env);
794        let mut index = 0;
795        for tx in transactions {
796            if *tx.tx_hash() == target_tx_hash {
797                // reached the target transaction
798                break
799            }
800
801            let tx_env = self.evm_config().tx_env(tx);
802            evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
803            index += 1;
804        }
805        Ok(index)
806    }
807
808    ///
809    /// All `TxEnv` fields are derived from the given [`RpcTxReq`], if fields are
810    /// `None`, they fall back to the [`reth_evm::EvmEnv`]'s settings.
811    fn create_txn_env(
812        &self,
813        evm_env: &EvmEnvFor<Self::Evm>,
814        mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
815        mut db: impl Database<Error: Into<EthApiError>>,
816    ) -> Result<TxEnvFor<Self::Evm>, Self::Error> {
817        if request.as_ref().nonce().is_none() {
818            let nonce = db
819                .basic(request.as_ref().from().unwrap_or_default())
820                .map_err(Into::into)?
821                .map(|acc| acc.nonce)
822                .unwrap_or_default();
823            request.as_mut().set_nonce(nonce);
824        }
825
826        Ok(self.converter().tx_env(request, evm_env)?)
827    }
828
829    /// Prepares the [`reth_evm::EvmEnv`] for execution of calls.
830    ///
831    /// Does not commit any changes to the underlying database.
832    ///
833    /// ## EVM settings
834    ///
835    /// 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>:
836    ///
837    ///  - `disable_eip3607` is set to `true`
838    ///  - `disable_base_fee` is set to `true`
839    ///  - `nonce` is set to `None`
840    ///
841    /// In addition, this changes the block's gas limit to the configured [`Self::call_gas_limit`].
842    #[expect(clippy::type_complexity)]
843    fn prepare_call_env<DB>(
844        &self,
845        mut evm_env: EvmEnvFor<Self::Evm>,
846        mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
847        db: &mut DB,
848        overrides: EvmOverrides,
849    ) -> Result<(EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>), Self::Error>
850    where
851        DB: Database + DatabaseCommit + OverrideBlockHashes,
852        EthApiError: From<<DB as Database>::Error>,
853    {
854        // track whether the request has a gas limit set
855        let request_has_gas_limit = request.as_ref().gas_limit().is_some();
856
857        if let Some(requested_gas) = request.as_ref().gas_limit() {
858            let global_gas_cap = self.call_gas_limit();
859            if global_gas_cap != 0 && global_gas_cap < requested_gas {
860                warn!(target: "rpc::eth::call", ?request, ?global_gas_cap, "Capping gas limit to global gas cap");
861                request.as_mut().set_gas_limit(global_gas_cap);
862            }
863        } else {
864            // cap request's gas limit to call gas limit
865            request.as_mut().set_gas_limit(self.call_gas_limit());
866        }
867
868        // Disable block gas limit check to allow executing transactions with higher gas limit (call
869        // gas limit): https://github.com/paradigmxyz/reth/issues/18577
870        evm_env.cfg_env.disable_block_gas_limit = true;
871
872        // Disabled because eth_call is sometimes used with eoa senders
873        // See <https://github.com/paradigmxyz/reth/issues/1959>
874        evm_env.cfg_env.disable_eip3607 = true;
875
876        // The basefee should be ignored for eth_call
877        // See:
878        // <https://github.com/ethereum/go-ethereum/blob/ee8e83fa5f6cb261dad2ed0a7bbcde4930c41e6c/internal/ethapi/api.go#L985>
879        evm_env.cfg_env.disable_base_fee = true;
880
881        // Disable EIP-7825 transaction gas limit to support larger transactions
882        evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
883
884        // Disable additional fee charges, e.g. opstack operator fee charge
885        // See:
886        // <https://github.com/paradigmxyz/reth/issues/18470>
887        evm_env.cfg_env.disable_fee_charge = true;
888
889        evm_env.cfg_env.memory_limit = self.evm_memory_limit();
890
891        // set nonce to None so that the correct nonce is chosen by the EVM
892        request.as_mut().take_nonce();
893
894        if let Some(block_overrides) = overrides.block {
895            apply_block_overrides(*block_overrides, db, evm_env.block_env.inner_mut());
896        }
897        if let Some(state_overrides) = overrides.state {
898            apply_state_overrides(state_overrides, db)
899                .map_err(EthApiError::from_state_overrides_err)?;
900        }
901
902        let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
903
904        // 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>
905        if tx_env.gas_price() == 0 {
906            evm_env.block_env.inner_mut().basefee = 0;
907        }
908
909        if !request_has_gas_limit {
910            // No gas limit was provided in the request, so we need to cap the transaction gas limit
911            if tx_env.gas_price() > 0 {
912                // If gas price is specified, cap transaction gas limit with caller allowance
913                trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
914                let cap = self.caller_gas_allowance(db, &evm_env, &tx_env)?;
915                // ensure we cap gas_limit to the block's
916                tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit()));
917            }
918        }
919
920        Ok((evm_env, tx_env))
921    }
922}