1use crate::{
4 constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, TEST_CONTRACT_ADDRESS},
5 fork::{CreateFork, ForkId, MultiFork},
6 state_snapshot::StateSnapshots,
7 utils::{configure_tx_env, configure_tx_req_env, new_evm_with_inspector},
8 InspectorExt,
9};
10use alloy_genesis::GenesisAccount;
11use alloy_network::{AnyRpcBlock, AnyTxEnvelope, TransactionResponse};
12use alloy_primitives::{keccak256, uint, Address, TxKind, B256, U256};
13use alloy_rpc_types::{BlockNumberOrTag, Transaction, TransactionRequest};
14use eyre::Context;
15use foundry_common::{is_known_system_sender, SYSTEM_TRANSACTION_TYPE};
16pub use foundry_fork_db::{cache::BlockchainDbMeta, BlockchainDb, SharedBackend};
17use revm::{
18 db::{CacheDB, DatabaseRef},
19 inspectors::NoOpInspector,
20 precompile::{PrecompileSpecId, Precompiles},
21 primitives::{
22 Account, AccountInfo, BlobExcessGasAndPrice, Bytecode, Env, EnvWithHandlerCfg, EvmState,
23 EvmStorageSlot, HashMap as Map, Log, ResultAndState, SpecId, KECCAK_EMPTY,
24 },
25 Database, DatabaseCommit, JournaledState,
26};
27use std::{
28 collections::{BTreeMap, HashMap, HashSet},
29 time::Instant,
30};
31
32mod diagnostic;
33pub use diagnostic::RevertDiagnostic;
34
35mod error;
36pub use error::{BackendError, BackendResult, DatabaseError, DatabaseResult};
37
38mod cow;
39pub use cow::CowBackend;
40
41mod in_memory_db;
42pub use in_memory_db::{EmptyDBWrapper, FoundryEvmInMemoryDB, MemDb};
43
44mod snapshot;
45pub use snapshot::{BackendStateSnapshot, RevertStateSnapshotAction, StateSnapshot};
46
47type ForkDB = CacheDB<SharedBackend>;
49
50pub type LocalForkId = U256;
55
56type ForkLookupIndex = usize;
59
60const DEFAULT_PERSISTENT_ACCOUNTS: [Address; 3] =
62 [CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, CALLER];
63
64pub const GLOBAL_FAIL_SLOT: U256 =
69 uint!(0x6661696c65640000000000000000000000000000000000000000000000000000_U256);
70
71#[auto_impl::auto_impl(&mut)]
73pub trait DatabaseExt: Database<Error = DatabaseError> + DatabaseCommit {
74 fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> U256;
80
81 fn revert_state(
94 &mut self,
95 id: U256,
96 journaled_state: &JournaledState,
97 env: &mut Env,
98 action: RevertStateSnapshotAction,
99 ) -> Option<JournaledState>;
100
101 fn delete_state_snapshot(&mut self, id: U256) -> bool;
106
107 fn delete_state_snapshots(&mut self);
109
110 fn create_select_fork(
114 &mut self,
115 fork: CreateFork,
116 env: &mut Env,
117 journaled_state: &mut JournaledState,
118 ) -> eyre::Result<LocalForkId> {
119 let id = self.create_fork(fork)?;
120 self.select_fork(id, env, journaled_state)?;
121 Ok(id)
122 }
123
124 fn create_select_fork_at_transaction(
128 &mut self,
129 fork: CreateFork,
130 env: &mut Env,
131 journaled_state: &mut JournaledState,
132 transaction: B256,
133 ) -> eyre::Result<LocalForkId> {
134 let id = self.create_fork_at_transaction(fork, transaction)?;
135 self.select_fork(id, env, journaled_state)?;
136 Ok(id)
137 }
138
139 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId>;
141
142 fn create_fork_at_transaction(
144 &mut self,
145 fork: CreateFork,
146 transaction: B256,
147 ) -> eyre::Result<LocalForkId>;
148
149 fn select_fork(
159 &mut self,
160 id: LocalForkId,
161 env: &mut Env,
162 journaled_state: &mut JournaledState,
163 ) -> eyre::Result<()>;
164
165 fn roll_fork(
173 &mut self,
174 id: Option<LocalForkId>,
175 block_number: u64,
176 env: &mut Env,
177 journaled_state: &mut JournaledState,
178 ) -> eyre::Result<()>;
179
180 fn roll_fork_to_transaction(
189 &mut self,
190 id: Option<LocalForkId>,
191 transaction: B256,
192 env: &mut Env,
193 journaled_state: &mut JournaledState,
194 ) -> eyre::Result<()>;
195
196 fn transact(
198 &mut self,
199 id: Option<LocalForkId>,
200 transaction: B256,
201 env: Env,
202 journaled_state: &mut JournaledState,
203 inspector: &mut dyn InspectorExt,
204 ) -> eyre::Result<()>;
205
206 fn transact_from_tx(
208 &mut self,
209 transaction: &TransactionRequest,
210 env: Env,
211 journaled_state: &mut JournaledState,
212 inspector: &mut dyn InspectorExt,
213 ) -> eyre::Result<()>;
214
215 fn active_fork_id(&self) -> Option<LocalForkId>;
217
218 fn active_fork_url(&self) -> Option<String>;
220
221 fn is_forked_mode(&self) -> bool {
223 self.active_fork_id().is_some()
224 }
225
226 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId>;
237
238 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId>;
240
241 fn diagnose_revert(
268 &self,
269 callee: Address,
270 journaled_state: &JournaledState,
271 ) -> Option<RevertDiagnostic>;
272
273 fn load_allocs(
277 &mut self,
278 allocs: &BTreeMap<Address, GenesisAccount>,
279 journaled_state: &mut JournaledState,
280 ) -> Result<(), BackendError>;
281
282 fn clone_account(
287 &mut self,
288 source: &GenesisAccount,
289 target: &Address,
290 journaled_state: &mut JournaledState,
291 ) -> Result<(), BackendError>;
292
293 fn is_persistent(&self, acc: &Address) -> bool;
295
296 fn remove_persistent_account(&mut self, account: &Address) -> bool;
298
299 fn add_persistent_account(&mut self, account: Address) -> bool;
301
302 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
304 fn remove_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
305 where
306 Self: Sized,
307 {
308 for acc in accounts {
309 self.remove_persistent_account(&acc);
310 }
311 }
312
313 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
315 fn extend_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
316 where
317 Self: Sized,
318 {
319 for acc in accounts {
320 self.add_persistent_account(acc);
321 }
322 }
323
324 fn allow_cheatcode_access(&mut self, account: Address) -> bool;
328
329 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool;
333
334 fn has_cheatcode_access(&self, account: &Address) -> bool;
336
337 fn ensure_cheatcode_access(&self, account: &Address) -> Result<(), BackendError> {
341 if !self.has_cheatcode_access(account) {
342 return Err(BackendError::NoCheats(*account));
343 }
344 Ok(())
345 }
346
347 fn ensure_cheatcode_access_forking_mode(&self, account: &Address) -> Result<(), BackendError> {
350 if self.is_forked_mode() {
351 return self.ensure_cheatcode_access(account);
352 }
353 Ok(())
354 }
355
356 fn set_blockhash(&mut self, block_number: U256, block_hash: B256);
371}
372
373struct _ObjectSafe(dyn DatabaseExt);
374
375#[derive(Clone, Debug)]
428#[must_use]
429pub struct Backend {
430 forks: MultiFork,
432 mem_db: FoundryEvmInMemoryDB,
434 fork_init_journaled_state: JournaledState,
451 active_fork_ids: Option<(LocalForkId, ForkLookupIndex)>,
455 inner: BackendInner,
457}
458
459impl Backend {
460 pub fn spawn(fork: Option<CreateFork>) -> eyre::Result<Self> {
465 Self::new(MultiFork::spawn(), fork)
466 }
467
468 pub fn new(forks: MultiFork, fork: Option<CreateFork>) -> eyre::Result<Self> {
475 trace!(target: "backend", forking_mode=?fork.is_some(), "creating executor backend");
476 let inner = BackendInner {
478 persistent_accounts: HashSet::from(DEFAULT_PERSISTENT_ACCOUNTS),
479 ..Default::default()
480 };
481
482 let mut backend = Self {
483 forks,
484 mem_db: CacheDB::new(Default::default()),
485 fork_init_journaled_state: inner.new_journaled_state(),
486 active_fork_ids: None,
487 inner,
488 };
489
490 if let Some(fork) = fork {
491 let (fork_id, fork, _) = backend.forks.create_fork(fork)?;
492 let fork_db = ForkDB::new(fork);
493 let fork_ids = backend.inner.insert_new_fork(
494 fork_id.clone(),
495 fork_db,
496 backend.inner.new_journaled_state(),
497 );
498 backend.inner.launched_with_fork = Some((fork_id, fork_ids.0, fork_ids.1));
499 backend.active_fork_ids = Some(fork_ids);
500 }
501
502 trace!(target: "backend", forking_mode=? backend.active_fork_ids.is_some(), "created executor backend");
503
504 Ok(backend)
505 }
506
507 pub(crate) fn new_with_fork(
510 id: &ForkId,
511 fork: Fork,
512 journaled_state: JournaledState,
513 ) -> eyre::Result<Self> {
514 let mut backend = Self::spawn(None)?;
515 let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state);
516 backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1));
517 backend.active_fork_ids = Some(fork_ids);
518 Ok(backend)
519 }
520
521 pub fn clone_empty(&self) -> Self {
523 Self {
524 forks: self.forks.clone(),
525 mem_db: CacheDB::new(Default::default()),
526 fork_init_journaled_state: self.inner.new_journaled_state(),
527 active_fork_ids: None,
528 inner: Default::default(),
529 }
530 }
531
532 pub fn insert_account_info(&mut self, address: Address, account: AccountInfo) {
533 if let Some(db) = self.active_fork_db_mut() {
534 db.insert_account_info(address, account)
535 } else {
536 self.mem_db.insert_account_info(address, account)
537 }
538 }
539
540 pub fn insert_account_storage(
542 &mut self,
543 address: Address,
544 slot: U256,
545 value: U256,
546 ) -> Result<(), DatabaseError> {
547 if let Some(db) = self.active_fork_db_mut() {
548 db.insert_account_storage(address, slot, value)
549 } else {
550 self.mem_db.insert_account_storage(address, slot, value)
551 }
552 }
553
554 pub fn replace_account_storage(
559 &mut self,
560 address: Address,
561 storage: Map<U256, U256>,
562 ) -> Result<(), DatabaseError> {
563 if let Some(db) = self.active_fork_db_mut() {
564 db.replace_account_storage(address, storage)
565 } else {
566 self.mem_db.replace_account_storage(address, storage)
567 }
568 }
569
570 pub fn state_snapshots(
572 &self,
573 ) -> &StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>> {
574 &self.inner.state_snapshots
575 }
576
577 pub fn set_test_contract(&mut self, acc: Address) -> &mut Self {
584 trace!(?acc, "setting test account");
585 self.add_persistent_account(acc);
586 self.allow_cheatcode_access(acc);
587 self
588 }
589
590 pub fn set_caller(&mut self, acc: Address) -> &mut Self {
592 trace!(?acc, "setting caller account");
593 self.inner.caller = Some(acc);
594 self.allow_cheatcode_access(acc);
595 self
596 }
597
598 pub fn set_spec_id(&mut self, spec_id: SpecId) -> &mut Self {
600 trace!(?spec_id, "setting spec ID");
601 self.inner.spec_id = spec_id;
602 self
603 }
604
605 pub fn caller_address(&self) -> Option<Address> {
607 self.inner.caller
608 }
609
610 pub fn has_state_snapshot_failure(&self) -> bool {
616 self.inner.has_state_snapshot_failure
617 }
618
619 pub fn set_state_snapshot_failure(&mut self, has_state_snapshot_failure: bool) {
621 self.inner.has_state_snapshot_failure = has_state_snapshot_failure
622 }
623
624 pub(crate) fn update_fork_db(
626 &self,
627 active_journaled_state: &mut JournaledState,
628 target_fork: &mut Fork,
629 ) {
630 self.update_fork_db_contracts(
631 self.inner.persistent_accounts.iter().copied(),
632 active_journaled_state,
633 target_fork,
634 )
635 }
636
637 pub(crate) fn update_fork_db_contracts(
639 &self,
640 accounts: impl IntoIterator<Item = Address>,
641 active_journaled_state: &mut JournaledState,
642 target_fork: &mut Fork,
643 ) {
644 if let Some(db) = self.active_fork_db() {
645 merge_account_data(accounts, db, active_journaled_state, target_fork)
646 } else {
647 merge_account_data(accounts, &self.mem_db, active_journaled_state, target_fork)
648 }
649 }
650
651 pub fn mem_db(&self) -> &FoundryEvmInMemoryDB {
653 &self.mem_db
654 }
655
656 pub fn is_active_fork(&self, id: LocalForkId) -> bool {
658 self.active_fork_ids.map(|(i, _)| i == id).unwrap_or_default()
659 }
660
661 pub fn is_in_forking_mode(&self) -> bool {
663 self.active_fork().is_some()
664 }
665
666 pub fn active_fork(&self) -> Option<&Fork> {
668 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork(idx))
669 }
670
671 pub fn active_fork_mut(&mut self) -> Option<&mut Fork> {
673 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork_mut(idx))
674 }
675
676 pub fn active_fork_db(&self) -> Option<&ForkDB> {
678 self.active_fork().map(|f| &f.db)
679 }
680
681 pub fn active_fork_db_mut(&mut self) -> Option<&mut ForkDB> {
683 self.active_fork_mut().map(|f| &mut f.db)
684 }
685
686 #[inline(always)]
688 pub fn db(&self) -> &dyn Database<Error = DatabaseError> {
689 match self.active_fork_db() {
690 Some(fork_db) => fork_db,
691 None => &self.mem_db,
692 }
693 }
694
695 #[inline(always)]
697 pub fn db_mut(&mut self) -> &mut dyn Database<Error = DatabaseError> {
698 match self.active_fork_ids.map(|(_, idx)| &mut self.inner.get_fork_mut(idx).db) {
699 Some(fork_db) => fork_db,
700 None => &mut self.mem_db,
701 }
702 }
703
704 pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot {
706 if let Some((id, idx)) = self.active_fork_ids {
707 let fork = self.inner.get_fork(idx).clone();
708 let fork_id = self.inner.ensure_fork_id(id).cloned().expect("Exists; qed");
709 BackendDatabaseSnapshot::Forked(id, fork_id, idx, Box::new(fork))
710 } else {
711 BackendDatabaseSnapshot::InMemory(self.mem_db.clone())
712 }
713 }
714
715 pub fn merged_logs(&self, mut logs: Vec<Log>) -> Vec<Log> {
717 if let Some((_, active)) = self.active_fork_ids {
718 let mut all_logs = Vec::with_capacity(logs.len());
719
720 self.inner
721 .forks
722 .iter()
723 .enumerate()
724 .filter_map(|(idx, f)| f.as_ref().map(|f| (idx, f)))
725 .for_each(|(idx, f)| {
726 if idx == active {
727 all_logs.append(&mut logs);
728 } else {
729 all_logs.extend(f.journaled_state.logs.clone())
730 }
731 });
732 return all_logs;
733 }
734
735 logs
736 }
737
738 pub(crate) fn initialize(&mut self, env: &EnvWithHandlerCfg) {
742 self.set_caller(env.tx.caller);
743 self.set_spec_id(env.handler_cfg.spec_id);
744
745 let test_contract = match env.tx.transact_to {
746 TxKind::Call(to) => to,
747 TxKind::Create => {
748 let nonce = self
749 .basic_ref(env.tx.caller)
750 .map(|b| b.unwrap_or_default().nonce)
751 .unwrap_or_default();
752 env.tx.caller.create(nonce)
753 }
754 };
755 self.set_test_contract(test_contract);
756 }
757
758 fn env_with_handler_cfg(&self, env: Env) -> EnvWithHandlerCfg {
760 EnvWithHandlerCfg::new_with_spec_id(Box::new(env), self.inner.spec_id)
761 }
762
763 #[instrument(name = "inspect", level = "debug", skip_all)]
768 pub fn inspect<I: InspectorExt>(
769 &mut self,
770 env: &mut EnvWithHandlerCfg,
771 inspector: &mut I,
772 ) -> eyre::Result<ResultAndState> {
773 self.initialize(env);
774 let mut evm = crate::utils::new_evm_with_inspector(self, env.clone(), inspector);
775
776 let res = evm.transact().wrap_err("EVM error")?;
777
778 env.env = evm.context.evm.inner.env;
779
780 Ok(res)
781 }
782
783 pub fn is_existing_precompile(&self, addr: &Address) -> bool {
785 self.inner.precompiles().contains(addr)
786 }
787
788 #[inline]
790 fn set_init_journaled_state(&mut self, journaled_state: JournaledState) {
791 trace!("recording fork init journaled_state");
792 self.fork_init_journaled_state = journaled_state;
793 }
794
795 fn prepare_init_journal_state(&mut self) -> Result<(), BackendError> {
805 let loaded_accounts = self
806 .fork_init_journaled_state
807 .state
808 .iter()
809 .filter(|(addr, _)| !self.is_existing_precompile(addr) && !self.is_persistent(addr))
810 .map(|(addr, _)| addr)
811 .copied()
812 .collect::<Vec<_>>();
813
814 for fork in self.inner.forks_iter_mut() {
815 let mut journaled_state = self.fork_init_journaled_state.clone();
816 for loaded_account in loaded_accounts.iter().copied() {
817 trace!(?loaded_account, "replacing account on init");
818 let init_account =
819 journaled_state.state.get_mut(&loaded_account).expect("exists; qed");
820
821 if init_account.is_created() {
825 trace!(?loaded_account, "skipping created account");
826 continue
827 }
828
829 let fork_account = Database::basic(&mut fork.db, loaded_account)?
832 .ok_or(BackendError::MissingAccount(loaded_account))?;
833 init_account.info = fork_account;
834 }
835 fork.journaled_state = journaled_state;
836 }
837 Ok(())
838 }
839
840 fn get_block_number_and_block_for_transaction(
842 &self,
843 id: LocalForkId,
844 transaction: B256,
845 ) -> eyre::Result<(u64, AnyRpcBlock)> {
846 let fork = self.inner.get_fork_by_id(id)?;
847 let tx = fork.db.db.get_transaction(transaction)?;
848
849 if let Some(tx_block) = tx.block_number {
851 let block = fork.db.db.get_full_block(tx_block)?;
852
853 let fork_block = tx_block - 1;
856 Ok((fork_block, block))
857 } else {
858 let block = fork.db.db.get_full_block(BlockNumberOrTag::Latest)?;
859
860 let number = block.header.number;
861
862 Ok((number, block))
863 }
864 }
865
866 pub fn replay_until(
870 &mut self,
871 id: LocalForkId,
872 env: Env,
873 tx_hash: B256,
874 journaled_state: &mut JournaledState,
875 ) -> eyre::Result<Option<Transaction<AnyTxEnvelope>>> {
876 trace!(?id, ?tx_hash, "replay until transaction");
877
878 let persistent_accounts = self.inner.persistent_accounts.clone();
879 let fork_id = self.ensure_fork_id(id)?.clone();
880
881 let env = self.env_with_handler_cfg(env);
882 let fork = self.inner.get_fork_by_id_mut(id)?;
883 let full_block = fork.db.db.get_full_block(env.block.number.to::<u64>())?;
884
885 for tx in full_block.inner.transactions.txns() {
886 if is_known_system_sender(tx.from()) ||
889 tx.transaction_type() == Some(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 env.clone(),
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: &Env) -> 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.clone(),
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 Env,
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.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(current, 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,
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 Env,
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 fork.journaled_state.depth = active_journaled_state.depth;
1110
1111 let caller = env.tx.caller;
1115 fork.journaled_state.state.entry(caller).or_insert_with(|| {
1116 let caller_account = active_journaled_state
1117 .state
1118 .get(&env.tx.caller)
1119 .map(|acc| acc.info.clone())
1120 .unwrap_or_default();
1121
1122 if !fork.db.accounts.contains_key(&caller) {
1123 fork.db.insert_account_info(caller, caller_account.clone());
1125 }
1126 caller_account.into()
1127 });
1128
1129 self.update_fork_db(active_journaled_state, &mut fork);
1130
1131 self.inner.set_fork(idx, fork);
1133 }
1134
1135 self.active_fork_ids = Some((id, idx));
1136 update_current_env_with_fork_env(env, fork_env);
1138
1139 Ok(())
1140 }
1141
1142 fn roll_fork(
1145 &mut self,
1146 id: Option<LocalForkId>,
1147 block_number: u64,
1148 env: &mut Env,
1149 journaled_state: &mut JournaledState,
1150 ) -> eyre::Result<()> {
1151 trace!(?id, ?block_number, "roll fork");
1152 let id = self.ensure_fork(id)?;
1153 let (fork_id, backend, fork_env) =
1154 self.forks.roll_fork(self.inner.ensure_fork_id(id).cloned()?, block_number)?;
1155 self.inner.roll_fork(id, fork_id, backend)?;
1157
1158 if let Some((active_id, active_idx)) = self.active_fork_ids {
1159 if active_id == id {
1161 update_current_env_with_fork_env(env, fork_env);
1164
1165 let mut persistent_addrs = self.inner.persistent_accounts.clone();
1170 persistent_addrs.extend(self.caller_address());
1172
1173 let active = self.inner.get_fork_mut(active_idx);
1174 active.journaled_state = self.fork_init_journaled_state.clone();
1175
1176 active.journaled_state.depth = journaled_state.depth;
1177 for addr in persistent_addrs {
1178 merge_journaled_state_data(addr, journaled_state, &mut active.journaled_state);
1179 }
1180
1181 for (addr, acc) in &journaled_state.state {
1189 if acc.is_created() {
1190 if acc.is_touched() {
1191 merge_journaled_state_data(
1192 *addr,
1193 journaled_state,
1194 &mut active.journaled_state,
1195 );
1196 }
1197 } else {
1198 let _ = active.journaled_state.load_account(*addr, &mut active.db);
1199 }
1200 }
1201
1202 *journaled_state = active.journaled_state.clone();
1203 }
1204 }
1205 Ok(())
1206 }
1207
1208 fn roll_fork_to_transaction(
1209 &mut self,
1210 id: Option<LocalForkId>,
1211 transaction: B256,
1212 env: &mut Env,
1213 journaled_state: &mut JournaledState,
1214 ) -> eyre::Result<()> {
1215 trace!(?id, ?transaction, "roll fork to transaction");
1216 let id = self.ensure_fork(id)?;
1217
1218 let (fork_block, block) =
1219 self.get_block_number_and_block_for_transaction(id, transaction)?;
1220
1221 self.roll_fork(Some(id), fork_block, env, journaled_state)?;
1223
1224 update_env_block(env, &block);
1225
1226 let env = env.clone();
1228
1229 self.replay_until(id, env, transaction, journaled_state)?;
1230
1231 Ok(())
1232 }
1233
1234 fn transact(
1235 &mut self,
1236 maybe_id: Option<LocalForkId>,
1237 transaction: B256,
1238 mut env: Env,
1239 journaled_state: &mut JournaledState,
1240 inspector: &mut dyn InspectorExt,
1241 ) -> eyre::Result<()> {
1242 trace!(?maybe_id, ?transaction, "execute transaction");
1243 let persistent_accounts = self.inner.persistent_accounts.clone();
1244 let id = self.ensure_fork(maybe_id)?;
1245 let fork_id = self.ensure_fork_id(id).cloned()?;
1246
1247 let tx = {
1248 let fork = self.inner.get_fork_by_id_mut(id)?;
1249 fork.db.db.get_transaction(transaction)?
1250 };
1251
1252 let (_fork_block, block) =
1259 self.get_block_number_and_block_for_transaction(id, transaction)?;
1260 update_env_block(&mut env, &block);
1261
1262 let env = self.env_with_handler_cfg(env);
1263 let fork = self.inner.get_fork_by_id_mut(id)?;
1264 commit_transaction(
1265 &tx,
1266 env,
1267 journaled_state,
1268 fork,
1269 &fork_id,
1270 &persistent_accounts,
1271 inspector,
1272 )
1273 }
1274
1275 fn transact_from_tx(
1276 &mut self,
1277 tx: &TransactionRequest,
1278 mut env: Env,
1279 journaled_state: &mut JournaledState,
1280 inspector: &mut dyn InspectorExt,
1281 ) -> eyre::Result<()> {
1282 trace!(?tx, "execute signed transaction");
1283
1284 self.commit(journaled_state.state.clone());
1285
1286 let res = {
1287 configure_tx_req_env(&mut env, tx, None)?;
1288 let env = self.env_with_handler_cfg(env);
1289
1290 let mut db = self.clone();
1291 let mut evm = new_evm_with_inspector(&mut db, env, inspector);
1292 evm.context.evm.journaled_state.depth = journaled_state.depth + 1;
1293 evm.transact()?
1294 };
1295
1296 self.commit(res.state);
1297 update_state(&mut journaled_state.state, self, None)?;
1298
1299 Ok(())
1300 }
1301
1302 fn active_fork_id(&self) -> Option<LocalForkId> {
1303 self.active_fork_ids.map(|(id, _)| id)
1304 }
1305
1306 fn active_fork_url(&self) -> Option<String> {
1307 let fork = self.inner.issued_local_fork_ids.get(&self.active_fork_id()?)?;
1308 self.forks.get_fork_url(fork.clone()).ok()?
1309 }
1310
1311 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
1312 if let Some(id) = id {
1313 if self.inner.issued_local_fork_ids.contains_key(&id) {
1314 return Ok(id);
1315 }
1316 eyre::bail!("Requested fork `{}` does not exit", id)
1317 }
1318 if let Some(id) = self.active_fork_id() {
1319 Ok(id)
1320 } else {
1321 eyre::bail!("No fork active")
1322 }
1323 }
1324
1325 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1326 self.inner.ensure_fork_id(id)
1327 }
1328
1329 fn diagnose_revert(
1330 &self,
1331 callee: Address,
1332 journaled_state: &JournaledState,
1333 ) -> Option<RevertDiagnostic> {
1334 let active_id = self.active_fork_id()?;
1335 let active_fork = self.active_fork()?;
1336
1337 if self.inner.forks.len() == 1 {
1338 return None;
1341 }
1342
1343 if !active_fork.is_contract(callee) && !is_contract_in_state(journaled_state, callee) {
1344 let mut available_on = Vec::new();
1346 for (id, fork) in self.inner.forks_iter().filter(|(id, _)| *id != active_id) {
1347 trace!(?id, address=?callee, "checking if account exists");
1348 if fork.is_contract(callee) {
1349 available_on.push(id);
1350 }
1351 }
1352
1353 return if available_on.is_empty() {
1354 Some(RevertDiagnostic::ContractDoesNotExist {
1355 contract: callee,
1356 active: active_id,
1357 persistent: self.is_persistent(&callee),
1358 })
1359 } else {
1360 Some(RevertDiagnostic::ContractExistsOnOtherForks {
1363 contract: callee,
1364 active: active_id,
1365 available_on,
1366 })
1367 };
1368 }
1369 None
1370 }
1371
1372 fn load_allocs(
1376 &mut self,
1377 allocs: &BTreeMap<Address, GenesisAccount>,
1378 journaled_state: &mut JournaledState,
1379 ) -> Result<(), BackendError> {
1380 for (addr, acc) in allocs {
1382 self.clone_account(acc, addr, journaled_state)?;
1383 }
1384
1385 Ok(())
1386 }
1387
1388 fn clone_account(
1393 &mut self,
1394 source: &GenesisAccount,
1395 target: &Address,
1396 journaled_state: &mut JournaledState,
1397 ) -> Result<(), BackendError> {
1398 let mut state_acc = journaled_state.load_account(*target, self)?;
1401
1402 if let Some(bytecode) = source.code.as_ref() {
1404 state_acc.info.code_hash = keccak256(bytecode);
1405 let bytecode = Bytecode::new_raw(bytecode.0.clone().into());
1406 state_acc.info.code = Some(bytecode);
1407 }
1408
1409 if let Some(storage) = source.storage.as_ref() {
1411 state_acc.storage = storage
1412 .iter()
1413 .map(|(slot, value)| {
1414 let slot = U256::from_be_bytes(slot.0);
1415 (
1416 slot,
1417 EvmStorageSlot::new_changed(
1418 state_acc
1419 .storage
1420 .get(&slot)
1421 .map(|s| s.present_value)
1422 .unwrap_or_default(),
1423 U256::from_be_bytes(value.0),
1424 ),
1425 )
1426 })
1427 .collect();
1428 }
1429 state_acc.info.nonce = source.nonce.unwrap_or_default();
1431 state_acc.info.balance = source.balance;
1432
1433 journaled_state.touch(target);
1435
1436 Ok(())
1437 }
1438
1439 fn add_persistent_account(&mut self, account: Address) -> bool {
1440 trace!(?account, "add persistent account");
1441 self.inner.persistent_accounts.insert(account)
1442 }
1443
1444 fn remove_persistent_account(&mut self, account: &Address) -> bool {
1445 trace!(?account, "remove persistent account");
1446 self.inner.persistent_accounts.remove(account)
1447 }
1448
1449 fn is_persistent(&self, acc: &Address) -> bool {
1450 self.inner.persistent_accounts.contains(acc)
1451 }
1452
1453 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
1454 trace!(?account, "allow cheatcode access");
1455 self.inner.cheatcode_access_accounts.insert(account)
1456 }
1457
1458 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
1459 trace!(?account, "revoke cheatcode access");
1460 self.inner.cheatcode_access_accounts.remove(account)
1461 }
1462
1463 fn has_cheatcode_access(&self, account: &Address) -> bool {
1464 self.inner.cheatcode_access_accounts.contains(account)
1465 }
1466
1467 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
1468 if let Some(db) = self.active_fork_db_mut() {
1469 db.block_hashes.insert(block_number, block_hash);
1470 } else {
1471 self.mem_db.block_hashes.insert(block_number, block_hash);
1472 }
1473 }
1474}
1475
1476impl DatabaseRef for Backend {
1477 type Error = DatabaseError;
1478
1479 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1480 if let Some(db) = self.active_fork_db() {
1481 db.basic_ref(address)
1482 } else {
1483 Ok(self.mem_db.basic_ref(address)?)
1484 }
1485 }
1486
1487 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1488 if let Some(db) = self.active_fork_db() {
1489 db.code_by_hash_ref(code_hash)
1490 } else {
1491 Ok(self.mem_db.code_by_hash_ref(code_hash)?)
1492 }
1493 }
1494
1495 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
1496 if let Some(db) = self.active_fork_db() {
1497 DatabaseRef::storage_ref(db, address, index)
1498 } else {
1499 Ok(DatabaseRef::storage_ref(&self.mem_db, address, index)?)
1500 }
1501 }
1502
1503 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
1504 if let Some(db) = self.active_fork_db() {
1505 db.block_hash_ref(number)
1506 } else {
1507 Ok(self.mem_db.block_hash_ref(number)?)
1508 }
1509 }
1510}
1511
1512impl DatabaseCommit for Backend {
1513 fn commit(&mut self, changes: Map<Address, Account>) {
1514 if let Some(db) = self.active_fork_db_mut() {
1515 db.commit(changes)
1516 } else {
1517 self.mem_db.commit(changes)
1518 }
1519 }
1520}
1521
1522impl Database for Backend {
1523 type Error = DatabaseError;
1524 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1525 if let Some(db) = self.active_fork_db_mut() {
1526 Ok(db.basic(address)?)
1527 } else {
1528 Ok(self.mem_db.basic(address)?)
1529 }
1530 }
1531
1532 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1533 if let Some(db) = self.active_fork_db_mut() {
1534 Ok(db.code_by_hash(code_hash)?)
1535 } else {
1536 Ok(self.mem_db.code_by_hash(code_hash)?)
1537 }
1538 }
1539
1540 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
1541 if let Some(db) = self.active_fork_db_mut() {
1542 Ok(Database::storage(db, address, index)?)
1543 } else {
1544 Ok(Database::storage(&mut self.mem_db, address, index)?)
1545 }
1546 }
1547
1548 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
1549 if let Some(db) = self.active_fork_db_mut() {
1550 Ok(db.block_hash(number)?)
1551 } else {
1552 Ok(self.mem_db.block_hash(number)?)
1553 }
1554 }
1555}
1556
1557#[derive(Clone, Debug)]
1559pub enum BackendDatabaseSnapshot {
1560 InMemory(FoundryEvmInMemoryDB),
1562 Forked(LocalForkId, ForkId, ForkLookupIndex, Box<Fork>),
1564}
1565
1566#[derive(Clone, Debug)]
1568pub struct Fork {
1569 db: ForkDB,
1570 journaled_state: JournaledState,
1571}
1572
1573impl Fork {
1574 pub fn is_contract(&self, acc: Address) -> bool {
1576 if let Ok(Some(acc)) = self.db.basic_ref(acc) {
1577 if acc.code_hash != KECCAK_EMPTY {
1578 return true;
1579 }
1580 }
1581 is_contract_in_state(&self.journaled_state, acc)
1582 }
1583}
1584
1585#[derive(Clone, Debug)]
1587pub struct BackendInner {
1588 pub launched_with_fork: Option<(ForkId, LocalForkId, ForkLookupIndex)>,
1593 pub issued_local_fork_ids: HashMap<LocalForkId, ForkId>,
1605 pub created_forks: HashMap<ForkId, ForkLookupIndex>,
1608 pub forks: Vec<Option<Fork>>,
1611 pub state_snapshots: StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>>,
1613 pub has_state_snapshot_failure: bool,
1623 pub caller: Option<Address>,
1625 pub next_fork_id: LocalForkId,
1627 pub persistent_accounts: HashSet<Address>,
1631 pub spec_id: SpecId,
1633 pub cheatcode_access_accounts: HashSet<Address>,
1635}
1636
1637impl BackendInner {
1638 pub fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1639 self.issued_local_fork_ids
1640 .get(&id)
1641 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1642 }
1643
1644 pub fn ensure_fork_index(&self, id: &ForkId) -> eyre::Result<ForkLookupIndex> {
1645 self.created_forks
1646 .get(id)
1647 .copied()
1648 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1649 }
1650
1651 pub fn ensure_fork_index_by_local_id(&self, id: LocalForkId) -> eyre::Result<ForkLookupIndex> {
1652 self.ensure_fork_index(self.ensure_fork_id(id)?)
1653 }
1654
1655 #[track_caller]
1657 fn get_fork(&self, idx: ForkLookupIndex) -> &Fork {
1658 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1659 self.forks[idx].as_ref().unwrap()
1660 }
1661
1662 #[track_caller]
1664 fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork {
1665 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1666 self.forks[idx].as_mut().unwrap()
1667 }
1668
1669 #[track_caller]
1671 fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> {
1672 let idx = self.ensure_fork_index_by_local_id(id)?;
1673 Ok(self.get_fork_mut(idx))
1674 }
1675
1676 #[track_caller]
1678 fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> {
1679 let idx = self.ensure_fork_index_by_local_id(id)?;
1680 Ok(self.get_fork(idx))
1681 }
1682
1683 fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork {
1685 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1686 self.forks[idx].take().unwrap()
1687 }
1688
1689 fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) {
1690 self.forks[idx] = Some(fork)
1691 }
1692
1693 pub fn forks_iter(&self) -> impl Iterator<Item = (LocalForkId, &Fork)> + '_ {
1695 self.issued_local_fork_ids
1696 .iter()
1697 .map(|(id, fork_id)| (*id, self.get_fork(self.created_forks[fork_id])))
1698 }
1699
1700 pub fn forks_iter_mut(&mut self) -> impl Iterator<Item = &mut Fork> + '_ {
1702 self.forks.iter_mut().filter_map(|f| f.as_mut())
1703 }
1704
1705 pub fn revert_state_snapshot(
1707 &mut self,
1708 id: LocalForkId,
1709 fork_id: ForkId,
1710 idx: ForkLookupIndex,
1711 fork: Fork,
1712 ) {
1713 self.created_forks.insert(fork_id.clone(), idx);
1714 self.issued_local_fork_ids.insert(id, fork_id);
1715 self.set_fork(idx, fork)
1716 }
1717
1718 pub fn update_fork_mapping(
1720 &mut self,
1721 id: LocalForkId,
1722 fork_id: ForkId,
1723 db: ForkDB,
1724 journaled_state: JournaledState,
1725 ) -> ForkLookupIndex {
1726 let idx = self.forks.len();
1727 self.issued_local_fork_ids.insert(id, fork_id.clone());
1728 self.created_forks.insert(fork_id, idx);
1729
1730 let fork = Fork { db, journaled_state };
1731 self.forks.push(Some(fork));
1732 idx
1733 }
1734
1735 pub fn roll_fork(
1736 &mut self,
1737 id: LocalForkId,
1738 new_fork_id: ForkId,
1739 backend: SharedBackend,
1740 ) -> eyre::Result<ForkLookupIndex> {
1741 let fork_id = self.ensure_fork_id(id)?;
1742 let idx = self.ensure_fork_index(fork_id)?;
1743
1744 if let Some(active) = self.forks[idx].as_mut() {
1745 let mut new_db = ForkDB::new(backend);
1747 for addr in self.persistent_accounts.iter().copied() {
1748 merge_db_account_data(addr, &active.db, &mut new_db);
1749 }
1750 active.db = new_db;
1751 }
1752 self.issued_local_fork_ids.insert(id, new_fork_id.clone());
1754 self.created_forks.insert(new_fork_id, idx);
1755 Ok(idx)
1756 }
1757
1758 pub fn insert_new_fork(
1762 &mut self,
1763 fork_id: ForkId,
1764 db: ForkDB,
1765 journaled_state: JournaledState,
1766 ) -> (LocalForkId, ForkLookupIndex) {
1767 let idx = self.forks.len();
1768 self.created_forks.insert(fork_id.clone(), idx);
1769 let id = self.next_id();
1770 self.issued_local_fork_ids.insert(id, fork_id);
1771 let fork = Fork { db, journaled_state };
1772 self.forks.push(Some(fork));
1773 (id, idx)
1774 }
1775
1776 fn next_id(&mut self) -> U256 {
1777 let id = self.next_fork_id;
1778 self.next_fork_id += U256::from(1);
1779 id
1780 }
1781
1782 pub fn len(&self) -> usize {
1784 self.issued_local_fork_ids.len()
1785 }
1786
1787 pub fn is_empty(&self) -> bool {
1789 self.issued_local_fork_ids.is_empty()
1790 }
1791
1792 pub fn precompiles(&self) -> &'static Precompiles {
1793 Precompiles::new(PrecompileSpecId::from_spec_id(self.spec_id))
1794 }
1795
1796 pub fn new_journaled_state(&self) -> JournaledState {
1798 JournaledState::new(self.spec_id, self.precompiles().addresses().copied().collect())
1799 }
1800}
1801
1802impl Default for BackendInner {
1803 fn default() -> Self {
1804 Self {
1805 launched_with_fork: None,
1806 issued_local_fork_ids: Default::default(),
1807 created_forks: Default::default(),
1808 forks: vec![],
1809 state_snapshots: Default::default(),
1810 has_state_snapshot_failure: false,
1811 caller: None,
1812 next_fork_id: Default::default(),
1813 persistent_accounts: Default::default(),
1814 spec_id: SpecId::LATEST,
1815 cheatcode_access_accounts: HashSet::from([
1818 CHEATCODE_ADDRESS,
1819 TEST_CONTRACT_ADDRESS,
1820 CALLER,
1821 ]),
1822 }
1823 }
1824}
1825
1826pub(crate) fn update_current_env_with_fork_env(current: &mut Env, fork: Env) {
1828 current.block = fork.block;
1829 current.cfg = fork.cfg;
1830 current.tx.chain_id = fork.tx.chain_id;
1831}
1832
1833pub(crate) fn merge_account_data<ExtDB: DatabaseRef>(
1836 accounts: impl IntoIterator<Item = Address>,
1837 active: &CacheDB<ExtDB>,
1838 active_journaled_state: &mut JournaledState,
1839 target_fork: &mut Fork,
1840) {
1841 for addr in accounts.into_iter() {
1842 merge_db_account_data(addr, active, &mut target_fork.db);
1843 merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state);
1844 }
1845
1846 while active_journaled_state.journal.len() > target_fork.journaled_state.journal.len() {
1849 target_fork.journaled_state.journal.push(Default::default());
1850 }
1851
1852 *active_journaled_state = target_fork.journaled_state.clone();
1853}
1854
1855fn merge_journaled_state_data(
1857 addr: Address,
1858 active_journaled_state: &JournaledState,
1859 fork_journaled_state: &mut JournaledState,
1860) {
1861 if let Some(mut acc) = active_journaled_state.state.get(&addr).cloned() {
1862 trace!(?addr, "updating journaled_state account data");
1863 if let Some(fork_account) = fork_journaled_state.state.get_mut(&addr) {
1864 fork_account.storage.extend(std::mem::take(&mut acc.storage));
1866 std::mem::swap(&mut fork_account.storage, &mut acc.storage);
1868 }
1869 fork_journaled_state.state.insert(addr, acc);
1870 }
1871}
1872
1873fn merge_db_account_data<ExtDB: DatabaseRef>(
1875 addr: Address,
1876 active: &CacheDB<ExtDB>,
1877 fork_db: &mut ForkDB,
1878) {
1879 trace!(?addr, "merging database data");
1880
1881 let Some(acc) = active.accounts.get(&addr) else { return };
1882
1883 if let Some(code) = active.contracts.get(&acc.info.code_hash) {
1885 trace!("merging contract cache");
1886 fork_db.contracts.insert(acc.info.code_hash, code.clone());
1887 }
1888
1889 use std::collections::hash_map::Entry;
1891 match fork_db.accounts.entry(addr) {
1892 Entry::Vacant(vacant) => {
1893 trace!("target account not present - inserting from active");
1894 vacant.insert(acc.clone());
1897 }
1898 Entry::Occupied(mut occupied) => {
1899 trace!("target account present - merging storage slots");
1900 let fork_account = occupied.get_mut();
1903 fork_account.storage.extend(&acc.storage);
1904 }
1905 }
1906}
1907
1908fn is_contract_in_state(journaled_state: &JournaledState, acc: Address) -> bool {
1910 journaled_state
1911 .state
1912 .get(&acc)
1913 .map(|acc| acc.info.code_hash != KECCAK_EMPTY)
1914 .unwrap_or_default()
1915}
1916
1917fn update_env_block(env: &mut Env, block: &AnyRpcBlock) {
1919 env.block.timestamp = U256::from(block.header.timestamp);
1920 env.block.coinbase = block.header.beneficiary;
1921 env.block.difficulty = block.header.difficulty;
1922 env.block.prevrandao = Some(block.header.mix_hash.unwrap_or_default());
1923 env.block.basefee = U256::from(block.header.base_fee_per_gas.unwrap_or_default());
1924 env.block.gas_limit = U256::from(block.header.gas_limit);
1925 env.block.number = U256::from(block.header.number);
1926 if let Some(excess_blob_gas) = block.header.excess_blob_gas {
1927 env.block.blob_excess_gas_and_price =
1928 Some(BlobExcessGasAndPrice::new(excess_blob_gas, false));
1929 }
1930}
1931
1932fn commit_transaction(
1935 tx: &Transaction<AnyTxEnvelope>,
1936 mut env: EnvWithHandlerCfg,
1937 journaled_state: &mut JournaledState,
1938 fork: &mut Fork,
1939 fork_id: &ForkId,
1940 persistent_accounts: &HashSet<Address>,
1941 inspector: &mut dyn InspectorExt,
1942) -> eyre::Result<()> {
1943 configure_tx_env(&mut env.env, tx);
1944
1945 let now = Instant::now();
1946 let res = {
1947 let fork = fork.clone();
1948 let journaled_state = journaled_state.clone();
1949 let depth = journaled_state.depth;
1950 let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?;
1951
1952 let mut evm = crate::utils::new_evm_with_inspector(&mut db as _, env, inspector);
1953 evm.context.evm.inner.journaled_state.depth = depth + 1;
1955 evm.transact().wrap_err("backend: failed committing transaction")?
1956 };
1957 trace!(elapsed = ?now.elapsed(), "transacted transaction");
1958
1959 apply_state_changeset(res.state, journaled_state, fork, persistent_accounts)?;
1960 Ok(())
1961}
1962
1963pub fn update_state<DB: Database>(
1966 state: &mut EvmState,
1967 db: &mut DB,
1968 persistent_accounts: Option<&HashSet<Address>>,
1969) -> Result<(), DB::Error> {
1970 for (addr, acc) in state.iter_mut() {
1971 if !persistent_accounts.is_some_and(|accounts| accounts.contains(addr)) {
1972 acc.info = db.basic(*addr)?.unwrap_or_default();
1973 for (key, val) in &mut acc.storage {
1974 val.present_value = db.storage(*addr, *key)?;
1975 }
1976 }
1977 }
1978
1979 Ok(())
1980}
1981
1982fn apply_state_changeset(
1985 state: Map<revm::primitives::Address, Account>,
1986 journaled_state: &mut JournaledState,
1987 fork: &mut Fork,
1988 persistent_accounts: &HashSet<Address>,
1989) -> Result<(), BackendError> {
1990 fork.db.commit(state);
1992
1993 update_state(&mut journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
1994 update_state(&mut fork.journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
1995
1996 Ok(())
1997}
1998
1999#[cfg(test)]
2000mod tests {
2001 use crate::{backend::Backend, fork::CreateFork, opts::EvmOpts};
2002 use alloy_primitives::{Address, U256};
2003 use alloy_provider::Provider;
2004 use foundry_common::provider::get_http_provider;
2005 use foundry_config::{Config, NamedChain};
2006 use foundry_fork_db::cache::{BlockchainDb, BlockchainDbMeta};
2007 use revm::DatabaseRef;
2008
2009 const ENDPOINT: Option<&str> = option_env!("ETH_RPC_URL");
2010
2011 #[tokio::test(flavor = "multi_thread")]
2012 async fn can_read_write_cache() {
2013 let Some(endpoint) = ENDPOINT else { return };
2014
2015 let provider = get_http_provider(endpoint);
2016
2017 let block_num = provider.get_block_number().await.unwrap();
2018
2019 let config = Config::figment();
2020 let mut evm_opts = config.extract::<EvmOpts>().unwrap();
2021 evm_opts.fork_block_number = Some(block_num);
2022
2023 let (env, _block) = evm_opts.fork_evm_env(endpoint).await.unwrap();
2024
2025 let fork = CreateFork {
2026 enable_caching: true,
2027 url: endpoint.to_string(),
2028 env: env.clone(),
2029 evm_opts,
2030 };
2031
2032 let backend = Backend::spawn(Some(fork)).unwrap();
2033
2034 let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap();
2036
2037 let idx = U256::from(0u64);
2038 let _value = backend.storage_ref(address, idx);
2039 let _account = backend.basic_ref(address);
2040
2041 let num_slots = 10u64;
2043 for idx in 1..num_slots {
2044 let _ = backend.storage_ref(address, U256::from(idx));
2045 }
2046 drop(backend);
2047
2048 let meta =
2049 BlockchainDbMeta { cfg_env: env.cfg, block_env: env.block, hosts: Default::default() };
2050
2051 let db = BlockchainDb::new(
2052 meta,
2053 Some(Config::foundry_block_cache_dir(NamedChain::Mainnet, block_num).unwrap()),
2054 );
2055 assert!(db.accounts().read().contains_key(&address));
2056 assert!(db.storage().read().contains_key(&address));
2057 assert_eq!(db.storage().read().get(&address).unwrap().len(), num_slots as usize);
2058 }
2059}