1use crate::{
4 AsEnvMut, Env, EnvMut, InspectorExt,
5 constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, TEST_CONTRACT_ADDRESS},
6 evm::new_evm_with_inspector,
7 fork::{CreateFork, ForkId, MultiFork},
8 state_snapshot::StateSnapshots,
9 utils::{configure_tx_env, configure_tx_req_env, get_blob_base_fee_update_fraction},
10};
11use alloy_consensus::Typed2718;
12use alloy_evm::Evm;
13use alloy_genesis::GenesisAccount;
14use alloy_network::{AnyRpcBlock, AnyTxEnvelope, TransactionResponse};
15use alloy_primitives::{Address, B256, TxKind, U256, keccak256, uint};
16use alloy_rpc_types::{BlockNumberOrTag, Transaction, TransactionRequest};
17use eyre::Context;
18use foundry_common::{SYSTEM_TRANSACTION_TYPE, is_known_system_sender};
19pub use foundry_fork_db::{BlockchainDb, SharedBackend, cache::BlockchainDbMeta};
20use revm::{
21 Database, DatabaseCommit, JournalEntry,
22 bytecode::Bytecode,
23 context::JournalInner,
24 context_interface::{
25 block::BlobExcessGasAndPrice, journaled_state::account::JournaledAccountTr,
26 result::ResultAndState,
27 },
28 database::{CacheDB, DatabaseRef},
29 inspector::NoOpInspector,
30 precompile::{PrecompileSpecId, Precompiles},
31 primitives::{HashMap as Map, KECCAK_EMPTY, Log, hardfork::SpecId},
32 state::{Account, AccountInfo, EvmState, EvmStorageSlot},
33};
34use std::{
35 collections::{BTreeMap, HashMap, HashSet},
36 fmt::Debug,
37 time::Instant,
38};
39
40mod diagnostic;
41pub use diagnostic::RevertDiagnostic;
42
43mod error;
44pub use error::{BackendError, BackendResult, DatabaseError, DatabaseResult};
45
46mod cow;
47pub use cow::CowBackend;
48
49mod in_memory_db;
50pub use in_memory_db::{EmptyDBWrapper, FoundryEvmInMemoryDB, MemDb};
51
52mod snapshot;
53pub use snapshot::{BackendStateSnapshot, RevertStateSnapshotAction, StateSnapshot};
54
55type ForkDB = CacheDB<SharedBackend>;
57
58pub type LocalForkId = U256;
63
64type ForkLookupIndex = usize;
67
68const DEFAULT_PERSISTENT_ACCOUNTS: [Address; 3] =
70 [CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, CALLER];
71
72pub const GLOBAL_FAIL_SLOT: U256 =
77 uint!(0x6661696c65640000000000000000000000000000000000000000000000000000_U256);
78
79pub type JournaledState = JournalInner<JournalEntry>;
80
81#[auto_impl::auto_impl(&mut)]
83pub trait DatabaseExt: Database<Error = DatabaseError> + DatabaseCommit + Debug {
84 fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256;
90
91 fn revert_state(
104 &mut self,
105 id: U256,
106 journaled_state: &JournaledState,
107 env: &mut EnvMut<'_>,
108 action: RevertStateSnapshotAction,
109 ) -> Option<JournaledState>;
110
111 fn delete_state_snapshot(&mut self, id: U256) -> bool;
116
117 fn delete_state_snapshots(&mut self);
119
120 fn create_select_fork(
124 &mut self,
125 fork: CreateFork,
126 env: &mut EnvMut<'_>,
127 journaled_state: &mut JournaledState,
128 ) -> eyre::Result<LocalForkId> {
129 let id = self.create_fork(fork)?;
130 self.select_fork(id, env, journaled_state)?;
131 Ok(id)
132 }
133
134 fn create_select_fork_at_transaction(
138 &mut self,
139 fork: CreateFork,
140 env: &mut EnvMut<'_>,
141 journaled_state: &mut JournaledState,
142 transaction: B256,
143 ) -> eyre::Result<LocalForkId> {
144 let id = self.create_fork_at_transaction(fork, transaction)?;
145 self.select_fork(id, env, journaled_state)?;
146 Ok(id)
147 }
148
149 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId>;
151
152 fn create_fork_at_transaction(
154 &mut self,
155 fork: CreateFork,
156 transaction: B256,
157 ) -> eyre::Result<LocalForkId>;
158
159 fn select_fork(
169 &mut self,
170 id: LocalForkId,
171 env: &mut EnvMut<'_>,
172 journaled_state: &mut JournaledState,
173 ) -> eyre::Result<()>;
174
175 fn roll_fork(
183 &mut self,
184 id: Option<LocalForkId>,
185 block_number: u64,
186 env: &mut EnvMut<'_>,
187 journaled_state: &mut JournaledState,
188 ) -> eyre::Result<()>;
189
190 fn roll_fork_to_transaction(
199 &mut self,
200 id: Option<LocalForkId>,
201 transaction: B256,
202 env: &mut EnvMut<'_>,
203 journaled_state: &mut JournaledState,
204 ) -> eyre::Result<()>;
205
206 fn transact(
208 &mut self,
209 id: Option<LocalForkId>,
210 transaction: B256,
211 env: Env,
212 journaled_state: &mut JournaledState,
213 inspector: &mut dyn InspectorExt,
214 ) -> eyre::Result<()>;
215
216 fn transact_from_tx(
218 &mut self,
219 transaction: &TransactionRequest,
220 env: Env,
221 journaled_state: &mut JournaledState,
222 inspector: &mut dyn InspectorExt,
223 ) -> eyre::Result<()>;
224
225 fn active_fork_id(&self) -> Option<LocalForkId>;
227
228 fn active_fork_url(&self) -> Option<String>;
230
231 fn is_forked_mode(&self) -> bool {
233 self.active_fork_id().is_some()
234 }
235
236 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId>;
247
248 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId>;
250
251 fn diagnose_revert(
278 &self,
279 callee: Address,
280 journaled_state: &JournaledState,
281 ) -> Option<RevertDiagnostic>;
282
283 fn load_allocs(
287 &mut self,
288 allocs: &BTreeMap<Address, GenesisAccount>,
289 journaled_state: &mut JournaledState,
290 ) -> Result<(), BackendError>;
291
292 fn clone_account(
297 &mut self,
298 source: &GenesisAccount,
299 target: &Address,
300 journaled_state: &mut JournaledState,
301 ) -> Result<(), BackendError>;
302
303 fn is_persistent(&self, acc: &Address) -> bool;
305
306 fn remove_persistent_account(&mut self, account: &Address) -> bool;
308
309 fn add_persistent_account(&mut self, account: Address) -> bool;
311
312 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
314 fn remove_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
315 where
316 Self: Sized,
317 {
318 for acc in accounts {
319 self.remove_persistent_account(&acc);
320 }
321 }
322
323 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
325 fn extend_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
326 where
327 Self: Sized,
328 {
329 for acc in accounts {
330 self.add_persistent_account(acc);
331 }
332 }
333
334 fn allow_cheatcode_access(&mut self, account: Address) -> bool;
338
339 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool;
343
344 fn has_cheatcode_access(&self, account: &Address) -> bool;
346
347 fn ensure_cheatcode_access(&self, account: &Address) -> Result<(), BackendError> {
351 if !self.has_cheatcode_access(account) {
352 return Err(BackendError::NoCheats(*account));
353 }
354 Ok(())
355 }
356
357 fn ensure_cheatcode_access_forking_mode(&self, account: &Address) -> Result<(), BackendError> {
360 if self.is_forked_mode() {
361 return self.ensure_cheatcode_access(account);
362 }
363 Ok(())
364 }
365
366 fn set_blockhash(&mut self, block_number: U256, block_hash: B256);
381}
382
383struct _ObjectSafe(dyn DatabaseExt);
384
385#[derive(Clone, Debug)]
438#[must_use]
439pub struct Backend {
440 forks: MultiFork,
442 mem_db: FoundryEvmInMemoryDB,
444 fork_init_journaled_state: JournaledState,
461 active_fork_ids: Option<(LocalForkId, ForkLookupIndex)>,
465 inner: BackendInner,
467}
468
469impl Backend {
470 pub fn spawn(fork: Option<CreateFork>) -> eyre::Result<Self> {
475 Self::new(MultiFork::spawn(), fork)
476 }
477
478 pub fn new(forks: MultiFork, fork: Option<CreateFork>) -> eyre::Result<Self> {
485 trace!(target: "backend", forking_mode=?fork.is_some(), "creating executor backend");
486 let inner = BackendInner {
488 persistent_accounts: HashSet::from(DEFAULT_PERSISTENT_ACCOUNTS),
489 ..Default::default()
490 };
491
492 let mut backend = Self {
493 forks,
494 mem_db: CacheDB::new(Default::default()),
495 fork_init_journaled_state: inner.new_journaled_state(),
496 active_fork_ids: None,
497 inner,
498 };
499
500 if let Some(fork) = fork {
501 let (fork_id, fork, _) = backend.forks.create_fork(fork)?;
502 let fork_db = ForkDB::new(fork);
503 let fork_ids = backend.inner.insert_new_fork(
504 fork_id.clone(),
505 fork_db,
506 backend.inner.new_journaled_state(),
507 );
508 backend.inner.launched_with_fork = Some((fork_id, fork_ids.0, fork_ids.1));
509 backend.active_fork_ids = Some(fork_ids);
510 }
511
512 trace!(target: "backend", forking_mode=? backend.active_fork_ids.is_some(), "created executor backend");
513
514 Ok(backend)
515 }
516
517 pub(crate) fn new_with_fork(
520 id: &ForkId,
521 fork: Fork,
522 journaled_state: JournaledState,
523 ) -> eyre::Result<Self> {
524 let mut backend = Self::spawn(None)?;
525 let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state);
526 backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1));
527 backend.active_fork_ids = Some(fork_ids);
528 Ok(backend)
529 }
530
531 pub fn clone_empty(&self) -> Self {
533 Self {
534 forks: self.forks.clone(),
535 mem_db: CacheDB::new(Default::default()),
536 fork_init_journaled_state: self.inner.new_journaled_state(),
537 active_fork_ids: None,
538 inner: Default::default(),
539 }
540 }
541
542 pub fn insert_account_info(&mut self, address: Address, account: AccountInfo) {
543 if let Some(db) = self.active_fork_db_mut() {
544 db.insert_account_info(address, account)
545 } else {
546 self.mem_db.insert_account_info(address, account)
547 }
548 }
549
550 pub fn insert_account_storage(
552 &mut self,
553 address: Address,
554 slot: U256,
555 value: U256,
556 ) -> Result<(), DatabaseError> {
557 if let Some(db) = self.active_fork_db_mut() {
558 db.insert_account_storage(address, slot, value)
559 } else {
560 self.mem_db.insert_account_storage(address, slot, value)
561 }
562 }
563
564 pub fn replace_account_storage(
569 &mut self,
570 address: Address,
571 storage: Map<U256, U256>,
572 ) -> Result<(), DatabaseError> {
573 if let Some(db) = self.active_fork_db_mut() {
574 db.replace_account_storage(address, storage)
575 } else {
576 self.mem_db.replace_account_storage(address, storage)
577 }
578 }
579
580 pub fn state_snapshots(
582 &self,
583 ) -> &StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>> {
584 &self.inner.state_snapshots
585 }
586
587 pub fn set_test_contract(&mut self, acc: Address) -> &mut Self {
594 trace!(?acc, "setting test account");
595 self.add_persistent_account(acc);
596 self.allow_cheatcode_access(acc);
597 self
598 }
599
600 pub fn set_caller(&mut self, acc: Address) -> &mut Self {
602 trace!(?acc, "setting caller account");
603 self.inner.caller = Some(acc);
604 self.allow_cheatcode_access(acc);
605 self
606 }
607
608 pub fn set_spec_id(&mut self, spec_id: SpecId) -> &mut Self {
610 trace!(?spec_id, "setting spec ID");
611 self.inner.spec_id = spec_id;
612 self
613 }
614
615 pub fn caller_address(&self) -> Option<Address> {
617 self.inner.caller
618 }
619
620 pub fn has_state_snapshot_failure(&self) -> bool {
626 self.inner.has_state_snapshot_failure
627 }
628
629 pub fn set_state_snapshot_failure(&mut self, has_state_snapshot_failure: bool) {
631 self.inner.has_state_snapshot_failure = has_state_snapshot_failure
632 }
633
634 pub(crate) fn update_fork_db(
636 &self,
637 active_journaled_state: &mut JournaledState,
638 target_fork: &mut Fork,
639 ) {
640 self.update_fork_db_contracts(
641 self.inner.persistent_accounts.iter().copied(),
642 active_journaled_state,
643 target_fork,
644 )
645 }
646
647 pub(crate) fn update_fork_db_contracts(
649 &self,
650 accounts: impl IntoIterator<Item = Address>,
651 active_journaled_state: &mut JournaledState,
652 target_fork: &mut Fork,
653 ) {
654 if let Some(db) = self.active_fork_db() {
655 merge_account_data(accounts, db, active_journaled_state, target_fork)
656 } else {
657 merge_account_data(accounts, &self.mem_db, active_journaled_state, target_fork)
658 }
659 }
660
661 pub fn mem_db(&self) -> &FoundryEvmInMemoryDB {
663 &self.mem_db
664 }
665
666 pub fn is_active_fork(&self, id: LocalForkId) -> bool {
668 self.active_fork_ids.map(|(i, _)| i == id).unwrap_or_default()
669 }
670
671 pub fn is_in_forking_mode(&self) -> bool {
673 self.active_fork().is_some()
674 }
675
676 pub fn active_fork(&self) -> Option<&Fork> {
678 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork(idx))
679 }
680
681 pub fn active_fork_mut(&mut self) -> Option<&mut Fork> {
683 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork_mut(idx))
684 }
685
686 pub fn active_fork_db(&self) -> Option<&ForkDB> {
688 self.active_fork().map(|f| &f.db)
689 }
690
691 pub fn active_fork_db_mut(&mut self) -> Option<&mut ForkDB> {
693 self.active_fork_mut().map(|f| &mut f.db)
694 }
695
696 pub fn db(&self) -> &dyn Database<Error = DatabaseError> {
698 match self.active_fork_db() {
699 Some(fork_db) => fork_db,
700 None => &self.mem_db,
701 }
702 }
703
704 pub fn db_mut(&mut self) -> &mut dyn Database<Error = DatabaseError> {
706 match self.active_fork_ids.map(|(_, idx)| &mut self.inner.get_fork_mut(idx).db) {
707 Some(fork_db) => fork_db,
708 None => &mut self.mem_db,
709 }
710 }
711
712 pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot {
714 if let Some((id, idx)) = self.active_fork_ids {
715 let fork = self.inner.get_fork(idx).clone();
716 let fork_id = self.inner.ensure_fork_id(id).cloned().expect("Exists; qed");
717 BackendDatabaseSnapshot::Forked(id, fork_id, idx, Box::new(fork))
718 } else {
719 BackendDatabaseSnapshot::InMemory(self.mem_db.clone())
720 }
721 }
722
723 pub fn merged_logs(&self, mut logs: Vec<Log>) -> Vec<Log> {
725 if let Some((_, active)) = self.active_fork_ids {
726 let mut all_logs = Vec::with_capacity(logs.len());
727
728 self.inner
729 .forks
730 .iter()
731 .enumerate()
732 .filter_map(|(idx, f)| f.as_ref().map(|f| (idx, f)))
733 .for_each(|(idx, f)| {
734 if idx == active {
735 all_logs.append(&mut logs);
736 } else {
737 all_logs.extend(f.journaled_state.logs.clone())
738 }
739 });
740 return all_logs;
741 }
742
743 logs
744 }
745
746 pub(crate) fn initialize(&mut self, env: &Env) {
750 self.set_caller(env.tx.caller);
751 self.set_spec_id(env.evm_env.cfg_env.spec);
752
753 let test_contract = match env.tx.kind {
754 TxKind::Call(to) => to,
755 TxKind::Create => {
756 let nonce = self
757 .basic_ref(env.tx.caller)
758 .map(|b| b.unwrap_or_default().nonce)
759 .unwrap_or_default();
760 env.tx.caller.create(nonce)
761 }
762 };
763 self.set_test_contract(test_contract);
764 }
765
766 #[instrument(name = "inspect", level = "debug", skip_all)]
771 pub fn inspect<I: InspectorExt>(
772 &mut self,
773 env: &mut Env,
774 inspector: I,
775 ) -> eyre::Result<ResultAndState> {
776 self.initialize(env);
777 let mut evm = crate::evm::new_evm_with_inspector(self, env.to_owned(), inspector);
778
779 let res = evm.transact(env.tx.clone()).wrap_err("EVM error")?;
780
781 *env = evm.as_env_mut().to_owned();
782
783 Ok(res)
784 }
785
786 pub fn is_existing_precompile(&self, addr: &Address) -> bool {
788 self.inner.precompiles().contains(addr)
789 }
790
791 #[inline]
793 fn set_init_journaled_state(&mut self, journaled_state: JournaledState) {
794 trace!("recording fork init journaled_state");
795 self.fork_init_journaled_state = journaled_state;
796 }
797
798 fn prepare_init_journal_state(&mut self) -> Result<(), BackendError> {
808 let loaded_accounts = self
809 .fork_init_journaled_state
810 .state
811 .iter()
812 .filter(|(addr, _)| !self.is_existing_precompile(addr) && !self.is_persistent(addr))
813 .map(|(addr, _)| addr)
814 .copied()
815 .collect::<Vec<_>>();
816
817 for fork in self.inner.forks_iter_mut() {
818 let mut journaled_state = self.fork_init_journaled_state.clone();
819 for loaded_account in loaded_accounts.iter().copied() {
820 trace!(?loaded_account, "replacing account on init");
821 let init_account =
822 journaled_state.state.get_mut(&loaded_account).expect("exists; qed");
823
824 if init_account.is_created() {
828 trace!(?loaded_account, "skipping created account");
829 continue;
830 }
831
832 let fork_account = Database::basic(&mut fork.db, loaded_account)?
835 .ok_or(BackendError::MissingAccount(loaded_account))?;
836 init_account.info = fork_account;
837 }
838 fork.journaled_state = journaled_state;
839 }
840 Ok(())
841 }
842
843 fn get_block_number_and_block_for_transaction(
845 &self,
846 id: LocalForkId,
847 transaction: B256,
848 ) -> eyre::Result<(u64, AnyRpcBlock)> {
849 let fork = self.inner.get_fork_by_id(id)?;
850 let tx = fork.db.db.get_transaction(transaction)?;
851
852 if let Some(tx_block) = tx.block_number {
854 let block = fork.db.db.get_full_block(tx_block)?;
855
856 let fork_block = tx_block - 1;
859 Ok((fork_block, block))
860 } else {
861 let block = fork.db.db.get_full_block(BlockNumberOrTag::Latest)?;
862
863 let number = block.header.number;
864
865 Ok((number, block))
866 }
867 }
868
869 pub fn replay_until(
873 &mut self,
874 id: LocalForkId,
875 mut env: Env,
876 tx_hash: B256,
877 journaled_state: &mut JournaledState,
878 ) -> eyre::Result<Option<Transaction<AnyTxEnvelope>>> {
879 trace!(?id, ?tx_hash, "replay until transaction");
880
881 let persistent_accounts = self.inner.persistent_accounts.clone();
882 let fork_id = self.ensure_fork_id(id)?.clone();
883
884 let fork = self.inner.get_fork_by_id_mut(id)?;
885 let full_block =
886 fork.db.db.get_full_block(env.evm_env.block_env.number.saturating_to::<u64>())?;
887
888 for tx in full_block.inner.transactions.txns() {
889 if is_known_system_sender(tx.inner().inner.signer())
892 || tx.ty() == SYSTEM_TRANSACTION_TYPE
893 {
894 trace!(tx=?tx.tx_hash(), "skipping system transaction");
895 continue;
896 }
897
898 if tx.tx_hash() == tx_hash {
899 return Ok(Some(tx.inner.clone()));
901 }
902 trace!(tx=?tx.tx_hash(), "committing transaction");
903
904 commit_transaction(
905 &tx.inner,
906 &mut env.as_env_mut(),
907 journaled_state,
908 fork,
909 &fork_id,
910 &persistent_accounts,
911 &mut NoOpInspector,
912 )?;
913 }
914
915 Ok(None)
916 }
917}
918
919impl DatabaseExt for Backend {
920 fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256 {
921 trace!("create snapshot");
922 let id = self.inner.state_snapshots.insert(BackendStateSnapshot::new(
923 self.create_db_snapshot(),
924 journaled_state.clone(),
925 env.to_owned(),
926 ));
927 trace!(target: "backend", "Created new snapshot {}", id);
928 id
929 }
930
931 fn revert_state(
932 &mut self,
933 id: U256,
934 current_state: &JournaledState,
935 current: &mut EnvMut<'_>,
936 action: RevertStateSnapshotAction,
937 ) -> Option<JournaledState> {
938 trace!(?id, "revert snapshot");
939 if let Some(mut snapshot) = self.inner.state_snapshots.remove_at(id) {
940 if action.is_keep() {
942 self.inner.state_snapshots.insert_at(snapshot.clone(), id);
943 }
944
945 if let Some(account) = current_state.state.get(&CHEATCODE_ADDRESS)
950 && let Some(slot) = account.storage.get(&GLOBAL_FAIL_SLOT)
951 && !slot.present_value.is_zero()
952 {
953 self.set_state_snapshot_failure(true);
954 }
955
956 snapshot.merge(current_state);
958 let BackendStateSnapshot { db, mut journaled_state, env } = snapshot;
959 match db {
960 BackendDatabaseSnapshot::InMemory(mem_db) => {
961 self.mem_db = mem_db;
962 }
963 BackendDatabaseSnapshot::Forked(id, fork_id, idx, mut fork) => {
964 let caller = current.tx.caller;
968 journaled_state.state.entry(caller).or_insert_with(|| {
969 let caller_account = current_state
970 .state
971 .get(&caller)
972 .map(|acc| acc.info.clone())
973 .unwrap_or_default();
974
975 if !fork.db.cache.accounts.contains_key(&caller) {
976 fork.db.insert_account_info(caller, caller_account.clone());
978 }
979 caller_account.into()
980 });
981 self.inner.revert_state_snapshot(id, fork_id, idx, *fork);
982 self.active_fork_ids = Some((id, idx))
983 }
984 }
985
986 update_current_env_with_fork_env(&mut current.as_env_mut(), env);
987 trace!(target: "backend", "Reverted snapshot {}", id);
988
989 Some(journaled_state)
990 } else {
991 warn!(target: "backend", "No snapshot to revert for {}", id);
992 None
993 }
994 }
995
996 fn delete_state_snapshot(&mut self, id: U256) -> bool {
997 self.inner.state_snapshots.remove_at(id).is_some()
998 }
999
1000 fn delete_state_snapshots(&mut self) {
1001 self.inner.state_snapshots.clear()
1002 }
1003
1004 fn create_fork(&mut self, create_fork: CreateFork) -> eyre::Result<LocalForkId> {
1005 trace!("create fork");
1006 let (fork_id, fork, _) = self.forks.create_fork(create_fork)?;
1007
1008 let fork_db = ForkDB::new(fork);
1009 let (id, _) =
1010 self.inner.insert_new_fork(fork_id, fork_db, self.fork_init_journaled_state.clone());
1011 Ok(id)
1012 }
1013
1014 fn create_fork_at_transaction(
1015 &mut self,
1016 fork: CreateFork,
1017 transaction: B256,
1018 ) -> eyre::Result<LocalForkId> {
1019 trace!(?transaction, "create fork at transaction");
1020 let id = self.create_fork(fork)?;
1021 let fork_id = self.ensure_fork_id(id).cloned()?;
1022 let mut env = self
1023 .forks
1024 .get_env(fork_id)?
1025 .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exist", id))?;
1026
1027 self.roll_fork_to_transaction(
1030 Some(id),
1031 transaction,
1032 &mut env.as_env_mut(),
1033 &mut self.inner.new_journaled_state(),
1034 )?;
1035
1036 Ok(id)
1037 }
1038
1039 fn select_fork(
1042 &mut self,
1043 id: LocalForkId,
1044 env: &mut EnvMut<'_>,
1045 active_journaled_state: &mut JournaledState,
1046 ) -> eyre::Result<()> {
1047 trace!(?id, "select fork");
1048 if self.is_active_fork(id) {
1049 return Ok(());
1051 }
1052
1053 if let Some(active_fork_id) = self.active_fork_id() {
1056 self.forks.update_block(
1057 self.ensure_fork_id(active_fork_id).cloned()?,
1058 env.block.number,
1059 env.block.timestamp,
1060 )?;
1061 }
1062
1063 let fork_id = self.ensure_fork_id(id).cloned()?;
1064 let idx = self.inner.ensure_fork_index(&fork_id)?;
1065 let fork_env = self
1066 .forks
1067 .get_env(fork_id)?
1068 .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exist", id))?;
1069
1070 if let Some(active) = self.active_fork_mut() {
1073 active.journaled_state = active_journaled_state.clone();
1074
1075 let caller = env.tx.caller;
1076 let caller_account = active.journaled_state.state.get(&env.tx.caller).cloned();
1077 let target_fork = self.inner.get_fork_mut(idx);
1078
1079 if target_fork.journaled_state.depth == 0 {
1081 if let Some(mut acc) = caller_account {
1083 let fork_account = Database::basic(&mut target_fork.db, caller)?
1084 .ok_or(BackendError::MissingAccount(caller))?;
1085
1086 acc.info = fork_account;
1087 target_fork.journaled_state.state.insert(caller, acc);
1088 }
1089 }
1090 } else {
1091 self.set_init_journaled_state(active_journaled_state.clone());
1098 self.prepare_init_journal_state()?;
1099
1100 self.fork_init_journaled_state.depth = 0;
1102 }
1103
1104 {
1105 let mut fork = self.inner.take_fork(idx);
1107
1108 let persistent_accounts = self.inner.persistent_accounts.clone();
1116 if let Some(db) = self.active_fork_db_mut() {
1117 for addr in persistent_accounts {
1118 let Ok(db_account) = db.load_account(addr) else { continue };
1119
1120 let Some(fork_account) = fork.journaled_state.state.get_mut(&addr) else {
1121 continue;
1122 };
1123
1124 for (key, val) in &db_account.storage {
1125 if let Some(fork_storage) = fork_account.storage.get_mut(key) {
1126 fork_storage.present_value = *val;
1127 }
1128 }
1129 }
1130 }
1131
1132 fork.journaled_state.depth = active_journaled_state.depth;
1137
1138 let caller = env.tx.caller;
1142 fork.journaled_state.state.entry(caller).or_insert_with(|| {
1143 let caller_account = active_journaled_state
1144 .state
1145 .get(&env.tx.caller)
1146 .map(|acc| acc.info.clone())
1147 .unwrap_or_default();
1148
1149 if !fork.db.cache.accounts.contains_key(&caller) {
1150 fork.db.insert_account_info(caller, caller_account.clone());
1152 }
1153 caller_account.into()
1154 });
1155
1156 self.update_fork_db(active_journaled_state, &mut fork);
1157
1158 self.inner.set_fork(idx, fork);
1160 }
1161
1162 self.active_fork_ids = Some((id, idx));
1163 update_current_env_with_fork_env(env, fork_env);
1165
1166 Ok(())
1167 }
1168
1169 fn roll_fork(
1172 &mut self,
1173 id: Option<LocalForkId>,
1174 block_number: u64,
1175 env: &mut EnvMut<'_>,
1176 journaled_state: &mut JournaledState,
1177 ) -> eyre::Result<()> {
1178 trace!(?id, ?block_number, "roll fork");
1179 let id = self.ensure_fork(id)?;
1180 let (fork_id, backend, fork_env) =
1181 self.forks.roll_fork(self.inner.ensure_fork_id(id).cloned()?, block_number)?;
1182 self.inner.roll_fork(id, fork_id, backend)?;
1184
1185 if let Some((active_id, active_idx)) = self.active_fork_ids {
1186 if active_id == id {
1188 update_current_env_with_fork_env(env, fork_env);
1191
1192 let mut persistent_addrs = self.inner.persistent_accounts.clone();
1197 persistent_addrs.extend(self.caller_address());
1199
1200 let active = self.inner.get_fork_mut(active_idx);
1201 active.journaled_state = self.fork_init_journaled_state.clone();
1202 active.journaled_state.depth = journaled_state.depth;
1203
1204 for addr in persistent_addrs {
1205 merge_journaled_state_data(addr, journaled_state, &mut active.journaled_state);
1206 }
1207
1208 for (addr, acc) in &journaled_state.state {
1216 if acc.is_created() {
1217 if acc.is_touched() {
1218 merge_journaled_state_data(
1219 *addr,
1220 journaled_state,
1221 &mut active.journaled_state,
1222 );
1223 }
1224 } else {
1225 let _ = active.journaled_state.load_account(&mut active.db, *addr);
1226 }
1227 }
1228
1229 *journaled_state = active.journaled_state.clone();
1230 }
1231 }
1232 Ok(())
1233 }
1234
1235 fn roll_fork_to_transaction(
1236 &mut self,
1237 id: Option<LocalForkId>,
1238 transaction: B256,
1239 env: &mut EnvMut<'_>,
1240 journaled_state: &mut JournaledState,
1241 ) -> eyre::Result<()> {
1242 trace!(?id, ?transaction, "roll fork to transaction");
1243 let id = self.ensure_fork(id)?;
1244
1245 let (fork_block, block) =
1246 self.get_block_number_and_block_for_transaction(id, transaction)?;
1247
1248 self.roll_fork(Some(id), fork_block, env, journaled_state)?;
1252
1253 update_env_block(env, &block);
1255
1256 let _ =
1259 self.forks.update_block_env(self.inner.ensure_fork_id(id).cloned()?, env.block.clone());
1260
1261 let env = env.to_owned();
1262
1263 self.replay_until(id, env, transaction, journaled_state)?;
1265
1266 Ok(())
1267 }
1268
1269 fn transact(
1270 &mut self,
1271 maybe_id: Option<LocalForkId>,
1272 transaction: B256,
1273 mut env: Env,
1274 journaled_state: &mut JournaledState,
1275 inspector: &mut dyn InspectorExt,
1276 ) -> eyre::Result<()> {
1277 trace!(?maybe_id, ?transaction, "execute transaction");
1278 let persistent_accounts = self.inner.persistent_accounts.clone();
1279 let id = self.ensure_fork(maybe_id)?;
1280 let fork_id = self.ensure_fork_id(id).cloned()?;
1281
1282 let tx = {
1283 let fork = self.inner.get_fork_by_id_mut(id)?;
1284 fork.db.db.get_transaction(transaction)?
1285 };
1286
1287 let (_fork_block, block) =
1294 self.get_block_number_and_block_for_transaction(id, transaction)?;
1295 update_env_block(&mut env.as_env_mut(), &block);
1296
1297 let fork = self.inner.get_fork_by_id_mut(id)?;
1298 commit_transaction(
1299 &tx.inner,
1300 &mut env.as_env_mut(),
1301 journaled_state,
1302 fork,
1303 &fork_id,
1304 &persistent_accounts,
1305 inspector,
1306 )
1307 }
1308
1309 fn transact_from_tx(
1310 &mut self,
1311 tx: &TransactionRequest,
1312 mut env: Env,
1313 journaled_state: &mut JournaledState,
1314 inspector: &mut dyn InspectorExt,
1315 ) -> eyre::Result<()> {
1316 trace!(?tx, "execute signed transaction");
1317
1318 self.commit(journaled_state.state.clone());
1319
1320 let res = {
1321 configure_tx_req_env(&mut env.as_env_mut(), tx, None)?;
1322
1323 let mut db = self.clone();
1324 let mut evm = new_evm_with_inspector(&mut db, env.to_owned(), inspector);
1325 evm.journaled_state.depth = journaled_state.depth + 1;
1326 evm.transact(env.tx)?
1327 };
1328
1329 self.commit(res.state);
1330 update_state(&mut journaled_state.state, self, None)?;
1331
1332 Ok(())
1333 }
1334
1335 fn active_fork_id(&self) -> Option<LocalForkId> {
1336 self.active_fork_ids.map(|(id, _)| id)
1337 }
1338
1339 fn active_fork_url(&self) -> Option<String> {
1340 let fork = self.inner.issued_local_fork_ids.get(&self.active_fork_id()?)?;
1341 self.forks.get_fork_url(fork.clone()).ok()?
1342 }
1343
1344 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
1345 if let Some(id) = id {
1346 if self.inner.issued_local_fork_ids.contains_key(&id) {
1347 return Ok(id);
1348 }
1349 eyre::bail!("Requested fork `{}` does not exist", id)
1350 }
1351 if let Some(id) = self.active_fork_id() { Ok(id) } else { eyre::bail!("No fork active") }
1352 }
1353
1354 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1355 self.inner.ensure_fork_id(id)
1356 }
1357
1358 fn diagnose_revert(
1359 &self,
1360 callee: Address,
1361 journaled_state: &JournaledState,
1362 ) -> Option<RevertDiagnostic> {
1363 let active_id = self.active_fork_id()?;
1364 let active_fork = self.active_fork()?;
1365
1366 if self.inner.forks.len() == 1 {
1367 return None;
1370 }
1371
1372 if !active_fork.is_contract(callee) && !is_contract_in_state(journaled_state, callee) {
1373 let mut available_on = Vec::new();
1375 for (id, fork) in self.inner.forks_iter().filter(|(id, _)| *id != active_id) {
1376 trace!(?id, address=?callee, "checking if account exists");
1377 if fork.is_contract(callee) {
1378 available_on.push(id);
1379 }
1380 }
1381
1382 return if available_on.is_empty() {
1383 Some(RevertDiagnostic::ContractDoesNotExist {
1384 contract: callee,
1385 active: active_id,
1386 persistent: self.is_persistent(&callee),
1387 })
1388 } else {
1389 Some(RevertDiagnostic::ContractExistsOnOtherForks {
1392 contract: callee,
1393 active: active_id,
1394 available_on,
1395 })
1396 };
1397 }
1398 None
1399 }
1400
1401 fn load_allocs(
1405 &mut self,
1406 allocs: &BTreeMap<Address, GenesisAccount>,
1407 journaled_state: &mut JournaledState,
1408 ) -> Result<(), BackendError> {
1409 for (addr, acc) in allocs {
1411 self.clone_account(acc, addr, journaled_state)?;
1412 }
1413
1414 Ok(())
1415 }
1416
1417 fn clone_account(
1422 &mut self,
1423 source: &GenesisAccount,
1424 target: &Address,
1425 journaled_state: &mut JournaledState,
1426 ) -> Result<(), BackendError> {
1427 let mut state_acc = journaled_state.load_account_mut(self, *target)?;
1430
1431 if let Some(bytecode) = source.code.as_ref() {
1433 let bytecode_hash = keccak256(bytecode);
1434 let bytecode = Bytecode::new_raw(bytecode.0.clone().into());
1435 state_acc.set_code(bytecode_hash, bytecode);
1436 }
1437
1438 state_acc.set_balance(source.balance);
1440
1441 if let Some(acc) = journaled_state.state.get_mut(target) {
1443 if let Some(storage) = source.storage.as_ref() {
1444 for (slot, value) in storage {
1445 let slot = U256::from_be_bytes(slot.0);
1446 acc.storage.insert(
1447 slot,
1448 EvmStorageSlot::new_changed(
1449 acc.storage.get(&slot).map(|s| s.present_value).unwrap_or_default(),
1450 U256::from_be_bytes(value.0),
1451 0,
1452 ),
1453 );
1454 }
1455 }
1456
1457 acc.info.nonce = source.nonce.unwrap_or_default();
1459 };
1460
1461 journaled_state.touch(*target);
1463
1464 Ok(())
1465 }
1466
1467 fn add_persistent_account(&mut self, account: Address) -> bool {
1468 trace!(?account, "add persistent account");
1469 self.inner.persistent_accounts.insert(account)
1470 }
1471
1472 fn remove_persistent_account(&mut self, account: &Address) -> bool {
1473 trace!(?account, "remove persistent account");
1474 self.inner.persistent_accounts.remove(account)
1475 }
1476
1477 fn is_persistent(&self, acc: &Address) -> bool {
1478 self.inner.persistent_accounts.contains(acc)
1479 }
1480
1481 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
1482 trace!(?account, "allow cheatcode access");
1483 self.inner.cheatcode_access_accounts.insert(account)
1484 }
1485
1486 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
1487 trace!(?account, "revoke cheatcode access");
1488 self.inner.cheatcode_access_accounts.remove(account)
1489 }
1490
1491 fn has_cheatcode_access(&self, account: &Address) -> bool {
1492 self.inner.cheatcode_access_accounts.contains(account)
1493 }
1494
1495 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
1496 if let Some(db) = self.active_fork_db_mut() {
1497 db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1498 } else {
1499 self.mem_db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1500 }
1501 }
1502}
1503
1504impl DatabaseRef for Backend {
1505 type Error = DatabaseError;
1506
1507 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1508 if let Some(db) = self.active_fork_db() {
1509 db.basic_ref(address)
1510 } else {
1511 Ok(self.mem_db.basic_ref(address)?)
1512 }
1513 }
1514
1515 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1516 if let Some(db) = self.active_fork_db() {
1517 db.code_by_hash_ref(code_hash)
1518 } else {
1519 Ok(self.mem_db.code_by_hash_ref(code_hash)?)
1520 }
1521 }
1522
1523 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
1524 if let Some(db) = self.active_fork_db() {
1525 DatabaseRef::storage_ref(db, address, index)
1526 } else {
1527 Ok(DatabaseRef::storage_ref(&self.mem_db, address, index)?)
1528 }
1529 }
1530
1531 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
1532 if let Some(db) = self.active_fork_db() {
1533 db.block_hash_ref(number)
1534 } else {
1535 Ok(self.mem_db.block_hash_ref(number)?)
1536 }
1537 }
1538}
1539
1540impl DatabaseCommit for Backend {
1541 fn commit(&mut self, changes: Map<Address, Account>) {
1542 if let Some(db) = self.active_fork_db_mut() {
1543 db.commit(changes)
1544 } else {
1545 self.mem_db.commit(changes)
1546 }
1547 }
1548}
1549
1550impl Database for Backend {
1551 type Error = DatabaseError;
1552 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1553 if let Some(db) = self.active_fork_db_mut() {
1554 Ok(db.basic(address)?)
1555 } else {
1556 Ok(self.mem_db.basic(address)?)
1557 }
1558 }
1559
1560 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1561 if let Some(db) = self.active_fork_db_mut() {
1562 Ok(db.code_by_hash(code_hash)?)
1563 } else {
1564 Ok(self.mem_db.code_by_hash(code_hash)?)
1565 }
1566 }
1567
1568 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
1569 if let Some(db) = self.active_fork_db_mut() {
1570 Ok(Database::storage(db, address, index)?)
1571 } else {
1572 Ok(Database::storage(&mut self.mem_db, address, index)?)
1573 }
1574 }
1575
1576 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
1577 if let Some(db) = self.active_fork_db_mut() {
1578 Ok(db.block_hash(number)?)
1579 } else {
1580 Ok(self.mem_db.block_hash(number)?)
1581 }
1582 }
1583}
1584
1585#[derive(Clone, Debug)]
1587pub enum BackendDatabaseSnapshot {
1588 InMemory(FoundryEvmInMemoryDB),
1590 Forked(LocalForkId, ForkId, ForkLookupIndex, Box<Fork>),
1592}
1593
1594#[derive(Clone, Debug)]
1596pub struct Fork {
1597 db: ForkDB,
1598 journaled_state: JournaledState,
1599}
1600
1601impl Fork {
1602 pub fn is_contract(&self, acc: Address) -> bool {
1604 if let Ok(Some(acc)) = self.db.basic_ref(acc)
1605 && acc.code_hash != KECCAK_EMPTY
1606 {
1607 return true;
1608 }
1609 is_contract_in_state(&self.journaled_state, acc)
1610 }
1611}
1612
1613#[derive(Clone, Debug)]
1615pub struct BackendInner {
1616 pub launched_with_fork: Option<(ForkId, LocalForkId, ForkLookupIndex)>,
1621 pub issued_local_fork_ids: HashMap<LocalForkId, ForkId>,
1633 pub created_forks: HashMap<ForkId, ForkLookupIndex>,
1636 pub forks: Vec<Option<Fork>>,
1639 pub state_snapshots: StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>>,
1641 pub has_state_snapshot_failure: bool,
1651 pub caller: Option<Address>,
1653 pub next_fork_id: LocalForkId,
1655 pub persistent_accounts: HashSet<Address>,
1659 pub spec_id: SpecId,
1661 pub cheatcode_access_accounts: HashSet<Address>,
1663}
1664
1665impl BackendInner {
1666 pub fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1667 self.issued_local_fork_ids
1668 .get(&id)
1669 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1670 }
1671
1672 pub fn ensure_fork_index(&self, id: &ForkId) -> eyre::Result<ForkLookupIndex> {
1673 self.created_forks
1674 .get(id)
1675 .copied()
1676 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1677 }
1678
1679 pub fn ensure_fork_index_by_local_id(&self, id: LocalForkId) -> eyre::Result<ForkLookupIndex> {
1680 self.ensure_fork_index(self.ensure_fork_id(id)?)
1681 }
1682
1683 #[track_caller]
1685 fn get_fork(&self, idx: ForkLookupIndex) -> &Fork {
1686 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1687 self.forks[idx].as_ref().unwrap()
1688 }
1689
1690 #[track_caller]
1692 fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork {
1693 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1694 self.forks[idx].as_mut().unwrap()
1695 }
1696
1697 #[track_caller]
1699 fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> {
1700 let idx = self.ensure_fork_index_by_local_id(id)?;
1701 Ok(self.get_fork_mut(idx))
1702 }
1703
1704 #[track_caller]
1706 fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> {
1707 let idx = self.ensure_fork_index_by_local_id(id)?;
1708 Ok(self.get_fork(idx))
1709 }
1710
1711 fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork {
1713 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1714 self.forks[idx].take().unwrap()
1715 }
1716
1717 fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) {
1718 self.forks[idx] = Some(fork)
1719 }
1720
1721 pub fn forks_iter(&self) -> impl Iterator<Item = (LocalForkId, &Fork)> + '_ {
1723 self.issued_local_fork_ids
1724 .iter()
1725 .map(|(id, fork_id)| (*id, self.get_fork(self.created_forks[fork_id])))
1726 }
1727
1728 pub fn forks_iter_mut(&mut self) -> impl Iterator<Item = &mut Fork> + '_ {
1730 self.forks.iter_mut().filter_map(|f| f.as_mut())
1731 }
1732
1733 pub fn revert_state_snapshot(
1735 &mut self,
1736 id: LocalForkId,
1737 fork_id: ForkId,
1738 idx: ForkLookupIndex,
1739 fork: Fork,
1740 ) {
1741 self.created_forks.insert(fork_id.clone(), idx);
1742 self.issued_local_fork_ids.insert(id, fork_id);
1743 self.set_fork(idx, fork)
1744 }
1745
1746 pub fn update_fork_mapping(
1748 &mut self,
1749 id: LocalForkId,
1750 fork_id: ForkId,
1751 db: ForkDB,
1752 journaled_state: JournaledState,
1753 ) -> ForkLookupIndex {
1754 let idx = self.forks.len();
1755 self.issued_local_fork_ids.insert(id, fork_id.clone());
1756 self.created_forks.insert(fork_id, idx);
1757
1758 let fork = Fork { db, journaled_state };
1759 self.forks.push(Some(fork));
1760 idx
1761 }
1762
1763 pub fn roll_fork(
1764 &mut self,
1765 id: LocalForkId,
1766 new_fork_id: ForkId,
1767 backend: SharedBackend,
1768 ) -> eyre::Result<ForkLookupIndex> {
1769 let fork_id = self.ensure_fork_id(id)?;
1770 let idx = self.ensure_fork_index(fork_id)?;
1771
1772 if let Some(active) = self.forks[idx].as_mut() {
1773 let mut new_db = ForkDB::new(backend);
1775 for addr in self.persistent_accounts.iter().copied() {
1776 merge_db_account_data(addr, &active.db, &mut new_db);
1777 }
1778 active.db = new_db;
1779 }
1780 self.issued_local_fork_ids.insert(id, new_fork_id.clone());
1782 self.created_forks.insert(new_fork_id, idx);
1783 Ok(idx)
1784 }
1785
1786 pub fn insert_new_fork(
1790 &mut self,
1791 fork_id: ForkId,
1792 db: ForkDB,
1793 journaled_state: JournaledState,
1794 ) -> (LocalForkId, ForkLookupIndex) {
1795 let idx = self.forks.len();
1796 self.created_forks.insert(fork_id.clone(), idx);
1797 let id = self.next_id();
1798 self.issued_local_fork_ids.insert(id, fork_id);
1799 let fork = Fork { db, journaled_state };
1800 self.forks.push(Some(fork));
1801 (id, idx)
1802 }
1803
1804 fn next_id(&mut self) -> U256 {
1805 let id = self.next_fork_id;
1806 self.next_fork_id += U256::from(1);
1807 id
1808 }
1809
1810 pub fn len(&self) -> usize {
1812 self.issued_local_fork_ids.len()
1813 }
1814
1815 pub fn is_empty(&self) -> bool {
1817 self.issued_local_fork_ids.is_empty()
1818 }
1819
1820 pub fn precompiles(&self) -> &'static Precompiles {
1821 Precompiles::new(PrecompileSpecId::from_spec_id(self.spec_id))
1822 }
1823
1824 pub fn new_journaled_state(&self) -> JournaledState {
1826 let mut journal = {
1827 let mut journal_inner = JournalInner::new();
1828 journal_inner.set_spec_id(self.spec_id);
1829 journal_inner
1830 };
1831 journal
1832 .warm_addresses
1833 .set_precompile_addresses(self.precompiles().addresses().copied().collect());
1834 journal
1835 }
1836}
1837
1838impl Default for BackendInner {
1839 fn default() -> Self {
1840 Self {
1841 launched_with_fork: None,
1842 issued_local_fork_ids: Default::default(),
1843 created_forks: Default::default(),
1844 forks: vec![],
1845 state_snapshots: Default::default(),
1846 has_state_snapshot_failure: false,
1847 caller: None,
1848 next_fork_id: Default::default(),
1849 persistent_accounts: Default::default(),
1850 spec_id: SpecId::default(),
1851 cheatcode_access_accounts: HashSet::from([
1854 CHEATCODE_ADDRESS,
1855 TEST_CONTRACT_ADDRESS,
1856 CALLER,
1857 ]),
1858 }
1859 }
1860}
1861
1862pub(crate) fn update_current_env_with_fork_env(current: &mut EnvMut<'_>, fork: Env) {
1864 *current.block = fork.evm_env.block_env;
1865 *current.cfg = fork.evm_env.cfg_env;
1866 current.tx.chain_id = fork.tx.chain_id;
1867}
1868
1869pub(crate) fn merge_account_data<ExtDB: DatabaseRef>(
1872 accounts: impl IntoIterator<Item = Address>,
1873 active: &CacheDB<ExtDB>,
1874 active_journaled_state: &mut JournaledState,
1875 target_fork: &mut Fork,
1876) {
1877 for addr in accounts.into_iter() {
1878 merge_db_account_data(addr, active, &mut target_fork.db);
1879 merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state);
1880 }
1881
1882 *active_journaled_state = target_fork.journaled_state.clone();
1883}
1884
1885fn merge_journaled_state_data(
1887 addr: Address,
1888 active_journaled_state: &JournaledState,
1889 fork_journaled_state: &mut JournaledState,
1890) {
1891 if let Some(mut acc) = active_journaled_state.state.get(&addr).cloned() {
1892 trace!(?addr, "updating journaled_state account data");
1893 if let Some(fork_account) = fork_journaled_state.state.get_mut(&addr) {
1894 fork_account.storage.extend(std::mem::take(&mut acc.storage));
1896 std::mem::swap(&mut fork_account.storage, &mut acc.storage);
1898 }
1899 fork_journaled_state.state.insert(addr, acc);
1900 }
1901}
1902
1903fn merge_db_account_data<ExtDB: DatabaseRef>(
1905 addr: Address,
1906 active: &CacheDB<ExtDB>,
1907 fork_db: &mut ForkDB,
1908) {
1909 trace!(?addr, "merging database data");
1910
1911 let Some(acc) = active.cache.accounts.get(&addr) else { return };
1912
1913 if let Some(code) = active.cache.contracts.get(&acc.info.code_hash) {
1915 trace!("merging contract cache");
1916 fork_db.cache.contracts.insert(acc.info.code_hash, code.clone());
1917 }
1918
1919 use std::collections::hash_map::Entry;
1921 match fork_db.cache.accounts.entry(addr) {
1922 Entry::Vacant(vacant) => {
1923 trace!("target account not present - inserting from active");
1924 vacant.insert(acc.clone());
1927 }
1928 Entry::Occupied(mut occupied) => {
1929 trace!("target account present - merging storage slots");
1930 let fork_account = occupied.get_mut();
1933 fork_account.storage.extend(&acc.storage);
1934 }
1935 }
1936}
1937
1938fn is_contract_in_state(journaled_state: &JournaledState, acc: Address) -> bool {
1940 journaled_state
1941 .state
1942 .get(&acc)
1943 .map(|acc| acc.info.code_hash != KECCAK_EMPTY)
1944 .unwrap_or_default()
1945}
1946
1947fn update_env_block(env: &mut EnvMut<'_>, block: &AnyRpcBlock) {
1949 env.block.timestamp = U256::from(block.header.timestamp);
1950 env.block.beneficiary = block.header.beneficiary;
1951 env.block.difficulty = block.header.difficulty;
1952 env.block.prevrandao = Some(block.header.mix_hash.unwrap_or_default());
1953 env.block.basefee = block.header.base_fee_per_gas.unwrap_or_default();
1954 env.block.gas_limit = block.header.gas_limit;
1955 env.block.number = U256::from(block.header.number);
1956
1957 if let Some(excess_blob_gas) = block.header.excess_blob_gas {
1958 env.block.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(
1959 excess_blob_gas,
1960 get_blob_base_fee_update_fraction(env.cfg.chain_id, block.header.timestamp),
1961 ));
1962 }
1963}
1964
1965fn commit_transaction(
1968 tx: &Transaction<AnyTxEnvelope>,
1969 env: &mut EnvMut<'_>,
1970 journaled_state: &mut JournaledState,
1971 fork: &mut Fork,
1972 fork_id: &ForkId,
1973 persistent_accounts: &HashSet<Address>,
1974 inspector: &mut dyn InspectorExt,
1975) -> eyre::Result<()> {
1976 configure_tx_env(env, tx);
1977
1978 let now = Instant::now();
1979 let res = {
1980 let fork = fork.clone();
1981 let journaled_state = journaled_state.clone();
1982 let depth = journaled_state.depth;
1983 let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?;
1984
1985 let mut evm = crate::evm::new_evm_with_inspector(&mut db as _, env.to_owned(), inspector);
1986 evm.journaled_state.depth = depth + 1;
1988 evm.transact(env.tx.clone()).wrap_err("backend: failed committing transaction")?
1989 };
1990 trace!(elapsed = ?now.elapsed(), "transacted transaction");
1991
1992 apply_state_changeset(res.state, journaled_state, fork, persistent_accounts)?;
1993 Ok(())
1994}
1995
1996pub fn update_state<DB: Database>(
1999 state: &mut EvmState,
2000 db: &mut DB,
2001 persistent_accounts: Option<&HashSet<Address>>,
2002) -> Result<(), DB::Error> {
2003 for (addr, acc) in state.iter_mut() {
2004 if !persistent_accounts.is_some_and(|accounts| accounts.contains(addr)) {
2005 acc.info = db.basic(*addr)?.unwrap_or_default();
2006 for (key, val) in &mut acc.storage {
2007 val.present_value = db.storage(*addr, *key)?;
2008 }
2009 }
2010 }
2011
2012 Ok(())
2013}
2014
2015fn apply_state_changeset(
2018 state: Map<revm::primitives::Address, Account>,
2019 journaled_state: &mut JournaledState,
2020 fork: &mut Fork,
2021 persistent_accounts: &HashSet<Address>,
2022) -> Result<(), BackendError> {
2023 fork.db.commit(state);
2025
2026 update_state(&mut journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2027 update_state(&mut fork.journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2028
2029 Ok(())
2030}
2031
2032#[cfg(test)]
2033mod tests {
2034 use crate::{backend::Backend, fork::CreateFork, opts::EvmOpts};
2035 use alloy_primitives::{U256, address};
2036 use alloy_provider::Provider;
2037 use foundry_common::provider::get_http_provider;
2038 use foundry_config::{Config, NamedChain};
2039 use foundry_fork_db::cache::{BlockchainDb, BlockchainDbMeta};
2040 use revm::database::DatabaseRef;
2041
2042 #[tokio::test(flavor = "multi_thread")]
2043 async fn can_read_write_cache() {
2044 let endpoint = &*foundry_test_utils::rpc::next_http_rpc_endpoint();
2045 let provider = get_http_provider(endpoint);
2046
2047 let block_num = provider.get_block_number().await.unwrap();
2048
2049 let config = Config::figment();
2050 let mut evm_opts = config.extract::<EvmOpts>().unwrap();
2051 evm_opts.fork_block_number = Some(block_num);
2052
2053 let (env, _block) = evm_opts.fork_evm_env(endpoint).await.unwrap();
2054
2055 let fork = CreateFork {
2056 enable_caching: true,
2057 url: endpoint.to_string(),
2058 env: env.clone(),
2059 evm_opts,
2060 };
2061
2062 let backend = Backend::spawn(Some(fork)).unwrap();
2063
2064 let address = address!("0x63091244180ae240c87d1f528f5f269134cb07b3");
2066
2067 let num_slots = 5;
2068 let _account = backend.basic_ref(address);
2069 for idx in 0..num_slots {
2070 let _ = backend.storage_ref(address, U256::from(idx));
2071 }
2072 drop(backend);
2073
2074 let meta = BlockchainDbMeta {
2075 chain: None,
2076 block_env: env.evm_env.block_env,
2077 hosts: Default::default(),
2078 };
2079
2080 let db = BlockchainDb::new(
2081 meta,
2082 Some(Config::foundry_block_cache_dir(NamedChain::Mainnet, block_num).unwrap()),
2083 );
2084 assert!(db.accounts().read().contains_key(&address));
2085 assert!(db.storage().read().contains_key(&address));
2086 assert_eq!(db.storage().read().get(&address).unwrap().len(), num_slots as usize);
2087 }
2088}