1use 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 env::BlockEnvironment, ConfigureEvm, Evm, EvmEnvFor, HaltReasonFor, InspectorFor,
24 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
49pub type SimulatedBlocksResult<N, E> = Result<Vec<SimulatedBlock<RpcBlock<N>>>, E>;
51
52pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthApiTypes {
55 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 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 for block in block_state_calls {
100 let mut evm_env = this
101 .evm_config()
102 .next_evm_env(&parent, &this.next_env_attributes(&parent)?)
103 .map_err(RethError::other)
104 .map_err(Self::Error::from_eth_err)?;
105
106 evm_env.cfg_env.disable_eip3607 = true;
108
109 if !validation {
110 evm_env.cfg_env.disable_nonce_check = true;
112 evm_env.cfg_env.disable_base_fee = true;
113 evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
114 evm_env.block_env.inner_mut().basefee = 0;
115 }
116
117 let SimBlock { block_overrides, state_overrides, calls } = block;
118
119 if let Some(block_overrides) = block_overrides {
120 if let Some(gas_limit_override) = block_overrides.gas_limit &&
122 gas_limit_override > evm_env.block_env.gas_limit() &&
123 gas_limit_override > this.call_gas_limit()
124 {
125 return Err(EthApiError::other(EthSimulateError::GasLimitReached).into())
126 }
127 apply_block_overrides(
128 block_overrides,
129 &mut db,
130 evm_env.block_env.inner_mut(),
131 );
132 }
133 if let Some(state_overrides) = state_overrides {
134 apply_state_overrides(state_overrides, &mut db)
135 .map_err(Self::Error::from_eth_err)?;
136 }
137
138 let block_gas_limit = evm_env.block_env.gas_limit();
139 let chain_id = evm_env.cfg_env.chain_id;
140
141 let default_gas_limit = {
142 let total_specified_gas =
143 calls.iter().filter_map(|tx| tx.as_ref().gas_limit()).sum::<u64>();
144 let txs_without_gas_limit =
145 calls.iter().filter(|tx| tx.as_ref().gas_limit().is_none()).count();
146
147 if total_specified_gas > block_gas_limit {
148 return Err(EthApiError::Other(Box::new(
149 EthSimulateError::BlockGasLimitExceeded,
150 ))
151 .into())
152 }
153
154 if txs_without_gas_limit > 0 {
155 (block_gas_limit - total_specified_gas) / txs_without_gas_limit as u64
156 } else {
157 0
158 }
159 };
160
161 let ctx = this
162 .evm_config()
163 .context_for_next_block(&parent, this.next_env_attributes(&parent)?)
164 .map_err(RethError::other)
165 .map_err(Self::Error::from_eth_err)?;
166 let map_err = |e: EthApiError| -> Self::Error {
167 match e.as_simulate_error() {
168 Some(sim_err) => Self::Error::from_eth_err(EthApiError::other(sim_err)),
169 None => Self::Error::from_eth_err(e),
170 }
171 };
172
173 let (result, results) = if trace_transfers {
174 let inspector = TransferInspector::new(false).with_logs(true);
177 let evm = this
178 .evm_config()
179 .evm_with_env_and_inspector(&mut db, evm_env, inspector);
180 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
181 simulate::execute_transactions(
182 builder,
183 calls,
184 default_gas_limit,
185 chain_id,
186 this.converter(),
187 )
188 .map_err(map_err)?
189 } else {
190 let evm = this.evm_config().evm_with_env(&mut db, evm_env);
191 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
192 simulate::execute_transactions(
193 builder,
194 calls,
195 default_gas_limit,
196 chain_id,
197 this.converter(),
198 )
199 .map_err(map_err)?
200 };
201
202 parent = result.block.clone_sealed_header();
203
204 let block = simulate::build_simulated_block::<Self::Error, _>(
205 result.block,
206 results,
207 return_full_transactions.into(),
208 this.converter(),
209 )?;
210
211 blocks.push(block);
212 }
213
214 Ok(blocks)
215 })
216 .await
217 }
218 }
219
220 fn call(
222 &self,
223 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
224 block_number: Option<BlockId>,
225 overrides: EvmOverrides,
226 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
227 async move {
228 let _permit = self.acquire_owned_blocking_io().await;
229 let res =
230 self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
231
232 Self::Error::ensure_success(res.result)
233 }
234 }
235
236 fn call_many(
239 &self,
240 bundles: Vec<Bundle<RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>>>,
241 state_context: Option<StateContext>,
242 mut state_override: Option<StateOverride>,
243 ) -> impl Future<Output = Result<Vec<Vec<EthCallResponse>>, Self::Error>> + Send {
244 async move {
245 if bundles.is_empty() {
247 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into());
248 }
249
250 let StateContext { transaction_index, block_number } =
251 state_context.unwrap_or_default();
252 let transaction_index = transaction_index.unwrap_or_default();
253
254 let mut target_block = block_number.unwrap_or_default();
255 let is_block_target_pending = target_block.is_pending();
256
257 if !is_block_target_pending {
260 target_block = self
261 .provider()
262 .block_hash_for_id(target_block)
263 .map_err(|_| EthApiError::HeaderNotFound(target_block))?
264 .ok_or_else(|| EthApiError::HeaderNotFound(target_block))?
265 .into();
266 }
267
268 let ((evm_env, _), block) = futures::try_join!(
269 self.evm_env_at(target_block),
270 self.recovered_block(target_block)
271 )?;
272
273 let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
274
275 let mut at = block.parent_hash();
279 let mut replay_block_txs = true;
280
281 let num_txs =
282 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
283 if !is_block_target_pending && num_txs == block.body().transactions().len() {
287 at = block.hash();
288 replay_block_txs = false;
289 }
290
291 self.spawn_with_state_at_block(at, move |this, mut db| {
292 let mut all_results = Vec::with_capacity(bundles.len());
293
294 if replay_block_txs {
295 let block_transactions = block.transactions_recovered().take(num_txs);
298 for tx in block_transactions {
299 let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
300 let res = this.transact(&mut db, evm_env.clone(), tx_env)?;
301 db.commit(res.state);
302 }
303 }
304
305 for (bundle_index, bundle) in bundles.into_iter().enumerate() {
307 let Bundle { transactions, block_override } = bundle;
308 if transactions.is_empty() {
309 continue;
311 }
312
313 let mut bundle_results = Vec::with_capacity(transactions.len());
314 let block_overrides = block_override.map(Box::new);
315
316 for (tx_index, tx) in transactions.into_iter().enumerate() {
318 let overrides =
321 EvmOverrides::new(state_override.take(), block_overrides.clone());
322
323 let (current_evm_env, prepared_tx) = this
324 .prepare_call_env(evm_env.clone(), tx, &mut db, overrides)
325 .map_err(|err| {
326 Self::Error::from_eth_err(EthApiError::call_many_error(
327 bundle_index,
328 tx_index,
329 err.into(),
330 ))
331 })?;
332 let res = this.transact(&mut db, current_evm_env, prepared_tx).map_err(
333 |err| {
334 Self::Error::from_eth_err(EthApiError::call_many_error(
335 bundle_index,
336 tx_index,
337 err.into(),
338 ))
339 },
340 )?;
341
342 match Self::Error::ensure_success(res.result) {
343 Ok(output) => {
344 bundle_results
345 .push(EthCallResponse { value: Some(output), error: None });
346 }
347 Err(err) => {
348 bundle_results.push(EthCallResponse {
349 value: None,
350 error: Some(err.to_string()),
351 });
352 }
353 }
354
355 db.commit(res.state);
358 }
359
360 all_results.push(bundle_results);
361 }
362
363 Ok(all_results)
364 })
365 .await
366 }
367 }
368
369 fn create_access_list_at(
372 &self,
373 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
374 block_number: Option<BlockId>,
375 state_override: Option<StateOverride>,
376 ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
377 where
378 Self: Trace,
379 {
380 async move {
381 let block_id = block_number.unwrap_or_default();
382 let (evm_env, at) = self.evm_env_at(block_id).await?;
383
384 self.spawn_blocking_io_fut(move |this| async move {
385 this.create_access_list_with(evm_env, at, request, state_override).await
386 })
387 .await
388 }
389 }
390
391 fn create_access_list_with(
394 &self,
395 mut evm_env: EvmEnvFor<Self::Evm>,
396 at: BlockId,
397 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
398 state_override: Option<StateOverride>,
399 ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
400 where
401 Self: Trace,
402 {
403 self.spawn_blocking_io_fut(move |this| async move {
404 let state = this.state_at_block_id(at).await?;
405 let mut db = State::builder().with_database(StateProviderDatabase::new(state)).build();
406
407 if let Some(state_overrides) = state_override {
408 apply_state_overrides(state_overrides, &mut db)
409 .map_err(Self::Error::from_eth_err)?;
410 }
411
412 let mut tx_env = this.create_txn_env(&evm_env, request.clone(), &mut db)?;
413
414 evm_env.cfg_env.disable_block_gas_limit = true;
417
418 evm_env.cfg_env.disable_base_fee = true;
422
423 evm_env.cfg_env.disable_eip3607 = true;
425
426 if request.as_ref().gas_limit().is_none() && tx_env.gas_price() > 0 {
427 let cap = this.caller_gas_allowance(&mut db, &evm_env, &tx_env)?;
428 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit()));
431 }
432
433 let initial = request.as_ref().access_list().cloned().unwrap_or_default();
435
436 let mut inspector = AccessListInspector::new(initial);
437
438 let result = this.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
439 let access_list = inspector.into_access_list();
440 let gas_used = result.result.gas_used();
441 tx_env.set_access_list(access_list.clone());
442 if let Err(err) = Self::Error::ensure_success(result.result) {
443 return Ok(AccessListResult {
444 access_list,
445 gas_used: U256::from(gas_used),
446 error: Some(err.to_string()),
447 });
448 }
449
450 let result = this.transact(&mut db, evm_env, tx_env)?;
452 let gas_used = result.result.gas_used();
453 let error = Self::Error::ensure_success(result.result).err().map(|e| e.to_string());
454
455 Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
456 })
457 }
458}
459
460pub trait Call:
462 LoadState<
463 RpcConvert: RpcConvert<Evm = Self::Evm>,
464 Error: FromEvmError<Self::Evm>
465 + From<<Self::RpcConvert as RpcConvert>::Error>
466 + From<ProviderError>,
467 > + SpawnBlocking
468{
469 fn call_gas_limit(&self) -> u64;
473
474 fn max_simulate_blocks(&self) -> u64;
476
477 fn evm_memory_limit(&self) -> u64;
479
480 fn caller_gas_allowance(
482 &self,
483 mut db: impl Database<Error: Into<EthApiError>>,
484 _evm_env: &EvmEnvFor<Self::Evm>,
485 tx_env: &TxEnvFor<Self::Evm>,
486 ) -> Result<u64, Self::Error> {
487 alloy_evm::call::caller_gas_allowance(&mut db, tx_env).map_err(Self::Error::from_eth_err)
488 }
489
490 fn with_state_at_block<F, R>(
492 &self,
493 at: BlockId,
494 f: F,
495 ) -> impl Future<Output = Result<R, Self::Error>> + Send
496 where
497 R: Send + 'static,
498 F: FnOnce(Self, StateProviderBox) -> Result<R, Self::Error> + Send + 'static,
499 {
500 self.spawn_blocking_io_fut(move |this| async move {
501 let state = this.state_at_block_id(at).await?;
502 f(this, state)
503 })
504 }
505
506 fn transact<DB>(
509 &self,
510 db: DB,
511 evm_env: EvmEnvFor<Self::Evm>,
512 tx_env: TxEnvFor<Self::Evm>,
513 ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
514 where
515 DB: Database<Error = EvmDatabaseError<ProviderError>> + fmt::Debug,
516 {
517 let mut evm = self.evm_config().evm_with_env(db, evm_env);
518 let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
519
520 Ok(res)
521 }
522
523 fn transact_with_inspector<DB, I>(
526 &self,
527 db: DB,
528 evm_env: EvmEnvFor<Self::Evm>,
529 tx_env: TxEnvFor<Self::Evm>,
530 inspector: I,
531 ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
532 where
533 DB: Database<Error = EvmDatabaseError<ProviderError>> + fmt::Debug,
534 I: InspectorFor<Self::Evm, DB>,
535 {
536 let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, inspector);
537 let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
538
539 Ok(res)
540 }
541
542 fn transact_call_at(
549 &self,
550 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
551 at: BlockId,
552 overrides: EvmOverrides,
553 ) -> impl Future<Output = Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>> + Send
554 where
555 Self: LoadPendingBlock,
556 {
557 async move {
558 let guard = CancelOnDrop::default();
559 let cancel = guard.clone();
560 let this = self.clone();
561
562 let res = self
563 .spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
564 if cancel.is_cancelled() {
565 return Err(EthApiError::InternalEthError.into())
567 }
568 this.transact(db, evm_env, tx_env)
569 })
570 .await;
571 drop(guard);
572 res
573 }
574 }
575
576 fn spawn_with_state_at_block<F, R>(
578 &self,
579 at: impl Into<BlockId>,
580 f: F,
581 ) -> impl Future<Output = Result<R, Self::Error>> + Send
582 where
583 F: FnOnce(Self, StateCacheDb) -> Result<R, Self::Error> + Send + 'static,
584 R: Send + 'static,
585 {
586 let at = at.into();
587 self.spawn_blocking_io_fut(move |this| async move {
588 let state = this.state_at_block_id(at).await?;
589 let db = State::builder()
590 .with_database(StateProviderDatabase::new(StateProviderTraitObjWrapper(state)))
591 .build();
592 f(this, db)
593 })
594 }
595
596 fn spawn_with_call_at<F, R>(
612 &self,
613 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
614 at: BlockId,
615 overrides: EvmOverrides,
616 f: F,
617 ) -> impl Future<Output = Result<R, Self::Error>> + Send
618 where
619 Self: LoadPendingBlock,
620 F: FnOnce(
621 &mut StateCacheDb,
622 EvmEnvFor<Self::Evm>,
623 TxEnvFor<Self::Evm>,
624 ) -> Result<R, Self::Error>
625 + Send
626 + 'static,
627 R: Send + 'static,
628 {
629 async move {
630 let (evm_env, at) = self.evm_env_at(at).await?;
631 self.spawn_with_state_at_block(at, move |this, mut db| {
632 let (evm_env, tx_env) =
633 this.prepare_call_env(evm_env, request, &mut db, overrides)?;
634
635 f(&mut db, evm_env, tx_env)
636 })
637 .await
638 }
639 }
640
641 fn spawn_replay_transaction<F, R>(
651 &self,
652 hash: B256,
653 f: F,
654 ) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
655 where
656 Self: LoadBlock + LoadTransaction,
657 F: FnOnce(
658 TransactionInfo,
659 ResultAndState<HaltReasonFor<Self::Evm>>,
660 StateCacheDb,
661 ) -> Result<R, Self::Error>
662 + Send
663 + 'static,
664 R: Send + 'static,
665 {
666 async move {
667 let (transaction, block) = match self.transaction_and_block(hash).await? {
668 None => return Ok(None),
669 Some(res) => res,
670 };
671 let (tx, tx_info) = transaction.split();
672
673 let evm_env = self.evm_env_for_header(block.sealed_block().sealed_header())?;
674
675 let parent_block = block.parent_hash();
678
679 self.spawn_with_state_at_block(parent_block, move |this, mut db| {
680 let block_txs = block.transactions_recovered();
681
682 this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
684
685 let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
686
687 let res = this.transact(&mut db, evm_env, tx_env)?;
688 f(tx_info, res, db)
689 })
690 .await
691 .map(Some)
692 }
693 }
694
695 fn replay_transactions_until<'a, DB, I>(
703 &self,
704 db: &mut DB,
705 evm_env: EvmEnvFor<Self::Evm>,
706 transactions: I,
707 target_tx_hash: B256,
708 ) -> Result<usize, Self::Error>
709 where
710 DB: Database<Error = EvmDatabaseError<ProviderError>> + DatabaseCommit + core::fmt::Debug,
711 I: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
712 {
713 let mut evm = self.evm_config().evm_with_env(db, evm_env);
714 let mut index = 0;
715 for tx in transactions {
716 if *tx.tx_hash() == target_tx_hash {
717 break
719 }
720
721 let tx_env = self.evm_config().tx_env(tx);
722 evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
723 index += 1;
724 }
725 Ok(index)
726 }
727
728 fn create_txn_env(
732 &self,
733 evm_env: &EvmEnvFor<Self::Evm>,
734 mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
735 mut db: impl Database<Error: Into<EthApiError>>,
736 ) -> Result<TxEnvFor<Self::Evm>, Self::Error> {
737 if request.as_ref().nonce().is_none() {
738 let nonce = db
739 .basic(request.as_ref().from().unwrap_or_default())
740 .map_err(Into::into)?
741 .map(|acc| acc.nonce)
742 .unwrap_or_default();
743 request.as_mut().set_nonce(nonce);
744 }
745
746 Ok(self.converter().tx_env(request, evm_env)?)
747 }
748
749 #[expect(clippy::type_complexity)]
763 fn prepare_call_env<DB>(
764 &self,
765 mut evm_env: EvmEnvFor<Self::Evm>,
766 mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
767 db: &mut DB,
768 overrides: EvmOverrides,
769 ) -> Result<(EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>), Self::Error>
770 where
771 DB: Database + DatabaseCommit + OverrideBlockHashes,
772 EthApiError: From<<DB as Database>::Error>,
773 {
774 let request_has_gas_limit = request.as_ref().gas_limit().is_some();
776
777 if let Some(requested_gas) = request.as_ref().gas_limit() {
778 let global_gas_cap = self.call_gas_limit();
779 if global_gas_cap != 0 && global_gas_cap < requested_gas {
780 warn!(target: "rpc::eth::call", ?request, ?global_gas_cap, "Capping gas limit to global gas cap");
781 request.as_mut().set_gas_limit(global_gas_cap);
782 }
783 } else {
784 request.as_mut().set_gas_limit(self.call_gas_limit());
786 }
787
788 evm_env.cfg_env.disable_block_gas_limit = true;
791
792 evm_env.cfg_env.disable_eip3607 = true;
795
796 evm_env.cfg_env.disable_base_fee = true;
800
801 evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
803
804 evm_env.cfg_env.disable_fee_charge = true;
808
809 evm_env.cfg_env.memory_limit = self.evm_memory_limit();
810
811 request.as_mut().take_nonce();
813
814 if let Some(block_overrides) = overrides.block {
815 apply_block_overrides(*block_overrides, db, evm_env.block_env.inner_mut());
816 }
817 if let Some(state_overrides) = overrides.state {
818 apply_state_overrides(state_overrides, db)
819 .map_err(EthApiError::from_state_overrides_err)?;
820 }
821
822 let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
823
824 if tx_env.gas_price() == 0 {
826 evm_env.block_env.inner_mut().basefee = 0;
827 }
828
829 if !request_has_gas_limit {
830 if tx_env.gas_price() > 0 {
832 trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
834 let cap = self.caller_gas_allowance(db, &evm_env, &tx_env)?;
835 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit()));
837 }
838 }
839
840 Ok((evm_env, tx_env))
841 }
842}