1use crate::inspectors::{
6 Cheatcodes, CmpOperands, EdgeCoverage, EdgeIndexMap, InspectorData, InspectorStack,
7 cheatcodes::BroadcastableTransactions,
8};
9use alloy_dyn_abi::{DynSolValue, FunctionExt, JsonAbiExt};
10use alloy_eips::eip4788::{BEACON_ROOTS_ADDRESS, SYSTEM_ADDRESS};
11use alloy_evm::Evm;
12use alloy_json_abi::Function;
13use alloy_primitives::{
14 Address, B256, Bytes, Log, TxKind, U256, keccak256,
15 map::{AddressHashMap, HashMap},
16};
17use alloy_sol_types::{SolCall, sol};
18use eyre::WrapErr;
19use foundry_evm_core::{
20 EvmEnv, FoundryBlock, FoundryChain, FoundryTransaction,
21 backend::{
22 Backend, BackendError, BackendResult, CowBackend, DatabaseError, DatabaseExt,
23 GLOBAL_FAIL_SLOT,
24 },
25 constants::{
26 CALLER, CHEATCODE_ADDRESS, CHEATCODE_CONTRACT_HASH, DEFAULT_CREATE2_DEPLOYER,
27 DEFAULT_CREATE2_DEPLOYER_CODE, DEFAULT_CREATE2_DEPLOYER_DEPLOYER,
28 },
29 decode::{RevertDecoder, SkipReason},
30 eip2935::{
31 HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE, history_storage_slot, history_storage_value,
32 history_window_start,
33 },
34 evm::{
35 ChainFor, EthEvmNetwork, EvmEnvFor, FoundryEvmFactory, FoundryEvmNetwork,
36 IntoInstructionResult, SpecFor, TxEnvFor,
37 },
38 utils::StateChangeset,
39};
40use foundry_evm_coverage::HitMaps;
41use foundry_evm_fuzz::ObservedCall;
42use foundry_evm_networks::NetworkConfigs;
43use foundry_evm_traces::{SparsedTraceArena, TraceRequirements};
44use revm::{
45 bytecode::Bytecode,
46 context::{Block, Cfg, ContextTr, Transaction},
47 context_interface::{
48 cfg::gas_params::Eip2780TxInfo,
49 result::{ExecutionResult, Output, ResultAndState},
50 transaction::SignedAuthorization,
51 },
52 database::{Database, DatabaseCommit, DatabaseRef},
53 interpreter::{InstructionResult, gas::InitialAndFloorGas},
54 primitives::hardfork::SpecId,
55};
56use sancov::SancovGuard;
57use std::{
58 borrow::Cow,
59 sync::{
60 Arc,
61 atomic::{AtomicBool, Ordering},
62 },
63 time::{Duration, Instant},
64};
65
66#[cfg(feature = "monad")]
67use alloy_monad_evm::MonadEvmFactory;
68#[cfg(feature = "monad")]
69use foundry_common::{SYSTEM_TRANSACTION_TYPE, is_known_system_sender};
70#[cfg(feature = "monad")]
71use foundry_evm_core::evm::{
72 MonadEvmNetwork, refresh_chain_journal, try_transact_monad_system_replay,
73};
74#[cfg(feature = "monad")]
75use monad_revm::{MonadChainContext, MonadHardfork};
76#[cfg(feature = "monad")]
77use revm::context::TxEnv;
78
79mod builder;
80pub use builder::ExecutorBuilder;
81
82mod campaign;
83
84pub mod fuzz;
85pub use fuzz::FuzzedExecutor;
86
87pub mod invariant;
88pub use invariant::InvariantExecutor;
89
90mod corpus;
91mod corpus_io;
92mod sancov;
93mod showmap;
94mod trace;
95
96pub use corpus::{DynamicTargetCtx, StatelessReplayTarget, persist_corpus_seed};
97pub use corpus_io::{
98 CorpusDirEntry, canonical_replay_dirs, parse_corpus_filename, read_corpus_dir, read_corpus_tree,
99};
100pub use showmap::{
101 InvariantReplayOptions, MinimizationReplayInput, ReplayFailure, ReplayObservation,
102 ShowmapDomain, ShowmapOpts, ShowmapReplayTarget, ShowmapStats, replay_corpus_to_showmap,
103 replay_sequence_for_minimization,
104};
105pub use trace::{TracingExecutor, TracingFork};
106
107const DURATION_BETWEEN_METRICS_REPORT: Duration = Duration::from_secs(5);
108
109sol! {
110 interface ITest {
111 function setUp() external;
112 function failed() external view returns (bool failed);
113
114 #[derive(Default)]
115 function beforeTestSetup(bytes4 testSelector) public view returns (bytes[] memory beforeTestCalldata);
116 }
117}
118
119#[derive(Clone, Debug)]
131pub struct Executor<FEN: FoundryEvmNetwork> {
132 backend: Arc<Backend<FEN>>,
141 evm_env: EvmEnvFor<FEN>,
143 tx_env: TxEnvFor<FEN>,
145 inspector: InspectorStack<FEN>,
147 gas_limit: u64,
149 legacy_assertions: bool,
151}
152
153#[cfg(feature = "monad")]
154impl Executor<MonadEvmNetwork> {
155 #[instrument(name = "transact_system_replay", level = "debug", skip_all)]
157 pub fn try_transact_system_replay_with_env_and_context(
158 &mut self,
159 mut evm_env: EvmEnv<MonadHardfork>,
160 mut tx_env: TxEnv,
161 chain_context: MonadChainContext,
162 ) -> eyre::Result<Option<RawCallResult<MonadEvmNetwork>>> {
163 let mut stack = self.inspector().clone();
164 let mut backend = CowBackend::new_borrowed(self.backend());
165 let Some(result) = backend.try_inspect_system_replay_with_context(
166 &mut evm_env,
167 &mut tx_env,
168 chain_context,
169 &mut stack,
170 )?
171 else {
172 return Ok(None);
173 };
174 let has_state_snapshot_failure = backend.has_state_snapshot_failure();
175 let fork_block_number = backend.active_fork_block_number();
176 let mut result = convert_executed_result(
177 evm_env,
178 tx_env,
179 stack,
180 result,
181 &backend,
182 has_state_snapshot_failure,
183 fork_block_number,
184 )?;
185 self.commit(&mut result);
186 Ok(Some(result))
187 }
188
189 #[instrument(name = "transact_monad_block_replay", level = "debug", skip_all)]
191 pub fn transact_with_monad_block_replay(
192 &mut self,
193 evm_env: EvmEnv<MonadHardfork>,
194 target_tx_env: TxEnv,
195 target_chain_context: MonadChainContext,
196 replay: Vec<(B256, TxEnv, MonadChainContext)>,
197 replay_system_txes: bool,
198 ) -> eyre::Result<Option<(RawCallResult<MonadEvmNetwork>, bool)>> {
199 let block_number = evm_env.block_env.number();
200 let mut stack = self.inspector().clone();
201 let sancov_edges = stack.inner.sancov_edges;
202 let sancov_trace_cmp = stack.inner.sancov_trace_cmp;
203 let sancov_active = sancov_edges || sancov_trace_cmp;
204 let backend = self.backend_mut();
205
206 let (result, evm_env, tx_env, used_system_replay) = {
207 let caller = target_tx_env.caller();
208 backend.set_caller(caller).set_spec_id(evm_env.cfg_env.spec);
209 let target_contract = match target_tx_env.kind() {
210 TxKind::Call(to) => to,
211 TxKind::Create => caller.create(target_tx_env.nonce()),
212 };
213 backend.set_test_contract(target_contract);
214 let mut evm = MonadEvmFactory::default()
215 .create_foundry_evm_with_inspector(backend, evm_env, &mut stack);
216 *evm.chain_mut() = target_chain_context.clone();
217 evm.disable_inspector();
218 for (tx_hash, tx_env, chain_context) in replay {
219 evm.ctx_mut().chain = chain_context;
220 refresh_chain_journal(evm.ctx_mut());
221 evm.ctx_mut().cfg.disable_balance_check = true;
222 let is_system = is_known_system_sender(tx_env.caller())
223 || tx_env.tx_type() == SYSTEM_TRANSACTION_TYPE;
224 let result = if is_system {
225 try_transact_monad_system_replay(&mut evm, &tx_env).wrap_err_with(|| {
226 format!(
227 "Failed to replay system transaction: {tx_hash:?} in block {block_number}"
228 )
229 })?
230 } else {
231 None
232 };
233 if let Some(result) = result {
234 evm.db_mut().commit(result.state);
235 } else if !is_system || replay_system_txes {
236 let created = match tx_env.kind() {
237 TxKind::Create => Some(tx_env.caller().create(tx_env.nonce())),
238 TxKind::Call(_) => None,
239 };
240 let result = evm.transact(tx_env).wrap_err_with(|| {
241 format!(
242 "Failed to execute transaction: {tx_hash:?} in block {block_number}"
243 )
244 })?;
245 if result.result.is_success()
246 && let Some(address) = created
247 {
248 evm.db_mut().add_persistent_account(address);
249 }
250 evm.db_mut().commit(result.state);
251 }
252 }
253
254 evm.enable_inspector();
255 evm.ctx_mut().chain = target_chain_context;
256 refresh_chain_journal(evm.ctx_mut());
257 let _guard = sancov_active.then(|| SancovGuard::new(sancov_edges, sancov_trace_cmp));
258 let target_is_system = is_known_system_sender(target_tx_env.caller())
259 || target_tx_env.tx_type() == SYSTEM_TRANSACTION_TYPE;
260 let system_result = if target_is_system {
261 try_transact_monad_system_replay(&mut evm, &target_tx_env)?
262 } else {
263 None
264 };
265 let (result, used_system_replay) = if let Some(result) = system_result {
266 (result, true)
267 } else if target_is_system && !replay_system_txes {
268 return Ok(None);
269 } else {
270 (evm.transact(target_tx_env.clone()).wrap_err("EVM error")?, false)
271 };
272 let tx_env = if used_system_replay { target_tx_env } else { evm.tx().clone() };
273 let evm_env = evm.finish().1;
274 (result, evm_env, tx_env, used_system_replay)
275 };
276
277 let has_state_snapshot_failure = backend.has_state_snapshot_failure();
278 let fork_block_number = backend.active_fork_block_number();
279 let mut result = convert_executed_result(
280 evm_env,
281 tx_env,
282 stack,
283 result,
284 &*backend,
285 has_state_snapshot_failure,
286 fork_block_number,
287 )?;
288 if sancov_edges {
289 SancovGuard::append_edges_into(&mut result);
290 }
291 if sancov_trace_cmp {
292 SancovGuard::drain_cmp_into(&mut result);
293 }
294 self.commit(&mut result);
295 Ok(Some((result, used_system_replay)))
296 }
297}
298
299impl<FEN: FoundryEvmNetwork> Executor<FEN> {
300 #[inline]
302 pub fn new(
303 mut backend: Backend<FEN>,
304 evm_env: EvmEnvFor<FEN>,
305 tx_env: TxEnvFor<FEN>,
306 mut inspector: InspectorStack<FEN>,
307 networks: NetworkConfigs,
308 gas_limit: u64,
309 legacy_assertions: bool,
310 ) -> Self {
311 inspector.networks(networks);
312 backend.set_networks(networks);
313 let extra_cheatcode_addresses = inspector.extra_cheatcode_addresses();
314 backend.extend_persistent_accounts(extra_cheatcode_addresses.iter().copied());
315
316 backend.insert_account_info(
319 CHEATCODE_ADDRESS,
320 revm::state::AccountInfo {
321 code: Some(Bytecode::new_raw(Bytes::from_static(&[0]))),
322 code_hash: CHEATCODE_CONTRACT_HASH,
325 ..Default::default()
326 },
327 );
328
329 for &address in extra_cheatcode_addresses {
330 backend.insert_account_info(
331 address,
332 revm::state::AccountInfo {
333 code: Some(Bytecode::new_raw(Bytes::from_static(&[0]))),
334 code_hash: keccak256(address),
335 ..Default::default()
336 },
337 );
338 }
339
340 if !backend.is_in_forking_mode() && evm_env.cfg_env.spec.into() >= SpecId::PRAGUE {
341 let mut account =
342 backend.basic_ref(HISTORY_STORAGE_ADDRESS).unwrap_or_default().unwrap_or_default();
343 account.code_hash = keccak256(&HISTORY_STORAGE_CODE);
344 account.code = Some(Bytecode::new_raw(HISTORY_STORAGE_CODE.clone()));
345 backend.insert_account_info(HISTORY_STORAGE_ADDRESS, account);
346
347 let current_block = evm_env.block_env.number();
348 let mut block_number = history_window_start(current_block);
349 while block_number < current_block {
350 let block_hash =
351 backend.block_hash(block_number.saturating_to()).unwrap_or_default();
352 let slot = history_storage_slot(block_number);
353 let value = history_storage_value(block_hash);
354 let _ = backend.insert_account_storage(HISTORY_STORAGE_ADDRESS, slot, value);
355 block_number += U256::ONE;
356 }
357 }
358
359 Self {
360 backend: Arc::new(backend),
361 evm_env,
362 tx_env,
363 inspector,
364 gas_limit,
365 legacy_assertions,
366 }
367 }
368
369 fn clone_with_backend(&self, backend: Backend<FEN>) -> Self {
370 let evm_env = self.evm_env.clone();
371 Self {
372 backend: Arc::new(backend),
373 evm_env,
374 tx_env: self.tx_env.clone(),
375 inspector: self.inspector().clone(),
376 gas_limit: self.gas_limit,
377 legacy_assertions: self.legacy_assertions,
378 }
379 }
380
381 pub fn backend(&self) -> &Backend<FEN> {
383 &self.backend
384 }
385
386 pub fn backend_mut(&mut self) -> &mut Backend<FEN> {
391 Arc::make_mut(&mut self.backend)
392 }
393
394 fn chain_context_for_synthetic_transaction(
395 &self,
396 tx: &TxEnvFor<FEN>,
397 ) -> eyre::Result<ChainFor<FEN>> {
398 self.backend().chain_context_for_synthetic_transaction(tx)
399 }
400
401 pub const fn evm_env(&self) -> &EvmEnvFor<FEN> {
403 &self.evm_env
404 }
405
406 pub const fn evm_env_mut(&mut self) -> &mut EvmEnvFor<FEN> {
408 &mut self.evm_env
409 }
410
411 pub const fn tx_env(&self) -> &TxEnvFor<FEN> {
413 &self.tx_env
414 }
415
416 pub const fn tx_env_mut(&mut self) -> &mut TxEnvFor<FEN> {
418 &mut self.tx_env
419 }
420
421 pub const fn inspector(&self) -> &InspectorStack<FEN> {
423 &self.inspector
424 }
425
426 pub const fn inspector_mut(&mut self) -> &mut InspectorStack<FEN> {
428 &mut self.inspector
429 }
430
431 pub const fn spec_id(&self) -> SpecFor<FEN> {
433 self.evm_env.cfg_env.spec
434 }
435
436 pub fn set_spec_id(&mut self, spec_id: SpecFor<FEN>) {
438 self.evm_env.cfg_env.set_spec_and_mainnet_gas_params(spec_id);
439 }
440
441 pub const fn gas_limit(&self) -> u64 {
446 self.gas_limit
447 }
448
449 pub const fn set_gas_limit(&mut self, gas_limit: u64) {
451 self.gas_limit = gas_limit;
452 }
453
454 pub const fn legacy_assertions(&self) -> bool {
457 self.legacy_assertions
458 }
459
460 pub const fn set_legacy_assertions(&mut self, legacy_assertions: bool) {
463 self.legacy_assertions = legacy_assertions;
464 }
465
466 pub fn deploy_create2_deployer(&mut self) -> eyre::Result<()> {
468 trace!("deploying local create2 deployer");
469 let create2_deployer_account = self
470 .backend()
471 .basic_ref(DEFAULT_CREATE2_DEPLOYER)?
472 .ok_or_else(|| BackendError::MissingAccount(DEFAULT_CREATE2_DEPLOYER))?;
473
474 if create2_deployer_account.code.is_none_or(|code| code.is_empty()) {
476 let creator = DEFAULT_CREATE2_DEPLOYER_DEPLOYER;
477
478 let initial_balance = self.get_balance(creator)?;
480 self.set_balance(creator, U256::MAX)?;
481
482 let res =
483 self.deploy(creator, DEFAULT_CREATE2_DEPLOYER_CODE.into(), U256::ZERO, None)?;
484 trace!(create2=?res.address, "deployed local create2 deployer");
485
486 self.set_balance(creator, initial_balance)?;
487 }
488 Ok(())
489 }
490
491 pub fn set_balance(&mut self, address: Address, amount: U256) -> BackendResult<()> {
493 trace!(?address, ?amount, "setting account balance");
494 let mut account = self.backend().basic_ref(address)?.unwrap_or_default();
495 account.balance = amount;
496 self.backend_mut().insert_account_info(address, account);
497 Ok(())
498 }
499
500 pub fn get_balance(&self, address: Address) -> BackendResult<U256> {
502 Ok(self.backend().basic_ref(address)?.map(|acc| acc.balance).unwrap_or_default())
503 }
504
505 pub fn set_account_nonce(&mut self, address: Address, nonce: u64) -> BackendResult<()> {
507 let mut account = self.backend().basic_ref(address)?.unwrap_or_default();
508 account.nonce = nonce;
509 self.backend_mut().insert_account_info(address, account);
510 Ok(())
511 }
512
513 pub fn set_nonce(&mut self, address: Address, nonce: u64) -> BackendResult<()> {
515 self.set_account_nonce(address, nonce)?;
516 self.tx_env_mut().set_nonce(nonce);
517 Ok(())
518 }
519
520 pub fn get_nonce(&self, address: Address) -> BackendResult<u64> {
522 Ok(self.backend().basic_ref(address)?.map(|acc| acc.nonce).unwrap_or_default())
523 }
524
525 pub fn set_code(&mut self, address: Address, code: Bytecode) -> BackendResult<()> {
527 let account = self.backend().basic_ref(address)?.unwrap_or_default().with_code(code);
528 self.backend_mut().insert_account_info(address, account);
529 Ok(())
530 }
531
532 pub fn set_storage(
534 &mut self,
535 address: Address,
536 storage: HashMap<U256, U256>,
537 ) -> BackendResult<()> {
538 self.backend_mut().replace_account_storage(address, storage)?;
539 Ok(())
540 }
541
542 pub fn set_storage_slot(
544 &mut self,
545 address: Address,
546 slot: U256,
547 value: U256,
548 ) -> BackendResult<()> {
549 self.backend_mut().insert_account_storage(address, slot, value)?;
550 Ok(())
551 }
552
553 pub fn apply_prestate_trace(
559 &mut self,
560 prestate: std::collections::BTreeMap<Address, alloy_rpc_types::trace::geth::AccountState>,
561 ) -> eyre::Result<()> {
562 let backend = self.backend_mut();
563 for (address, account_state) in prestate {
564 let code = account_state.code.map(Bytecode::new_raw).unwrap_or_default();
565 let info = revm::state::AccountInfo::default()
566 .with_balance(account_state.balance.unwrap_or_default())
567 .with_nonce(account_state.nonce.unwrap_or_default())
568 .with_code(code);
569 backend.insert_account_info(address, info);
570
571 for (slot, value) in account_state.storage {
572 let slot = slot.into();
573 let value = value.into();
574 backend.insert_account_storage(address, slot, value)?;
575 }
576 }
577 Ok(())
578 }
579
580 pub fn is_empty_code(&self, address: Address) -> BackendResult<bool> {
582 Ok(self.backend().basic_ref(address)?.is_none_or(|acc| acc.is_empty_code_hash()))
583 }
584
585 #[inline]
586 pub fn set_trace_requirements(&mut self, requirements: TraceRequirements) -> &mut Self {
587 self.inspector_mut().tracing_requirements(requirements);
588 self
589 }
590
591 #[inline]
592 pub fn set_script_execution(&mut self, script_address: Address) {
593 self.inspector_mut().script(script_address);
594 }
595
596 #[inline]
597 pub fn set_trace_printer(&mut self, trace_printer: bool) -> &mut Self {
598 self.inspector_mut().print(trace_printer);
599 self
600 }
601
602 #[inline]
603 pub fn create2_deployer(&self) -> Address {
604 self.inspector().create2_deployer
605 }
606
607 pub fn deploy(
612 &mut self,
613 from: Address,
614 code: Bytes,
615 value: U256,
616 rd: Option<&RevertDecoder>,
617 ) -> Result<DeployResult<FEN>, EvmError<FEN>> {
618 let (evm_env, tx_env) = self.prepare_call_env(from, TxKind::Create, code, value);
619 self.deploy_with_env(evm_env, tx_env, rd)
620 }
621
622 #[instrument(name = "deploy", level = "debug", skip_all)]
629 pub fn deploy_with_env(
630 &mut self,
631 evm_env: EvmEnvFor<FEN>,
632 tx_env: TxEnvFor<FEN>,
633 rd: Option<&RevertDecoder>,
634 ) -> Result<DeployResult<FEN>, EvmError<FEN>> {
635 let chain_context = self.chain_context_for_synthetic_transaction(&tx_env)?;
636 self.deploy_with_env_and_context(evm_env, tx_env, chain_context, rd)
637 }
638
639 #[instrument(name = "deploy", level = "debug", skip_all)]
645 pub fn deploy_with_env_and_context(
646 &mut self,
647 evm_env: EvmEnvFor<FEN>,
648 tx_env: TxEnvFor<FEN>,
649 chain_context: ChainFor<FEN>,
650 rd: Option<&RevertDecoder>,
651 ) -> Result<DeployResult<FEN>, EvmError<FEN>> {
652 assert!(tx_env.kind().is_create(), "Expected create transaction, got {:?}", tx_env.kind());
653 trace!(sender=%tx_env.caller(), "deploying contract");
654
655 let mut result = self.transact_with_env_and_context(evm_env, tx_env, chain_context)?;
656 result = result.into_result(rd)?;
657 let Some(Output::Create(_, Some(address))) = result.out else {
658 panic!("Deployment succeeded, but no address was returned: {result:#?}");
659 };
660
661 self.backend_mut().add_persistent_account(address);
664
665 trace!(%address, "deployed contract");
666
667 Ok(DeployResult { raw: result, address })
668 }
669
670 #[instrument(name = "setup", level = "debug", skip_all)]
677 pub fn setup(
678 &mut self,
679 from: Option<Address>,
680 to: Address,
681 rd: Option<&RevertDecoder>,
682 ) -> Result<RawCallResult<FEN>, EvmError<FEN>> {
683 trace!(?from, ?to, "setting up contract");
684
685 let from = from.unwrap_or(CALLER);
686 self.backend_mut().set_test_contract(to).set_caller(from);
687 let calldata = Bytes::from_static(&ITest::setUpCall::SELECTOR);
688 let mut res = self.transact_raw(from, to, calldata, U256::ZERO)?;
689 res = res.into_result(rd)?;
690
691 self.evm_env_mut().block_env = res.evm_env.block_env.clone();
693 self.evm_env_mut().cfg_env.chain_id = res.evm_env.cfg_env.chain_id;
695
696 let success = self.is_raw_call_success(to, Cow::Borrowed(&res.state_changeset), &res);
697 if !success {
698 return Err(res.into_execution_error("execution error".to_string()).into());
699 }
700
701 Ok(res)
702 }
703
704 pub fn call(
706 &self,
707 from: Address,
708 to: Address,
709 func: &Function,
710 args: &[DynSolValue],
711 value: U256,
712 rd: Option<&RevertDecoder>,
713 ) -> Result<CallResult<DynSolValue, FEN>, EvmError<FEN>> {
714 let calldata = Bytes::from(func.abi_encode_input(args)?);
715 let result = self.call_raw(from, to, calldata, value)?;
716 result.into_decoded_result(func, rd)
717 }
718
719 pub fn call_sol<C: SolCall>(
721 &self,
722 from: Address,
723 to: Address,
724 args: &C,
725 value: U256,
726 rd: Option<&RevertDecoder>,
727 ) -> Result<CallResult<C::Return, FEN>, EvmError<FEN>> {
728 let calldata = Bytes::from(args.abi_encode());
729 let mut raw = self.call_raw(from, to, calldata, value)?;
730 raw = raw.into_result(rd)?;
731 Ok(CallResult { decoded_result: C::abi_decode_returns(&raw.result)?, raw })
732 }
733
734 pub fn transact(
736 &mut self,
737 from: Address,
738 to: Address,
739 func: &Function,
740 args: &[DynSolValue],
741 value: U256,
742 rd: Option<&RevertDecoder>,
743 ) -> Result<CallResult<DynSolValue, FEN>, EvmError<FEN>> {
744 let calldata = Bytes::from(func.abi_encode_input(args)?);
745 let result = self.transact_raw(from, to, calldata, value)?;
746 result.into_decoded_result(func, rd)
747 }
748
749 pub fn call_raw(
751 &self,
752 from: Address,
753 to: Address,
754 calldata: Bytes,
755 value: U256,
756 ) -> eyre::Result<RawCallResult<FEN>> {
757 let (evm_env, tx_env) = self.prepare_call_env(from, TxKind::Call(to), calldata, value);
758 self.call_with_env(evm_env, tx_env)
759 }
760
761 pub fn call_raw_with_authorization(
764 &mut self,
765 from: Address,
766 to: Address,
767 calldata: Bytes,
768 value: U256,
769 authorization_list: Vec<SignedAuthorization>,
770 ) -> eyre::Result<RawCallResult<FEN>> {
771 let (evm_env, mut tx_env) = self.prepare_call_env(from, to.into(), calldata, value);
772 tx_env.set_signed_authorization(authorization_list);
773 tx_env.set_tx_type(4);
774 self.call_with_env(evm_env, tx_env)
775 }
776
777 pub fn transact_raw(
779 &mut self,
780 from: Address,
781 to: Address,
782 calldata: Bytes,
783 value: U256,
784 ) -> eyre::Result<RawCallResult<FEN>> {
785 let (evm_env, tx_env) = self.prepare_call_env(from, TxKind::Call(to), calldata, value);
786 self.transact_with_env(evm_env, tx_env)
787 }
788
789 pub fn transact_raw_with_authorization(
792 &mut self,
793 from: Address,
794 to: Address,
795 calldata: Bytes,
796 value: U256,
797 authorization_list: Vec<SignedAuthorization>,
798 ) -> eyre::Result<RawCallResult<FEN>> {
799 let (evm_env, mut tx_env) = self.prepare_call_env(from, TxKind::Call(to), calldata, value);
800 tx_env.set_signed_authorization(authorization_list);
801 tx_env.set_tx_type(4);
802 self.transact_with_env(evm_env, tx_env)
803 }
804
805 pub fn apply_beacon_root(
808 &mut self,
809 parent_beacon_block_root: alloy_primitives::B256,
810 ) -> eyre::Result<()> {
811 let calldata = Bytes::from(parent_beacon_block_root);
812 let mut evm_env = self.evm_env.clone();
813 let inspector = self.inspector().clone();
814 let mut state = {
815 let mut backend = CowBackend::new_borrowed(self.backend());
816 let mut evm = FEN::EvmFactory::default().create_foundry_evm_with_inspector(
817 &mut backend,
818 evm_env.clone(),
819 inspector,
820 );
821 *evm.chain_mut() = ChainFor::<FEN>::for_transaction(&TxEnvFor::<FEN>::default());
822 let result =
823 evm.transact_system_call(SYSTEM_ADDRESS, BEACON_ROOTS_ADDRESS, calldata)?;
824 evm_env = evm.finish().1;
825 result.state
826 };
827 state.retain(|address, _| *address == BEACON_ROOTS_ADDRESS);
828
829 self.backend_mut().commit(state);
830 self.inspector_mut().set_block(evm_env.block_env);
831
832 Ok(())
833 }
834
835 #[instrument(name = "call", level = "debug", skip_all)]
839 pub fn call_with_env(
840 &self,
841 evm_env: EvmEnvFor<FEN>,
842 tx_env: TxEnvFor<FEN>,
843 ) -> eyre::Result<RawCallResult<FEN>> {
844 let chain_context = self.chain_context_for_synthetic_transaction(&tx_env)?;
845 self.call_with_env_and_context(evm_env, tx_env, chain_context)
846 }
847
848 #[instrument(name = "call", level = "debug", skip_all)]
850 pub fn call_with_env_and_context(
851 &self,
852 mut evm_env: EvmEnvFor<FEN>,
853 mut tx_env: TxEnvFor<FEN>,
854 chain_context: ChainFor<FEN>,
855 ) -> eyre::Result<RawCallResult<FEN>> {
856 let mut stack = self.inspector().clone();
857 let sancov_edges = stack.inner.sancov_edges;
858 let sancov_trace_cmp = stack.inner.sancov_trace_cmp;
859 let sancov_active = sancov_edges || sancov_trace_cmp;
860 let mut backend = CowBackend::new_borrowed(self.backend());
861 let result = {
862 let _guard = sancov_active.then(|| SancovGuard::new(sancov_edges, sancov_trace_cmp));
863 backend.inspect_with_context(&mut evm_env, &mut tx_env, chain_context, &mut stack)?
864 };
865 let has_state_snapshot_failure = backend.has_state_snapshot_failure();
866 let fork_block_number = backend.active_fork_block_number();
867 let mut result = convert_executed_result(
868 evm_env,
869 tx_env,
870 stack,
871 result,
872 &backend,
873 has_state_snapshot_failure,
874 fork_block_number,
875 )?;
876 if sancov_edges {
877 SancovGuard::append_edges_into(&mut result);
878 }
879 if sancov_trace_cmp {
880 SancovGuard::drain_cmp_into(&mut result);
881 }
882 Ok(result)
883 }
884
885 #[instrument(name = "transact", level = "debug", skip_all)]
887 pub fn transact_with_env(
888 &mut self,
889 evm_env: EvmEnvFor<FEN>,
890 tx_env: TxEnvFor<FEN>,
891 ) -> eyre::Result<RawCallResult<FEN>> {
892 let chain_context = self.chain_context_for_synthetic_transaction(&tx_env)?;
893 self.transact_with_env_and_context(evm_env, tx_env, chain_context)
894 }
895
896 #[instrument(name = "transact", level = "debug", skip_all)]
898 pub fn transact_with_env_and_context(
899 &mut self,
900 mut evm_env: EvmEnvFor<FEN>,
901 mut tx_env: TxEnvFor<FEN>,
902 chain_context: ChainFor<FEN>,
903 ) -> eyre::Result<RawCallResult<FEN>> {
904 let mut stack = self.inspector().clone();
905 let sancov_edges = stack.inner.sancov_edges;
906 let sancov_trace_cmp = stack.inner.sancov_trace_cmp;
907 let sancov_active = sancov_edges || sancov_trace_cmp;
908 let backend = self.backend_mut();
909 let result = {
910 let _guard = sancov_active.then(|| SancovGuard::new(sancov_edges, sancov_trace_cmp));
911 backend.inspect_with_context(&mut evm_env, &mut tx_env, chain_context, &mut stack)?
912 };
913 let has_state_snapshot_failure = backend.has_state_snapshot_failure();
914 let fork_block_number = backend.active_fork_block_number();
915 let mut result = convert_executed_result(
916 evm_env,
917 tx_env,
918 stack,
919 result,
920 &*backend,
921 has_state_snapshot_failure,
922 fork_block_number,
923 )?;
924 if sancov_edges {
925 SancovGuard::append_edges_into(&mut result);
926 }
927 if sancov_trace_cmp {
928 SancovGuard::drain_cmp_into(&mut result);
929 }
930 self.commit(&mut result);
931 Ok(result)
932 }
933
934 #[instrument(name = "transact_block_replay", level = "debug", skip_all)]
936 pub fn transact_with_ordinary_block_replay(
937 &mut self,
938 mut evm_env: EvmEnvFor<FEN>,
939 target_tx_env: TxEnvFor<FEN>,
940 replay: Vec<(B256, TxEnvFor<FEN>)>,
941 ) -> eyre::Result<RawCallResult<FEN>> {
942 eyre::ensure!(
945 target_tx_env.tx_type() != 0x79,
946 "EIP-8130 target transactions are not supported by tooling replay"
947 );
948 for (hash, tx) in &replay {
949 eyre::ensure!(
950 tx.tx_type() != 0x79,
951 "EIP-8130 prefix transaction {hash} is not supported by tooling replay"
952 );
953 }
954 let block_number = evm_env.block_env.number();
955 let mut stack = self.inspector().clone();
956 let sancov_edges = stack.inner.sancov_edges;
957 let sancov_trace_cmp = stack.inner.sancov_trace_cmp;
958 let sancov_active = sancov_edges || sancov_trace_cmp;
959 let backend = self.backend_mut();
960
961 let (result, evm_env, tx_env) = {
962 let caller = target_tx_env.caller();
963 backend.set_caller(caller).set_spec_id(evm_env.cfg_env.spec);
964 let target_contract = match target_tx_env.kind() {
965 TxKind::Call(to) => to,
966 TxKind::Create => caller.create(target_tx_env.nonce()),
969 };
970 backend.set_test_contract(target_contract);
971 let target_chain_context = ChainFor::<FEN>::for_transaction(&target_tx_env);
972 if !replay.is_empty() {
973 evm_env.cfg_env.disable_balance_check = true;
974 }
975 let mut evm = FEN::EvmFactory::default()
976 .create_foundry_evm_with_inspector(backend, evm_env, &mut stack);
977 *evm.chain_mut() = target_chain_context;
978 evm.disable_inspector();
979 for (tx_hash, tx_env) in replay {
980 let created = match tx_env.kind() {
981 TxKind::Create => Some(tx_env.caller().create(tx_env.nonce())),
982 TxKind::Call(_) => None,
983 };
984 let result = evm.transact(tx_env).wrap_err_with(|| {
985 format!("Failed to execute transaction: {tx_hash:?} in block {block_number}")
986 })?;
987 if result.result.is_success()
988 && let Some(address) = created
989 {
990 evm.db_mut().add_persistent_account(address);
991 }
992 evm.db_mut().commit(result.state);
993 }
994
995 evm.enable_inspector();
996 let _guard = sancov_active.then(|| SancovGuard::new(sancov_edges, sancov_trace_cmp));
997 let result = evm.transact(target_tx_env).wrap_err("EVM error")?;
998 let tx_env = evm.tx().clone();
999 let evm_env = evm.finish().1;
1000 (result, evm_env, tx_env)
1001 };
1002
1003 let has_state_snapshot_failure = backend.has_state_snapshot_failure();
1004 let fork_block_number = backend.active_fork_block_number();
1005 let mut result = convert_executed_result(
1006 evm_env,
1007 tx_env,
1008 stack,
1009 result,
1010 &*backend,
1011 has_state_snapshot_failure,
1012 fork_block_number,
1013 )?;
1014 if sancov_edges {
1015 SancovGuard::append_edges_into(&mut result);
1016 }
1017 if sancov_trace_cmp {
1018 SancovGuard::drain_cmp_into(&mut result);
1019 }
1020 self.commit(&mut result);
1021 Ok(result)
1022 }
1023
1024 #[instrument(name = "commit", level = "debug", skip_all)]
1029 fn commit(&mut self, result: &mut RawCallResult<FEN>) {
1030 self.backend_mut().commit(result.state_changeset.clone());
1032
1033 self.inspector_mut().cheatcodes = result.cheatcodes.take();
1035 if let Some(cheats) = self.inspector_mut().cheatcodes.as_mut() {
1036 cheats.broadcastable_transactions.clear();
1038 cheats.ignored_traces.ignored.clear();
1039 if let Some(last_pause_call) = cheats.ignored_traces.last_pause_call.as_mut() {
1042 *last_pause_call = (0, 0);
1043 }
1044 }
1045
1046 self.inspector_mut().set_block(result.evm_env.block_env.clone());
1048 self.inspector_mut().set_gas_price(result.tx_env.gas_price());
1049 }
1050
1051 pub fn is_raw_call_mut_success(
1056 &self,
1057 address: Address,
1058 call_result: &mut RawCallResult<FEN>,
1059 ) -> bool {
1060 self.is_raw_call_success(
1061 address,
1062 Cow::Owned(std::mem::take(&mut call_result.state_changeset)),
1063 call_result,
1064 )
1065 }
1066
1067 pub fn is_raw_call_success(
1071 &self,
1072 address: Address,
1073 state_changeset: Cow<'_, StateChangeset>,
1074 call_result: &RawCallResult<FEN>,
1075 ) -> bool {
1076 if call_result.has_state_snapshot_failure {
1077 return false;
1079 }
1080 self.is_success(address, call_result.reverted, state_changeset)
1081 }
1082
1083 pub fn is_raw_call_mut_success_handler_gate(
1087 &self,
1088 address: Address,
1089 call_result: &mut RawCallResult<FEN>,
1090 ) -> bool {
1091 if call_result.has_state_snapshot_failure {
1092 return false;
1093 }
1094 let state_changeset = std::mem::take(&mut call_result.state_changeset);
1095 self.is_success_handler_gate(address, call_result.reverted, Cow::Owned(state_changeset))
1096 }
1097
1098 pub fn is_success(
1120 &self,
1121 address: Address,
1122 reverted: bool,
1123 state_changeset: Cow<'_, StateChangeset>,
1124 ) -> bool {
1125 self.is_success_raw(address, reverted, state_changeset, false)
1126 }
1127
1128 pub fn is_success_handler_gate(
1134 &self,
1135 address: Address,
1136 reverted: bool,
1137 state_changeset: Cow<'_, StateChangeset>,
1138 ) -> bool {
1139 self.is_success_raw(address, reverted, state_changeset, true)
1140 }
1141
1142 #[instrument(name = "is_success", level = "debug", skip_all)]
1143 fn is_success_raw(
1144 &self,
1145 address: Address,
1146 reverted: bool,
1147 state_changeset: Cow<'_, StateChangeset>,
1148 pending_global_failure_only: bool,
1149 ) -> bool {
1150 if reverted {
1152 return false;
1153 }
1154
1155 if self.backend().has_state_snapshot_failure() {
1157 return false;
1158 }
1159
1160 let global_failed = if pending_global_failure_only {
1165 Self::has_pending_global_failure(&state_changeset)
1166 } else {
1167 self.has_global_failure(&state_changeset)
1168 };
1169 if global_failed {
1170 return false;
1171 }
1172
1173 if !self.legacy_assertions {
1174 return true;
1175 }
1176
1177 {
1179 let mut backend = self.backend().clone_empty();
1181
1182 for address in [address, CHEATCODE_ADDRESS] {
1185 let Ok(acc) = self.backend().basic_ref(address) else { return false };
1186 backend.insert_account_info(address, acc.unwrap_or_default());
1187 }
1188
1189 backend.commit(state_changeset.into_owned());
1194
1195 let executor = self.clone_with_backend(backend);
1197 let call = executor.call_sol(CALLER, address, &ITest::failedCall {}, U256::ZERO, None);
1198 match call {
1199 Ok(CallResult { raw: _, decoded_result: failed }) => {
1200 trace!(failed, "DSTest::failed()");
1201 !failed
1202 }
1203 Err(err) => {
1204 trace!(%err, "failed to call DSTest::failed()");
1205 true
1206 }
1207 }
1208 }
1209 }
1210
1211 pub fn has_pending_global_failure(state_changeset: &StateChangeset) -> bool {
1214 if let Some(acc) = state_changeset.get(&CHEATCODE_ADDRESS)
1215 && let Some(failed_slot) = acc.storage.get(&GLOBAL_FAIL_SLOT)
1216 && !failed_slot.present_value().is_zero()
1217 {
1218 return true;
1219 }
1220
1221 false
1222 }
1223
1224 pub fn has_global_failure(&self, state_changeset: &StateChangeset) -> bool {
1227 if Self::has_pending_global_failure(state_changeset) {
1228 return true;
1229 }
1230
1231 self.backend()
1232 .storage_ref(CHEATCODE_ADDRESS, GLOBAL_FAIL_SLOT)
1233 .is_ok_and(|failed_slot| !failed_slot.is_zero())
1234 }
1235
1236 pub fn prepare_call_env(
1241 &self,
1242 caller: Address,
1243 kind: TxKind,
1244 data: Bytes,
1245 value: U256,
1246 ) -> (EvmEnvFor<FEN>, TxEnvFor<FEN>) {
1247 let mut cfg_env = self.evm_env.cfg_env.clone();
1248 cfg_env.spec = self.spec_id();
1249
1250 let mut block_env = self.evm_env.block_env.clone();
1254 block_env.set_basefee(0);
1255 block_env.set_gas_limit(self.gas_limit);
1256
1257 let mut tx_env = self.tx_env.clone();
1258 tx_env.set_caller(caller);
1259 tx_env.set_kind(kind);
1260 tx_env.set_data(data);
1261 tx_env.set_value(value);
1262 tx_env.set_gas_price(0);
1264 tx_env.set_gas_priority_fee(None);
1265 tx_env.set_gas_limit(self.gas_limit);
1266 tx_env.set_chain_id(Some(self.evm_env.cfg_env.chain_id));
1267
1268 (EvmEnv { cfg_env, block_env }, tx_env)
1269 }
1270
1271 pub fn call_sol_default<C: SolCall>(&self, to: Address, args: &C) -> C::Return
1272 where
1273 C::Return: Default,
1274 {
1275 self.call_sol(CALLER, to, args, U256::ZERO, None)
1276 .map(|c| c.decoded_result)
1277 .inspect_err(|e| warn!(target: "forge::test", "failed calling {:?}: {e}", C::SIGNATURE))
1278 .unwrap_or_default()
1279 }
1280}
1281
1282#[derive(Debug, thiserror::Error)]
1284#[error("execution reverted: {reason} (gas: {})", raw.gas_used)]
1285pub struct ExecutionErr<FEN: FoundryEvmNetwork = EthEvmNetwork> {
1286 pub raw: RawCallResult<FEN>,
1288 pub reason: String,
1290}
1291
1292impl<FEN: FoundryEvmNetwork> std::ops::Deref for ExecutionErr<FEN> {
1293 type Target = RawCallResult<FEN>;
1294
1295 #[inline]
1296 fn deref(&self) -> &Self::Target {
1297 &self.raw
1298 }
1299}
1300
1301impl<FEN: FoundryEvmNetwork> std::ops::DerefMut for ExecutionErr<FEN> {
1302 #[inline]
1303 fn deref_mut(&mut self) -> &mut Self::Target {
1304 &mut self.raw
1305 }
1306}
1307
1308#[derive(Debug, thiserror::Error)]
1309pub enum EvmError<FEN: FoundryEvmNetwork = EthEvmNetwork> {
1310 #[error(transparent)]
1312 Execution(Box<ExecutionErr<FEN>>),
1313 #[error(transparent)]
1315 Abi(#[from] alloy_dyn_abi::Error),
1316 #[error("{0}")]
1318 Skip(SkipReason),
1319 #[error("{0}")]
1321 Eyre(
1322 #[from]
1323 #[source]
1324 eyre::Report,
1325 ),
1326}
1327
1328impl<FEN: FoundryEvmNetwork> From<ExecutionErr<FEN>> for EvmError<FEN> {
1329 fn from(err: ExecutionErr<FEN>) -> Self {
1330 Self::Execution(Box::new(err))
1331 }
1332}
1333
1334impl<FEN: FoundryEvmNetwork> From<alloy_sol_types::Error> for EvmError<FEN> {
1335 fn from(err: alloy_sol_types::Error) -> Self {
1336 Self::Abi(err.into())
1337 }
1338}
1339
1340#[derive(Debug)]
1342pub struct DeployResult<FEN: FoundryEvmNetwork = EthEvmNetwork> {
1343 pub raw: RawCallResult<FEN>,
1345 pub address: Address,
1347}
1348
1349impl<FEN: FoundryEvmNetwork> std::ops::Deref for DeployResult<FEN> {
1350 type Target = RawCallResult<FEN>;
1351
1352 #[inline]
1353 fn deref(&self) -> &Self::Target {
1354 &self.raw
1355 }
1356}
1357
1358impl<FEN: FoundryEvmNetwork> std::ops::DerefMut for DeployResult<FEN> {
1359 #[inline]
1360 fn deref_mut(&mut self) -> &mut Self::Target {
1361 &mut self.raw
1362 }
1363}
1364
1365impl<FEN: FoundryEvmNetwork> From<DeployResult<FEN>> for RawCallResult<FEN> {
1366 fn from(d: DeployResult<FEN>) -> Self {
1367 d.raw
1368 }
1369}
1370
1371#[derive(Debug)]
1373pub struct RawCallResult<FEN: FoundryEvmNetwork = EthEvmNetwork> {
1374 pub exit_reason: Option<InstructionResult>,
1376 pub execution_cancelled: bool,
1378 pub reverted: bool,
1380 pub has_state_snapshot_failure: bool,
1385 pub result: Bytes,
1387 pub gas_used: u64,
1389 pub gas_refunded: u64,
1391 pub stipend: u64,
1393 pub logs: Vec<Log>,
1395 pub labels: AddressHashMap<String>,
1397 pub traces: Option<SparsedTraceArena>,
1399 pub debug_bytecodes: AddressHashMap<Bytes>,
1401 pub line_coverage: Option<HitMaps>,
1403 pub edge_coverage: Option<EdgeCoverage>,
1405 pub evm_cmp_values: Option<Vec<CmpOperands>>,
1407 pub observed_calls: Vec<ObservedCall>,
1409 pub sancov_coverage: Option<Vec<u8>>,
1412 pub sancov_cmp_values: Option<Vec<foundry_evm_sancov::CmpSample>>,
1414 pub transactions: Option<BroadcastableTransactions<FEN::Network>>,
1416 pub state_changeset: StateChangeset,
1418 pub evm_env: EvmEnvFor<FEN>,
1420 pub tx_env: TxEnvFor<FEN>,
1422 pub cheatcodes: Option<Box<Cheatcodes<FEN>>>,
1424 pub out: Option<Output>,
1426 pub fork_block_number: Option<u64>,
1428 pub chisel_state: Option<(Vec<U256>, Vec<u8>)>,
1430 pub reverter: Option<Address>,
1431 pub skip_payloads: Vec<Bytes>,
1436}
1437
1438impl<FEN: FoundryEvmNetwork> Default for RawCallResult<FEN> {
1439 fn default() -> Self {
1440 Self {
1441 exit_reason: None,
1442 execution_cancelled: false,
1443 reverted: false,
1444 has_state_snapshot_failure: false,
1445 result: Bytes::new(),
1446 gas_used: 0,
1447 gas_refunded: 0,
1448 stipend: 0,
1449 logs: Vec::new(),
1450 labels: HashMap::default(),
1451 traces: None,
1452 debug_bytecodes: HashMap::default(),
1453 line_coverage: None,
1454 edge_coverage: None,
1455 evm_cmp_values: None,
1456 observed_calls: Vec::new(),
1457 sancov_coverage: None,
1458 sancov_cmp_values: None,
1459 transactions: None,
1460 state_changeset: HashMap::default(),
1461 evm_env: EvmEnv::default(),
1462 tx_env: TxEnvFor::<FEN>::default(),
1463 cheatcodes: Default::default(),
1464 out: None,
1465 fork_block_number: None,
1466 chisel_state: None,
1467 reverter: None,
1468 skip_payloads: Vec::new(),
1469 }
1470 }
1471}
1472
1473impl<FEN: FoundryEvmNetwork> RawCallResult<FEN> {
1474 pub fn from_evm_result(r: Result<Self, EvmError<FEN>>) -> eyre::Result<(Self, Option<String>)> {
1476 match r {
1477 Ok(r) => Ok((r, None)),
1478 Err(EvmError::Execution(e)) => Ok((e.raw, Some(e.reason))),
1479 Err(e) => Err(e.into()),
1480 }
1481 }
1482
1483 pub fn skip_reason(&self) -> Option<SkipReason> {
1488 if !self.reverted || !self.skip_payloads.contains(&self.result) {
1489 return None;
1490 }
1491 SkipReason::decode(&self.result)
1492 }
1493
1494 pub fn into_evm_error(self, rd: Option<&RevertDecoder>) -> EvmError<FEN> {
1496 if let Some(reason) = self.skip_reason() {
1497 return EvmError::Skip(reason);
1498 }
1499 let reason = rd.unwrap_or_default().decode(&self.result, self.exit_reason);
1500 EvmError::Execution(Box::new(self.into_execution_error(reason)))
1501 }
1502
1503 pub const fn into_execution_error(self, reason: String) -> ExecutionErr<FEN> {
1505 ExecutionErr { raw: self, reason }
1506 }
1507
1508 pub fn into_result(self, rd: Option<&RevertDecoder>) -> Result<Self, EvmError<FEN>> {
1510 if let Some(reason) = self.exit_reason
1511 && reason.is_ok()
1512 {
1513 Ok(self)
1514 } else {
1515 Err(self.into_evm_error(rd))
1516 }
1517 }
1518
1519 pub fn into_decoded_result(
1521 mut self,
1522 func: &Function,
1523 rd: Option<&RevertDecoder>,
1524 ) -> Result<CallResult<DynSolValue, FEN>, EvmError<FEN>> {
1525 self = self.into_result(rd)?;
1526 let mut result = func.abi_decode_output(&self.result)?;
1527 let decoded_result =
1528 if result.len() == 1 { result.pop().unwrap() } else { DynSolValue::Tuple(result) };
1529 Ok(CallResult { raw: self, decoded_result })
1530 }
1531
1532 pub fn transactions(&self) -> Option<&BroadcastableTransactions<FEN::Network>> {
1534 self.cheatcodes.as_ref().map(|c| &c.broadcastable_transactions)
1535 }
1536
1537 pub fn merge_edge_coverage(
1539 &mut self,
1540 history_map: &mut Vec<u8>,
1541 edge_indices: &mut EdgeIndexMap,
1542 ) -> (bool, bool) {
1543 let mut new_coverage = false;
1544 let mut is_edge = false;
1545 if let Some(x) = &mut self.edge_coverage {
1546 match x {
1547 EdgeCoverage::Hash(x) => {
1548 if history_map.len() < x.len() {
1549 history_map.resize(x.len(), 0);
1550 }
1551 for (curr, hist) in std::iter::zip(x.iter_mut(), history_map.iter_mut()) {
1554 Self::merge_edge_count(*curr, hist, &mut new_coverage, &mut is_edge);
1555
1556 *curr = 0;
1558 }
1559 }
1560 EdgeCoverage::CollisionFree(hits) => {
1561 for hit in hits.drain(..) {
1562 let edge_index = edge_indices.edge_index(hit.edge);
1563 if history_map.len() <= edge_index {
1564 history_map.resize(edge_index + 1, 0);
1565 }
1566 Self::merge_edge_count(
1567 hit.count,
1568 &mut history_map[edge_index],
1569 &mut new_coverage,
1570 &mut is_edge,
1571 );
1572 }
1573 }
1574 }
1575 }
1576 (new_coverage, is_edge)
1577 }
1578
1579 const fn merge_edge_count(
1580 curr: u8,
1581 hist: &mut u8,
1582 new_coverage: &mut bool,
1583 is_edge: &mut bool,
1584 ) {
1585 let Some(bucket) = Self::bin_count(curr) else {
1586 return;
1587 };
1588
1589 if *hist < bucket {
1591 if *hist == 0 {
1592 *is_edge = true;
1594 }
1595 *hist = bucket;
1596 *new_coverage = true;
1597 }
1598 }
1599
1600 const fn bin_count(count: u8) -> Option<u8> {
1603 match count {
1604 0 => None,
1605 1 => Some(1),
1606 2 => Some(2),
1607 3 => Some(4),
1608 4..=7 => Some(8),
1609 8..=15 => Some(16),
1610 16..=31 => Some(32),
1611 32..=127 => Some(64),
1612 128..=255 => Some(128),
1613 }
1614 }
1615
1616 pub fn merge_sancov_coverage(&mut self, history_map: &mut Vec<u8>) -> (bool, bool) {
1619 let mut new_coverage = false;
1620 let mut is_edge = false;
1621 if let Some(x) = &mut self.sancov_coverage {
1622 if history_map.len() < x.len() {
1623 history_map.resize(x.len(), 0);
1624 }
1625 for (curr, hist) in std::iter::zip(x.iter_mut(), history_map.iter_mut()) {
1626 if *curr > 0 {
1627 if let Some(bucket) = Self::bin_count(*curr)
1628 && *hist < bucket
1629 {
1630 if *hist == 0 {
1631 is_edge = true;
1632 }
1633 *hist = bucket;
1634 new_coverage = true;
1635 }
1636 *curr = 0;
1637 }
1638 }
1639 }
1640 (new_coverage, is_edge)
1641 }
1642
1643 pub fn merge_all_coverage(
1646 &mut self,
1647 evm_history: &mut Vec<u8>,
1648 evm_edge_indices: &mut EdgeIndexMap,
1649 sancov_history: &mut Vec<u8>,
1650 ) -> (bool, bool) {
1651 let (new_evm, edge_evm) = self.merge_edge_coverage(evm_history, evm_edge_indices);
1652 let (new_san, edge_san) = self.merge_sancov_coverage(sancov_history);
1653 (new_evm || new_san, edge_evm || edge_san)
1654 }
1655}
1656
1657pub struct CallResult<T = DynSolValue, FEN: FoundryEvmNetwork = EthEvmNetwork> {
1659 pub raw: RawCallResult<FEN>,
1661 pub decoded_result: T,
1663}
1664
1665impl<T, FEN: FoundryEvmNetwork> std::ops::Deref for CallResult<T, FEN> {
1666 type Target = RawCallResult<FEN>;
1667
1668 #[inline]
1669 fn deref(&self) -> &Self::Target {
1670 &self.raw
1671 }
1672}
1673
1674impl<T, FEN: FoundryEvmNetwork> std::ops::DerefMut for CallResult<T, FEN> {
1675 #[inline]
1676 fn deref_mut(&mut self) -> &mut Self::Target {
1677 &mut self.raw
1678 }
1679}
1680
1681pub(crate) fn calculate_stipend(tx_env: &impl Transaction, cfg: &impl Cfg) -> u64 {
1682 calculate_initial_gas(tx_env, cfg).initial_total_gas()
1683}
1684
1685pub(crate) fn calculate_initial_gas(
1687 tx_env: &impl Transaction,
1688 cfg: &impl Cfg,
1689) -> InitialAndFloorGas {
1690 let eip2780 = cfg.is_amsterdam_eip2780_enabled().then(|| Eip2780TxInfo {
1691 value: tx_env.value(),
1692 is_self_transfer: matches!(tx_env.kind(), TxKind::Call(to) if to == tx_env.caller()),
1693 });
1694 revm::interpreter::gas::calculate_initial_tx_gas_for_tx(tx_env, cfg.spec().into(), eip2780)
1695}
1696
1697fn convert_executed_result<FEN: FoundryEvmNetwork, H: IntoInstructionResult>(
1699 evm_env: EvmEnvFor<FEN>,
1700 tx_env: TxEnvFor<FEN>,
1701 mut inspector: InspectorStack<FEN>,
1702 ResultAndState { result, state: state_changeset }: ResultAndState<H>,
1703 db: &dyn DatabaseRef<Error = DatabaseError>,
1704 has_state_snapshot_failure: bool,
1705 fork_block_number: Option<u64>,
1706) -> eyre::Result<RawCallResult<FEN>> {
1707 let execution_cancelled = inspector.execution_cancelled();
1708 let (exit_reason, gas_refunded, gas_used, out, exec_logs) = match result {
1709 ExecutionResult::Success { reason, gas, output, logs } => {
1710 (reason.into(), gas.final_refunded(), gas.tx_gas_used(), Some(output), logs)
1711 }
1712 ExecutionResult::Revert { gas, output, logs } => {
1713 (InstructionResult::Revert, 0_u64, gas.tx_gas_used(), Some(Output::Call(output)), logs)
1714 }
1715 ExecutionResult::Halt { reason, gas, logs } => {
1716 (reason.into_instruction_result(), 0_u64, gas.tx_gas_used(), None, logs)
1717 }
1718 };
1719 let stipend = calculate_stipend(&tx_env, evm_env.cfg_env());
1720
1721 let result = match &out {
1722 Some(Output::Call(data)) => data.clone(),
1723 _ => Bytes::new(),
1724 };
1725 let observed_calls = inspector
1726 .inner
1727 .fuzzer
1728 .as_mut()
1729 .map(|fuzzer| fuzzer.take_observed_calls())
1730 .unwrap_or_default();
1731
1732 let InspectorData {
1733 mut logs,
1734 labels,
1735 traces,
1736 line_coverage,
1737 edge_coverage,
1738 evm_cmp_values,
1739 mut cheatcodes,
1740 chisel_state,
1741 reverter,
1742 } = inspector.collect();
1743 let fork_block_number = cheatcodes
1744 .as_ref()
1745 .and_then(|cheats| cheats.fork_block_number_override)
1746 .or(fork_block_number);
1747 let debug_bytecodes = collect_debug_bytecodes(traces.as_ref(), db);
1748
1749 if logs.is_empty() {
1750 logs = exec_logs;
1751 }
1752
1753 let transactions = cheatcodes
1754 .as_ref()
1755 .map(|c| c.broadcastable_transactions.clone())
1756 .filter(|txs| !txs.is_empty());
1757 let skip_payloads =
1758 cheatcodes.as_mut().map(|c| std::mem::take(&mut c.skip_payloads)).unwrap_or_default();
1759
1760 Ok(RawCallResult {
1761 exit_reason: Some(exit_reason),
1762 execution_cancelled,
1763 reverted: !exit_reason.is_ok(),
1764 has_state_snapshot_failure,
1765 result,
1766 gas_used,
1767 gas_refunded,
1768 stipend,
1769 logs,
1770 labels,
1771 traces,
1772 debug_bytecodes,
1773 line_coverage,
1774 edge_coverage,
1775 evm_cmp_values,
1776 observed_calls,
1777 sancov_coverage: None,
1778 sancov_cmp_values: None,
1779 transactions,
1780 state_changeset,
1781 evm_env,
1782 tx_env,
1783 cheatcodes,
1784 out,
1785 fork_block_number,
1786 chisel_state,
1787 reverter,
1788 skip_payloads,
1789 })
1790}
1791
1792fn collect_debug_bytecodes(
1793 traces: Option<&SparsedTraceArena>,
1794 db: &dyn DatabaseRef<Error = DatabaseError>,
1795) -> AddressHashMap<Bytes> {
1796 let mut bytecodes = HashMap::default();
1797 let Some(traces) = traces else { return bytecodes };
1798
1799 for node in traces.arena.nodes() {
1800 let address = node.trace.address;
1801 if bytecodes.contains_key(&address) {
1802 continue;
1803 }
1804
1805 let Ok(Some(account)) = db.basic_ref(address) else { continue };
1806 let code: Option<Bytecode> =
1807 account.code.or_else(|| db.code_by_hash_ref(account.code_hash).ok());
1808 let code: Bytes = code.map(|code| code.original_bytes()).unwrap_or_default();
1809
1810 if !code.is_empty() {
1811 bytecodes.insert(address, code);
1812 }
1813 }
1814
1815 bytecodes
1816}
1817
1818pub struct FuzzTestTimer {
1820 inner: Option<(Instant, Duration)>,
1822}
1823
1824impl FuzzTestTimer {
1825 pub fn new(timeout: Option<u32>) -> Self {
1826 Self { inner: timeout.map(|timeout| (Instant::now(), Duration::from_secs(timeout.into()))) }
1827 }
1828
1829 pub const fn is_enabled(&self) -> bool {
1831 self.inner.is_some()
1832 }
1833
1834 pub fn is_timed_out(&self) -> bool {
1836 self.inner.is_some_and(|(start, duration)| start.elapsed() > duration)
1837 }
1838}
1839
1840#[derive(Clone, Debug)]
1843pub struct EarlyExit {
1844 inner: Arc<AtomicBool>,
1846 fail_fast: bool,
1848}
1849
1850impl EarlyExit {
1851 pub fn new(fail_fast: bool) -> Self {
1852 Self { inner: Arc::new(AtomicBool::new(false)), fail_fast }
1853 }
1854
1855 pub fn record_failure(&self) {
1857 if self.fail_fast {
1858 self.inner.store(true, Ordering::Relaxed);
1859 }
1860 }
1861
1862 pub fn record_ctrl_c(&self) {
1864 self.inner.store(true, Ordering::Relaxed);
1865 }
1866
1867 pub fn should_stop(&self) -> bool {
1869 self.inner.load(Ordering::Relaxed)
1870 }
1871}
1872
1873#[derive(Clone, Debug)]
1875pub(crate) enum EvmExecutionCancellation {
1876 EarlyExit(EarlyExit),
1878 Campaign { early_exit: EarlyExit, stop: Arc<AtomicBool>, deadline: Option<Instant> },
1880}
1881
1882impl EvmExecutionCancellation {
1883 pub(crate) const fn early_exit(early_exit: EarlyExit) -> Self {
1884 Self::EarlyExit(early_exit)
1885 }
1886
1887 pub(crate) const fn campaign(
1888 early_exit: EarlyExit,
1889 stop: Arc<AtomicBool>,
1890 deadline: Option<Instant>,
1891 ) -> Self {
1892 Self::Campaign { early_exit, stop, deadline }
1893 }
1894
1895 pub(crate) fn should_stop(&self, poll_deadline: bool) -> bool {
1897 match self {
1898 Self::EarlyExit(early_exit) => early_exit.should_stop(),
1899 Self::Campaign { early_exit, stop, deadline } => {
1900 if early_exit.should_stop() || stop.load(Ordering::Relaxed) {
1901 return true;
1902 }
1903 if poll_deadline && deadline.is_some_and(|deadline| Instant::now() > deadline) {
1904 stop.store(true, Ordering::Relaxed);
1905 return true;
1906 }
1907 false
1908 }
1909 }
1910 }
1911
1912 pub(crate) fn request_stop(&self) {
1913 if let Self::Campaign { stop, .. } = self {
1914 stop.store(true, Ordering::Relaxed);
1915 }
1916 }
1917
1918 pub(crate) fn stop_requested(&self) -> bool {
1920 matches!(self, Self::Campaign { stop, .. } if stop.load(Ordering::Relaxed))
1921 }
1922
1923 pub(crate) const fn early_exit_ref(&self) -> &EarlyExit {
1924 match self {
1925 Self::EarlyExit(early_exit) | Self::Campaign { early_exit, .. } => early_exit,
1926 }
1927 }
1928}
1929
1930#[inline]
1932pub fn should_ignore_revert(
1933 fail_on_revert: bool,
1934 target: Address,
1935 reverter: Option<Address>,
1936 extra_cheatcode_addresses: &[Address],
1937) -> bool {
1938 !fail_on_revert
1939 && reverter.is_some_and(|reverter| {
1940 reverter != target
1941 && reverter != CHEATCODE_ADDRESS
1942 && !extra_cheatcode_addresses.contains(&reverter)
1943 })
1944}
1945
1946#[cfg(test)]
1947mod tests {
1948 use super::*;
1949 use crate::inspectors::{EdgeCovHit, EdgeKey};
1950 use foundry_cheatcodes::{
1951 CheatsConfig,
1952 Vm::{blobhashesCall, mockCallRevert_1Call, revertToStateCall, snapshotStateCall},
1953 };
1954 use foundry_config::Config;
1955 use foundry_evm_core::{constants::MAGIC_SKIP, evm::TempoEvmNetwork, opts::EvmOpts};
1956 use foundry_evm_hardforks::TempoHardfork;
1957 use foundry_evm_traces::InternalTraceMode;
1958 use revm::context::CfgEnv;
1959 use std::{sync::mpsc, thread};
1960 use tempo_revm::{TempoBlockEnv, TempoTxEnv};
1961
1962 #[cfg(not(feature = "monad"))]
1963 use revm::context::TxEnv;
1964
1965 #[cfg(feature = "base")]
1966 use foundry_evm_core::evm::BaseEvmNetwork;
1967 #[cfg(feature = "base")]
1968 use foundry_evm_hardforks::BaseSpecId;
1969
1970 #[cfg(feature = "monad")]
1971 use foundry_evm_core::constants::MONAD_CHEATCODE_ADDRESS;
1972
1973 fn dense_call(edge: EdgeKey) -> RawCallResult {
1974 RawCallResult {
1975 edge_coverage: Some(EdgeCoverage::CollisionFree(vec![EdgeCovHit { edge, count: 1 }])),
1976 ..Default::default()
1977 }
1978 }
1979
1980 #[test]
1981 fn nested_revert_is_ignored_only_when_allowed() {
1982 let target = Address::repeat_byte(0x11);
1983 let nested = Address::repeat_byte(0x22);
1984
1985 assert!(should_ignore_revert(false, target, Some(nested), &[]));
1986 assert!(!should_ignore_revert(true, target, Some(nested), &[]));
1987 assert!(!should_ignore_revert(false, target, Some(target), &[]));
1988 assert!(!should_ignore_revert(false, target, Some(CHEATCODE_ADDRESS), &[]));
1989 assert!(!should_ignore_revert(false, target, None, &[]));
1990 }
1991
1992 #[cfg(feature = "monad")]
1993 #[test]
1994 fn network_cheatcode_revert_handling_is_monad_specific() {
1995 let target = Address::repeat_byte(0x11);
1996
1997 assert!(should_ignore_revert(false, target, Some(MONAD_CHEATCODE_ADDRESS), &[]));
1998 assert!(!should_ignore_revert(
1999 false,
2000 target,
2001 Some(MONAD_CHEATCODE_ADDRESS),
2002 &[MONAD_CHEATCODE_ADDRESS],
2003 ));
2004 }
2005
2006 #[cfg(feature = "monad")]
2007 #[test]
2008 fn executor_tooling_follows_concrete_builder() {
2009 let ethereum = ExecutorBuilder::<EthEvmNetwork>::new().build(
2010 EvmEnv::default(),
2011 TxEnv::default(),
2012 Backend::spawn(None).unwrap(),
2013 NetworkConfigs::with_monad(),
2014 );
2015 assert!(ethereum.backend().networks().is_monad());
2016 assert!(!ethereum.backend().is_persistent(&MONAD_CHEATCODE_ADDRESS));
2017
2018 let monad = ExecutorBuilder::<MonadEvmNetwork>::new().build(
2019 EvmEnv::<MonadHardfork>::default(),
2020 TxEnv::default(),
2021 Backend::spawn(None).unwrap(),
2022 NetworkConfigs::with_monad(),
2023 );
2024 assert!(monad.inspector().networks.is_monad());
2025 assert!(monad.backend().networks().is_monad());
2026 assert!(monad.backend().is_persistent(&MONAD_CHEATCODE_ADDRESS));
2027 }
2028
2029 #[test]
2030 fn tempo_labels_follow_concrete_builder() {
2031 let ethereum = ExecutorBuilder::<EthEvmNetwork>::new().build(
2032 EvmEnv::default(),
2033 TxEnv::default(),
2034 Backend::spawn(None).unwrap(),
2035 NetworkConfigs::with_tempo(),
2036 );
2037 assert!(ethereum.inspector().tempo_labels.is_none());
2038
2039 let tempo = ExecutorBuilder::<TempoEvmNetwork>::new().build(
2040 EvmEnv::<TempoHardfork, TempoBlockEnv>::default(),
2041 TempoTxEnv::default(),
2042 Backend::spawn(None).unwrap(),
2043 NetworkConfigs::default(),
2044 );
2045 assert!(tempo.inspector().tempo_labels.is_some());
2046 }
2047
2048 #[test]
2049 fn collision_free_edge_merge_uses_stable_indices() {
2050 let first =
2051 EdgeKey { address: Address::ZERO, depth: None, pc: 0, jump_dest: U256::from(10) };
2052 let second =
2053 EdgeKey { address: Address::ZERO, depth: None, pc: 0, jump_dest: U256::from(20) };
2054 let mut history = Vec::new();
2055 let mut edge_indices = EdgeIndexMap::default();
2056
2057 assert_eq!(
2058 dense_call(first).merge_edge_coverage(&mut history, &mut edge_indices),
2059 (true, true)
2060 );
2061 assert_eq!(history, [1]);
2062
2063 assert_eq!(
2064 dense_call(second).merge_edge_coverage(&mut history, &mut edge_indices),
2065 (true, true)
2066 );
2067 assert_eq!(history, [1, 1]);
2068
2069 assert_eq!(
2070 dense_call(first).merge_edge_coverage(&mut history, &mut edge_indices),
2071 (false, false)
2072 );
2073 assert_eq!(history, [1, 1]);
2074 }
2075
2076 #[test]
2077 fn collision_free_edge_merge_handles_sparse_observation_indices() {
2078 let first =
2079 EdgeKey { address: Address::ZERO, depth: None, pc: 0, jump_dest: U256::from(10) };
2080 let second =
2081 EdgeKey { address: Address::ZERO, depth: None, pc: 0, jump_dest: U256::from(20) };
2082 let mut edge_indices = EdgeIndexMap::default();
2083 edge_indices.edge_index(first);
2084 edge_indices.edge_index(second);
2085 let mut history = Vec::new();
2086
2087 assert_eq!(
2088 dense_call(second).merge_edge_coverage(&mut history, &mut edge_indices),
2089 (true, true)
2090 );
2091 assert_eq!(history, [0, 1]);
2092 }
2093
2094 #[test]
2095 fn cheatcode_skip_payload_is_classified_as_skip() {
2096 let raw = RawCallResult::<EthEvmNetwork> {
2097 reverted: true,
2098 result: Bytes::from_static(b"FOUNDRY::SKIPwith reason"),
2099 skip_payloads: vec![Bytes::from_static(b"FOUNDRY::SKIPwith reason")],
2100 ..Default::default()
2101 };
2102
2103 let err = raw.into_evm_error(None);
2104 assert!(matches!(err, EvmError::Skip(_)));
2105 }
2106
2107 #[test]
2108 fn forged_skip_payload_is_execution_error() {
2109 let raw = RawCallResult::<EthEvmNetwork> {
2110 reverted: true,
2111 result: Bytes::from_static(MAGIC_SKIP),
2112 reverter: Some(CHEATCODE_ADDRESS),
2113 ..Default::default()
2114 };
2115
2116 let err = raw.into_evm_error(None);
2117 assert!(matches!(err, EvmError::Execution(_)));
2118 }
2119
2120 #[cfg(feature = "base")]
2121 #[test]
2122 fn base_block_replay_rejects_eip8130_before_execution() {
2123 for target_is_eip8130 in [true, false] {
2124 let mut executor = ExecutorBuilder::<BaseEvmNetwork>::new().build(
2125 EvmEnv::<BaseSpecId>::default(),
2126 TxEnvFor::<BaseEvmNetwork>::default(),
2127 Backend::spawn(None).unwrap(),
2128 NetworkConfigs::with_base(),
2129 );
2130 let unsupported = TxEnvFor::<BaseEvmNetwork> {
2131 eip8130: Some(
2132 serde_json::from_value(serde_json::json!({
2133 "signed": {
2134 "tx": {
2135 "chainId": 8453, "sender": null, "nonceKey": "0x0",
2136 "nonceSequence": 0, "validAfter": 0, "validBefore": 0,
2137 "maxPriorityFeePerGas": "0x0", "maxFeePerGas": "0x0",
2138 "gasLimit": 100000, "accountChanges": [], "calls": [],
2139 "metadata": "0x", "payer": null
2140 },
2141 "senderAuth": "0x", "payerAuth": "0x"
2142 },
2143 "mode": "Verified", "simulation_sender_actor_id": null
2144 }))
2145 .unwrap(),
2146 ),
2147 ..Default::default()
2148 };
2149 let ordinary = TxEnvFor::<BaseEvmNetwork>::default();
2150 let hash = B256::repeat_byte(1);
2151 let (target, prefix, expected) = if target_is_eip8130 {
2152 (
2153 unsupported,
2154 vec![(hash, ordinary)],
2155 "EIP-8130 target transactions are not supported by tooling replay".to_string(),
2156 )
2157 } else {
2158 (
2159 ordinary.clone(),
2160 vec![(B256::ZERO, ordinary), (hash, unsupported)],
2161 format!(
2162 "EIP-8130 prefix transaction {hash} is not supported by tooling replay"
2163 ),
2164 )
2165 };
2166 let error = executor
2167 .transact_with_ordinary_block_replay(
2168 EvmEnv::<BaseSpecId>::default(),
2169 target,
2170 prefix,
2171 )
2172 .unwrap_err();
2173 assert_eq!(error.to_string(), expected);
2174 assert_eq!(executor.get_nonce(Address::ZERO).unwrap(), 0);
2175 }
2176 }
2177
2178 #[test]
2179 fn block_replay_commits_prefix_and_traces_only_target() {
2180 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2181 let mut executor = ExecutorBuilder::default().gas_limit(1 << 20).build(
2182 EvmEnv::default(),
2183 TxEnv::default(),
2184 backend,
2185 NetworkConfigs::default(),
2186 );
2187 executor.set_balance(CALLER, U256::MAX).unwrap();
2188 executor.set_trace_requirements(TraceRequirements::none().with_calls(true));
2189
2190 let address = Address::repeat_byte(0x11);
2191 executor
2193 .set_code(
2194 address,
2195 Bytecode::new_raw(Bytes::from_static(&[
2196 0x60, 0x00, 0x54, 0x60, 0x01, 0x01, 0x80, 0x60, 0x00, 0x55, 0x60, 0x00, 0x52,
2197 0x60, 0x20, 0x60, 0x00, 0xf3,
2198 ])),
2199 )
2200 .unwrap();
2201 let prefix = TxEnv {
2202 caller: CALLER,
2203 gas_limit: 100_000,
2204 kind: TxKind::Call(address),
2205 ..Default::default()
2206 };
2207 let reverted_create = TxEnv {
2208 nonce: 1,
2209 kind: TxKind::Create,
2210 data: Bytes::from_static(&[0x5f, 0x5f, 0xfd]),
2211 ..prefix.clone()
2212 };
2213 let target = TxEnv { nonce: 2, ..prefix.clone() };
2214
2215 let result = executor
2216 .transact_with_ordinary_block_replay(
2217 EvmEnv::default(),
2218 target,
2219 vec![(B256::repeat_byte(1), prefix), (B256::repeat_byte(2), reverted_create)],
2220 )
2221 .unwrap();
2222
2223 assert_eq!(result.result, Bytes::from(B256::with_last_byte(2).0));
2224 assert_eq!(result.tx_env.nonce, 2);
2225 assert_eq!(executor.get_nonce(CALLER).unwrap(), 3);
2226 assert_eq!(executor.backend().storage_ref(address, U256::ZERO).unwrap(), U256::from(2));
2227 assert_eq!(result.traces.unwrap().arena.nodes().len(), 1);
2228 }
2229
2230 #[test]
2231 fn block_replay_initializes_create_target_from_canonical_nonce() {
2232 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2233 let mut executor = ExecutorBuilder::default().gas_limit(1 << 20).build(
2234 EvmEnv::default(),
2235 TxEnv::default(),
2236 backend,
2237 NetworkConfigs::default(),
2238 );
2239 executor.set_balance(CALLER, U256::MAX).unwrap();
2240
2241 let prefix = TxEnv {
2242 caller: CALLER,
2243 gas_limit: 100_000,
2244 kind: TxKind::Call(Address::repeat_byte(0x11)),
2245 ..Default::default()
2246 };
2247 let target = TxEnv {
2248 nonce: 1,
2249 kind: TxKind::Create,
2250 data: Bytes::from_static(&[0x00]),
2251 ..prefix.clone()
2252 };
2253 let expected = CALLER.create(1);
2254
2255 let result = executor
2256 .transact_with_ordinary_block_replay(
2257 EvmEnv::default(),
2258 target,
2259 vec![(B256::repeat_byte(1), prefix)],
2260 )
2261 .unwrap();
2262
2263 assert!(
2264 matches!(result.out, Some(Output::Create(_, Some(address))) if address == expected)
2265 );
2266 assert!(executor.backend().is_persistent(&expected));
2267 assert!(executor.backend().has_cheatcode_access(&expected));
2268 }
2269
2270 #[test]
2271 fn block_replay_preserves_successful_prefix_deployment() {
2272 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2273 let mut executor = ExecutorBuilder::default().gas_limit(1 << 20).build(
2274 EvmEnv::default(),
2275 TxEnv::default(),
2276 backend,
2277 NetworkConfigs::default(),
2278 );
2279 executor.set_balance(CALLER, U256::MAX).unwrap();
2280
2281 let deployed = CALLER.create(0);
2282 let prefix = TxEnv {
2283 caller: CALLER,
2284 gas_limit: 100_000,
2285 kind: TxKind::Create,
2286 data: Bytes::from_static(&[0x00]),
2287 ..Default::default()
2288 };
2289 let target = TxEnv { nonce: 1, kind: TxKind::Call(deployed), ..prefix.clone() };
2290
2291 executor
2292 .transact_with_ordinary_block_replay(
2293 EvmEnv::default(),
2294 target,
2295 vec![(B256::repeat_byte(1), prefix)],
2296 )
2297 .unwrap();
2298
2299 assert!(executor.backend().is_persistent(&deployed));
2300 }
2301
2302 #[cfg(feature = "monad")]
2303 #[test]
2304 fn block_replay_executes_monad_system_prefix() {
2305 use foundry_evm_core::evm::MonadEvmNetwork;
2306
2307 let backend = Backend::<MonadEvmNetwork>::spawn(None).unwrap();
2308 let mut executor = ExecutorBuilder::<MonadEvmNetwork>::default().gas_limit(1 << 20).build(
2309 EvmEnv::<MonadHardfork>::default(),
2310 TxEnv::default(),
2311 backend,
2312 NetworkConfigs::with_monad(),
2313 );
2314 executor.set_balance(CALLER, U256::MAX).unwrap();
2315
2316 let system_address = alloy_primitives::address!("6f49a8f621353f12378d0046e7d7e4b9b249dc9e");
2317 let staking_address =
2318 alloy_primitives::address!("0000000000000000000000000000000000001000");
2319 let selector = keccak256("syscallSnapshot()");
2320 let system = TxEnv {
2321 caller: system_address,
2322 gas_limit: 0,
2323 kind: TxKind::Call(staking_address),
2324 data: Bytes::copy_from_slice(&selector[..4]),
2325 chain_id: None,
2326 ..Default::default()
2327 };
2328 let target = TxEnv {
2329 caller: CALLER,
2330 gas_limit: 100_000,
2331 kind: TxKind::Call(Address::repeat_byte(0x11)),
2332 ..Default::default()
2333 };
2334 let system_chain = MonadChainContext::for_transaction(&system);
2335 let target_chain = MonadChainContext::for_transaction(&target);
2336
2337 let (result, used_system_replay) = executor
2338 .transact_with_monad_block_replay(
2339 EvmEnv::<MonadHardfork>::default(),
2340 target,
2341 target_chain,
2342 vec![(B256::repeat_byte(1), system, system_chain)],
2343 false,
2344 )
2345 .unwrap()
2346 .unwrap();
2347
2348 assert!(!used_system_replay);
2349 assert!(!result.reverted);
2350 assert_eq!(executor.get_nonce(system_address).unwrap(), 1);
2351 }
2352
2353 #[cfg(feature = "monad")]
2354 #[test]
2355 fn block_replay_executes_monad_system_target() {
2356 use foundry_evm_core::evm::MonadEvmNetwork;
2357
2358 let backend = Backend::<MonadEvmNetwork>::spawn(None).unwrap();
2359 let mut executor = ExecutorBuilder::<MonadEvmNetwork>::default().gas_limit(1 << 20).build(
2360 EvmEnv::<MonadHardfork>::default(),
2361 TxEnv::default(),
2362 backend,
2363 NetworkConfigs::with_monad(),
2364 );
2365
2366 let system_address = alloy_primitives::address!("6f49a8f621353f12378d0046e7d7e4b9b249dc9e");
2367 let staking_address =
2368 alloy_primitives::address!("0000000000000000000000000000000000001000");
2369 let selector = keccak256("syscallSnapshot()");
2370 let target = TxEnv {
2371 caller: system_address,
2372 gas_limit: 0,
2373 kind: TxKind::Call(staking_address),
2374 data: Bytes::copy_from_slice(&selector[..4]),
2375 chain_id: None,
2376 ..Default::default()
2377 };
2378 let target_chain = MonadChainContext::for_transaction(&target);
2379
2380 let (result, used_system_replay) = executor
2381 .transact_with_monad_block_replay(
2382 EvmEnv::<MonadHardfork>::default(),
2383 target,
2384 target_chain,
2385 Vec::new(),
2386 false,
2387 )
2388 .unwrap()
2389 .unwrap();
2390
2391 assert!(used_system_replay);
2392 assert!(!result.reverted);
2393 assert_eq!(executor.get_nonce(system_address).unwrap(), 1);
2394 }
2395
2396 #[test]
2397 fn mismatched_skip_payload_is_execution_error() {
2398 let raw = RawCallResult::<EthEvmNetwork> {
2399 reverted: true,
2400 result: Bytes::from_static(b"FOUNDRY::SKIPforged"),
2401 skip_payloads: vec![Bytes::from_static(b"FOUNDRY::SKIPgenuine")],
2402 ..Default::default()
2403 };
2404
2405 let err = raw.into_evm_error(None);
2406 assert!(matches!(err, EvmError::Execution(_)));
2407 }
2408
2409 #[test]
2410 fn set_spec_id_updates_spec_dependent_cfg_state() {
2411 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2412 let mut executor = ExecutorBuilder::default().build(
2413 EvmEnv::default(),
2414 TxEnv::default(),
2415 backend,
2416 NetworkConfigs::default(),
2417 );
2418
2419 executor.evm_env_mut().cfg_env.set_spec_and_mainnet_gas_params(SpecId::HOMESTEAD);
2420 assert_eq!(
2421 executor.evm_env().cfg_env.gas_params(),
2422 &revm::context_interface::cfg::GasParams::new_spec(SpecId::HOMESTEAD),
2423 );
2424 assert!(!executor.evm_env().cfg_env.is_amsterdam_eip8037_enabled());
2425
2426 executor.set_spec_id(SpecId::AMSTERDAM);
2427
2428 assert_eq!(executor.spec_id(), SpecId::AMSTERDAM);
2429 assert_eq!(
2430 executor.evm_env().cfg_env.gas_params(),
2431 &revm::context_interface::cfg::GasParams::new_spec(SpecId::AMSTERDAM),
2432 );
2433 assert!(executor.evm_env().cfg_env.is_amsterdam_eip8037_enabled());
2434 }
2435
2436 #[test]
2437 fn calculate_stipend_uses_eip2780_transaction_context() {
2438 let caller = Address::repeat_byte(0x11);
2439 let recipient = Address::repeat_byte(0x22);
2440 let mut tx = TxEnv { caller, kind: TxKind::Call(recipient), ..Default::default() };
2441 let cfg = CfgEnv::new_with_spec(SpecId::AMSTERDAM);
2442
2443 assert_eq!(
2444 calculate_stipend(&tx, &cfg),
2445 revm::primitives::eip2780::TX_BASE_COST
2446 + revm::primitives::eip8038::COLD_ACCOUNT_ACCESS
2447 );
2448 let cfg = cfg.with_enable_amsterdam_eip2780(false);
2449 assert_eq!(
2450 calculate_stipend(&tx, &cfg),
2451 revm::context_interface::cfg::GasParams::new_spec(SpecId::AMSTERDAM).tx_base_stipend()
2452 );
2453
2454 tx.kind = TxKind::Call(caller);
2455 let cfg = cfg.with_enable_amsterdam_eip2780(true);
2456 assert_eq!(calculate_stipend(&tx, &cfg), revm::primitives::eip2780::TX_BASE_COST);
2457 }
2458
2459 #[test]
2460 fn amsterdam_intercepted_create_refunds_state_gas() {
2461 let cheats_config =
2462 Arc::new(CheatsConfig::new(&Config::default(), EvmOpts::default(), None, None, false));
2463 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2464 let mut executor = ExecutorBuilder::default()
2465 .inspectors(|stack| stack.cheatcodes(cheats_config))
2466 .spec_id(SpecId::AMSTERDAM)
2467 .gas_limit(1_000_000)
2468 .build(EvmEnv::default(), TxEnv::default(), backend, NetworkConfigs::default());
2469
2470 let target = Address::repeat_byte(0x11);
2471 executor
2473 .set_code(
2474 target,
2475 Bytecode::new_raw(Bytes::from_static(&[0x5f, 0x5f, 0x5f, 0xf0, 0x50, 0x00])),
2476 )
2477 .unwrap();
2478 executor.inspector_mut().cheatcodes.as_mut().unwrap().intercept_next_create_call = true;
2479
2480 let result = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2481
2482 assert!(!result.reverted);
2483 assert!(
2484 result.gas_used
2485 < revm::context_interface::cfg::GasParams::new_spec(SpecId::AMSTERDAM)
2486 .create_state_gas(),
2487 "failed CREATE retained its conditional state-gas charge"
2488 );
2489 }
2490
2491 #[test]
2492 fn amsterdam_mocked_call_revert_refunds_state_gas() {
2493 let cheats_config =
2494 Arc::new(CheatsConfig::new(&Config::default(), EvmOpts::default(), None, None, false));
2495 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2496 let mut executor = ExecutorBuilder::default()
2497 .inspectors(|stack| stack.cheatcodes(cheats_config))
2498 .spec_id(SpecId::AMSTERDAM)
2499 .gas_limit(1_000_000)
2500 .build(EvmEnv::default(), TxEnv::default(), backend, NetworkConfigs::default());
2501
2502 let target = Address::repeat_byte(0x11);
2503 let mocked = Address::repeat_byte(0x22);
2504 executor
2505 .transact_raw(
2506 CALLER,
2507 CHEATCODE_ADDRESS,
2508 mockCallRevert_1Call {
2509 callee: mocked,
2510 msgValue: U256::ONE,
2511 data: Bytes::new(),
2512 revertData: Bytes::new(),
2513 }
2514 .abi_encode()
2515 .into(),
2516 U256::ZERO,
2517 )
2518 .unwrap();
2519 executor.set_code(mocked, Bytecode::default()).unwrap();
2520 executor.set_balance(target, U256::ONE).unwrap();
2521
2522 let mut code = vec![0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x01, 0x73];
2524 code.extend_from_slice(mocked.as_slice());
2525 code.extend_from_slice(&[0x5a, 0xf1, 0x50, 0x00]);
2526 executor.set_code(target, Bytecode::new_raw(code.into())).unwrap();
2527
2528 let result = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2529
2530 assert!(!result.reverted);
2531 assert!(
2532 result.gas_used
2533 < revm::context_interface::cfg::GasParams::new_spec(SpecId::AMSTERDAM)
2534 .new_account_state_gas(),
2535 "reverted mocked CALL retained its conditional state-gas charge"
2536 );
2537 }
2538
2539 #[test]
2540 fn set_trace_requirements_replaces_trace_mode_between_transactions() {
2541 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2542 let mut executor = ExecutorBuilder::default().gas_limit(1 << 20).build(
2543 EvmEnv::default(),
2544 TxEnv::default(),
2545 backend,
2546 NetworkConfigs::default(),
2547 );
2548 executor.evm_env_mut().cfg_env.disable_nonce_check = true;
2549 let target = Address::repeat_byte(0x11);
2550 executor
2552 .set_code(
2553 target,
2554 Bytecode::new_raw(Bytes::from_static(&[
2555 0x60, 0x04, 0x56, 0x00, 0x5b, 0x60, 0x01, 0x60, 0x00, 0x55, 0x00,
2556 ])),
2557 )
2558 .unwrap();
2559
2560 let untraced = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2561 assert!(untraced.traces.is_none());
2562
2563 executor.set_trace_requirements(TraceRequirements::none().with_debug(true));
2564 let debug = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2565 let debug_steps = &debug.traces.as_ref().unwrap().nodes()[0].trace.steps;
2566 assert_eq!(debug_steps.len(), 7);
2567 assert!(debug_steps.iter().all(|step| step.stack.is_some() && step.memory.is_some()));
2568
2569 executor.set_trace_requirements(
2570 TraceRequirements::none().with_decode_internal(InternalTraceMode::Full),
2571 );
2572 let internal = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2573 let internal_steps = &internal.traces.as_ref().unwrap().nodes()[0].trace.steps;
2574 assert_eq!(internal_steps.len(), 2);
2575 assert!(internal_steps.iter().all(|step| step.stack.is_some() && step.memory.is_some()));
2576
2577 executor.set_trace_requirements(TraceRequirements::none());
2578 let untraced = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2579 assert!(untraced.traces.is_none());
2580 }
2581
2582 #[test]
2583 fn early_exit_interrupts_active_evm_execution() {
2584 const GAS_LIMIT: u64 = 1 << 24;
2585 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2586 let mut executor = ExecutorBuilder::default().gas_limit(GAS_LIMIT).build(
2587 EvmEnv::default(),
2588 TxEnv::default(),
2589 backend,
2590 NetworkConfigs::default(),
2591 );
2592 let early_exit = EarlyExit::new(false);
2593 executor.inspector_mut().set_early_exit(early_exit.clone());
2594
2595 let target = Address::repeat_byte(0x11);
2596 executor
2598 .set_code(target, Bytecode::new_raw(Bytes::from_static(&[0x5b, 0x60, 0x00, 0x56])))
2599 .unwrap();
2600
2601 let (started_tx, started_rx) = mpsc::channel();
2602 let (result_tx, result_rx) = mpsc::channel();
2603 let handle = thread::spawn(move || {
2604 started_tx.send(()).unwrap();
2605 let result = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO);
2606 let _ = result_tx.send(result);
2607 });
2608
2609 started_rx.recv().unwrap();
2610 thread::sleep(Duration::from_millis(1));
2611 early_exit.record_ctrl_c();
2612
2613 let result = result_rx.recv_timeout(Duration::from_secs(1));
2614 handle.join().unwrap();
2615 let result = result.expect("active EVM execution did not observe early exit").unwrap();
2616 assert!(result.execution_cancelled);
2617 assert!(!result.reverted);
2618 assert_eq!(result.exit_reason, Some(InstructionResult::Stop));
2619 assert!(result.gas_used > 21_000, "interrupt fired before EVM execution started");
2620 assert!(result.gas_used < GAS_LIMIT, "execution ran out of gas instead of exiting");
2621 }
2622
2623 #[test]
2624 fn completed_execution_is_not_retroactively_cancelled() {
2625 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2626 let mut executor = ExecutorBuilder::default().gas_limit(1 << 24).build(
2627 EvmEnv::default(),
2628 TxEnv::default(),
2629 backend,
2630 NetworkConfigs::default(),
2631 );
2632 let early_exit = EarlyExit::new(false);
2633 executor.inspector_mut().set_early_exit(early_exit.clone());
2634
2635 let target = Address::repeat_byte(0x11);
2636 executor.set_code(target, Bytecode::new_raw(Bytes::from_static(&[0x00]))).unwrap();
2637 let result = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2638 early_exit.record_ctrl_c();
2639
2640 assert!(!result.execution_cancelled);
2641 assert!(!result.reverted);
2642 }
2643
2644 #[test]
2645 fn campaign_deadline_interrupts_active_evm_execution() {
2646 const GAS_LIMIT: u64 = 1 << 24;
2647 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2648 let mut executor = ExecutorBuilder::default().gas_limit(GAS_LIMIT).build(
2649 EvmEnv::default(),
2650 TxEnv::default(),
2651 backend,
2652 NetworkConfigs::default(),
2653 );
2654 let cancellation = EvmExecutionCancellation::campaign(
2655 EarlyExit::new(false),
2656 Arc::new(AtomicBool::new(false)),
2657 Some(Instant::now()),
2658 );
2659 executor.inspector_mut().set_execution_cancellation(cancellation);
2660
2661 let target = Address::repeat_byte(0x11);
2662 executor
2663 .set_code(target, Bytecode::new_raw(Bytes::from_static(&[0x5b, 0x60, 0x00, 0x56])))
2664 .unwrap();
2665
2666 let result = executor.transact_raw(CALLER, target, Bytes::new(), U256::ZERO).unwrap();
2667 assert!(result.execution_cancelled);
2668 assert!(!result.reverted);
2669 assert_eq!(result.exit_reason, Some(InstructionResult::Stop));
2670 assert!(result.gas_used < GAS_LIMIT, "execution ran out of gas instead of timing out");
2671 }
2672
2673 #[test]
2674 fn beacon_root_system_call_does_not_persist_system_address() {
2675 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2676 let mut executor = ExecutorBuilder::default().spec_id(SpecId::CANCUN).build(
2677 EvmEnv::default(),
2678 TxEnv::default(),
2679 backend,
2680 NetworkConfigs::default(),
2681 );
2682 let before = executor.backend().basic_ref(SYSTEM_ADDRESS).unwrap();
2683
2684 executor.apply_beacon_root(B256::repeat_byte(0x11)).unwrap();
2685
2686 assert_eq!(
2687 executor.backend().basic_ref(SYSTEM_ADDRESS).unwrap(),
2688 before,
2689 "EIP-4788 system calls must not persist the system caller account",
2690 );
2691 }
2692
2693 #[test]
2708 fn pre_override_blob_hashes_restored_on_revert_to_state() {
2709 let cheats_config =
2710 Arc::new(CheatsConfig::new(&Config::default(), EvmOpts::default(), None, None, false));
2711
2712 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
2713 let mut executor = ExecutorBuilder::default()
2714 .inspectors(|stack| stack.cheatcodes(cheats_config))
2715 .spec_id(SpecId::CANCUN)
2716 .build(EvmEnv::default(), TxEnv::default(), backend, NetworkConfigs::default());
2717
2718 let original: Vec<B256> = vec![B256::repeat_byte(0x11), B256::repeat_byte(0x22)];
2719 executor.tx_env_mut().set_blob_hashes(original.clone());
2720
2721 let snap_result = executor
2722 .transact_raw(
2723 CALLER,
2724 CHEATCODE_ADDRESS,
2725 snapshotStateCall {}.abi_encode().into(),
2726 U256::ZERO,
2727 )
2728 .expect("snapshotState failed");
2729 assert!(!snap_result.reverted, "snapshotState reverted unexpectedly");
2730 let snapshot_id = U256::from_be_slice(&snap_result.result[..32]);
2731
2732 let new_hashes = vec![B256::repeat_byte(0x33)];
2733 let blob_result = executor
2734 .transact_raw(
2735 CALLER,
2736 CHEATCODE_ADDRESS,
2737 blobhashesCall { hashes: new_hashes }.abi_encode().into(),
2738 U256::ZERO,
2739 )
2740 .expect("blobhashes failed");
2741 assert!(!blob_result.reverted, "blobhashes reverted unexpectedly");
2742
2743 let revert_result = executor
2744 .transact_raw(
2745 CALLER,
2746 CHEATCODE_ADDRESS,
2747 revertToStateCall { snapshotId: snapshot_id }.abi_encode().into(),
2748 U256::ZERO,
2749 )
2750 .expect("revertToState failed");
2751 assert!(!revert_result.reverted, "revertToState reverted unexpectedly");
2752
2753 assert_eq!(
2754 revert_result.tx_env.blob_hashes, original,
2755 "pre_override_blob_hashes must be restored to original non-empty hashes, not []",
2756 );
2757 assert!(
2758 executor.inspector().cheatcodes.as_ref().unwrap().env_overrides.is_empty(),
2759 "inactive env overrides must be removed after restoring their metadata",
2760 );
2761 }
2762 #[cfg(feature = "monad")]
2763 #[test]
2764 fn concrete_system_replay_preserves_envelope_and_rejects_without_commit() {
2765 let mut executor = ExecutorBuilder::<MonadEvmNetwork>::new().gas_limit(1 << 20).build(
2766 EvmEnv::<MonadHardfork>::default(),
2767 TxEnv::default(),
2768 Backend::spawn(None).unwrap(),
2769 NetworkConfigs::with_monad(),
2770 );
2771 let caller = alloy_primitives::address!("6f49a8f621353f12378d0046e7d7e4b9b249dc9e");
2772 let selector = keccak256("syscallSnapshot()");
2773 let system = TxEnv {
2774 caller,
2775 gas_limit: 0,
2776 kind: TxKind::Call(alloy_primitives::address!(
2777 "0000000000000000000000000000000000001000"
2778 )),
2779 data: Bytes::copy_from_slice(&selector[..4]),
2780 chain_id: None,
2781 ..Default::default()
2782 };
2783 let result = executor
2784 .try_transact_system_replay_with_env_and_context(
2785 EvmEnv::<MonadHardfork>::default(),
2786 system.clone(),
2787 MonadChainContext::for_transaction(&system),
2788 )
2789 .unwrap()
2790 .unwrap();
2791 assert!(!result.reverted);
2792 assert_eq!(result.tx_env, system);
2793 assert_eq!(executor.get_nonce(caller).unwrap(), 1);
2794
2795 assert!(
2797 executor
2798 .try_transact_system_replay_with_env_and_context(
2799 EvmEnv::<MonadHardfork>::default(),
2800 system.clone(),
2801 MonadChainContext::for_transaction(&system),
2802 )
2803 .is_err()
2804 );
2805 assert_eq!(executor.get_nonce(caller).unwrap(), 1);
2806
2807 let ordinary = TxEnv { caller: CALLER, ..Default::default() };
2808 let nonce = executor.get_nonce(CALLER).unwrap();
2809 assert!(
2810 executor
2811 .try_transact_system_replay_with_env_and_context(
2812 EvmEnv::<MonadHardfork>::default(),
2813 ordinary.clone(),
2814 MonadChainContext::for_transaction(&ordinary),
2815 )
2816 .unwrap()
2817 .is_none()
2818 );
2819 assert_eq!(executor.get_nonce(CALLER).unwrap(), nonce);
2820 }
2821}