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::{cancelled::CancelOnDrop, database::StateProviderDatabase, db::State};
29use reth_rpc_convert::{RpcConvert, RpcTxReq};
30use reth_rpc_eth_types::{
31 cache::db::StateProviderTraitObjWrapper,
32 error::{AsEthApiError, FromEthApiError},
33 simulate::{self, EthSimulateError},
34 EthApiError, StateCacheDb,
35};
36use reth_storage_api::{BlockIdReader, ProviderTx, StateProvider};
37use revm::{
38 context::Block,
39 context_interface::{result::ResultAndState, Transaction},
40 Database, DatabaseCommit,
41};
42use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
43use tracing::{trace, warn};
44
45pub type SimulatedBlocksResult<N, E> = Result<Vec<SimulatedBlock<RpcBlock<N>>>, E>;
47
48pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthApiTypes {
51 fn estimate_gas_at(
53 &self,
54 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
55 at: BlockId,
56 state_override: Option<StateOverride>,
57 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
58 EstimateCall::estimate_gas_at(self, request, at, state_override)
59 }
60
61 fn simulate_v1(
66 &self,
67 payload: SimulatePayload<RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>>,
68 block: Option<BlockId>,
69 ) -> impl Future<Output = SimulatedBlocksResult<Self::NetworkTypes, Self::Error>> + Send {
70 async move {
71 if payload.block_state_calls.len() > self.max_simulate_blocks() as usize {
72 return Err(EthApiError::InvalidParams("too many blocks.".to_string()).into())
73 }
74
75 let block = block.unwrap_or_default();
76
77 let SimulatePayload {
78 block_state_calls,
79 trace_transfers,
80 validation,
81 return_full_transactions,
82 } = payload;
83
84 if block_state_calls.is_empty() {
85 return Err(EthApiError::InvalidParams(String::from("calls are empty.")).into())
86 }
87
88 let base_block =
89 self.recovered_block(block).await?.ok_or(EthApiError::HeaderNotFound(block))?;
90 let mut parent = base_block.sealed_header().clone();
91
92 self.spawn_with_state_at_block(block, move |this, mut db| {
93 let mut blocks: Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>> =
94 Vec::with_capacity(block_state_calls.len());
95 for block in block_state_calls {
96 let mut evm_env = this
97 .evm_config()
98 .next_evm_env(&parent, &this.next_env_attributes(&parent)?)
99 .map_err(RethError::other)
100 .map_err(Self::Error::from_eth_err)?;
101
102 evm_env.cfg_env.disable_eip3607 = true;
104
105 if !validation {
106 evm_env.cfg_env.disable_nonce_check = true;
108 evm_env.cfg_env.disable_base_fee = true;
109 evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
110 evm_env.block_env.inner_mut().basefee = 0;
111 }
112
113 let SimBlock { block_overrides, state_overrides, calls } = block;
114
115 if let Some(block_overrides) = block_overrides {
116 if let Some(gas_limit_override) = block_overrides.gas_limit &&
118 gas_limit_override > evm_env.block_env.gas_limit() &&
119 gas_limit_override > this.call_gas_limit()
120 {
121 return Err(EthApiError::other(EthSimulateError::GasLimitReached).into())
122 }
123 apply_block_overrides(
124 block_overrides,
125 &mut db,
126 evm_env.block_env.inner_mut(),
127 );
128 }
129 if let Some(state_overrides) = state_overrides {
130 apply_state_overrides(state_overrides, &mut db)
131 .map_err(Self::Error::from_eth_err)?;
132 }
133
134 let block_gas_limit = evm_env.block_env.gas_limit();
135 let chain_id = evm_env.cfg_env.chain_id;
136
137 let default_gas_limit = {
138 let total_specified_gas =
139 calls.iter().filter_map(|tx| tx.as_ref().gas_limit()).sum::<u64>();
140 let txs_without_gas_limit =
141 calls.iter().filter(|tx| tx.as_ref().gas_limit().is_none()).count();
142
143 if total_specified_gas > block_gas_limit {
144 return Err(EthApiError::Other(Box::new(
145 EthSimulateError::BlockGasLimitExceeded,
146 ))
147 .into())
148 }
149
150 if txs_without_gas_limit > 0 {
151 (block_gas_limit - total_specified_gas) / txs_without_gas_limit as u64
152 } else {
153 0
154 }
155 };
156
157 let ctx = this
158 .evm_config()
159 .context_for_next_block(&parent, this.next_env_attributes(&parent)?)
160 .map_err(RethError::other)
161 .map_err(Self::Error::from_eth_err)?;
162 let map_err = |e: EthApiError| -> Self::Error {
163 match e.as_simulate_error() {
164 Some(sim_err) => Self::Error::from_eth_err(EthApiError::other(sim_err)),
165 None => Self::Error::from_eth_err(e),
166 }
167 };
168
169 let (result, results) = if trace_transfers {
170 let inspector = TransferInspector::new(false).with_logs(true);
173 let evm = this
174 .evm_config()
175 .evm_with_env_and_inspector(&mut db, evm_env, inspector);
176 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
177 simulate::execute_transactions(
178 builder,
179 calls,
180 default_gas_limit,
181 chain_id,
182 this.converter(),
183 )
184 .map_err(map_err)?
185 } else {
186 let evm = this.evm_config().evm_with_env(&mut db, evm_env);
187 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
188 simulate::execute_transactions(
189 builder,
190 calls,
191 default_gas_limit,
192 chain_id,
193 this.converter(),
194 )
195 .map_err(map_err)?
196 };
197
198 parent = result.block.clone_sealed_header();
199
200 let block = simulate::build_simulated_block::<Self::Error, _>(
201 result.block,
202 results,
203 return_full_transactions.into(),
204 this.converter(),
205 )?;
206
207 blocks.push(block);
208 }
209
210 Ok(blocks)
211 })
212 .await
213 }
214 }
215
216 fn call(
218 &self,
219 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
220 block_number: Option<BlockId>,
221 overrides: EvmOverrides,
222 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
223 async move {
224 let _permit = self.acquire_owned_blocking_io().await;
225 let res =
226 self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
227
228 Self::Error::ensure_success(res.result)
229 }
230 }
231
232 fn call_many(
235 &self,
236 bundles: Vec<Bundle<RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>>>,
237 state_context: Option<StateContext>,
238 mut state_override: Option<StateOverride>,
239 ) -> impl Future<Output = Result<Vec<Vec<EthCallResponse>>, Self::Error>> + Send {
240 async move {
241 if bundles.is_empty() {
243 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into());
244 }
245
246 let StateContext { transaction_index, block_number } =
247 state_context.unwrap_or_default();
248 let transaction_index = transaction_index.unwrap_or_default();
249
250 let mut target_block = block_number.unwrap_or_default();
251 let is_block_target_pending = target_block.is_pending();
252
253 if !is_block_target_pending {
256 target_block = self
257 .provider()
258 .block_hash_for_id(target_block)
259 .map_err(|_| EthApiError::HeaderNotFound(target_block))?
260 .ok_or_else(|| EthApiError::HeaderNotFound(target_block))?
261 .into();
262 }
263
264 let ((evm_env, _), block) = futures::try_join!(
265 self.evm_env_at(target_block),
266 self.recovered_block(target_block)
267 )?;
268
269 let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
270
271 let mut at = block.parent_hash();
275 let mut replay_block_txs = true;
276
277 let num_txs =
278 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
279 if !is_block_target_pending && num_txs == block.body().transactions().len() {
283 at = block.hash();
284 replay_block_txs = false;
285 }
286
287 self.spawn_with_state_at_block(at, move |this, mut db| {
288 let mut all_results = Vec::with_capacity(bundles.len());
289
290 if replay_block_txs {
291 let block_transactions = block.transactions_recovered().take(num_txs);
294 for tx in block_transactions {
295 let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
296 let res = this.transact(&mut db, evm_env.clone(), tx_env)?;
297 db.commit(res.state);
298 }
299 }
300
301 for (bundle_index, bundle) in bundles.into_iter().enumerate() {
303 let Bundle { transactions, block_override } = bundle;
304 if transactions.is_empty() {
305 continue;
307 }
308
309 let mut bundle_results = Vec::with_capacity(transactions.len());
310 let block_overrides = block_override.map(Box::new);
311
312 for (tx_index, tx) in transactions.into_iter().enumerate() {
314 let overrides =
317 EvmOverrides::new(state_override.take(), block_overrides.clone());
318
319 let (current_evm_env, prepared_tx) = this
320 .prepare_call_env(evm_env.clone(), tx, &mut db, overrides)
321 .map_err(|err| {
322 Self::Error::from_eth_err(EthApiError::call_many_error(
323 bundle_index,
324 tx_index,
325 err.into(),
326 ))
327 })?;
328 let res = this.transact(&mut db, current_evm_env, prepared_tx).map_err(
329 |err| {
330 Self::Error::from_eth_err(EthApiError::call_many_error(
331 bundle_index,
332 tx_index,
333 err.into(),
334 ))
335 },
336 )?;
337
338 match Self::Error::ensure_success(res.result) {
339 Ok(output) => {
340 bundle_results
341 .push(EthCallResponse { value: Some(output), error: None });
342 }
343 Err(err) => {
344 bundle_results.push(EthCallResponse {
345 value: None,
346 error: Some(err.to_string()),
347 });
348 }
349 }
350
351 db.commit(res.state);
354 }
355
356 all_results.push(bundle_results);
357 }
358
359 Ok(all_results)
360 })
361 .await
362 }
363 }
364
365 fn create_access_list_at(
368 &self,
369 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
370 block_number: Option<BlockId>,
371 state_override: Option<StateOverride>,
372 ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
373 where
374 Self: Trace,
375 {
376 async move {
377 let block_id = block_number.unwrap_or_default();
378 let (evm_env, at) = self.evm_env_at(block_id).await?;
379
380 self.spawn_blocking_io_fut(move |this| async move {
381 this.create_access_list_with(evm_env, at, request, state_override).await
382 })
383 .await
384 }
385 }
386
387 fn create_access_list_with(
390 &self,
391 mut evm_env: EvmEnvFor<Self::Evm>,
392 at: BlockId,
393 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
394 state_override: Option<StateOverride>,
395 ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
396 where
397 Self: Trace,
398 {
399 self.spawn_blocking_io_fut(move |this| async move {
400 let state = this.state_at_block_id(at).await?;
401 let mut db = State::builder().with_database(StateProviderDatabase::new(state)).build();
402
403 if let Some(state_overrides) = state_override {
404 apply_state_overrides(state_overrides, &mut db)
405 .map_err(Self::Error::from_eth_err)?;
406 }
407
408 let mut tx_env = this.create_txn_env(&evm_env, request.clone(), &mut db)?;
409
410 evm_env.cfg_env.disable_block_gas_limit = true;
413
414 evm_env.cfg_env.disable_base_fee = true;
418
419 evm_env.cfg_env.disable_eip3607 = true;
421
422 if request.as_ref().gas_limit().is_none() && tx_env.gas_price() > 0 {
423 let cap = this.caller_gas_allowance(&mut db, &evm_env, &tx_env)?;
424 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit()));
427 }
428
429 let initial = request.as_ref().access_list().cloned().unwrap_or_default();
431
432 let mut inspector = AccessListInspector::new(initial);
433
434 let result = this.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
435 let access_list = inspector.into_access_list();
436 let gas_used = result.result.gas_used();
437 tx_env.set_access_list(access_list.clone());
438 if let Err(err) = Self::Error::ensure_success(result.result) {
439 return Ok(AccessListResult {
440 access_list,
441 gas_used: U256::from(gas_used),
442 error: Some(err.to_string()),
443 });
444 }
445
446 let result = this.transact(&mut db, evm_env, tx_env)?;
448 let gas_used = result.result.gas_used();
449 let error = Self::Error::ensure_success(result.result).err().map(|e| e.to_string());
450
451 Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
452 })
453 }
454}
455
456pub trait Call:
458 LoadState<
459 RpcConvert: RpcConvert<Evm = Self::Evm>,
460 Error: FromEvmError<Self::Evm>
461 + From<<Self::RpcConvert as RpcConvert>::Error>
462 + From<ProviderError>,
463 > + SpawnBlocking
464{
465 fn call_gas_limit(&self) -> u64;
469
470 fn max_simulate_blocks(&self) -> u64;
472
473 fn evm_memory_limit(&self) -> u64;
475
476 fn caller_gas_allowance(
478 &self,
479 mut db: impl Database<Error: Into<EthApiError>>,
480 _evm_env: &EvmEnvFor<Self::Evm>,
481 tx_env: &TxEnvFor<Self::Evm>,
482 ) -> Result<u64, Self::Error> {
483 alloy_evm::call::caller_gas_allowance(&mut db, tx_env).map_err(Self::Error::from_eth_err)
484 }
485
486 fn with_state_at_block<F, R>(
488 &self,
489 at: BlockId,
490 f: F,
491 ) -> impl Future<Output = Result<R, Self::Error>> + Send
492 where
493 R: Send + 'static,
494 F: FnOnce(Self, &dyn StateProvider) -> Result<R, Self::Error> + Send + 'static,
495 {
496 self.spawn_blocking_io_fut(move |this| async move {
497 let state = this.state_at_block_id(at).await?;
498 f(this, &state)
499 })
500 }
501
502 fn transact<DB>(
505 &self,
506 db: DB,
507 evm_env: EvmEnvFor<Self::Evm>,
508 tx_env: TxEnvFor<Self::Evm>,
509 ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
510 where
511 DB: Database<Error = ProviderError> + fmt::Debug,
512 {
513 let mut evm = self.evm_config().evm_with_env(db, evm_env);
514 let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
515
516 Ok(res)
517 }
518
519 fn transact_with_inspector<DB, I>(
522 &self,
523 db: DB,
524 evm_env: EvmEnvFor<Self::Evm>,
525 tx_env: TxEnvFor<Self::Evm>,
526 inspector: I,
527 ) -> Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>
528 where
529 DB: Database<Error = ProviderError> + fmt::Debug,
530 I: InspectorFor<Self::Evm, DB>,
531 {
532 let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, inspector);
533 let res = evm.transact(tx_env).map_err(Self::Error::from_evm_err)?;
534
535 Ok(res)
536 }
537
538 fn transact_call_at(
545 &self,
546 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
547 at: BlockId,
548 overrides: EvmOverrides,
549 ) -> impl Future<Output = Result<ResultAndState<HaltReasonFor<Self::Evm>>, Self::Error>> + Send
550 where
551 Self: LoadPendingBlock,
552 {
553 async move {
554 let guard = CancelOnDrop::default();
555 let cancel = guard.clone();
556 let this = self.clone();
557
558 let res = self
559 .spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
560 if cancel.is_cancelled() {
561 return Err(EthApiError::InternalEthError.into())
563 }
564 this.transact(db, evm_env, tx_env)
565 })
566 .await;
567 drop(guard);
568 res
569 }
570 }
571
572 fn spawn_with_state_at_block<F, R>(
574 &self,
575 at: impl Into<BlockId>,
576 f: F,
577 ) -> impl Future<Output = Result<R, Self::Error>> + Send
578 where
579 F: FnOnce(Self, StateCacheDb) -> Result<R, Self::Error> + Send + 'static,
580 R: Send + 'static,
581 {
582 let at = at.into();
583 self.spawn_blocking_io_fut(move |this| async move {
584 let state = this.state_at_block_id(at).await?;
585 let db = State::builder()
586 .with_database(StateProviderDatabase::new(StateProviderTraitObjWrapper(state)))
587 .build();
588 f(this, db)
589 })
590 }
591
592 fn spawn_with_call_at<F, R>(
608 &self,
609 request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
610 at: BlockId,
611 overrides: EvmOverrides,
612 f: F,
613 ) -> impl Future<Output = Result<R, Self::Error>> + Send
614 where
615 Self: LoadPendingBlock,
616 F: FnOnce(
617 &mut StateCacheDb,
618 EvmEnvFor<Self::Evm>,
619 TxEnvFor<Self::Evm>,
620 ) -> Result<R, Self::Error>
621 + Send
622 + 'static,
623 R: Send + 'static,
624 {
625 async move {
626 let (evm_env, at) = self.evm_env_at(at).await?;
627 self.spawn_with_state_at_block(at, move |this, mut db| {
628 let (evm_env, tx_env) =
629 this.prepare_call_env(evm_env, request, &mut db, overrides)?;
630
631 f(&mut db, evm_env, tx_env)
632 })
633 .await
634 }
635 }
636
637 fn spawn_replay_transaction<F, R>(
647 &self,
648 hash: B256,
649 f: F,
650 ) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
651 where
652 Self: LoadBlock + LoadTransaction,
653 F: FnOnce(
654 TransactionInfo,
655 ResultAndState<HaltReasonFor<Self::Evm>>,
656 StateCacheDb,
657 ) -> Result<R, Self::Error>
658 + Send
659 + 'static,
660 R: Send + 'static,
661 {
662 async move {
663 let (transaction, block) = match self.transaction_and_block(hash).await? {
664 None => return Ok(None),
665 Some(res) => res,
666 };
667 let (tx, tx_info) = transaction.split();
668
669 let (evm_env, _) = self.evm_env_at(block.hash().into()).await?;
670
671 let parent_block = block.parent_hash();
674
675 self.spawn_with_state_at_block(parent_block, move |this, mut db| {
676 let block_txs = block.transactions_recovered();
677
678 this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
680
681 let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
682
683 let res = this.transact(&mut db, evm_env, tx_env)?;
684 f(tx_info, res, db)
685 })
686 .await
687 .map(Some)
688 }
689 }
690
691 fn replay_transactions_until<'a, DB, I>(
699 &self,
700 db: &mut DB,
701 evm_env: EvmEnvFor<Self::Evm>,
702 transactions: I,
703 target_tx_hash: B256,
704 ) -> Result<usize, Self::Error>
705 where
706 DB: Database<Error = ProviderError> + DatabaseCommit + core::fmt::Debug,
707 I: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
708 {
709 let mut evm = self.evm_config().evm_with_env(db, evm_env);
710 let mut index = 0;
711 for tx in transactions {
712 if *tx.tx_hash() == target_tx_hash {
713 break
715 }
716
717 let tx_env = self.evm_config().tx_env(tx);
718 evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
719 index += 1;
720 }
721 Ok(index)
722 }
723
724 fn create_txn_env(
728 &self,
729 evm_env: &EvmEnvFor<Self::Evm>,
730 mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
731 mut db: impl Database<Error: Into<EthApiError>>,
732 ) -> Result<TxEnvFor<Self::Evm>, Self::Error> {
733 if request.as_ref().nonce().is_none() {
734 let nonce = db
735 .basic(request.as_ref().from().unwrap_or_default())
736 .map_err(Into::into)?
737 .map(|acc| acc.nonce)
738 .unwrap_or_default();
739 request.as_mut().set_nonce(nonce);
740 }
741
742 Ok(self.converter().tx_env(request, evm_env)?)
743 }
744
745 #[expect(clippy::type_complexity)]
759 fn prepare_call_env<DB>(
760 &self,
761 mut evm_env: EvmEnvFor<Self::Evm>,
762 mut request: RpcTxReq<<Self::RpcConvert as RpcConvert>::Network>,
763 db: &mut DB,
764 overrides: EvmOverrides,
765 ) -> Result<(EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>), Self::Error>
766 where
767 DB: Database + DatabaseCommit + OverrideBlockHashes,
768 EthApiError: From<<DB as Database>::Error>,
769 {
770 let request_has_gas_limit = request.as_ref().gas_limit().is_some();
772
773 if let Some(requested_gas) = request.as_ref().gas_limit() {
774 let global_gas_cap = self.call_gas_limit();
775 if global_gas_cap != 0 && global_gas_cap < requested_gas {
776 warn!(target: "rpc::eth::call", ?request, ?global_gas_cap, "Capping gas limit to global gas cap");
777 request.as_mut().set_gas_limit(global_gas_cap);
778 }
779 } else {
780 request.as_mut().set_gas_limit(self.call_gas_limit());
782 }
783
784 evm_env.cfg_env.disable_block_gas_limit = true;
787
788 evm_env.cfg_env.disable_eip3607 = true;
791
792 evm_env.cfg_env.disable_base_fee = true;
796
797 evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
799
800 evm_env.cfg_env.disable_fee_charge = true;
804
805 evm_env.cfg_env.memory_limit = self.evm_memory_limit();
806
807 request.as_mut().take_nonce();
809
810 if let Some(block_overrides) = overrides.block {
811 apply_block_overrides(*block_overrides, db, evm_env.block_env.inner_mut());
812 }
813 if let Some(state_overrides) = overrides.state {
814 apply_state_overrides(state_overrides, db)
815 .map_err(EthApiError::from_state_overrides_err)?;
816 }
817
818 let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
819
820 if tx_env.gas_price() == 0 {
822 evm_env.block_env.inner_mut().basefee = 0;
823 }
824
825 if !request_has_gas_limit {
826 if tx_env.gas_price() > 0 {
828 trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
830 let cap = self.caller_gas_allowance(db, &evm_env, &tx_env)?;
831 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit()));
833 }
834 }
835
836 Ok((evm_env, tx_env))
837 }
838}