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