1use crate::{
4 constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, TEST_CONTRACT_ADDRESS},
5 evm::new_evm_with_inspector,
6 fork::{CreateFork, ForkId, MultiFork},
7 state_snapshot::StateSnapshots,
8 utils::{configure_tx_env, configure_tx_req_env},
9 AsEnvMut, Env, EnvMut, InspectorExt,
10};
11use alloy_consensus::Typed2718;
12use alloy_evm::Evm;
13use alloy_genesis::GenesisAccount;
14use alloy_network::{AnyRpcBlock, AnyTxEnvelope, TransactionResponse};
15use alloy_primitives::{keccak256, uint, Address, TxKind, B256, U256};
16use alloy_rpc_types::{BlockNumberOrTag, Transaction, TransactionRequest};
17use eyre::Context;
18use foundry_common::{is_known_system_sender, SYSTEM_TRANSACTION_TYPE};
19pub use foundry_fork_db::{cache::BlockchainDbMeta, BlockchainDb, SharedBackend};
20use revm::{
21 bytecode::Bytecode,
22 context::JournalInner,
23 context_interface::{block::BlobExcessGasAndPrice, result::ResultAndState},
24 database::{CacheDB, DatabaseRef},
25 inspector::NoOpInspector,
26 precompile::{PrecompileSpecId, Precompiles},
27 primitives::{hardfork::SpecId, HashMap as Map, Log, KECCAK_EMPTY},
28 state::{Account, AccountInfo, EvmState, EvmStorageSlot},
29 Database, DatabaseCommit, JournalEntry,
30};
31use std::{
32 collections::{BTreeMap, HashMap, HashSet},
33 time::Instant,
34};
35
36mod diagnostic;
37pub use diagnostic::RevertDiagnostic;
38
39mod error;
40pub use error::{BackendError, BackendResult, DatabaseError, DatabaseResult};
41
42mod cow;
43pub use cow::CowBackend;
44
45mod in_memory_db;
46pub use in_memory_db::{EmptyDBWrapper, FoundryEvmInMemoryDB, MemDb};
47
48mod snapshot;
49pub use snapshot::{BackendStateSnapshot, RevertStateSnapshotAction, StateSnapshot};
50
51type ForkDB = CacheDB<SharedBackend>;
53
54pub type LocalForkId = U256;
59
60type ForkLookupIndex = usize;
63
64const DEFAULT_PERSISTENT_ACCOUNTS: [Address; 3] =
66 [CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, CALLER];
67
68pub const GLOBAL_FAIL_SLOT: U256 =
73 uint!(0x6661696c65640000000000000000000000000000000000000000000000000000_U256);
74
75pub type JournaledState = JournalInner<JournalEntry>;
76
77#[auto_impl::auto_impl(&mut)]
79pub trait DatabaseExt: Database<Error = DatabaseError> + DatabaseCommit {
80 fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256;
86
87 fn revert_state(
100 &mut self,
101 id: U256,
102 journaled_state: &JournaledState,
103 env: &mut EnvMut<'_>,
104 action: RevertStateSnapshotAction,
105 ) -> Option<JournaledState>;
106
107 fn delete_state_snapshot(&mut self, id: U256) -> bool;
112
113 fn delete_state_snapshots(&mut self);
115
116 fn create_select_fork(
120 &mut self,
121 fork: CreateFork,
122 env: &mut EnvMut<'_>,
123 journaled_state: &mut JournaledState,
124 ) -> eyre::Result<LocalForkId> {
125 let id = self.create_fork(fork)?;
126 self.select_fork(id, env, journaled_state)?;
127 Ok(id)
128 }
129
130 fn create_select_fork_at_transaction(
134 &mut self,
135 fork: CreateFork,
136 env: &mut EnvMut<'_>,
137 journaled_state: &mut JournaledState,
138 transaction: B256,
139 ) -> eyre::Result<LocalForkId> {
140 let id = self.create_fork_at_transaction(fork, transaction)?;
141 self.select_fork(id, env, journaled_state)?;
142 Ok(id)
143 }
144
145 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId>;
147
148 fn create_fork_at_transaction(
150 &mut self,
151 fork: CreateFork,
152 transaction: B256,
153 ) -> eyre::Result<LocalForkId>;
154
155 fn select_fork(
165 &mut self,
166 id: LocalForkId,
167 env: &mut EnvMut<'_>,
168 journaled_state: &mut JournaledState,
169 ) -> eyre::Result<()>;
170
171 fn roll_fork(
179 &mut self,
180 id: Option<LocalForkId>,
181 block_number: u64,
182 env: &mut EnvMut<'_>,
183 journaled_state: &mut JournaledState,
184 ) -> eyre::Result<()>;
185
186 fn roll_fork_to_transaction(
195 &mut self,
196 id: Option<LocalForkId>,
197 transaction: B256,
198 env: &mut EnvMut<'_>,
199 journaled_state: &mut JournaledState,
200 ) -> eyre::Result<()>;
201
202 fn transact(
204 &mut self,
205 id: Option<LocalForkId>,
206 transaction: B256,
207 env: Env,
208 journaled_state: &mut JournaledState,
209 inspector: &mut dyn InspectorExt,
210 ) -> eyre::Result<()>;
211
212 fn transact_from_tx(
214 &mut self,
215 transaction: &TransactionRequest,
216 env: Env,
217 journaled_state: &mut JournaledState,
218 inspector: &mut dyn InspectorExt,
219 ) -> eyre::Result<()>;
220
221 fn active_fork_id(&self) -> Option<LocalForkId>;
223
224 fn active_fork_url(&self) -> Option<String>;
226
227 fn is_forked_mode(&self) -> bool {
229 self.active_fork_id().is_some()
230 }
231
232 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId>;
243
244 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId>;
246
247 fn diagnose_revert(
274 &self,
275 callee: Address,
276 journaled_state: &JournaledState,
277 ) -> Option<RevertDiagnostic>;
278
279 fn load_allocs(
283 &mut self,
284 allocs: &BTreeMap<Address, GenesisAccount>,
285 journaled_state: &mut JournaledState,
286 ) -> Result<(), BackendError>;
287
288 fn clone_account(
293 &mut self,
294 source: &GenesisAccount,
295 target: &Address,
296 journaled_state: &mut JournaledState,
297 ) -> Result<(), BackendError>;
298
299 fn is_persistent(&self, acc: &Address) -> bool;
301
302 fn remove_persistent_account(&mut self, account: &Address) -> bool;
304
305 fn add_persistent_account(&mut self, account: Address) -> bool;
307
308 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
310 fn remove_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
311 where
312 Self: Sized,
313 {
314 for acc in accounts {
315 self.remove_persistent_account(&acc);
316 }
317 }
318
319 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
321 fn extend_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
322 where
323 Self: Sized,
324 {
325 for acc in accounts {
326 self.add_persistent_account(acc);
327 }
328 }
329
330 fn allow_cheatcode_access(&mut self, account: Address) -> bool;
334
335 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool;
339
340 fn has_cheatcode_access(&self, account: &Address) -> bool;
342
343 fn ensure_cheatcode_access(&self, account: &Address) -> Result<(), BackendError> {
347 if !self.has_cheatcode_access(account) {
348 return Err(BackendError::NoCheats(*account));
349 }
350 Ok(())
351 }
352
353 fn ensure_cheatcode_access_forking_mode(&self, account: &Address) -> Result<(), BackendError> {
356 if self.is_forked_mode() {
357 return self.ensure_cheatcode_access(account);
358 }
359 Ok(())
360 }
361
362 fn set_blockhash(&mut self, block_number: U256, block_hash: B256);
377}
378
379struct _ObjectSafe(dyn DatabaseExt);
380
381#[derive(Clone, Debug)]
434#[must_use]
435pub struct Backend {
436 forks: MultiFork,
438 mem_db: FoundryEvmInMemoryDB,
440 fork_init_journaled_state: JournaledState,
457 active_fork_ids: Option<(LocalForkId, ForkLookupIndex)>,
461 inner: BackendInner,
463}
464
465impl Backend {
466 pub fn spawn(fork: Option<CreateFork>) -> eyre::Result<Self> {
471 Self::new(MultiFork::spawn(), fork)
472 }
473
474 pub fn new(forks: MultiFork, fork: Option<CreateFork>) -> eyre::Result<Self> {
481 trace!(target: "backend", forking_mode=?fork.is_some(), "creating executor backend");
482 let inner = BackendInner {
484 persistent_accounts: HashSet::from(DEFAULT_PERSISTENT_ACCOUNTS),
485 ..Default::default()
486 };
487
488 let mut backend = Self {
489 forks,
490 mem_db: CacheDB::new(Default::default()),
491 fork_init_journaled_state: inner.new_journaled_state(),
492 active_fork_ids: None,
493 inner,
494 };
495
496 if let Some(fork) = fork {
497 let (fork_id, fork, _) = backend.forks.create_fork(fork)?;
498 let fork_db = ForkDB::new(fork);
499 let fork_ids = backend.inner.insert_new_fork(
500 fork_id.clone(),
501 fork_db,
502 backend.inner.new_journaled_state(),
503 );
504 backend.inner.launched_with_fork = Some((fork_id, fork_ids.0, fork_ids.1));
505 backend.active_fork_ids = Some(fork_ids);
506 }
507
508 trace!(target: "backend", forking_mode=? backend.active_fork_ids.is_some(), "created executor backend");
509
510 Ok(backend)
511 }
512
513 pub(crate) fn new_with_fork(
516 id: &ForkId,
517 fork: Fork,
518 journaled_state: JournaledState,
519 ) -> eyre::Result<Self> {
520 let mut backend = Self::spawn(None)?;
521 let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state);
522 backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1));
523 backend.active_fork_ids = Some(fork_ids);
524 Ok(backend)
525 }
526
527 pub fn clone_empty(&self) -> Self {
529 Self {
530 forks: self.forks.clone(),
531 mem_db: CacheDB::new(Default::default()),
532 fork_init_journaled_state: self.inner.new_journaled_state(),
533 active_fork_ids: None,
534 inner: Default::default(),
535 }
536 }
537
538 pub fn insert_account_info(&mut self, address: Address, account: AccountInfo) {
539 if let Some(db) = self.active_fork_db_mut() {
540 db.insert_account_info(address, account)
541 } else {
542 self.mem_db.insert_account_info(address, account)
543 }
544 }
545
546 pub fn insert_account_storage(
548 &mut self,
549 address: Address,
550 slot: U256,
551 value: U256,
552 ) -> Result<(), DatabaseError> {
553 if let Some(db) = self.active_fork_db_mut() {
554 db.insert_account_storage(address, slot, value)
555 } else {
556 self.mem_db.insert_account_storage(address, slot, value)
557 }
558 }
559
560 pub fn replace_account_storage(
565 &mut self,
566 address: Address,
567 storage: Map<U256, U256>,
568 ) -> Result<(), DatabaseError> {
569 if let Some(db) = self.active_fork_db_mut() {
570 db.replace_account_storage(address, storage)
571 } else {
572 self.mem_db.replace_account_storage(address, storage)
573 }
574 }
575
576 pub fn state_snapshots(
578 &self,
579 ) -> &StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>> {
580 &self.inner.state_snapshots
581 }
582
583 pub fn set_test_contract(&mut self, acc: Address) -> &mut Self {
590 trace!(?acc, "setting test account");
591 self.add_persistent_account(acc);
592 self.allow_cheatcode_access(acc);
593 self
594 }
595
596 pub fn set_caller(&mut self, acc: Address) -> &mut Self {
598 trace!(?acc, "setting caller account");
599 self.inner.caller = Some(acc);
600 self.allow_cheatcode_access(acc);
601 self
602 }
603
604 pub fn set_spec_id(&mut self, spec_id: SpecId) -> &mut Self {
606 trace!(?spec_id, "setting spec ID");
607 self.inner.spec_id = spec_id;
608 self
609 }
610
611 pub fn caller_address(&self) -> Option<Address> {
613 self.inner.caller
614 }
615
616 pub fn has_state_snapshot_failure(&self) -> bool {
622 self.inner.has_state_snapshot_failure
623 }
624
625 pub fn set_state_snapshot_failure(&mut self, has_state_snapshot_failure: bool) {
627 self.inner.has_state_snapshot_failure = has_state_snapshot_failure
628 }
629
630 pub(crate) fn update_fork_db(
632 &self,
633 active_journaled_state: &mut JournaledState,
634 target_fork: &mut Fork,
635 ) {
636 self.update_fork_db_contracts(
637 self.inner.persistent_accounts.iter().copied(),
638 active_journaled_state,
639 target_fork,
640 )
641 }
642
643 pub(crate) fn update_fork_db_contracts(
645 &self,
646 accounts: impl IntoIterator<Item = Address>,
647 active_journaled_state: &mut JournaledState,
648 target_fork: &mut Fork,
649 ) {
650 if let Some(db) = self.active_fork_db() {
651 merge_account_data(accounts, db, active_journaled_state, target_fork)
652 } else {
653 merge_account_data(accounts, &self.mem_db, active_journaled_state, target_fork)
654 }
655 }
656
657 pub fn mem_db(&self) -> &FoundryEvmInMemoryDB {
659 &self.mem_db
660 }
661
662 pub fn is_active_fork(&self, id: LocalForkId) -> bool {
664 self.active_fork_ids.map(|(i, _)| i == id).unwrap_or_default()
665 }
666
667 pub fn is_in_forking_mode(&self) -> bool {
669 self.active_fork().is_some()
670 }
671
672 pub fn active_fork(&self) -> Option<&Fork> {
674 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork(idx))
675 }
676
677 pub fn active_fork_mut(&mut self) -> Option<&mut Fork> {
679 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork_mut(idx))
680 }
681
682 pub fn active_fork_db(&self) -> Option<&ForkDB> {
684 self.active_fork().map(|f| &f.db)
685 }
686
687 pub fn active_fork_db_mut(&mut self) -> Option<&mut ForkDB> {
689 self.active_fork_mut().map(|f| &mut f.db)
690 }
691
692 #[inline(always)]
694 pub fn db(&self) -> &dyn Database<Error = DatabaseError> {
695 match self.active_fork_db() {
696 Some(fork_db) => fork_db,
697 None => &self.mem_db,
698 }
699 }
700
701 #[inline(always)]
703 pub fn db_mut(&mut self) -> &mut dyn Database<Error = DatabaseError> {
704 match self.active_fork_ids.map(|(_, idx)| &mut self.inner.get_fork_mut(idx).db) {
705 Some(fork_db) => fork_db,
706 None => &mut self.mem_db,
707 }
708 }
709
710 pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot {
712 if let Some((id, idx)) = self.active_fork_ids {
713 let fork = self.inner.get_fork(idx).clone();
714 let fork_id = self.inner.ensure_fork_id(id).cloned().expect("Exists; qed");
715 BackendDatabaseSnapshot::Forked(id, fork_id, idx, Box::new(fork))
716 } else {
717 BackendDatabaseSnapshot::InMemory(self.mem_db.clone())
718 }
719 }
720
721 pub fn merged_logs(&self, mut logs: Vec<Log>) -> Vec<Log> {
723 if let Some((_, active)) = self.active_fork_ids {
724 let mut all_logs = Vec::with_capacity(logs.len());
725
726 self.inner
727 .forks
728 .iter()
729 .enumerate()
730 .filter_map(|(idx, f)| f.as_ref().map(|f| (idx, f)))
731 .for_each(|(idx, f)| {
732 if idx == active {
733 all_logs.append(&mut logs);
734 } else {
735 all_logs.extend(f.journaled_state.logs.clone())
736 }
737 });
738 return all_logs;
739 }
740
741 logs
742 }
743
744 pub(crate) fn initialize(&mut self, env: &Env) {
748 self.set_caller(env.tx.caller);
749 self.set_spec_id(env.evm_env.cfg_env.spec);
750
751 let test_contract = match env.tx.kind {
752 TxKind::Call(to) => to,
753 TxKind::Create => {
754 let nonce = self
755 .basic_ref(env.tx.caller)
756 .map(|b| b.unwrap_or_default().nonce)
757 .unwrap_or_default();
758 env.tx.caller.create(nonce)
759 }
760 };
761 self.set_test_contract(test_contract);
762 }
763
764 #[instrument(name = "inspect", level = "debug", skip_all)]
769 pub fn inspect<I: InspectorExt>(
770 &mut self,
771 env: &mut Env,
772 inspector: &mut I,
773 ) -> eyre::Result<ResultAndState> {
774 self.initialize(env);
775 let mut evm = crate::evm::new_evm_with_inspector(self, env.to_owned(), inspector);
776
777 let res = evm.transact(env.tx.clone()).wrap_err("EVM error")?;
778
779 *env = evm.as_env_mut().to_owned();
780
781 Ok(res)
782 }
783
784 pub fn is_existing_precompile(&self, addr: &Address) -> bool {
786 self.inner.precompiles().contains(addr)
787 }
788
789 #[inline]
791 fn set_init_journaled_state(&mut self, journaled_state: JournaledState) {
792 trace!("recording fork init journaled_state");
793 self.fork_init_journaled_state = journaled_state;
794 }
795
796 fn prepare_init_journal_state(&mut self) -> Result<(), BackendError> {
806 let loaded_accounts = self
807 .fork_init_journaled_state
808 .state
809 .iter()
810 .filter(|(addr, _)| !self.is_existing_precompile(addr) && !self.is_persistent(addr))
811 .map(|(addr, _)| addr)
812 .copied()
813 .collect::<Vec<_>>();
814
815 for fork in self.inner.forks_iter_mut() {
816 let mut journaled_state = self.fork_init_journaled_state.clone();
817 for loaded_account in loaded_accounts.iter().copied() {
818 trace!(?loaded_account, "replacing account on init");
819 let init_account =
820 journaled_state.state.get_mut(&loaded_account).expect("exists; qed");
821
822 if init_account.is_created() {
826 trace!(?loaded_account, "skipping created account");
827 continue
828 }
829
830 let fork_account = Database::basic(&mut fork.db, loaded_account)?
833 .ok_or(BackendError::MissingAccount(loaded_account))?;
834 init_account.info = fork_account;
835 }
836 fork.journaled_state = journaled_state;
837 }
838 Ok(())
839 }
840
841 fn get_block_number_and_block_for_transaction(
843 &self,
844 id: LocalForkId,
845 transaction: B256,
846 ) -> eyre::Result<(u64, AnyRpcBlock)> {
847 let fork = self.inner.get_fork_by_id(id)?;
848 let tx = fork.db.db.get_transaction(transaction)?;
849
850 if let Some(tx_block) = tx.block_number {
852 let block = fork.db.db.get_full_block(tx_block)?;
853
854 let fork_block = tx_block - 1;
857 Ok((fork_block, block))
858 } else {
859 let block = fork.db.db.get_full_block(BlockNumberOrTag::Latest)?;
860
861 let number = block.header.number;
862
863 Ok((number, block))
864 }
865 }
866
867 pub fn replay_until(
871 &mut self,
872 id: LocalForkId,
873 mut env: Env,
874 tx_hash: B256,
875 journaled_state: &mut JournaledState,
876 ) -> eyre::Result<Option<Transaction<AnyTxEnvelope>>> {
877 trace!(?id, ?tx_hash, "replay until transaction");
878
879 let persistent_accounts = self.inner.persistent_accounts.clone();
880 let fork_id = self.ensure_fork_id(id)?.clone();
881
882 let fork = self.inner.get_fork_by_id_mut(id)?;
883 let full_block = fork.db.db.get_full_block(env.evm_env.block_env.number)?;
884
885 for tx in full_block.inner.transactions.txns() {
886 if is_known_system_sender(tx.inner().inner.signer()) ||
889 tx.ty() == SYSTEM_TRANSACTION_TYPE
890 {
891 trace!(tx=?tx.tx_hash(), "skipping system transaction");
892 continue;
893 }
894
895 if tx.tx_hash() == tx_hash {
896 return Ok(Some(tx.inner.clone()))
898 }
899 trace!(tx=?tx.tx_hash(), "committing transaction");
900
901 commit_transaction(
902 &tx.inner,
903 &mut env.as_env_mut(),
904 journaled_state,
905 fork,
906 &fork_id,
907 &persistent_accounts,
908 &mut NoOpInspector,
909 )?;
910 }
911
912 Ok(None)
913 }
914}
915
916impl DatabaseExt for Backend {
917 fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256 {
918 trace!("create snapshot");
919 let id = self.inner.state_snapshots.insert(BackendStateSnapshot::new(
920 self.create_db_snapshot(),
921 journaled_state.clone(),
922 env.to_owned(),
923 ));
924 trace!(target: "backend", "Created new snapshot {}", id);
925 id
926 }
927
928 fn revert_state(
929 &mut self,
930 id: U256,
931 current_state: &JournaledState,
932 current: &mut EnvMut<'_>,
933 action: RevertStateSnapshotAction,
934 ) -> Option<JournaledState> {
935 trace!(?id, "revert snapshot");
936 if let Some(mut snapshot) = self.inner.state_snapshots.remove_at(id) {
937 if action.is_keep() {
939 self.inner.state_snapshots.insert_at(snapshot.clone(), id);
940 }
941
942 if let Some(account) = current_state.state.get(&CHEATCODE_ADDRESS) {
947 if let Some(slot) = account.storage.get(&GLOBAL_FAIL_SLOT) {
948 if !slot.present_value.is_zero() {
949 self.set_state_snapshot_failure(true);
950 }
951 }
952 }
953
954 snapshot.merge(current_state);
956 let BackendStateSnapshot { db, mut journaled_state, env } = snapshot;
957 match db {
958 BackendDatabaseSnapshot::InMemory(mem_db) => {
959 self.mem_db = mem_db;
960 }
961 BackendDatabaseSnapshot::Forked(id, fork_id, idx, mut fork) => {
962 let caller = current.tx.caller;
966 journaled_state.state.entry(caller).or_insert_with(|| {
967 let caller_account = current_state
968 .state
969 .get(&caller)
970 .map(|acc| acc.info.clone())
971 .unwrap_or_default();
972
973 if !fork.db.cache.accounts.contains_key(&caller) {
974 fork.db.insert_account_info(caller, caller_account.clone());
976 }
977 caller_account.into()
978 });
979 self.inner.revert_state_snapshot(id, fork_id, idx, *fork);
980 self.active_fork_ids = Some((id, idx))
981 }
982 }
983
984 update_current_env_with_fork_env(&mut current.as_env_mut(), env);
985 trace!(target: "backend", "Reverted snapshot {}", id);
986
987 Some(journaled_state)
988 } else {
989 warn!(target: "backend", "No snapshot to revert for {}", id);
990 None
991 }
992 }
993
994 fn delete_state_snapshot(&mut self, id: U256) -> bool {
995 self.inner.state_snapshots.remove_at(id).is_some()
996 }
997
998 fn delete_state_snapshots(&mut self) {
999 self.inner.state_snapshots.clear()
1000 }
1001
1002 fn create_fork(&mut self, create_fork: CreateFork) -> eyre::Result<LocalForkId> {
1003 trace!("create fork");
1004 let (fork_id, fork, _) = self.forks.create_fork(create_fork)?;
1005
1006 let fork_db = ForkDB::new(fork);
1007 let (id, _) =
1008 self.inner.insert_new_fork(fork_id, fork_db, self.fork_init_journaled_state.clone());
1009 Ok(id)
1010 }
1011
1012 fn create_fork_at_transaction(
1013 &mut self,
1014 fork: CreateFork,
1015 transaction: B256,
1016 ) -> eyre::Result<LocalForkId> {
1017 trace!(?transaction, "create fork at transaction");
1018 let id = self.create_fork(fork)?;
1019 let fork_id = self.ensure_fork_id(id).cloned()?;
1020 let mut env = self
1021 .forks
1022 .get_env(fork_id)?
1023 .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exit", id))?;
1024
1025 self.roll_fork_to_transaction(
1028 Some(id),
1029 transaction,
1030 &mut env.as_env_mut(),
1031 &mut self.inner.new_journaled_state(),
1032 )?;
1033 Ok(id)
1034 }
1035
1036 fn select_fork(
1039 &mut self,
1040 id: LocalForkId,
1041 env: &mut EnvMut<'_>,
1042 active_journaled_state: &mut JournaledState,
1043 ) -> eyre::Result<()> {
1044 trace!(?id, "select fork");
1045 if self.is_active_fork(id) {
1046 return Ok(());
1048 }
1049
1050 if let Some(active_fork_id) = self.active_fork_id() {
1053 self.forks.update_block(
1054 self.ensure_fork_id(active_fork_id).cloned()?,
1055 env.block.number,
1056 env.block.timestamp,
1057 )?;
1058 }
1059
1060 let fork_id = self.ensure_fork_id(id).cloned()?;
1061 let idx = self.inner.ensure_fork_index(&fork_id)?;
1062 let fork_env = self
1063 .forks
1064 .get_env(fork_id)?
1065 .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exit", id))?;
1066
1067 if let Some(active) = self.active_fork_mut() {
1070 active.journaled_state = active_journaled_state.clone();
1071
1072 let caller = env.tx.caller;
1073 let caller_account = active.journaled_state.state.get(&env.tx.caller).cloned();
1074 let target_fork = self.inner.get_fork_mut(idx);
1075
1076 if target_fork.journaled_state.depth == 0 {
1078 if let Some(mut acc) = caller_account {
1080 let fork_account = Database::basic(&mut target_fork.db, caller)?
1081 .ok_or(BackendError::MissingAccount(caller))?;
1082
1083 acc.info = fork_account;
1084 target_fork.journaled_state.state.insert(caller, acc);
1085 }
1086 }
1087 } else {
1088 self.set_init_journaled_state(active_journaled_state.clone());
1095 self.prepare_init_journal_state()?;
1096
1097 self.fork_init_journaled_state.depth = 0;
1099 }
1100
1101 {
1102 let mut fork = self.inner.take_fork(idx);
1104
1105 let persistent_accounts = self.inner.persistent_accounts.clone();
1113 if let Some(db) = self.active_fork_db_mut() {
1114 for addr in persistent_accounts {
1115 let Ok(db_account) = db.load_account(addr) else { continue };
1116
1117 let Some(fork_account) = fork.journaled_state.state.get_mut(&addr) else {
1118 continue
1119 };
1120
1121 for (key, val) in &db_account.storage {
1122 if let Some(fork_storage) = fork_account.storage.get_mut(key) {
1123 fork_storage.present_value = *val;
1124 }
1125 }
1126 }
1127 }
1128
1129 fork.journaled_state.depth = active_journaled_state.depth;
1134
1135 let caller = env.tx.caller;
1139 fork.journaled_state.state.entry(caller).or_insert_with(|| {
1140 let caller_account = active_journaled_state
1141 .state
1142 .get(&env.tx.caller)
1143 .map(|acc| acc.info.clone())
1144 .unwrap_or_default();
1145
1146 if !fork.db.cache.accounts.contains_key(&caller) {
1147 fork.db.insert_account_info(caller, caller_account.clone());
1149 }
1150 caller_account.into()
1151 });
1152
1153 self.update_fork_db(active_journaled_state, &mut fork);
1154
1155 self.inner.set_fork(idx, fork);
1157 }
1158
1159 self.active_fork_ids = Some((id, idx));
1160 update_current_env_with_fork_env(env, fork_env);
1162
1163 Ok(())
1164 }
1165
1166 fn roll_fork(
1169 &mut self,
1170 id: Option<LocalForkId>,
1171 block_number: u64,
1172 env: &mut EnvMut<'_>,
1173 journaled_state: &mut JournaledState,
1174 ) -> eyre::Result<()> {
1175 trace!(?id, ?block_number, "roll fork");
1176 let id = self.ensure_fork(id)?;
1177 let (fork_id, backend, fork_env) =
1178 self.forks.roll_fork(self.inner.ensure_fork_id(id).cloned()?, block_number)?;
1179 self.inner.roll_fork(id, fork_id, backend)?;
1181
1182 if let Some((active_id, active_idx)) = self.active_fork_ids {
1183 if active_id == id {
1185 update_current_env_with_fork_env(env, fork_env);
1188
1189 let mut persistent_addrs = self.inner.persistent_accounts.clone();
1194 persistent_addrs.extend(self.caller_address());
1196
1197 let active = self.inner.get_fork_mut(active_idx);
1198 active.journaled_state = self.fork_init_journaled_state.clone();
1199
1200 active.journaled_state.depth = journaled_state.depth;
1201 for addr in persistent_addrs {
1202 merge_journaled_state_data(addr, journaled_state, &mut active.journaled_state);
1203 }
1204
1205 for (addr, acc) in &journaled_state.state {
1213 if acc.is_created() {
1214 if acc.is_touched() {
1215 merge_journaled_state_data(
1216 *addr,
1217 journaled_state,
1218 &mut active.journaled_state,
1219 );
1220 }
1221 } else {
1222 let _ = active.journaled_state.load_account(&mut active.db, *addr);
1223 }
1224 }
1225
1226 *journaled_state = active.journaled_state.clone();
1227 }
1228 }
1229 Ok(())
1230 }
1231
1232 fn roll_fork_to_transaction(
1233 &mut self,
1234 id: Option<LocalForkId>,
1235 transaction: B256,
1236 env: &mut EnvMut<'_>,
1237 journaled_state: &mut JournaledState,
1238 ) -> eyre::Result<()> {
1239 trace!(?id, ?transaction, "roll fork to transaction");
1240 let id = self.ensure_fork(id)?;
1241
1242 let (fork_block, block) =
1243 self.get_block_number_and_block_for_transaction(id, transaction)?;
1244
1245 self.roll_fork(Some(id), fork_block, env, journaled_state)?;
1247
1248 update_env_block(env, &block);
1249
1250 let env = env.to_owned();
1251
1252 self.replay_until(id, env, transaction, journaled_state)?;
1254
1255 Ok(())
1256 }
1257
1258 fn transact(
1259 &mut self,
1260 maybe_id: Option<LocalForkId>,
1261 transaction: B256,
1262 mut env: Env,
1263 journaled_state: &mut JournaledState,
1264 inspector: &mut dyn InspectorExt,
1265 ) -> eyre::Result<()> {
1266 trace!(?maybe_id, ?transaction, "execute transaction");
1267 let persistent_accounts = self.inner.persistent_accounts.clone();
1268 let id = self.ensure_fork(maybe_id)?;
1269 let fork_id = self.ensure_fork_id(id).cloned()?;
1270
1271 let tx = {
1272 let fork = self.inner.get_fork_by_id_mut(id)?;
1273 fork.db.db.get_transaction(transaction)?
1274 };
1275
1276 let (_fork_block, block) =
1283 self.get_block_number_and_block_for_transaction(id, transaction)?;
1284 update_env_block(&mut env.as_env_mut(), &block);
1285
1286 let fork = self.inner.get_fork_by_id_mut(id)?;
1287 commit_transaction(
1288 &tx.inner,
1289 &mut env.as_env_mut(),
1290 journaled_state,
1291 fork,
1292 &fork_id,
1293 &persistent_accounts,
1294 inspector,
1295 )
1296 }
1297
1298 fn transact_from_tx(
1299 &mut self,
1300 tx: &TransactionRequest,
1301 mut env: Env,
1302 journaled_state: &mut JournaledState,
1303 inspector: &mut dyn InspectorExt,
1304 ) -> eyre::Result<()> {
1305 trace!(?tx, "execute signed transaction");
1306
1307 self.commit(journaled_state.state.clone());
1308
1309 let res = {
1310 configure_tx_req_env(&mut env.as_env_mut(), tx, None)?;
1311
1312 let mut db = self.clone();
1313 let mut evm = new_evm_with_inspector(&mut db, env.to_owned(), inspector);
1314 evm.journaled_state.depth = journaled_state.depth + 1;
1315 evm.transact(env.tx)?
1316 };
1317
1318 self.commit(res.state);
1319 update_state(&mut journaled_state.state, self, None)?;
1320
1321 Ok(())
1322 }
1323
1324 fn active_fork_id(&self) -> Option<LocalForkId> {
1325 self.active_fork_ids.map(|(id, _)| id)
1326 }
1327
1328 fn active_fork_url(&self) -> Option<String> {
1329 let fork = self.inner.issued_local_fork_ids.get(&self.active_fork_id()?)?;
1330 self.forks.get_fork_url(fork.clone()).ok()?
1331 }
1332
1333 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
1334 if let Some(id) = id {
1335 if self.inner.issued_local_fork_ids.contains_key(&id) {
1336 return Ok(id);
1337 }
1338 eyre::bail!("Requested fork `{}` does not exit", id)
1339 }
1340 if let Some(id) = self.active_fork_id() {
1341 Ok(id)
1342 } else {
1343 eyre::bail!("No fork active")
1344 }
1345 }
1346
1347 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1348 self.inner.ensure_fork_id(id)
1349 }
1350
1351 fn diagnose_revert(
1352 &self,
1353 callee: Address,
1354 journaled_state: &JournaledState,
1355 ) -> Option<RevertDiagnostic> {
1356 let active_id = self.active_fork_id()?;
1357 let active_fork = self.active_fork()?;
1358
1359 if self.inner.forks.len() == 1 {
1360 return None;
1363 }
1364
1365 if !active_fork.is_contract(callee) && !is_contract_in_state(journaled_state, callee) {
1366 let mut available_on = Vec::new();
1368 for (id, fork) in self.inner.forks_iter().filter(|(id, _)| *id != active_id) {
1369 trace!(?id, address=?callee, "checking if account exists");
1370 if fork.is_contract(callee) {
1371 available_on.push(id);
1372 }
1373 }
1374
1375 return if available_on.is_empty() {
1376 Some(RevertDiagnostic::ContractDoesNotExist {
1377 contract: callee,
1378 active: active_id,
1379 persistent: self.is_persistent(&callee),
1380 })
1381 } else {
1382 Some(RevertDiagnostic::ContractExistsOnOtherForks {
1385 contract: callee,
1386 active: active_id,
1387 available_on,
1388 })
1389 };
1390 }
1391 None
1392 }
1393
1394 fn load_allocs(
1398 &mut self,
1399 allocs: &BTreeMap<Address, GenesisAccount>,
1400 journaled_state: &mut JournaledState,
1401 ) -> Result<(), BackendError> {
1402 for (addr, acc) in allocs {
1404 self.clone_account(acc, addr, journaled_state)?;
1405 }
1406
1407 Ok(())
1408 }
1409
1410 fn clone_account(
1415 &mut self,
1416 source: &GenesisAccount,
1417 target: &Address,
1418 journaled_state: &mut JournaledState,
1419 ) -> Result<(), BackendError> {
1420 let mut state_acc = journaled_state.load_account(self, *target)?;
1423
1424 if let Some(bytecode) = source.code.as_ref() {
1426 state_acc.info.code_hash = keccak256(bytecode);
1427 let bytecode = Bytecode::new_raw(bytecode.0.clone().into());
1428 state_acc.info.code = Some(bytecode);
1429 }
1430
1431 if let Some(storage) = source.storage.as_ref() {
1433 state_acc.storage = storage
1434 .iter()
1435 .map(|(slot, value)| {
1436 let slot = U256::from_be_bytes(slot.0);
1437 (
1438 slot,
1439 EvmStorageSlot::new_changed(
1440 state_acc
1441 .storage
1442 .get(&slot)
1443 .map(|s| s.present_value)
1444 .unwrap_or_default(),
1445 U256::from_be_bytes(value.0),
1446 ),
1447 )
1448 })
1449 .collect();
1450 }
1451 state_acc.info.nonce = source.nonce.unwrap_or_default();
1453 state_acc.info.balance = source.balance;
1454
1455 journaled_state.touch(*target);
1457
1458 Ok(())
1459 }
1460
1461 fn add_persistent_account(&mut self, account: Address) -> bool {
1462 trace!(?account, "add persistent account");
1463 self.inner.persistent_accounts.insert(account)
1464 }
1465
1466 fn remove_persistent_account(&mut self, account: &Address) -> bool {
1467 trace!(?account, "remove persistent account");
1468 self.inner.persistent_accounts.remove(account)
1469 }
1470
1471 fn is_persistent(&self, acc: &Address) -> bool {
1472 self.inner.persistent_accounts.contains(acc)
1473 }
1474
1475 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
1476 trace!(?account, "allow cheatcode access");
1477 self.inner.cheatcode_access_accounts.insert(account)
1478 }
1479
1480 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
1481 trace!(?account, "revoke cheatcode access");
1482 self.inner.cheatcode_access_accounts.remove(account)
1483 }
1484
1485 fn has_cheatcode_access(&self, account: &Address) -> bool {
1486 self.inner.cheatcode_access_accounts.contains(account)
1487 }
1488
1489 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
1490 if let Some(db) = self.active_fork_db_mut() {
1491 db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1492 } else {
1493 self.mem_db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1494 }
1495 }
1496}
1497
1498impl DatabaseRef for Backend {
1499 type Error = DatabaseError;
1500
1501 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1502 if let Some(db) = self.active_fork_db() {
1503 db.basic_ref(address)
1504 } else {
1505 Ok(self.mem_db.basic_ref(address)?)
1506 }
1507 }
1508
1509 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1510 if let Some(db) = self.active_fork_db() {
1511 db.code_by_hash_ref(code_hash)
1512 } else {
1513 Ok(self.mem_db.code_by_hash_ref(code_hash)?)
1514 }
1515 }
1516
1517 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
1518 if let Some(db) = self.active_fork_db() {
1519 DatabaseRef::storage_ref(db, address, index)
1520 } else {
1521 Ok(DatabaseRef::storage_ref(&self.mem_db, address, index)?)
1522 }
1523 }
1524
1525 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
1526 if let Some(db) = self.active_fork_db() {
1527 db.block_hash_ref(number)
1528 } else {
1529 Ok(self.mem_db.block_hash_ref(number)?)
1530 }
1531 }
1532}
1533
1534impl DatabaseCommit for Backend {
1535 fn commit(&mut self, changes: Map<Address, Account>) {
1536 if let Some(db) = self.active_fork_db_mut() {
1537 db.commit(changes)
1538 } else {
1539 self.mem_db.commit(changes)
1540 }
1541 }
1542}
1543
1544impl Database for Backend {
1545 type Error = DatabaseError;
1546 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1547 if let Some(db) = self.active_fork_db_mut() {
1548 Ok(db.basic(address)?)
1549 } else {
1550 Ok(self.mem_db.basic(address)?)
1551 }
1552 }
1553
1554 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1555 if let Some(db) = self.active_fork_db_mut() {
1556 Ok(db.code_by_hash(code_hash)?)
1557 } else {
1558 Ok(self.mem_db.code_by_hash(code_hash)?)
1559 }
1560 }
1561
1562 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
1563 if let Some(db) = self.active_fork_db_mut() {
1564 Ok(Database::storage(db, address, index)?)
1565 } else {
1566 Ok(Database::storage(&mut self.mem_db, address, index)?)
1567 }
1568 }
1569
1570 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
1571 if let Some(db) = self.active_fork_db_mut() {
1572 Ok(db.block_hash(number)?)
1573 } else {
1574 Ok(self.mem_db.block_hash(number)?)
1575 }
1576 }
1577}
1578
1579#[derive(Clone, Debug)]
1581pub enum BackendDatabaseSnapshot {
1582 InMemory(FoundryEvmInMemoryDB),
1584 Forked(LocalForkId, ForkId, ForkLookupIndex, Box<Fork>),
1586}
1587
1588#[derive(Clone, Debug)]
1590pub struct Fork {
1591 db: ForkDB,
1592 journaled_state: JournaledState,
1593}
1594
1595impl Fork {
1596 pub fn is_contract(&self, acc: Address) -> bool {
1598 if let Ok(Some(acc)) = self.db.basic_ref(acc) {
1599 if acc.code_hash != KECCAK_EMPTY {
1600 return true;
1601 }
1602 }
1603 is_contract_in_state(&self.journaled_state, acc)
1604 }
1605}
1606
1607#[derive(Clone, Debug)]
1609pub struct BackendInner {
1610 pub launched_with_fork: Option<(ForkId, LocalForkId, ForkLookupIndex)>,
1615 pub issued_local_fork_ids: HashMap<LocalForkId, ForkId>,
1627 pub created_forks: HashMap<ForkId, ForkLookupIndex>,
1630 pub forks: Vec<Option<Fork>>,
1633 pub state_snapshots: StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>>,
1635 pub has_state_snapshot_failure: bool,
1645 pub caller: Option<Address>,
1647 pub next_fork_id: LocalForkId,
1649 pub persistent_accounts: HashSet<Address>,
1653 pub spec_id: SpecId,
1655 pub cheatcode_access_accounts: HashSet<Address>,
1657}
1658
1659impl BackendInner {
1660 pub fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1661 self.issued_local_fork_ids
1662 .get(&id)
1663 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1664 }
1665
1666 pub fn ensure_fork_index(&self, id: &ForkId) -> eyre::Result<ForkLookupIndex> {
1667 self.created_forks
1668 .get(id)
1669 .copied()
1670 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1671 }
1672
1673 pub fn ensure_fork_index_by_local_id(&self, id: LocalForkId) -> eyre::Result<ForkLookupIndex> {
1674 self.ensure_fork_index(self.ensure_fork_id(id)?)
1675 }
1676
1677 #[track_caller]
1679 fn get_fork(&self, idx: ForkLookupIndex) -> &Fork {
1680 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1681 self.forks[idx].as_ref().unwrap()
1682 }
1683
1684 #[track_caller]
1686 fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork {
1687 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1688 self.forks[idx].as_mut().unwrap()
1689 }
1690
1691 #[track_caller]
1693 fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> {
1694 let idx = self.ensure_fork_index_by_local_id(id)?;
1695 Ok(self.get_fork_mut(idx))
1696 }
1697
1698 #[track_caller]
1700 fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> {
1701 let idx = self.ensure_fork_index_by_local_id(id)?;
1702 Ok(self.get_fork(idx))
1703 }
1704
1705 fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork {
1707 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1708 self.forks[idx].take().unwrap()
1709 }
1710
1711 fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) {
1712 self.forks[idx] = Some(fork)
1713 }
1714
1715 pub fn forks_iter(&self) -> impl Iterator<Item = (LocalForkId, &Fork)> + '_ {
1717 self.issued_local_fork_ids
1718 .iter()
1719 .map(|(id, fork_id)| (*id, self.get_fork(self.created_forks[fork_id])))
1720 }
1721
1722 pub fn forks_iter_mut(&mut self) -> impl Iterator<Item = &mut Fork> + '_ {
1724 self.forks.iter_mut().filter_map(|f| f.as_mut())
1725 }
1726
1727 pub fn revert_state_snapshot(
1729 &mut self,
1730 id: LocalForkId,
1731 fork_id: ForkId,
1732 idx: ForkLookupIndex,
1733 fork: Fork,
1734 ) {
1735 self.created_forks.insert(fork_id.clone(), idx);
1736 self.issued_local_fork_ids.insert(id, fork_id);
1737 self.set_fork(idx, fork)
1738 }
1739
1740 pub fn update_fork_mapping(
1742 &mut self,
1743 id: LocalForkId,
1744 fork_id: ForkId,
1745 db: ForkDB,
1746 journaled_state: JournaledState,
1747 ) -> ForkLookupIndex {
1748 let idx = self.forks.len();
1749 self.issued_local_fork_ids.insert(id, fork_id.clone());
1750 self.created_forks.insert(fork_id, idx);
1751
1752 let fork = Fork { db, journaled_state };
1753 self.forks.push(Some(fork));
1754 idx
1755 }
1756
1757 pub fn roll_fork(
1758 &mut self,
1759 id: LocalForkId,
1760 new_fork_id: ForkId,
1761 backend: SharedBackend,
1762 ) -> eyre::Result<ForkLookupIndex> {
1763 let fork_id = self.ensure_fork_id(id)?;
1764 let idx = self.ensure_fork_index(fork_id)?;
1765
1766 if let Some(active) = self.forks[idx].as_mut() {
1767 let mut new_db = ForkDB::new(backend);
1769 for addr in self.persistent_accounts.iter().copied() {
1770 merge_db_account_data(addr, &active.db, &mut new_db);
1771 }
1772 active.db = new_db;
1773 }
1774 self.issued_local_fork_ids.insert(id, new_fork_id.clone());
1776 self.created_forks.insert(new_fork_id, idx);
1777 Ok(idx)
1778 }
1779
1780 pub fn insert_new_fork(
1784 &mut self,
1785 fork_id: ForkId,
1786 db: ForkDB,
1787 journaled_state: JournaledState,
1788 ) -> (LocalForkId, ForkLookupIndex) {
1789 let idx = self.forks.len();
1790 self.created_forks.insert(fork_id.clone(), idx);
1791 let id = self.next_id();
1792 self.issued_local_fork_ids.insert(id, fork_id);
1793 let fork = Fork { db, journaled_state };
1794 self.forks.push(Some(fork));
1795 (id, idx)
1796 }
1797
1798 fn next_id(&mut self) -> U256 {
1799 let id = self.next_fork_id;
1800 self.next_fork_id += U256::from(1);
1801 id
1802 }
1803
1804 pub fn len(&self) -> usize {
1806 self.issued_local_fork_ids.len()
1807 }
1808
1809 pub fn is_empty(&self) -> bool {
1811 self.issued_local_fork_ids.is_empty()
1812 }
1813
1814 pub fn precompiles(&self) -> &'static Precompiles {
1815 Precompiles::new(PrecompileSpecId::from_spec_id(self.spec_id))
1816 }
1817
1818 pub fn new_journaled_state(&self) -> JournaledState {
1820 let mut journal = {
1821 let mut journal_inner = JournalInner::new();
1822 journal_inner.set_spec_id(self.spec_id);
1823 journal_inner
1824 };
1825 journal.precompiles.extend(self.precompiles().addresses().copied());
1826 journal
1827 }
1828}
1829
1830impl Default for BackendInner {
1831 fn default() -> Self {
1832 Self {
1833 launched_with_fork: None,
1834 issued_local_fork_ids: Default::default(),
1835 created_forks: Default::default(),
1836 forks: vec![],
1837 state_snapshots: Default::default(),
1838 has_state_snapshot_failure: false,
1839 caller: None,
1840 next_fork_id: Default::default(),
1841 persistent_accounts: Default::default(),
1842 spec_id: SpecId::default(),
1843 cheatcode_access_accounts: HashSet::from([
1846 CHEATCODE_ADDRESS,
1847 TEST_CONTRACT_ADDRESS,
1848 CALLER,
1849 ]),
1850 }
1851 }
1852}
1853
1854pub(crate) fn update_current_env_with_fork_env(current: &mut EnvMut<'_>, fork: Env) {
1856 *current.block = fork.evm_env.block_env;
1857 *current.cfg = fork.evm_env.cfg_env;
1858 current.tx.chain_id = fork.tx.chain_id;
1859}
1860
1861pub(crate) fn merge_account_data<ExtDB: DatabaseRef>(
1864 accounts: impl IntoIterator<Item = Address>,
1865 active: &CacheDB<ExtDB>,
1866 active_journaled_state: &mut JournaledState,
1867 target_fork: &mut Fork,
1868) {
1869 for addr in accounts.into_iter() {
1870 merge_db_account_data(addr, active, &mut target_fork.db);
1871 merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state);
1872 }
1873
1874 *active_journaled_state = target_fork.journaled_state.clone();
1875}
1876
1877fn merge_journaled_state_data(
1879 addr: Address,
1880 active_journaled_state: &JournaledState,
1881 fork_journaled_state: &mut JournaledState,
1882) {
1883 if let Some(mut acc) = active_journaled_state.state.get(&addr).cloned() {
1884 trace!(?addr, "updating journaled_state account data");
1885 if let Some(fork_account) = fork_journaled_state.state.get_mut(&addr) {
1886 fork_account.storage.extend(std::mem::take(&mut acc.storage));
1888 std::mem::swap(&mut fork_account.storage, &mut acc.storage);
1890 }
1891 fork_journaled_state.state.insert(addr, acc);
1892 }
1893}
1894
1895fn merge_db_account_data<ExtDB: DatabaseRef>(
1897 addr: Address,
1898 active: &CacheDB<ExtDB>,
1899 fork_db: &mut ForkDB,
1900) {
1901 trace!(?addr, "merging database data");
1902
1903 let Some(acc) = active.cache.accounts.get(&addr) else { return };
1904
1905 if let Some(code) = active.cache.contracts.get(&acc.info.code_hash) {
1907 trace!("merging contract cache");
1908 fork_db.cache.contracts.insert(acc.info.code_hash, code.clone());
1909 }
1910
1911 use std::collections::hash_map::Entry;
1913 match fork_db.cache.accounts.entry(addr) {
1914 Entry::Vacant(vacant) => {
1915 trace!("target account not present - inserting from active");
1916 vacant.insert(acc.clone());
1919 }
1920 Entry::Occupied(mut occupied) => {
1921 trace!("target account present - merging storage slots");
1922 let fork_account = occupied.get_mut();
1925 fork_account.storage.extend(&acc.storage);
1926 }
1927 }
1928}
1929
1930fn is_contract_in_state(journaled_state: &JournaledState, acc: Address) -> bool {
1932 journaled_state
1933 .state
1934 .get(&acc)
1935 .map(|acc| acc.info.code_hash != KECCAK_EMPTY)
1936 .unwrap_or_default()
1937}
1938
1939fn update_env_block(env: &mut EnvMut<'_>, block: &AnyRpcBlock) {
1941 env.block.timestamp = block.header.timestamp;
1942 env.block.beneficiary = block.header.beneficiary;
1943 env.block.difficulty = block.header.difficulty;
1944 env.block.prevrandao = Some(block.header.mix_hash.unwrap_or_default());
1945 env.block.basefee = block.header.base_fee_per_gas.unwrap_or_default();
1946 env.block.gas_limit = block.header.gas_limit;
1947 env.block.number = block.header.number;
1948 if let Some(excess_blob_gas) = block.header.excess_blob_gas {
1949 env.block.blob_excess_gas_and_price =
1950 Some(BlobExcessGasAndPrice::new(excess_blob_gas, false));
1951 }
1952}
1953
1954fn commit_transaction(
1957 tx: &Transaction<AnyTxEnvelope>,
1958 env: &mut EnvMut<'_>,
1959 journaled_state: &mut JournaledState,
1960 fork: &mut Fork,
1961 fork_id: &ForkId,
1962 persistent_accounts: &HashSet<Address>,
1963 inspector: &mut dyn InspectorExt,
1964) -> eyre::Result<()> {
1965 configure_tx_env(env, tx);
1966
1967 let now = Instant::now();
1968 let res = {
1969 let fork = fork.clone();
1970 let journaled_state = journaled_state.clone();
1971 let depth = journaled_state.depth;
1972 let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?;
1973
1974 let mut evm = crate::evm::new_evm_with_inspector(&mut db as _, env.to_owned(), inspector);
1975 evm.journaled_state.depth = depth + 1;
1977 evm.transact(env.tx.clone()).wrap_err("backend: failed committing transaction")?
1978 };
1979 trace!(elapsed = ?now.elapsed(), "transacted transaction");
1980
1981 apply_state_changeset(res.state, journaled_state, fork, persistent_accounts)?;
1982 Ok(())
1983}
1984
1985pub fn update_state<DB: Database>(
1988 state: &mut EvmState,
1989 db: &mut DB,
1990 persistent_accounts: Option<&HashSet<Address>>,
1991) -> Result<(), DB::Error> {
1992 for (addr, acc) in state.iter_mut() {
1993 if !persistent_accounts.is_some_and(|accounts| accounts.contains(addr)) {
1994 acc.info = db.basic(*addr)?.unwrap_or_default();
1995 for (key, val) in &mut acc.storage {
1996 val.present_value = db.storage(*addr, *key)?;
1997 }
1998 }
1999 }
2000
2001 Ok(())
2002}
2003
2004fn apply_state_changeset(
2007 state: Map<revm::primitives::Address, Account>,
2008 journaled_state: &mut JournaledState,
2009 fork: &mut Fork,
2010 persistent_accounts: &HashSet<Address>,
2011) -> Result<(), BackendError> {
2012 fork.db.commit(state);
2014
2015 update_state(&mut journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2016 update_state(&mut fork.journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2017
2018 Ok(())
2019}
2020
2021#[cfg(test)]
2022mod tests {
2023 use crate::{backend::Backend, fork::CreateFork, opts::EvmOpts};
2024 use alloy_primitives::{Address, U256};
2025 use alloy_provider::Provider;
2026 use foundry_common::provider::get_http_provider;
2027 use foundry_config::{Config, NamedChain};
2028 use foundry_fork_db::cache::{BlockchainDb, BlockchainDbMeta};
2029 use revm::database::DatabaseRef;
2030
2031 const ENDPOINT: Option<&str> = option_env!("ETH_RPC_URL");
2032
2033 #[tokio::test(flavor = "multi_thread")]
2034 async fn can_read_write_cache() {
2035 let Some(endpoint) = ENDPOINT else { return };
2036
2037 let provider = get_http_provider(endpoint);
2038
2039 let block_num = provider.get_block_number().await.unwrap();
2040
2041 let config = Config::figment();
2042 let mut evm_opts = config.extract::<EvmOpts>().unwrap();
2043 evm_opts.fork_block_number = Some(block_num);
2044
2045 let (env, _block) = evm_opts.fork_evm_env(endpoint).await.unwrap();
2046
2047 let fork = CreateFork {
2048 enable_caching: true,
2049 url: endpoint.to_string(),
2050 env: env.clone(),
2051 evm_opts,
2052 };
2053
2054 let backend = Backend::spawn(Some(fork)).unwrap();
2055
2056 let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap();
2058
2059 let idx = U256::from(0u64);
2060 let _value = backend.storage_ref(address, idx);
2061 let _account = backend.basic_ref(address);
2062
2063 let num_slots = 10u64;
2065 for idx in 1..num_slots {
2066 let _ = backend.storage_ref(address, U256::from(idx));
2067 }
2068 drop(backend);
2069
2070 let meta = BlockchainDbMeta { block_env: env.evm_env.block_env, hosts: Default::default() };
2071
2072 let db = BlockchainDb::new(
2073 meta,
2074 Some(Config::foundry_block_cache_dir(NamedChain::Mainnet, block_num).unwrap()),
2075 );
2076 assert!(db.accounts().read().contains_key(&address));
2077 assert!(db.storage().read().contains_key(&address));
2078 assert_eq!(db.storage().read().get(&address).unwrap().len(), num_slots as usize);
2079 }
2080}