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