1use super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace};
5use crate::{
6 helpers::estimate::EstimateCall, FromEvmError, FullEthApiTypes, RpcBlock, RpcNodeCore,
7};
8use alloy_consensus::BlockHeader;
9use alloy_eips::eip2930::AccessListResult;
10use alloy_primitives::{Bytes, B256, U256};
11use alloy_rpc_types_eth::{
12 simulate::{SimBlock, SimulatePayload, SimulatedBlock},
13 state::{EvmOverrides, StateOverride},
14 transaction::TransactionRequest,
15 BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo,
16};
17use futures::Future;
18use reth_errors::{ProviderError, RethError};
19use reth_evm::{
20 ConfigureEvm, Evm, EvmEnv, EvmEnvFor, HaltReasonFor, InspectorFor, SpecFor, TransactionEnv,
21 TxEnvFor,
22};
23use reth_node_api::{BlockBody, NodePrimitives};
24use reth_primitives_traits::{Recovered, SealedHeader, SignedTransaction};
25use reth_provider::{BlockIdReader, ProviderHeader, ProviderTx};
26use reth_revm::{
27 database::StateProviderDatabase,
28 db::{CacheDB, State},
29 DatabaseRef,
30};
31use reth_rpc_eth_types::{
32 cache::db::{StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
33 error::{api::FromEvmHalt, ensure_success, FromEthApiError},
34 revm_utils::{apply_block_overrides, apply_state_overrides, caller_gas_allowance},
35 simulate::{self, EthSimulateError},
36 EthApiError, RevertError, RpcInvalidTransactionError, StateCacheDb,
37};
38use revm::{
39 context_interface::{
40 result::{ExecutionResult, ResultAndState},
41 Transaction,
42 },
43 Database, DatabaseCommit,
44};
45use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
46use tracing::trace;
47
48pub type SimulatedBlocksResult<N, E> = Result<Vec<SimulatedBlock<RpcBlock<N>>>, E>;
50
51pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthApiTypes {
54 fn estimate_gas_at(
56 &self,
57 request: TransactionRequest,
58 at: BlockId,
59 state_override: Option<StateOverride>,
60 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
61 EstimateCall::estimate_gas_at(self, request, at, state_override)
62 }
63
64 fn simulate_v1(
69 &self,
70 payload: SimulatePayload,
71 block: Option<BlockId>,
72 ) -> impl Future<Output = SimulatedBlocksResult<Self::NetworkTypes, Self::Error>> + Send {
73 async move {
74 if payload.block_state_calls.len() > self.max_simulate_blocks() as usize {
75 return Err(EthApiError::InvalidParams("too many blocks.".to_string()).into())
76 }
77
78 let block = block.unwrap_or_default();
79
80 let SimulatePayload {
81 block_state_calls,
82 trace_transfers,
83 validation,
84 return_full_transactions,
85 } = payload;
86
87 if block_state_calls.is_empty() {
88 return Err(EthApiError::InvalidParams(String::from("calls are empty.")).into())
89 }
90
91 let base_block =
92 self.recovered_block(block).await?.ok_or(EthApiError::HeaderNotFound(block))?;
93 let mut parent = base_block.sealed_header().clone();
94
95 let this = self.clone();
96 self.spawn_with_state_at_block(block, move |state| {
97 let mut db =
98 State::builder().with_database(StateProviderDatabase::new(state)).build();
99 let mut blocks: Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>> =
100 Vec::with_capacity(block_state_calls.len());
101 for block in block_state_calls {
102 let mut evm_env = this
103 .evm_config()
104 .next_evm_env(&parent, &this.next_env_attributes(&parent)?)
105 .map_err(RethError::other)
106 .map_err(Self::Error::from_eth_err)?;
107
108 evm_env.cfg_env.disable_eip3607 = true;
110
111 if !validation {
112 evm_env.cfg_env.disable_base_fee = !validation;
113 evm_env.block_env.basefee = 0;
114 }
115
116 let SimBlock { block_overrides, state_overrides, calls } = block;
117
118 if let Some(block_overrides) = block_overrides {
119 if let Some(gas_limit_override) = block_overrides.gas_limit {
121 if gas_limit_override > evm_env.block_env.gas_limit &&
122 gas_limit_override > this.call_gas_limit()
123 {
124 return Err(
125 EthApiError::other(EthSimulateError::GasLimitReached).into()
126 )
127 }
128 }
129 apply_block_overrides(block_overrides, &mut db, &mut evm_env.block_env);
130 }
131 if let Some(state_overrides) = state_overrides {
132 apply_state_overrides(state_overrides, &mut db)?;
133 }
134
135 let block_env = evm_env.block_env.clone();
136 let chain_id = evm_env.cfg_env.chain_id;
137
138 let default_gas_limit = {
139 let total_specified_gas = calls.iter().filter_map(|tx| tx.gas).sum::<u64>();
140 let txs_without_gas_limit =
141 calls.iter().filter(|tx| tx.gas.is_none()).count();
142
143 if total_specified_gas > block_env.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_env.gas_limit - total_specified_gas) /
152 txs_without_gas_limit as u64
153 } else {
154 0
155 }
156 };
157
158 let ctx = this
159 .evm_config()
160 .context_for_next_block(&parent, this.next_env_attributes(&parent)?);
161 let (result, results) = if trace_transfers {
162 let inspector = TransferInspector::new(false).with_logs(true);
165 let evm = this
166 .evm_config()
167 .evm_with_env_and_inspector(&mut db, evm_env, inspector);
168 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
169 simulate::execute_transactions(
170 builder,
171 calls,
172 default_gas_limit,
173 chain_id,
174 this.tx_resp_builder(),
175 )?
176 } else {
177 let evm = this.evm_config().evm_with_env(&mut db, evm_env);
178 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
179 simulate::execute_transactions(
180 builder,
181 calls,
182 default_gas_limit,
183 chain_id,
184 this.tx_resp_builder(),
185 )?
186 };
187
188 let block = simulate::build_simulated_block(
189 result.block,
190 results,
191 return_full_transactions,
192 this.tx_resp_builder(),
193 )?;
194
195 parent = SealedHeader::new(
196 block.inner.header.inner.clone(),
197 block.inner.header.hash,
198 );
199
200 blocks.push(block);
201 }
202
203 Ok(blocks)
204 })
205 .await
206 }
207 }
208
209 fn call(
211 &self,
212 request: TransactionRequest,
213 block_number: Option<BlockId>,
214 overrides: EvmOverrides,
215 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
216 async move {
217 let (res, _env) =
218 self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
219
220 ensure_success(res.result)
221 }
222 }
223
224 fn call_many(
227 &self,
228 bundles: Vec<Bundle>,
229 state_context: Option<StateContext>,
230 mut state_override: Option<StateOverride>,
231 ) -> impl Future<Output = Result<Vec<Vec<EthCallResponse>>, Self::Error>> + Send {
232 async move {
233 if bundles.is_empty() {
235 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into());
236 }
237
238 let StateContext { transaction_index, block_number } =
239 state_context.unwrap_or_default();
240 let transaction_index = transaction_index.unwrap_or_default();
241
242 let mut target_block = block_number.unwrap_or_default();
243 let is_block_target_pending = target_block.is_pending();
244
245 if !is_block_target_pending {
248 target_block = self
249 .provider()
250 .block_hash_for_id(target_block)
251 .map_err(|_| EthApiError::HeaderNotFound(target_block))?
252 .ok_or_else(|| EthApiError::HeaderNotFound(target_block))?
253 .into();
254 }
255
256 let ((evm_env, _), block) = futures::try_join!(
257 self.evm_env_at(target_block),
258 self.recovered_block(target_block)
259 )?;
260
261 let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
262
263 let mut at = block.parent_hash();
267 let mut replay_block_txs = true;
268
269 let num_txs =
270 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
271 if !is_block_target_pending && num_txs == block.body().transactions().len() {
275 at = block.hash();
276 replay_block_txs = false;
277 }
278
279 let this = self.clone();
280 self.spawn_with_state_at_block(at.into(), move |state| {
281 let mut all_results = Vec::with_capacity(bundles.len());
282 let mut db = CacheDB::new(StateProviderDatabase::new(state));
283
284 if replay_block_txs {
285 let block_transactions = block.transactions_recovered().take(num_txs);
288 for tx in block_transactions {
289 let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
290 let (res, _) = this.transact(&mut db, evm_env.clone(), tx_env)?;
291 db.commit(res.state);
292 }
293 }
294
295 for bundle in bundles {
297 let Bundle { transactions, block_override } = bundle;
298 if transactions.is_empty() {
299 continue;
301 }
302
303 let mut bundle_results = Vec::with_capacity(transactions.len());
304 let block_overrides = block_override.map(Box::new);
305
306 for tx in transactions {
308 let overrides =
311 EvmOverrides::new(state_override.take(), block_overrides.clone());
312
313 let (current_evm_env, prepared_tx) =
314 this.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
315 let (res, _) = this.transact(&mut db, current_evm_env, prepared_tx)?;
316
317 match ensure_success::<_, Self::Error>(res.result) {
318 Ok(output) => {
319 bundle_results
320 .push(EthCallResponse { value: Some(output), error: None });
321 }
322 Err(err) => {
323 bundle_results.push(EthCallResponse {
324 value: None,
325 error: Some(err.to_string()),
326 });
327 }
328 }
329
330 db.commit(res.state);
333 }
334
335 all_results.push(bundle_results);
336 }
337
338 Ok(all_results)
339 })
340 .await
341 }
342 }
343
344 fn create_access_list_at(
347 &self,
348 request: TransactionRequest,
349 block_number: Option<BlockId>,
350 ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
351 where
352 Self: Trace,
353 {
354 async move {
355 let block_id = block_number.unwrap_or_default();
356 let (evm_env, at) = self.evm_env_at(block_id).await?;
357
358 self.spawn_blocking_io(move |this| this.create_access_list_with(evm_env, at, request))
359 .await
360 }
361 }
362
363 fn create_access_list_with(
366 &self,
367 mut evm_env: EvmEnvFor<Self::Evm>,
368 at: BlockId,
369 mut request: TransactionRequest,
370 ) -> Result<AccessListResult, Self::Error>
371 where
372 Self: Trace,
373 {
374 let state = self.state_at_block_id(at)?;
375 let mut db = CacheDB::new(StateProviderDatabase::new(state));
376
377 let mut tx_env = self.create_txn_env(&evm_env, request.clone(), &mut db)?;
378
379 evm_env.cfg_env.disable_block_gas_limit = true;
382
383 evm_env.cfg_env.disable_base_fee = true;
387
388 evm_env.cfg_env.disable_eip3607 = true;
390
391 if request.gas.is_none() && tx_env.gas_price() > 0 {
392 let cap = caller_gas_allowance(&mut db, &tx_env)?;
393 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit));
395 }
396
397 let initial = request.access_list.take().unwrap_or_default();
399
400 let mut inspector = AccessListInspector::new(initial);
401
402 let (result, (evm_env, mut tx_env)) =
403 self.inspect(&mut db, evm_env, tx_env, &mut inspector)?;
404 let access_list = inspector.into_access_list();
405 tx_env.set_access_list(access_list.clone());
406 match result.result {
407 ExecutionResult::Halt { reason, gas_used } => {
408 let error =
409 Some(Self::Error::from_evm_halt(reason, tx_env.gas_limit()).to_string());
410 return Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
411 }
412 ExecutionResult::Revert { output, gas_used } => {
413 let error = Some(RevertError::new(output).to_string());
414 return Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
415 }
416 ExecutionResult::Success { .. } => {}
417 };
418
419 let (result, (_, tx_env)) = self.transact(&mut db, evm_env, tx_env)?;
421 let res = match result.result {
422 ExecutionResult::Halt { reason, gas_used } => {
423 let error =
424 Some(Self::Error::from_evm_halt(reason, tx_env.gas_limit()).to_string());
425 AccessListResult { access_list, gas_used: U256::from(gas_used), error }
426 }
427 ExecutionResult::Revert { output, gas_used } => {
428 let error = Some(RevertError::new(output).to_string());
429 AccessListResult { access_list, gas_used: U256::from(gas_used), error }
430 }
431 ExecutionResult::Success { gas_used, .. } => {
432 AccessListResult { access_list, gas_used: U256::from(gas_used), error: None }
433 }
434 };
435
436 Ok(res)
437 }
438}
439
440pub trait Call:
442 LoadState<
443 Evm: ConfigureEvm<
444 Primitives: NodePrimitives<
445 BlockHeader = ProviderHeader<Self::Provider>,
446 SignedTx = ProviderTx<Self::Provider>,
447 >,
448 >,
449 Error: FromEvmError<Self::Evm>,
450 > + SpawnBlocking
451{
452 fn call_gas_limit(&self) -> u64;
456
457 fn max_simulate_blocks(&self) -> u64;
459
460 fn with_state_at_block<F, R>(&self, at: BlockId, f: F) -> Result<R, Self::Error>
462 where
463 F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result<R, Self::Error>,
464 {
465 let state = self.state_at_block_id(at)?;
466 f(StateProviderTraitObjWrapper(&state))
467 }
468
469 #[expect(clippy::type_complexity)]
472 fn transact<DB>(
473 &self,
474 db: DB,
475 evm_env: EvmEnvFor<Self::Evm>,
476 tx_env: TxEnvFor<Self::Evm>,
477 ) -> Result<
478 (ResultAndState<HaltReasonFor<Self::Evm>>, (EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>)),
479 Self::Error,
480 >
481 where
482 DB: Database<Error = ProviderError>,
483 {
484 let mut evm = self.evm_config().evm_with_env(db, evm_env.clone());
485 let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
486
487 Ok((res, (evm_env, tx_env)))
488 }
489
490 #[expect(clippy::type_complexity)]
493 fn transact_with_inspector<DB, I>(
494 &self,
495 db: DB,
496 evm_env: EvmEnvFor<Self::Evm>,
497 tx_env: TxEnvFor<Self::Evm>,
498 inspector: I,
499 ) -> Result<
500 (ResultAndState<HaltReasonFor<Self::Evm>>, (EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>)),
501 Self::Error,
502 >
503 where
504 DB: Database<Error = ProviderError>,
505 I: InspectorFor<Self::Evm, DB>,
506 {
507 let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env.clone(), inspector);
508 let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
509
510 Ok((res, (evm_env, tx_env)))
511 }
512
513 #[expect(clippy::type_complexity)]
515 fn transact_call_at(
516 &self,
517 request: TransactionRequest,
518 at: BlockId,
519 overrides: EvmOverrides,
520 ) -> impl Future<
521 Output = Result<
522 (ResultAndState<HaltReasonFor<Self::Evm>>, (EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>)),
523 Self::Error,
524 >,
525 > + Send
526 where
527 Self: LoadPendingBlock,
528 {
529 let this = self.clone();
530 self.spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
531 this.transact(db, evm_env, tx_env)
532 })
533 }
534
535 fn spawn_with_state_at_block<F, R>(
537 &self,
538 at: BlockId,
539 f: F,
540 ) -> impl Future<Output = Result<R, Self::Error>> + Send
541 where
542 F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result<R, Self::Error> + Send + 'static,
543 R: Send + 'static,
544 {
545 self.spawn_tracing(move |this| {
546 let state = this.state_at_block_id(at)?;
547 f(StateProviderTraitObjWrapper(&state))
548 })
549 }
550
551 fn spawn_with_call_at<F, R>(
567 &self,
568 request: TransactionRequest,
569 at: BlockId,
570 overrides: EvmOverrides,
571 f: F,
572 ) -> impl Future<Output = Result<R, Self::Error>> + Send
573 where
574 Self: LoadPendingBlock,
575 F: FnOnce(
576 StateCacheDbRefMutWrapper<'_, '_>,
577 EvmEnvFor<Self::Evm>,
578 TxEnvFor<Self::Evm>,
579 ) -> Result<R, Self::Error>
580 + Send
581 + 'static,
582 R: Send + 'static,
583 {
584 async move {
585 let (evm_env, at) = self.evm_env_at(at).await?;
586 let this = self.clone();
587 self.spawn_blocking_io(move |_| {
588 let state = this.state_at_block_id(at)?;
589 let mut db =
590 CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state)));
591
592 let (evm_env, tx_env) =
593 this.prepare_call_env(evm_env, request, &mut db, overrides)?;
594
595 f(StateCacheDbRefMutWrapper(&mut db), evm_env, tx_env)
596 })
597 .await
598 }
599 }
600
601 fn spawn_replay_transaction<F, R>(
611 &self,
612 hash: B256,
613 f: F,
614 ) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
615 where
616 Self: LoadBlock + LoadTransaction,
617 F: FnOnce(
618 TransactionInfo,
619 ResultAndState<HaltReasonFor<Self::Evm>>,
620 StateCacheDb<'_>,
621 ) -> Result<R, Self::Error>
622 + Send
623 + 'static,
624 R: Send + 'static,
625 {
626 async move {
627 let (transaction, block) = match self.transaction_and_block(hash).await? {
628 None => return Ok(None),
629 Some(res) => res,
630 };
631 let (tx, tx_info) = transaction.split();
632
633 let (evm_env, _) = self.evm_env_at(block.hash().into()).await?;
634
635 let parent_block = block.parent_hash();
638
639 let this = self.clone();
640 self.spawn_with_state_at_block(parent_block.into(), move |state| {
641 let mut db = CacheDB::new(StateProviderDatabase::new(state));
642 let block_txs = block.transactions_recovered();
643
644 this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
646
647 let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
648
649 let (res, _) = this.transact(&mut db, evm_env, tx_env)?;
650 f(tx_info, res, db)
651 })
652 .await
653 .map(Some)
654 }
655 }
656
657 fn replay_transactions_until<'a, DB, I>(
665 &self,
666 db: &mut DB,
667 evm_env: EvmEnvFor<Self::Evm>,
668 transactions: I,
669 target_tx_hash: B256,
670 ) -> Result<usize, Self::Error>
671 where
672 DB: Database<Error = ProviderError> + DatabaseCommit,
673 I: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
674 {
675 let mut evm = self.evm_config().evm_with_env(db, evm_env);
676 let mut index = 0;
677 for tx in transactions {
678 if *tx.tx_hash() == target_tx_hash {
679 break
681 }
682
683 let tx_env = self.evm_config().tx_env(tx);
684 evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
685 index += 1;
686 }
687 Ok(index)
688 }
689
690 fn create_txn_env(
695 &self,
696 evm_env: &EvmEnv<SpecFor<Self::Evm>>,
697 request: TransactionRequest,
698 db: impl Database<Error: Into<EthApiError>>,
699 ) -> Result<TxEnvFor<Self::Evm>, Self::Error>;
700
701 #[expect(clippy::type_complexity)]
715 fn prepare_call_env<DB>(
716 &self,
717 mut evm_env: EvmEnvFor<Self::Evm>,
718 mut request: TransactionRequest,
719 db: &mut CacheDB<DB>,
720 overrides: EvmOverrides,
721 ) -> Result<(EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>), Self::Error>
722 where
723 DB: DatabaseRef,
724 EthApiError: From<<DB as DatabaseRef>::Error>,
725 {
726 if request.gas > Some(self.call_gas_limit()) {
727 return Err(
729 EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh).into()
730 )
731 }
732
733 evm_env.block_env.gas_limit = self.call_gas_limit();
735
736 evm_env.cfg_env.disable_eip3607 = true;
739
740 evm_env.cfg_env.disable_base_fee = true;
744
745 request.nonce = None;
747
748 if let Some(block_overrides) = overrides.block {
749 apply_block_overrides(*block_overrides, db, &mut evm_env.block_env);
750 }
751 if let Some(state_overrides) = overrides.state {
752 apply_state_overrides(state_overrides, db)?;
753 }
754
755 let request_gas = request.gas;
756 let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
757
758 if request_gas.is_none() {
759 if tx_env.gas_price() > 0 {
761 trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
763 let cap = caller_gas_allowance(db, &tx_env)?;
764 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit));
766 }
767 }
768
769 Ok((evm_env, tx_env))
770 }
771}