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 super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace};
5use crate::{helpers::estimate::EstimateCall, FromEvmError, FullEthApiTypes, RpcBlock};
6use alloy_consensus::{transaction::Transaction, BlockHeader};
7use alloy_eip7928::BlockAccessIndex;
8use alloy_eips::{
9    eip1559::calc_effective_gas_price, eip2718::Typed2718, eip2930::AccessListResult,
10};
11use alloy_network::TransactionBuilder;
12use alloy_primitives::{Bytes, B256, U256};
13use alloy_rpc_types_eth::{
14    simulate::{SimBlock, SimulatePayload, SimulatedBlock},
15    state::{EvmOverrides, StateOverride},
16    BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo,
17};
18use evm2::evm::{CacheDB, DynDatabase};
19use evm2_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
20use futures::Future;
21use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
22use reth_errors::{ProviderError, RethError};
23use reth_evm::{
24    database::StateProviderDatabase,
25    execute::{BlockBuilder, BlockExecutor, BlockExecutorFactory, BlockTransactionResult},
26    BlockExecutorFor, BundleState, ConfigureEvm, Database, Evm, EvmEnv, EvmEnvFor, EvmTypesFor,
27    TransactionEnvMut, TxEnvFor, TxResultWithStateFor,
28};
29use reth_execution_types::BundleSource;
30use reth_primitives_traits::{BlockBody, BlockTy, Recovered, RecoveredBlock};
31use reth_rpc_convert::{RpcConvert, RpcTxReq};
32use reth_rpc_eth_types::{
33    cache::db::{
34        apply_block_overrides, apply_state_overrides, apply_state_overrides_with_state,
35        attach_bal_before_tx,
36    },
37    error::{AsEthApiError, FromEthApiError},
38    simulate::{self, EthSimulateError, SimulatedState},
39    utils::CallManyBudget,
40    EthApiError, RpcInvalidTransactionError, StateCacheDb,
41};
42use reth_storage_api::{BlockIdReader, ProviderTx, StateProvider};
43use reth_tasks::{cancel::is_cancelled, CancelOnDrop};
44use std::fmt;
45use tracing::{debug, trace};
46
47/// Result type for `eth_simulateV1` RPC method.
48pub type SimulatedBlocksResult<N, E> = Result<Vec<SimulatedBlock<RpcBlock<N>>>, E>;
49
50/// Execution related functions for the [`EthApiServer`](crate::EthApiServer) trait in
51/// the `eth_` namespace.
52pub trait EthCall: EstimateCall + LoadBlock + FullEthApiTypes {
53    /// Estimate gas needed for execution of the `request` at the [`BlockId`].
54    fn estimate_gas_at(
55        &self,
56        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
57        at: BlockId,
58        overrides: EvmOverrides,
59    ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
60        EstimateCall::estimate_gas_at(self, request, at, overrides)
61    }
62
63    /// `eth_simulateV1` executes an arbitrary number of transactions on top of the requested state.
64    /// The transactions are packed into individual blocks. Overrides can be provided.
65    ///
66    /// See also: <https://github.com/ethereum/go-ethereum/pull/27720>
67    fn simulate_v1(
68        &self,
69        payload: SimulatePayload<RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>>,
70        block: Option<BlockId>,
71    ) -> impl Future<Output = SimulatedBlocksResult<Self::NetworkTypes, Self::Error>> + Send {
72        async move {
73            if payload.block_state_calls.len() > self.max_simulate_blocks() as usize {
74                return Err(EthApiError::other(EthSimulateError::TooManyBlocks).into())
75            }
76
77            let block = block.unwrap_or_default();
78
79            let SimulatePayload {
80                block_state_calls,
81                trace_transfers,
82                validation,
83                return_full_transactions,
84            } = payload;
85
86            if block_state_calls.is_empty() {
87                return Err(EthApiError::InvalidParams(String::from("calls are empty.")).into())
88            }
89
90            let permit = self
91                .acquire_owned_blocking_io()
92                .await
93                .map_err(|_| EthApiError::InternalEthError)?;
94
95            let base_block = self
96                .recovered_block(block)
97                .await?
98                .ok_or_else(|| EthApiError::other(EthSimulateError::BlockNotFound { block }))?;
99            let parent = base_block.sealed_header().clone();
100            let max_simulate_blocks = self.max_simulate_blocks();
101            // Load the state of the block resolved above: resolving a tag such as `latest` again
102            // could return a newer block than `parent`.
103            let state_at = if block.is_pending() { block } else { parent.hash().into() };
104
105            self.spawn_with_state_at_block(state_at, move |this, db| {
106                let _permit = permit;
107                let state_provider = db.db.into_inner().into_inner().0;
108                let mut db = CacheDB::new(evm2::evm::Db::new(StateProviderDatabase::new(
109                    (&state_provider).into_evm_state_provider(),
110                )));
111                let mut parent = parent;
112                let mut simulation_state =
113                    this.compute_state_root_for_eth_simulate().then(SimulatedState::default);
114
115                let chain_id = this.provider().chain_spec().chain_id();
116
117                // Validate block ordering and fill gaps with empty blocks so every entry has an
118                // explicit `number` and `time` override and the chain is contiguous (see the
119                // execution-apis spec note: "If the block number is increased more than 1 compared
120                // to the previous block, new empty blocks are generated in between.").
121                let block_state_calls = simulate::sanitize_chain(
122                    block_state_calls,
123                    &parent,
124                    chain_id,
125                    max_simulate_blocks,
126                )?;
127
128                let mut blocks: Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>> =
129                    Vec::with_capacity(block_state_calls.len());
130
131                let call_gas_limit = this.call_gas_limit();
132                let mut remaining_call_gas_limit = (call_gas_limit > 0).then_some(call_gas_limit);
133
134                for block in block_state_calls {
135                    let SimBlock { block_overrides, state_overrides, calls } = block;
136
137                    let attributes = this
138                        .pending_env_builder()
139                        .pending_env_attributes(&parent, block_overrides.as_ref())
140                        .map_err(Self::Error::from_eth_err)?;
141
142                    let mut evm_env = this
143                        .evm_config()
144                        .next_evm_env(&parent, &attributes)
145                        .map_err(RethError::other)
146                        .map_err(Self::Error::from_eth_err)?;
147
148                    // Always disable EIP-3607
149                    evm_env.version_mut().features.remove(evm2::EvmFeatures::EIP3607);
150
151                    // EIP-7825's transaction gas cap is only active with Amsterdam's
152                    // regular/state-gas accounting, and only in validation mode. Without
153                    // validation the whole gas limit is execution gas.
154                    if !validation || !evm_env.version().feature(evm2::EvmFeatures::EIP8037) {
155                        evm_env.version_mut().tx_gas_limit_cap = u64::MAX;
156                    }
157
158                    if !validation {
159                        // If not explicitly required, we disable nonce check <https://github.com/paradigmxyz/reth/issues/16108>
160                        evm_env.version_mut().features.remove(evm2::EvmFeatures::NONCE_CHECK);
161                        evm_env.version_mut().features.remove(evm2::EvmFeatures::BASE_FEE_CHECK);
162                        evm_env.block_env_mut().basefee = U256::ZERO;
163                    }
164
165                    // Set prevrandao to zero for simulated blocks by default,
166                    // matching spec behavior where MixDigest is zero-initialized.
167                    // If user provides an override, it will be applied by apply_block_overrides.
168                    evm_env.block_env_mut().prevrandao = U256::ZERO;
169                    if !this
170                        .provider()
171                        .chain_spec()
172                        .is_paris_active_at_block(evm_env.block_env().number.to())
173                    {
174                        evm_env.block_env_mut().difficulty = parent.difficulty();
175                    }
176
177                    if let Some(block_overrides) = block_overrides {
178                        // ensure we don't allow uncapped gas limit per block
179                        if let Some(gas_limit_override) = block_overrides.gas_limit &&
180                            gas_limit_override > evm_env.block_env().gas_limit.to::<u64>() &&
181                            gas_limit_override > this.call_gas_limit()
182                        {
183                            return Err(EthApiError::other(EthSimulateError::GasLimitReached).into())
184                        }
185                        apply_block_overrides(block_overrides, &mut db, &mut evm_env);
186                    }
187                    if let Some(ref state_overrides) = state_overrides {
188                        let mut changes = simulation_state.as_ref().map(|_| BundleState::default());
189                        apply_state_overrides_with_state(
190                            state_overrides.clone(),
191                            &mut db,
192                            changes.as_mut(),
193                        )
194                        .map_err(Self::Error::from_eth_err)?;
195                        if let Some(simulation_state) = simulation_state.as_mut() &&
196                            let Some(changes) = changes
197                        {
198                            simulation_state
199                                .extend(&state_provider, &changes)
200                                .map_err(Self::Error::from_eth_err)?;
201                        }
202                    }
203
204                    let chain_id = evm_env.chain_id();
205                    let build_bal = this.provider().chain_spec().is_amsterdam_active_at_timestamp(
206                        evm_env.block_env().timestamp.to::<u64>(),
207                    );
208
209                    let ctx = this
210                        .evm_config()
211                        .context_for_next_block(&parent, attributes)
212                        .map_err(RethError::other)
213                        .map_err(Self::Error::from_eth_err)?;
214                    let map_err = |e: EthApiError| -> Self::Error {
215                        match e.as_simulate_error() {
216                            Some(sim_err) => Self::Error::from_eth_err(EthApiError::other(sim_err)),
217                            None => Self::Error::from_eth_err(e),
218                        }
219                    };
220
221                    // EIP-7708 already emits transfer logs: https://eips.ethereum.org/EIPS/eip-7708
222                    let trace_transfers =
223                        trace_transfers && !evm_env.version().feature(evm2::EvmFeatures::EIP7708);
224                    let mut evm = this.evm_config().evm_with_env(&mut db, evm_env.clone());
225                    if trace_transfers {
226                        // prepare inspector to capture transfer inside the evm so they are recorded
227                        // and included in logs
228                        evm.set_inspector(TransferInspector::new(false).with_logs(true));
229                    }
230                    let mut builder =
231                        this.evm_config().create_block_builder(evm, evm_env, &parent, ctx);
232                    if build_bal {
233                        builder.executor_mut().enable_block_access_list_builder();
234                    }
235
236                    if let Some(ref state_overrides) = state_overrides {
237                        simulate::apply_precompile_overrides(state_overrides, builder.evm_mut())
238                            .map_err(|e| Self::Error::from_eth_err(EthApiError::other(e)))?;
239                    }
240
241                    let (result, results) = simulate::execute_transactions(
242                        builder,
243                        &*state_provider,
244                        calls,
245                        &mut remaining_call_gas_limit,
246                        chain_id,
247                        simulation_state.as_mut(),
248                        this.converter(),
249                        |call, db| this.simulate_call_nonce(call, db),
250                    )
251                    .map_err(map_err)?;
252
253                    db.commit_source(&BundleSource(&result.execution_state));
254                    let simulated_header = result.block.clone_sealed_header();
255                    db.insert_block_hash(
256                        &U256::from(simulated_header.number()),
257                        &simulated_header.hash(),
258                    );
259                    parent = simulated_header;
260
261                    let block =
262                        simulate::build_simulated_block::<Self::Error, _, EvmTypesFor<Self::Evm>>(
263                            result.block,
264                            results,
265                            return_full_transactions.into(),
266                            this.converter(),
267                        )?;
268
269                    blocks.push(block);
270                }
271
272                Ok(blocks)
273            })
274            .await
275        }
276    }
277
278    /// Executes the call request (`eth_call`) and returns the output
279    fn call(
280        &self,
281        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
282        block_number: Option<BlockId>,
283        overrides: EvmOverrides,
284    ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
285        async move {
286            let res =
287                self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
288
289            Self::Error::ensure_success::<EvmTypesFor<Self::Evm>>(res.result)
290        }
291    }
292
293    /// Simulate transactions at an arbitrary blockchain index, with the optionality of state
294    /// overrides.
295    ///
296    /// The request is bounded by [`CallManyBudget`]: its calls share the RPC gas cap.
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            let mut budget = CallManyBudget::for_bundles(&bundles, self.call_gas_limit())?;
312
313            let permit = self
314                .acquire_owned_blocking_io()
315                .await
316                .map_err(|_| EthApiError::InternalEthError)?;
317
318            let StateContext { transaction_index, block_number } =
319                state_context.unwrap_or_default();
320            let transaction_index = transaction_index.unwrap_or_default();
321
322            let mut target_block = block_number.unwrap_or_default();
323            let is_block_target_pending = target_block.is_pending();
324
325            // if it's not pending, we should always use block_hash over block_number to ensure that
326            // different provider calls query data related to the same block.
327            if !is_block_target_pending {
328                let Some(block_hash) = self
329                    .provider()
330                    .block_hash_for_id(target_block)
331                    .map_err(Self::Error::from_eth_err::<ProviderError>)?
332                else {
333                    return Err(EthApiError::HeaderNotFound(target_block).into())
334                };
335                target_block = block_hash.into();
336            }
337
338            let block = self
339                .recovered_block(target_block)
340                .await?
341                .ok_or(EthApiError::HeaderNotFound(target_block))?;
342            let evm_env = self.evm_env_for_header(block.sealed_block().sealed_header())?;
343
344            // we're essentially replaying the transactions in the block here, hence we need the
345            // state that points to the beginning of the block, which is the state at
346            // the parent block
347            let mut at = block.parent_hash();
348            let mut replay_block_txs = true;
349
350            let num_txs =
351                transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
352            // but if all transactions are to be replayed, we can use the state at the block itself,
353            // however only if we're not targeting the pending block, because for pending we can't
354            // rely on the block's state being available
355            if !is_block_target_pending && num_txs == block.body().transactions().len() {
356                at = block.hash();
357                replay_block_txs = false;
358            }
359
360            self.spawn_with_state_at_block(at, move |this, mut db| {
361                let _permit = permit;
362                let mut all_results = Vec::with_capacity(bundles.len());
363
364                if replay_block_txs {
365                    // no BAL positioning here: bundle transactions commit state on top, and an
366                    // attached BAL would take read precedence over the committed changes
367                    this.replay_block_until(&mut db, &block, num_txs, None)?;
368                }
369
370                // transact all bundles
371                for (bundle_index, bundle) in bundles.into_iter().enumerate() {
372                    let Bundle { transactions, block_override } = bundle;
373                    if transactions.is_empty() {
374                        // Skip empty bundles
375                        continue;
376                    }
377
378                    let mut bundle_results = Vec::with_capacity(transactions.len());
379                    let block_overrides = block_override.map(Box::new);
380
381                    // transact all transactions in the bundle
382                    for (tx_index, tx) in transactions.into_iter().enumerate() {
383                        if is_cancelled() {
384                            return Err(EthApiError::InternalEthError.into())
385                        }
386
387                        // Apply overrides, state overrides are only applied for the first tx in the
388                        // request
389                        let overrides =
390                            EvmOverrides::new(state_override.take(), block_overrides.clone());
391
392                        let (current_evm_env, mut prepared_tx) = this
393                            .prepare_call_env(evm_env.clone(), tx, &mut db, overrides)
394                            .map_err(|err| {
395                                Self::Error::from_eth_err(EthApiError::call_many_error(
396                                    bundle_index,
397                                    tx_index,
398                                    err.into(),
399                                ))
400                            })?;
401                        budget.admit(&mut prepared_tx)?;
402                        let res = this.transact(&mut db, current_evm_env, prepared_tx).map_err(
403                            |err| {
404                                Self::Error::from_eth_err(EthApiError::call_many_error(
405                                    bundle_index,
406                                    tx_index,
407                                    budget.map_call_err(err).into(),
408                                ))
409                            },
410                        )?;
411                        budget.charge(&res.result).map_err(|err| {
412                            Self::Error::from_eth_err(EthApiError::call_many_error(
413                                bundle_index,
414                                tx_index,
415                                err.into(),
416                            ))
417                        })?;
418
419                        match Self::Error::ensure_success::<EvmTypesFor<Self::Evm>>(res.result) {
420                            Ok(output) => {
421                                bundle_results
422                                    .push(EthCallResponse { value: Some(output), error: None });
423                            }
424                            Err(err) => {
425                                bundle_results.push(EthCallResponse {
426                                    value: None,
427                                    error: Some(err.to_string()),
428                                });
429                            }
430                        }
431
432                        // Commit state changes after each transaction to allow subsequent calls to
433                        // see the updates
434                        db.commit_source(&res.pending_state);
435                    }
436
437                    all_results.push(bundle_results);
438                }
439
440                Ok(all_results)
441            })
442            .await
443        }
444    }
445
446    /// Creates [`AccessListResult`] for the [`RpcTxReq`] at the given
447    /// [`BlockId`], or latest block.
448    fn create_access_list_at(
449        &self,
450        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
451        block_number: Option<BlockId>,
452        state_override: Option<StateOverride>,
453    ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
454    where
455        Self: Trace,
456    {
457        async move {
458            let block_id = block_number.unwrap_or_default();
459            let (evm_env, at) = self.evm_env_at(block_id).await?;
460
461            self.create_access_list_with(evm_env, at, request, state_override).await
462        }
463    }
464
465    /// Creates [`AccessListResult`] for the [`RpcTxReq`] at the given
466    /// [`BlockId`].
467    fn create_access_list_with(
468        &self,
469        evm_env: EvmEnvFor<Self::Evm>,
470        at: BlockId,
471        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
472        state_override: Option<StateOverride>,
473    ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
474    where
475        Self: Trace,
476    {
477        self.spawn_with_state_at_block(at, |this, mut db| {
478            let initial = request.as_ref().access_list().cloned().unwrap_or_default();
479            let (evm_env, mut tx_env) = this.prepare_call_env(
480                evm_env,
481                request,
482                &mut db,
483                EvmOverrides::state(state_override),
484            )?;
485            let chain_id = evm_env.chain_id();
486
487            let mut evm = this.evm_config().evm_with_env(&mut db, evm_env);
488
489            // EIP-7702 authorities are warmed during authorization processing, so listing them
490            // would only add access list cost.
491            let inspector =
492                AccessListInspector::new(initial).with_excluded_from_tx(tx_env.inner(), chain_id);
493            let (inspector, result) = evm
494                .transact_with_inspector(&tx_env, inspector)
495                .map_err(Self::Error::from_evm_err)?;
496            let access_list = inspector.into_access_list();
497            let gas_used = result.result.tx_gas_used();
498            if let Err(err) = Self::Error::ensure_success::<EvmTypesFor<Self::Evm>>(result.result) {
499                return Ok(AccessListResult {
500                    access_list,
501                    gas_used: U256::from(gas_used),
502                    error: Some(err.to_string()),
503                });
504            }
505
506            tx_env.inner_mut().set_access_list(access_list.clone());
507
508            // Transact again to get the exact gas used with the returned access list.
509            let result = evm.transact_result(&tx_env).map_err(Self::Error::from_evm_err)?;
510            let gas_used = result.tx_gas_used();
511            let error = Self::Error::ensure_success::<EvmTypesFor<Self::Evm>>(result)
512                .err()
513                .map(|e| e.to_string());
514
515            Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
516        })
517    }
518}
519
520/// Executes code on state.
521pub trait Call:
522    LoadState<
523        RpcConvert: RpcConvert<Evm = Self::Evm>,
524        Error: FromEvmError<Self::Evm>
525                   + From<<Self::RpcConvert as RpcConvert>::Error>
526                   + From<ProviderError>,
527    > + SpawnBlocking
528{
529    /// Returns default gas limit to use for `eth_call` and tracing RPC methods.
530    ///
531    /// Data access in default trait method implementations.
532    fn call_gas_limit(&self) -> u64 {
533        self.eth_api_settings().gas_cap
534    }
535
536    /// Returns the maximum number of blocks accepted for `eth_simulateV1`.
537    fn max_simulate_blocks(&self) -> u64 {
538        self.eth_api_settings().max_simulate_blocks
539    }
540
541    /// Returns whether `eth_simulateV1` should compute state roots.
542    fn compute_state_root_for_eth_simulate(&self) -> bool {
543        self.eth_api_settings().compute_state_root_for_eth_simulate
544    }
545
546    /// Returns the maximum memory the EVM can allocate per RPC request.
547    fn evm_memory_limit(&self) -> u64 {
548        self.eth_api_settings().evm_memory_limit
549    }
550
551    /// Returns the nonce for an `eth_simulateV1` call that has none.
552    ///
553    /// `db` holds the simulation state before the call, including all earlier calls. `None` falls
554    /// back to the sender's account nonce, which suits networks with a single nonce per account.
555    fn simulate_call_nonce(
556        &self,
557        _request: &RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
558        _db: &mut dyn DynDatabase,
559    ) -> Result<Option<u64>, EthApiError> {
560        Ok(None)
561    }
562
563    /// Returns the max gas limit that the caller can afford given a transaction environment.
564    fn caller_gas_allowance(
565        &self,
566        mut db: impl Database<Error: Into<EthApiError>>,
567        _evm_env: &EvmEnvFor<Self::Evm>,
568        tx_env: &TxEnvFor<Self::Evm>,
569    ) -> Result<u64, Self::Error> {
570        let balance = db
571            .get_account(&tx_env.signer())
572            .map_err(Into::into)
573            .map_err(Self::Error::from_eth_err)?
574            .map(|account| account.balance)
575            .unwrap_or_default();
576        let value = tx_env.value();
577        let blob_fee = if tx_env.is_eip4844() {
578            U256::from(tx_env.blob_gas_used().unwrap_or_default()) *
579                U256::from(tx_env.max_fee_per_blob_gas().unwrap_or_default())
580        } else {
581            U256::ZERO
582        };
583        // Reserve the maximum blob fee before allocating execution gas. Subtract separately so
584        // an overflowing value plus blob fee cannot become an affordable allowance.
585        let available = balance
586            .checked_sub(value)
587            .and_then(|remaining| remaining.checked_sub(blob_fee))
588            .ok_or_else(|| {
589                EthApiError::from(RpcInvalidTransactionError::InsufficientFunds {
590                    cost: value.saturating_add(blob_fee),
591                    balance,
592                })
593            })?;
594
595        Ok(available
596            .checked_div(U256::from(tx_env.effective_gas_price(None)))
597            .unwrap_or_default()
598            .saturating_to())
599    }
600
601    /// Executes the `TxEnv` against the given [Database] without committing state
602    /// changes.
603    fn transact<DB>(
604        &self,
605        db: DB,
606        evm_env: EvmEnvFor<Self::Evm>,
607        tx_env: TxEnvFor<Self::Evm>,
608    ) -> Result<TxResultWithStateFor<Self::Evm>, Self::Error>
609    where
610        DB: Database + fmt::Debug,
611    {
612        let mut evm = self.evm_config().evm_with_env(db, evm_env);
613        let res = evm.transact(&tx_env).map_err(Self::Error::from_evm_err)?;
614
615        Ok(res)
616    }
617
618    /// Executes the [`reth_evm::EvmEnv`] against the given [`Database`] without committing state
619    /// changes.
620    fn transact_with_inspector<DB, I>(
621        &self,
622        db: DB,
623        evm_env: EvmEnvFor<Self::Evm>,
624        tx_env: TxEnvFor<Self::Evm>,
625        inspector: I,
626    ) -> Result<(I, TxResultWithStateFor<Self::Evm>), Self::Error>
627    where
628        DB: Database + fmt::Debug,
629        I: evm2::Inspector<EvmTypesFor<Self::Evm>> + 'static,
630    {
631        let mut evm = self.evm_config().evm_with_env(db, evm_env);
632        let res =
633            evm.transact_with_inspector(&tx_env, inspector).map_err(Self::Error::from_evm_err)?;
634
635        Ok(res)
636    }
637
638    /// Executes the call request at the given [`BlockId`].
639    ///
640    /// This spawns a new task that obtains the state for the given [`BlockId`] and then transacts
641    /// the call [`Self::transact`]. If the future is dropped before the (blocking) transact
642    /// call is invoked, then the task is cancelled early, (for example if the request is terminated
643    /// early client-side).
644    fn transact_call_at(
645        &self,
646        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
647        at: BlockId,
648        overrides: EvmOverrides,
649    ) -> impl Future<Output = Result<TxResultWithStateFor<Self::Evm>, Self::Error>> + Send
650    where
651        Self: LoadPendingBlock,
652    {
653        async move {
654            let permit = self
655                .acquire_owned_blocking_io()
656                .await
657                .map_err(|_| EthApiError::InternalEthError)?;
658            let guard = CancelOnDrop::default();
659            let cancel = guard.clone();
660            let this = self.clone();
661
662            let res = self
663                .spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
664                    let _permit = permit;
665                    if cancel.is_cancelled() {
666                        // callsite dropped the guard
667                        return Err(EthApiError::InternalEthError.into())
668                    }
669                    this.transact(db, evm_env, tx_env)
670                })
671                .await;
672            drop(guard);
673            res
674        }
675    }
676
677    /// Executes the closure with the state that corresponds to the given [`BlockId`] on a new task
678    fn spawn_with_state_at_block<F, R>(
679        &self,
680        at: impl Into<BlockId>,
681        f: F,
682    ) -> impl Future<Output = Result<R, Self::Error>> + Send
683    where
684        F: FnOnce(Self, StateCacheDb) -> Result<R, Self::Error> + Send + 'static,
685        R: Send + 'static,
686    {
687        self.spawn_blocking_io_with_state(at.into(), move |this, state| {
688            let db = evm2::evm::CacheDB::new(evm2::evm::Db::new(StateProviderDatabase::new(
689                state.into_evm_state_provider(),
690            )));
691            f(this, db)
692        })
693    }
694
695    /// Prepares the state and env for the given [`RpcTxReq`] at the given [`BlockId`] and
696    /// executes the closure on a new task returning the result of the closure.
697    ///
698    /// This returns the configured [`reth_evm::EvmEnv`] for the given [`RpcTxReq`] at
699    /// the given [`BlockId`] and with configured call settings: `prepare_call_env`.
700    ///
701    /// This is primarily used by `eth_call`.
702    ///
703    /// # Blocking behaviour
704    ///
705    /// This assumes executing the call is relatively more expensive on IO than CPU because it
706    /// transacts a single transaction on an empty in memory database. Because `eth_call`s are
707    /// usually allowed to consume a lot of gas, this also allows a lot of memory operations so
708    /// we assume this is not primarily CPU bound and instead spawn the call on a regular tokio task
709    /// instead, where blocking IO is less problematic.
710    fn spawn_with_call_at<F, R>(
711        &self,
712        request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
713        at: BlockId,
714        overrides: EvmOverrides,
715        f: F,
716    ) -> impl Future<Output = Result<R, Self::Error>> + Send
717    where
718        Self: LoadPendingBlock,
719        F: FnOnce(
720                &mut StateCacheDb,
721                EvmEnvFor<Self::Evm>,
722                TxEnvFor<Self::Evm>,
723            ) -> Result<R, Self::Error>
724            + Send
725            + 'static,
726        R: Send + 'static,
727    {
728        async move {
729            let (evm_env, at) = self.evm_env_at(at).await?;
730            self.spawn_with_state_at_block(at, move |this, mut db| {
731                let (evm_env, tx_env) =
732                    this.prepare_call_env(evm_env, request, &mut db, overrides)?;
733
734                f(&mut db, evm_env, tx_env)
735            })
736            .await
737        }
738    }
739
740    /// Retrieves the transaction if it exists and executes it.
741    ///
742    /// Before the transaction is executed, the state is positioned right before the transaction,
743    /// either by attaching the block's cached BAL or by executing all previous transactions in the
744    /// block. The transaction is executed through the block executor, see [`Call::block_executor`].
745    /// The callback `f` is invoked with the [`TxResultWithStateFor`] after the transaction was
746    /// executed and the database that points to the beginning of the transaction. The database
747    /// may have the block's BAL attached and must only be used for reads, because an attached
748    /// BAL takes read precedence over state committed on top, see [`attach_bal_before_tx`].
749    ///
750    /// Note: Implementers should use a threadpool where blocking is allowed, such as
751    /// [`BlockingTaskPool`](reth_tasks::pool::BlockingTaskPool).
752    fn spawn_replay_transaction<F, R>(
753        &self,
754        hash: B256,
755        f: F,
756    ) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
757    where
758        Self: LoadBlock + LoadTransaction,
759        F: FnOnce(
760                TransactionInfo,
761                TxResultWithStateFor<Self::Evm>,
762                StateCacheDb,
763            ) -> Result<R, Self::Error>
764            + Send
765            + 'static,
766        R: Send + 'static,
767    {
768        async move {
769            let (transaction, block, bal) =
770                match self.transaction_and_block_and_maybe_bal(hash).await? {
771                    None => return Ok(None),
772                    Some(res) => res,
773                };
774            let (tx, tx_info) = transaction.split();
775
776            // we need to get the state of the parent block because we're essentially replaying the
777            // block the transaction is included in
778            let parent_block = block.parent_hash();
779            let evm_env = self.evm_env_for_header(block.sealed_block().sealed_header())?;
780
781            self.spawn_with_state_at_block(parent_block, move |this, mut db| {
782                if let Some((bal, tx_index)) = bal.zip(tx_info.index) {
783                    attach_bal_before_tx(&mut db, &bal, tx_index as usize);
784
785                    let mut executor = this.block_executor(&block, &mut db, evm_env)?;
786                    executor.set_block_access_index(BlockAccessIndex::from_tx_index(tx_index));
787                    let res = executor
788                        .execute_transaction_without_commit(tx)
789                        .map_err(Self::Error::from_evm_err)?
790                        .into_result();
791                    let cache = executor.evm_mut().take_state_cache();
792                    drop(executor);
793                    db.cache.merge(cache);
794                    return f(tx_info, res, db)
795                }
796
797                let block_txs = block.transactions_recovered();
798
799                let ctx = this
800                    .evm_config()
801                    .context_for_block(block.sealed_block())
802                    .map_err(RethError::other)
803                    .map_err(Self::Error::from_eth_err)?;
804                let changes = this
805                    .evm_config()
806                    .pre_block_state_changes(&mut db, evm_env.clone(), ctx)
807                    .map_err(|err| EthApiError::EvmCustom(err.to_string()))
808                    .map_err(Self::Error::from_eth_err)?;
809                db.commit_source(&reth_execution_types::BundleSource(&changes));
810
811                let mut executor = this.block_executor(&block, &mut db, evm_env)?;
812                this.replay_transactions_until_with_executor(
813                    &mut executor,
814                    block_txs,
815                    tx_info.index.expect("included transaction has an index") as usize,
816                )?;
817                let res = executor
818                    .execute_transaction_without_commit(tx)
819                    .map_err(Self::Error::from_evm_err)?
820                    .into_result();
821                let cache = executor.evm_mut().take_state_cache();
822                drop(executor);
823                db.cache.merge(cache);
824                f(tx_info, res, db)
825            })
826            .await
827            .map(Some)
828        }
829    }
830
831    /// Replays all transactions before the target transaction index through the given executor.
832    ///
833    /// If the target index is greater than or equal to the iterator length, all transactions are
834    /// replayed.
835    fn replay_transactions_until_with_executor<'a, Txs>(
836        &self,
837        executor: &mut BlockExecutorFor<'_, Self::Evm>,
838        transactions: Txs,
839        target_tx_index: usize,
840    ) -> Result<(), Self::Error>
841    where
842        Txs: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
843    {
844        for (index, tx) in transactions.into_iter().enumerate() {
845            if index == target_tx_index {
846                // reached the target transaction
847                break
848            }
849            if is_cancelled() {
850                return Err(EthApiError::InternalEthError.into())
851            }
852
853            executor.execute_transaction(tx).map_err(Self::Error::from_evm_err)?;
854        }
855        Ok(())
856    }
857
858    /// Creates a block executor for `block` on `db` with the given EVM environment.
859    ///
860    /// Replaying a block's own transactions through the executor rather than a bare EVM includes
861    /// the changes the executor applies on top of each EVM result, so replayed results agree with
862    /// the block's receipts and state. The executor does not apply the block's pre-execution
863    /// changes: callers apply them to `db` first or position `db` with the block's BAL, see
864    /// [`attach_bal_before_tx`].
865    fn block_executor<'a>(
866        &'a self,
867        block: &'a RecoveredBlock<BlockTy<Self::Primitives>>,
868        db: &'a mut StateCacheDb,
869        evm_env: EvmEnvFor<Self::Evm>,
870    ) -> Result<BlockExecutorFor<'a, Self::Evm>, Self::Error> {
871        let ctx = self
872            .evm_config()
873            .context_for_block(block.sealed_block())
874            .map_err(RethError::other)
875            .map_err(Self::Error::from_eth_err)?;
876        let evm = self.evm_config().evm_with_env(db, evm_env);
877        Ok(self.evm_config().block_executor_factory().create_executor(evm, ctx))
878    }
879
880    ///
881    /// All `TxEnv` fields are derived from the given [`RpcTxReq`], if fields are
882    /// `None`, they fall back to the [`reth_evm::EvmEnv`]'s settings.
883    fn create_txn_env(
884        &self,
885        evm_env: &EvmEnvFor<Self::Evm>,
886        mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
887        mut db: impl Database<Error: Into<EthApiError>>,
888    ) -> Result<TxEnvFor<Self::Evm>, Self::Error> {
889        if request.as_ref().nonce().is_none() {
890            let nonce = db
891                .get_account(&request.as_ref().from().unwrap_or_default())
892                .map_err(Into::into)
893                .map_err(Self::Error::from_eth_err)?
894                .map(|account| account.nonce)
895                .unwrap_or_default();
896            request.as_mut().set_nonce(nonce);
897        }
898
899        Ok(self.converter().tx_env(request, evm_env)?)
900    }
901
902    /// Prepares the [`reth_evm::EvmEnv`] for execution of calls.
903    ///
904    /// Does not commit any changes to the underlying database.
905    ///
906    /// ## EVM settings
907    ///
908    /// 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>:
909    ///
910    ///  - `disable_eip3607` is set to `true`
911    ///  - `disable_base_fee` is set to `true`
912    ///  - `nonce` is set to `None`
913    ///
914    /// In addition, this changes the block's gas limit to the configured [`Self::call_gas_limit`].
915    #[expect(clippy::type_complexity)]
916    fn prepare_call_env<DB>(
917        &self,
918        mut evm_env: EvmEnvFor<Self::Evm>,
919        mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
920        db: &mut CacheDB<DB>,
921        overrides: EvmOverrides,
922    ) -> Result<(EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>), Self::Error>
923    where
924        DB: DynDatabase,
925    {
926        // track whether the request has a gas limit set
927        let requested_gas = request.as_ref().gas_limit();
928
929        // Disable block gas limit check to allow executing transactions with higher gas limit (call
930        // gas limit): https://github.com/paradigmxyz/reth/issues/18577
931        evm_env.version_mut().features.remove(evm2::EvmFeatures::BLOCK_GAS_LIMIT_CHECK);
932
933        // Disabled because eth_call is sometimes used with eoa senders
934        // See <https://github.com/paradigmxyz/reth/issues/1959>
935        evm_env.version_mut().features.remove(evm2::EvmFeatures::EIP3607);
936
937        // The basefee should be ignored for eth_call
938        // See:
939        // <https://github.com/ethereum/go-ethereum/blob/ee8e83fa5f6cb261dad2ed0a7bbcde4930c41e6c/internal/ethapi/api.go#L985>
940        evm_env.version_mut().features.remove(evm2::EvmFeatures::BASE_FEE_CHECK);
941
942        // Disable EIP-7825 transaction gas limit to support larger transactions. Under Amsterdam's
943        // EIP-8037 it only caps execution gas, the rest going to the state gas reservoir, so keep
944        // it to execute the call like a transaction.
945        if !evm_env.version().feature(evm2::EvmFeatures::EIP8037) {
946            evm_env.version_mut().tx_gas_limit_cap = u64::MAX;
947        }
948
949        // Disable additional fee charges, e.g. opstack operator fee charge
950        // See:
951        // <https://github.com/paradigmxyz/reth/issues/18470>
952        evm_env.version_mut().features.remove(evm2::EvmFeatures::FEE_CHARGE);
953
954        // Calls do not pay upfront fees. Preserve the caller's actual balance so value transfers
955        // still fail during execution when it is insufficient, without topping up the account.
956        evm_env
957            .version_mut()
958            .features
959            .remove(evm2::EvmFeatures::BALANCE_CHECK | evm2::EvmFeatures::BALANCE_TOP_UP);
960
961        evm_env.version_mut().memory_limit = self.evm_memory_limit();
962
963        // set nonce to None so that the correct nonce is chosen by the EVM
964        request.as_mut().take_nonce();
965
966        if let Some(block_overrides) = overrides.block {
967            apply_block_overrides(*block_overrides, db, &mut evm_env);
968        }
969        if let Some(state_overrides) = overrides.state {
970            apply_state_overrides(state_overrides, db)
971                .map_err(EthApiError::from_state_overrides_err)?;
972        }
973
974        let gas_price = request_gas_price(request.as_ref(), evm_env.block_base_fee());
975        // Convert the request once, as sent, and apply every gas limit cap to the prepared env:
976        // converting again with a changed gas limit could change the recovered caller or fee payer
977        // when the signature commits to the gas limit.
978        let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
979
980        if let Some(requested_gas) = requested_gas {
981            let global_gas_cap = self.call_gas_limit();
982            if global_gas_cap != 0 && global_gas_cap < requested_gas {
983                // Callers routinely send gas limits above the cap, so this is not worth a warning.
984                // Log only the limits: the request carries caller calldata and addresses.
985                debug!(target: "rpc::eth::call", requested_gas, global_gas_cap, "Capping gas limit to global gas cap");
986                tx_env.inner_mut().set_gas_limit(global_gas_cap);
987            }
988        } else {
989            // cap request's gas limit to call gas limit
990            tx_env
991                .inner_mut()
992                .set_gas_limit(self.call_gas_limit().min(evm_env.version().tx_gas_caps().0));
993        }
994
995        // 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>
996        if gas_price == 0 {
997            evm_env.block_env_mut().basefee = U256::ZERO;
998        }
999
1000        if requested_gas.is_none() {
1001            // No gas limit was provided in the request, so we need to cap the transaction gas limit
1002            if gas_price > 0 {
1003                // If gas price is specified, cap transaction gas limit with caller allowance
1004                trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
1005                let mut cap = self.caller_gas_allowance(&mut *db, &evm_env, &tx_env)?;
1006                // The allowance must not raise the already applied RPC gas cap.
1007                if self.call_gas_limit() != 0 {
1008                    cap = cap.min(tx_env.gas_limit());
1009                }
1010                // ensure we cap gas_limit to the block's
1011                tx_env
1012                    .inner_mut()
1013                    .set_gas_limit(cap.min(evm_env.block_env().gas_limit.to::<u64>()));
1014            }
1015        }
1016
1017        Ok((evm_env, tx_env))
1018    }
1019}
1020
1021pub(super) fn request_gas_price(
1022    request: &alloy_rpc_types_eth::TransactionRequest,
1023    block_base_fee: u64,
1024) -> u128 {
1025    if let Some(gas_price) = request.gas_price {
1026        return gas_price
1027    }
1028
1029    match (request.max_fee_per_gas, request.max_priority_fee_per_gas) {
1030        (None, None) => 0,
1031        (max_fee, priority_fee) => calc_effective_gas_price(
1032            max_fee.unwrap_or(u128::MAX),
1033            priority_fee.unwrap_or_default(),
1034            Some(block_base_fee),
1035        ),
1036    }
1037}