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 #[allow(clippy::type_complexity)]
69 fn simulate_v1(
70 &self,
71 payload: SimulatePayload,
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 total_gas_limit = self.call_gas_limit();
94
95 let base_block =
96 self.recovered_block(block).await?.ok_or(EthApiError::HeaderNotFound(block))?;
97 let mut parent = base_block.sealed_header().clone();
98
99 let this = self.clone();
100 self.spawn_with_state_at_block(block, move |state| {
101 let mut db =
102 State::builder().with_database(StateProviderDatabase::new(state)).build();
103 let mut gas_used = 0;
104 let mut blocks: Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>> =
105 Vec::with_capacity(block_state_calls.len());
106 for block in block_state_calls {
107 let mut evm_env = this
108 .evm_config()
109 .next_evm_env(&parent, &this.next_env_attributes(&parent)?)
110 .map_err(RethError::other)
111 .map_err(Self::Error::from_eth_err)?;
112
113 evm_env.cfg_env.disable_eip3607 = true;
115
116 if !validation {
117 evm_env.cfg_env.disable_base_fee = !validation;
118 evm_env.block_env.basefee = 0;
119 }
120
121 let SimBlock { block_overrides, state_overrides, calls } = block;
122
123 if let Some(block_overrides) = block_overrides {
124 apply_block_overrides(block_overrides, &mut db, &mut evm_env.block_env);
125 }
126 if let Some(state_overrides) = state_overrides {
127 apply_state_overrides(state_overrides, &mut db)?;
128 }
129
130 let block_env = evm_env.block_env.clone();
131 let chain_id = evm_env.cfg_env.chain_id;
132
133 if (total_gas_limit - gas_used) < evm_env.block_env.gas_limit {
134 return Err(
135 EthApiError::Other(Box::new(EthSimulateError::GasLimitReached)).into()
136 )
137 }
138
139 let default_gas_limit = {
140 let total_specified_gas = calls.iter().filter_map(|tx| tx.gas).sum::<u64>();
141 let txs_without_gas_limit =
142 calls.iter().filter(|tx| tx.gas.is_none()).count();
143
144 if total_specified_gas > block_env.gas_limit {
145 return Err(EthApiError::Other(Box::new(
146 EthSimulateError::BlockGasLimitExceeded,
147 ))
148 .into())
149 }
150
151 if txs_without_gas_limit > 0 {
152 (block_env.gas_limit - total_specified_gas) /
153 txs_without_gas_limit as u64
154 } else {
155 0
156 }
157 };
158
159 let ctx = this
160 .evm_config()
161 .context_for_next_block(&parent, this.next_env_attributes(&parent)?);
162 let (result, results) = if trace_transfers {
163 let inspector = TransferInspector::new(false).with_logs(true);
166 let evm = this
167 .evm_config()
168 .evm_with_env_and_inspector(&mut db, evm_env, inspector);
169 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
170 simulate::execute_transactions(
171 builder,
172 calls,
173 validation,
174 default_gas_limit,
175 chain_id,
176 this.tx_resp_builder(),
177 )?
178 } else {
179 let evm = this.evm_config().evm_with_env(&mut db, evm_env);
180 let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
181 simulate::execute_transactions(
182 builder,
183 calls,
184 validation,
185 default_gas_limit,
186 chain_id,
187 this.tx_resp_builder(),
188 )?
189 };
190
191 let block = simulate::build_simulated_block(
192 result.block,
193 results,
194 return_full_transactions,
195 this.tx_resp_builder(),
196 )?;
197
198 parent = SealedHeader::new(
199 block.inner.header.inner.clone(),
200 block.inner.header.hash,
201 );
202 gas_used += block.inner.header.gas_used();
203
204 blocks.push(block);
205 }
206
207 Ok(blocks)
208 })
209 .await
210 }
211 }
212
213 fn call(
215 &self,
216 request: TransactionRequest,
217 block_number: Option<BlockId>,
218 overrides: EvmOverrides,
219 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
220 async move {
221 let (res, _env) =
222 self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
223
224 ensure_success(res.result)
225 }
226 }
227
228 fn call_many(
231 &self,
232 bundle: Bundle,
233 state_context: Option<StateContext>,
234 mut state_override: Option<StateOverride>,
235 ) -> impl Future<Output = Result<Vec<EthCallResponse>, Self::Error>> + Send {
236 async move {
237 let Bundle { transactions, block_override } = bundle;
238 if transactions.is_empty() {
239 return Err(
240 EthApiError::InvalidParams(String::from("transactions are empty.")).into()
241 )
242 }
243
244 let StateContext { transaction_index, block_number } =
245 state_context.unwrap_or_default();
246 let transaction_index = transaction_index.unwrap_or_default();
247
248 let mut target_block = block_number.unwrap_or_default();
249 let is_block_target_pending = target_block.is_pending();
250
251 if !is_block_target_pending {
254 target_block = self
255 .provider()
256 .block_hash_for_id(target_block)
257 .map_err(|_| EthApiError::HeaderNotFound(target_block))?
258 .ok_or_else(|| EthApiError::HeaderNotFound(target_block))?
259 .into();
260 }
261
262 let ((evm_env, _), block) = futures::try_join!(
263 self.evm_env_at(target_block),
264 self.recovered_block(target_block)
265 )?;
266
267 let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
268
269 let mut at = block.parent_hash();
273 let mut replay_block_txs = true;
274
275 let num_txs =
276 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
277 if !is_block_target_pending && num_txs == block.body().transactions().len() {
281 at = block.hash();
282 replay_block_txs = false;
283 }
284
285 let this = self.clone();
286 self.spawn_with_state_at_block(at.into(), move |state| {
287 let mut results = Vec::with_capacity(transactions.len());
288 let mut db = CacheDB::new(StateProviderDatabase::new(state));
289
290 if replay_block_txs {
291 let transactions = block.transactions_recovered().take(num_txs);
294 for tx in 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 let block_overrides = block_override.map(Box::new);
302
303 let mut transactions = transactions.into_iter().peekable();
304 while let Some(tx) = transactions.next() {
305 let state_overrides = state_override.take();
307 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
308
309 let (evm_env, tx) =
310 this.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
311 let (res, _) = this.transact(&mut db, evm_env, tx)?;
312
313 match ensure_success::<_, Self::Error>(res.result) {
314 Ok(output) => {
315 results.push(EthCallResponse { value: Some(output), error: None });
316 }
317 Err(err) => {
318 results.push(EthCallResponse {
319 value: None,
320 error: Some(err.to_string()),
321 });
322 }
323 }
324
325 if transactions.peek().is_some() {
326 db.commit(res.state);
329 }
330 }
331
332 Ok(results)
333 })
334 .await
335 }
336 }
337
338 fn create_access_list_at(
341 &self,
342 request: TransactionRequest,
343 block_number: Option<BlockId>,
344 ) -> impl Future<Output = Result<AccessListResult, Self::Error>> + Send
345 where
346 Self: Trace,
347 {
348 async move {
349 let block_id = block_number.unwrap_or_default();
350 let (evm_env, at) = self.evm_env_at(block_id).await?;
351
352 self.spawn_blocking_io(move |this| this.create_access_list_with(evm_env, at, request))
353 .await
354 }
355 }
356
357 fn create_access_list_with(
360 &self,
361 mut evm_env: EvmEnvFor<Self::Evm>,
362 at: BlockId,
363 mut request: TransactionRequest,
364 ) -> Result<AccessListResult, Self::Error>
365 where
366 Self: Trace,
367 {
368 let state = self.state_at_block_id(at)?;
369 let mut db = CacheDB::new(StateProviderDatabase::new(state));
370
371 let mut tx_env = self.create_txn_env(&evm_env, request.clone(), &mut db)?;
372
373 evm_env.cfg_env.disable_block_gas_limit = true;
376
377 evm_env.cfg_env.disable_base_fee = true;
381
382 if request.gas.is_none() && tx_env.gas_price() > 0 {
383 let cap = caller_gas_allowance(&mut db, &tx_env)?;
384 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit));
386 }
387
388 let initial = request.access_list.take().unwrap_or_default();
390
391 let mut inspector = AccessListInspector::new(initial);
392
393 let (result, (evm_env, mut tx_env)) =
394 self.inspect(&mut db, evm_env, tx_env, &mut inspector)?;
395 let access_list = inspector.into_access_list();
396 tx_env.set_access_list(access_list.clone());
397 match result.result {
398 ExecutionResult::Halt { reason, gas_used } => {
399 let error =
400 Some(Self::Error::from_evm_halt(reason, tx_env.gas_limit()).to_string());
401 return Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
402 }
403 ExecutionResult::Revert { output, gas_used } => {
404 let error = Some(RevertError::new(output).to_string());
405 return Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
406 }
407 ExecutionResult::Success { .. } => {}
408 };
409
410 let (result, (_, tx_env)) = self.transact(&mut db, evm_env, tx_env)?;
412 let res = match result.result {
413 ExecutionResult::Halt { reason, gas_used } => {
414 let error =
415 Some(Self::Error::from_evm_halt(reason, tx_env.gas_limit()).to_string());
416 AccessListResult { access_list, gas_used: U256::from(gas_used), error }
417 }
418 ExecutionResult::Revert { output, gas_used } => {
419 let error = Some(RevertError::new(output).to_string());
420 AccessListResult { access_list, gas_used: U256::from(gas_used), error }
421 }
422 ExecutionResult::Success { gas_used, .. } => {
423 AccessListResult { access_list, gas_used: U256::from(gas_used), error: None }
424 }
425 };
426
427 Ok(res)
428 }
429}
430
431pub trait Call:
433 LoadState<
434 Evm: ConfigureEvm<
435 Primitives: NodePrimitives<
436 BlockHeader = ProviderHeader<Self::Provider>,
437 SignedTx = ProviderTx<Self::Provider>,
438 >,
439 >,
440 Error: FromEvmError<Self::Evm>,
441 > + SpawnBlocking
442{
443 fn call_gas_limit(&self) -> u64;
447
448 fn max_simulate_blocks(&self) -> u64;
450
451 fn with_state_at_block<F, R>(&self, at: BlockId, f: F) -> Result<R, Self::Error>
453 where
454 F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result<R, Self::Error>,
455 {
456 let state = self.state_at_block_id(at)?;
457 f(StateProviderTraitObjWrapper(&state))
458 }
459
460 #[expect(clippy::type_complexity)]
463 fn transact<DB>(
464 &self,
465 db: DB,
466 evm_env: EvmEnvFor<Self::Evm>,
467 tx_env: TxEnvFor<Self::Evm>,
468 ) -> Result<
469 (ResultAndState<HaltReasonFor<Self::Evm>>, (EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>)),
470 Self::Error,
471 >
472 where
473 DB: Database<Error = ProviderError>,
474 {
475 let mut evm = self.evm_config().evm_with_env(db, evm_env.clone());
476 let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
477
478 Ok((res, (evm_env, tx_env)))
479 }
480
481 #[expect(clippy::type_complexity)]
484 fn transact_with_inspector<DB, I>(
485 &self,
486 db: DB,
487 evm_env: EvmEnvFor<Self::Evm>,
488 tx_env: TxEnvFor<Self::Evm>,
489 inspector: I,
490 ) -> Result<
491 (ResultAndState<HaltReasonFor<Self::Evm>>, (EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>)),
492 Self::Error,
493 >
494 where
495 DB: Database<Error = ProviderError>,
496 I: InspectorFor<Self::Evm, DB>,
497 {
498 let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env.clone(), inspector);
499 let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
500
501 Ok((res, (evm_env, tx_env)))
502 }
503
504 #[expect(clippy::type_complexity)]
506 fn transact_call_at(
507 &self,
508 request: TransactionRequest,
509 at: BlockId,
510 overrides: EvmOverrides,
511 ) -> impl Future<
512 Output = Result<
513 (ResultAndState<HaltReasonFor<Self::Evm>>, (EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>)),
514 Self::Error,
515 >,
516 > + Send
517 where
518 Self: LoadPendingBlock,
519 {
520 let this = self.clone();
521 self.spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
522 this.transact(db, evm_env, tx_env)
523 })
524 }
525
526 fn spawn_with_state_at_block<F, R>(
528 &self,
529 at: BlockId,
530 f: F,
531 ) -> impl Future<Output = Result<R, Self::Error>> + Send
532 where
533 F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result<R, Self::Error> + Send + 'static,
534 R: Send + 'static,
535 {
536 self.spawn_tracing(move |this| {
537 let state = this.state_at_block_id(at)?;
538 f(StateProviderTraitObjWrapper(&state))
539 })
540 }
541
542 fn spawn_with_call_at<F, R>(
558 &self,
559 request: TransactionRequest,
560 at: BlockId,
561 overrides: EvmOverrides,
562 f: F,
563 ) -> impl Future<Output = Result<R, Self::Error>> + Send
564 where
565 Self: LoadPendingBlock,
566 F: FnOnce(
567 StateCacheDbRefMutWrapper<'_, '_>,
568 EvmEnvFor<Self::Evm>,
569 TxEnvFor<Self::Evm>,
570 ) -> Result<R, Self::Error>
571 + Send
572 + 'static,
573 R: Send + 'static,
574 {
575 async move {
576 let (evm_env, at) = self.evm_env_at(at).await?;
577 let this = self.clone();
578 self.spawn_blocking_io(move |_| {
579 let state = this.state_at_block_id(at)?;
580 let mut db =
581 CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state)));
582
583 let (evm_env, tx_env) =
584 this.prepare_call_env(evm_env, request, &mut db, overrides)?;
585
586 f(StateCacheDbRefMutWrapper(&mut db), evm_env, tx_env)
587 })
588 .await
589 }
590 }
591
592 fn spawn_replay_transaction<F, R>(
602 &self,
603 hash: B256,
604 f: F,
605 ) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
606 where
607 Self: LoadBlock + LoadTransaction,
608 F: FnOnce(
609 TransactionInfo,
610 ResultAndState<HaltReasonFor<Self::Evm>>,
611 StateCacheDb<'_>,
612 ) -> Result<R, Self::Error>
613 + Send
614 + 'static,
615 R: Send + 'static,
616 {
617 async move {
618 let (transaction, block) = match self.transaction_and_block(hash).await? {
619 None => return Ok(None),
620 Some(res) => res,
621 };
622 let (tx, tx_info) = transaction.split();
623
624 let (evm_env, _) = self.evm_env_at(block.hash().into()).await?;
625
626 let parent_block = block.parent_hash();
629
630 let this = self.clone();
631 self.spawn_with_state_at_block(parent_block.into(), move |state| {
632 let mut db = CacheDB::new(StateProviderDatabase::new(state));
633 let block_txs = block.transactions_recovered();
634
635 this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
637
638 let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
639
640 let (res, _) = this.transact(&mut db, evm_env, tx_env)?;
641 f(tx_info, res, db)
642 })
643 .await
644 .map(Some)
645 }
646 }
647
648 fn replay_transactions_until<'a, DB, I>(
656 &self,
657 db: &mut DB,
658 evm_env: EvmEnvFor<Self::Evm>,
659 transactions: I,
660 target_tx_hash: B256,
661 ) -> Result<usize, Self::Error>
662 where
663 DB: Database<Error = ProviderError> + DatabaseCommit,
664 I: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
665 {
666 let mut evm = self.evm_config().evm_with_env(db, evm_env);
667 let mut index = 0;
668 for tx in transactions {
669 if *tx.tx_hash() == target_tx_hash {
670 break
672 }
673
674 let tx_env = self.evm_config().tx_env(tx);
675 evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
676 index += 1;
677 }
678 Ok(index)
679 }
680
681 fn create_txn_env(
686 &self,
687 evm_env: &EvmEnv<SpecFor<Self::Evm>>,
688 request: TransactionRequest,
689 db: impl Database<Error: Into<EthApiError>>,
690 ) -> Result<TxEnvFor<Self::Evm>, Self::Error>;
691
692 #[expect(clippy::type_complexity)]
706 fn prepare_call_env<DB>(
707 &self,
708 mut evm_env: EvmEnvFor<Self::Evm>,
709 mut request: TransactionRequest,
710 db: &mut CacheDB<DB>,
711 overrides: EvmOverrides,
712 ) -> Result<(EvmEnvFor<Self::Evm>, TxEnvFor<Self::Evm>), Self::Error>
713 where
714 DB: DatabaseRef,
715 EthApiError: From<<DB as DatabaseRef>::Error>,
716 {
717 if request.gas > Some(self.call_gas_limit()) {
718 return Err(
720 EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh).into()
721 )
722 }
723
724 evm_env.block_env.gas_limit = self.call_gas_limit();
726
727 evm_env.cfg_env.disable_eip3607 = true;
730
731 evm_env.cfg_env.disable_base_fee = true;
735
736 request.nonce = None;
738
739 if let Some(block_overrides) = overrides.block {
740 apply_block_overrides(*block_overrides, db, &mut evm_env.block_env);
741 }
742 if let Some(state_overrides) = overrides.state {
743 apply_state_overrides(state_overrides, db)?;
744 }
745
746 let request_gas = request.gas;
747 let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
748
749 if request_gas.is_none() {
750 if tx_env.gas_price() > 0 {
752 trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
754 let cap = caller_gas_allowance(db, &tx_env)?;
755 tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit));
757 }
758 }
759
760 Ok((evm_env, tx_env))
761 }
762}