1use crate::{
4 EthInspectorExt, FoundryBlock, FoundryTransaction,
5 constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, TEST_CONTRACT_ADDRESS},
6 evm::new_eth_evm_with_inspector,
7 fork::{CreateFork, ForkId, MultiFork},
8 state_snapshot::StateSnapshots,
9 utils::get_blob_base_fee_update_fraction,
10};
11use alloy_consensus::{BlockHeader, Typed2718};
12use alloy_evm::{Evm, EvmEnv, FromRecoveredTx};
13use alloy_genesis::GenesisAccount;
14use alloy_network::{
15 AnyNetwork, AnyRpcBlock, AnyRpcTransaction, AnyTxEnvelope, BlockResponse, TransactionResponse,
16};
17use alloy_primitives::{Address, B256, TxKind, U256, keccak256, uint};
18use alloy_rpc_types::{BlockNumberOrTag, Transaction};
19use eyre::Context;
20use foundry_common::{SYSTEM_TRANSACTION_TYPE, is_known_system_sender};
21pub use foundry_fork_db::{BlockchainDb, SharedBackend, cache::BlockchainDbMeta};
22use revm::{
23 Database, DatabaseCommit, JournalEntry,
24 bytecode::Bytecode,
25 context::{BlockEnv, JournalInner, TxEnv},
26 context_interface::{journaled_state::account::JournaledAccountTr, result::ResultAndState},
27 database::{CacheDB, DatabaseRef},
28 inspector::NoOpInspector,
29 precompile::{PrecompileSpecId, Precompiles},
30 primitives::{HashMap as Map, KECCAK_EMPTY, Log, hardfork::SpecId},
31 state::{Account, AccountInfo, EvmState, EvmStorageSlot},
32};
33use std::{
34 collections::{BTreeMap, HashMap, HashSet},
35 fmt::Debug,
36 time::Instant,
37};
38
39mod diagnostic;
40pub use diagnostic::RevertDiagnostic;
41
42mod error;
43pub use error::{BackendError, BackendResult, DatabaseError, DatabaseResult};
44
45mod cow;
46pub use cow::CowBackend;
47
48mod in_memory_db;
49pub use in_memory_db::{EmptyDBWrapper, FoundryEvmInMemoryDB, MemDb};
50
51mod snapshot;
52pub use snapshot::{BackendStateSnapshot, RevertStateSnapshotAction, StateSnapshot};
53
54type ForkDB = CacheDB<SharedBackend>;
56
57pub type LocalForkId = U256;
62
63type ForkLookupIndex = usize;
66
67const DEFAULT_PERSISTENT_ACCOUNTS: [Address; 3] =
69 [CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, CALLER];
70
71pub const GLOBAL_FAIL_SLOT: U256 =
76 uint!(0x6661696c65640000000000000000000000000000000000000000000000000000_U256);
77
78pub type JournaledState = JournalInner<JournalEntry>;
79
80#[auto_impl::auto_impl(&mut)]
82pub trait DatabaseExt<BLOCK = BlockEnv, TX = TxEnv, SPEC = SpecId>:
83 Database<Error = DatabaseError> + DatabaseCommit + Debug
84{
85 fn snapshot_state(
91 &mut self,
92 journaled_state: &JournaledState,
93 evm_env: &EvmEnv<SPEC, BLOCK>,
94 ) -> U256;
95
96 fn revert_state(
109 &mut self,
110 id: U256,
111 journaled_state: &JournaledState,
112 evm_env: &mut EvmEnv<SPEC, BLOCK>,
113 tx_env: &mut TX,
114 action: RevertStateSnapshotAction,
115 ) -> Option<JournaledState>;
116
117 fn delete_state_snapshot(&mut self, id: U256) -> bool;
122
123 fn delete_state_snapshots(&mut self);
125
126 fn create_select_fork(
130 &mut self,
131 fork: CreateFork,
132 evm_env: &mut EvmEnv<SPEC, BLOCK>,
133 tx_env: &mut TX,
134 journaled_state: &mut JournaledState,
135 ) -> eyre::Result<LocalForkId> {
136 let id = self.create_fork(fork)?;
137 self.select_fork(id, evm_env, tx_env, journaled_state)?;
138 Ok(id)
139 }
140
141 fn create_select_fork_at_transaction(
145 &mut self,
146 fork: CreateFork,
147 evm_env: &mut EvmEnv<SPEC, BLOCK>,
148 tx_env: &mut TX,
149 journaled_state: &mut JournaledState,
150 transaction: B256,
151 ) -> eyre::Result<LocalForkId> {
152 let id = self.create_fork_at_transaction(fork, transaction)?;
153 self.select_fork(id, evm_env, tx_env, journaled_state)?;
154 Ok(id)
155 }
156
157 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId>;
159
160 fn create_fork_at_transaction(
162 &mut self,
163 fork: CreateFork,
164 transaction: B256,
165 ) -> eyre::Result<LocalForkId>;
166
167 fn select_fork(
177 &mut self,
178 id: LocalForkId,
179 evm_env: &mut EvmEnv<SPEC, BLOCK>,
180 tx_env: &mut TX,
181 journaled_state: &mut JournaledState,
182 ) -> eyre::Result<()>;
183
184 fn roll_fork(
192 &mut self,
193 id: Option<LocalForkId>,
194 block_number: u64,
195 evm_env: &mut EvmEnv<SPEC, BLOCK>,
196 tx_env: &mut TX,
197 journaled_state: &mut JournaledState,
198 ) -> eyre::Result<()>;
199
200 fn roll_fork_to_transaction(
209 &mut self,
210 id: Option<LocalForkId>,
211 transaction: B256,
212 evm_env: &mut EvmEnv<SPEC, BLOCK>,
213 tx_env: &mut TX,
214 journaled_state: &mut JournaledState,
215 ) -> eyre::Result<()>;
216
217 fn transact(
219 &mut self,
220 id: Option<LocalForkId>,
221 transaction: B256,
222 evm_env: EvmEnv<SPEC, BLOCK>,
223 tx_env: TX,
224 journaled_state: &mut JournaledState,
225 inspector: &mut dyn EthInspectorExt<BLOCK, TX, SPEC>,
226 ) -> eyre::Result<()>;
227
228 fn transact_from_tx(
230 &mut self,
231 tx_env: &TX,
232 evm_env: EvmEnv<SPEC, BLOCK>,
233 journaled_state: &mut JournaledState,
234 inspector: &mut dyn EthInspectorExt<BLOCK, TX, SPEC>,
235 ) -> eyre::Result<()>;
236
237 fn active_fork_id(&self) -> Option<LocalForkId>;
239
240 fn active_fork_url(&self) -> Option<String>;
242
243 fn is_forked_mode(&self) -> bool {
245 self.active_fork_id().is_some()
246 }
247
248 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId>;
259
260 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId>;
262
263 fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic>;
290
291 fn load_allocs(
295 &mut self,
296 allocs: &BTreeMap<Address, GenesisAccount>,
297 journaled_state: &mut JournaledState,
298 ) -> Result<(), BackendError>;
299
300 fn clone_account(
305 &mut self,
306 source: &GenesisAccount,
307 target: &Address,
308 journaled_state: &mut JournaledState,
309 ) -> Result<(), BackendError>;
310
311 fn is_persistent(&self, acc: &Address) -> bool;
313
314 fn remove_persistent_account(&mut self, account: &Address) -> bool;
316
317 fn add_persistent_account(&mut self, account: Address) -> bool;
319
320 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
322 fn remove_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
323 where
324 Self: Sized,
325 {
326 for acc in accounts {
327 self.remove_persistent_account(&acc);
328 }
329 }
330
331 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
333 fn extend_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
334 where
335 Self: Sized,
336 {
337 for acc in accounts {
338 self.add_persistent_account(acc);
339 }
340 }
341
342 fn allow_cheatcode_access(&mut self, account: Address) -> bool;
346
347 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool;
351
352 fn has_cheatcode_access(&self, account: &Address) -> bool;
354
355 fn ensure_cheatcode_access(&self, account: &Address) -> Result<(), BackendError> {
359 if !self.has_cheatcode_access(account) {
360 return Err(BackendError::NoCheats(*account));
361 }
362 Ok(())
363 }
364
365 fn ensure_cheatcode_access_forking_mode(&self, account: &Address) -> Result<(), BackendError> {
368 if self.is_forked_mode() {
369 return self.ensure_cheatcode_access(account);
370 }
371 Ok(())
372 }
373
374 fn set_blockhash(&mut self, block_number: U256, block_hash: B256);
389}
390
391struct _ObjectSafe(dyn DatabaseExt);
392
393#[derive(Clone, Debug)]
446#[must_use]
447pub struct Backend {
448 forks: MultiFork<AnyNetwork>,
450 mem_db: FoundryEvmInMemoryDB,
452 fork_init_journaled_state: JournaledState,
469 active_fork_ids: Option<(LocalForkId, ForkLookupIndex)>,
473 inner: BackendInner,
475}
476
477impl Backend {
478 pub fn spawn(fork: Option<CreateFork>) -> eyre::Result<Self> {
483 Self::new(MultiFork::spawn(), fork)
484 }
485
486 pub fn new(forks: MultiFork<AnyNetwork>, fork: Option<CreateFork>) -> eyre::Result<Self> {
493 trace!(target: "backend", forking_mode=?fork.is_some(), "creating executor backend");
494 let inner = BackendInner {
496 persistent_accounts: HashSet::from(DEFAULT_PERSISTENT_ACCOUNTS),
497 ..Default::default()
498 };
499
500 let mut backend = Self {
501 forks,
502 mem_db: CacheDB::new(Default::default()),
503 fork_init_journaled_state: inner.new_journaled_state(),
504 active_fork_ids: None,
505 inner,
506 };
507
508 if let Some(fork) = fork {
509 let (fork_id, fork, _) = backend.forks.create_fork(fork)?;
510 let fork_db = ForkDB::new(fork);
511 let fork_ids = backend.inner.insert_new_fork(
512 fork_id.clone(),
513 fork_db,
514 backend.inner.new_journaled_state(),
515 );
516 backend.inner.launched_with_fork = Some((fork_id, fork_ids.0, fork_ids.1));
517 backend.active_fork_ids = Some(fork_ids);
518 }
519
520 trace!(target: "backend", forking_mode=? backend.active_fork_ids.is_some(), "created executor backend");
521
522 Ok(backend)
523 }
524
525 pub(crate) fn new_with_fork(
528 id: &ForkId,
529 fork: Fork,
530 journaled_state: JournaledState,
531 ) -> eyre::Result<Self> {
532 let mut backend = Self::spawn(None)?;
533 let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state);
534 backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1));
535 backend.active_fork_ids = Some(fork_ids);
536 Ok(backend)
537 }
538
539 pub fn clone_empty(&self) -> Self {
541 Self {
542 forks: self.forks.clone(),
543 mem_db: CacheDB::new(Default::default()),
544 fork_init_journaled_state: self.inner.new_journaled_state(),
545 active_fork_ids: None,
546 inner: Default::default(),
547 }
548 }
549
550 pub fn insert_account_info(&mut self, address: Address, account: AccountInfo) {
551 if let Some(db) = self.active_fork_db_mut() {
552 db.insert_account_info(address, account)
553 } else {
554 self.mem_db.insert_account_info(address, account)
555 }
556 }
557
558 pub fn insert_account_storage(
560 &mut self,
561 address: Address,
562 slot: U256,
563 value: U256,
564 ) -> Result<(), DatabaseError> {
565 if let Some(db) = self.active_fork_db_mut() {
566 db.insert_account_storage(address, slot, value)
567 } else {
568 self.mem_db.insert_account_storage(address, slot, value)
569 }
570 }
571
572 pub fn replace_account_storage(
577 &mut self,
578 address: Address,
579 storage: Map<U256, U256>,
580 ) -> Result<(), DatabaseError> {
581 if let Some(db) = self.active_fork_db_mut() {
582 db.replace_account_storage(address, storage)
583 } else {
584 self.mem_db.replace_account_storage(address, storage)
585 }
586 }
587
588 pub fn state_snapshots(
590 &self,
591 ) -> &StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>> {
592 &self.inner.state_snapshots
593 }
594
595 pub fn set_test_contract(&mut self, acc: Address) -> &mut Self {
602 trace!(?acc, "setting test account");
603 self.add_persistent_account(acc);
604 self.allow_cheatcode_access(acc);
605 self
606 }
607
608 pub fn set_caller(&mut self, acc: Address) -> &mut Self {
610 trace!(?acc, "setting caller account");
611 self.inner.caller = Some(acc);
612 self.allow_cheatcode_access(acc);
613 self
614 }
615
616 pub fn set_spec_id(&mut self, spec_id: SpecId) -> &mut Self {
618 trace!(?spec_id, "setting spec ID");
619 self.inner.spec_id = spec_id;
620 self
621 }
622
623 pub fn caller_address(&self) -> Option<Address> {
625 self.inner.caller
626 }
627
628 pub fn has_state_snapshot_failure(&self) -> bool {
634 self.inner.has_state_snapshot_failure
635 }
636
637 pub fn set_state_snapshot_failure(&mut self, has_state_snapshot_failure: bool) {
639 self.inner.has_state_snapshot_failure = has_state_snapshot_failure
640 }
641
642 pub(crate) fn update_fork_db(
644 &self,
645 active_journaled_state: &mut JournaledState,
646 target_fork: &mut Fork,
647 ) {
648 self.update_fork_db_contracts(
649 self.inner.persistent_accounts.iter().copied(),
650 active_journaled_state,
651 target_fork,
652 )
653 }
654
655 pub(crate) fn update_fork_db_contracts(
657 &self,
658 accounts: impl IntoIterator<Item = Address>,
659 active_journaled_state: &mut JournaledState,
660 target_fork: &mut Fork,
661 ) {
662 if let Some(db) = self.active_fork_db() {
663 merge_account_data(accounts, db, active_journaled_state, target_fork)
664 } else {
665 merge_account_data(accounts, &self.mem_db, active_journaled_state, target_fork)
666 }
667 }
668
669 pub fn mem_db(&self) -> &FoundryEvmInMemoryDB {
671 &self.mem_db
672 }
673
674 pub fn is_active_fork(&self, id: LocalForkId) -> bool {
676 self.active_fork_ids.map(|(i, _)| i == id).unwrap_or_default()
677 }
678
679 pub fn is_in_forking_mode(&self) -> bool {
681 self.active_fork().is_some()
682 }
683
684 pub fn active_fork(&self) -> Option<&Fork> {
686 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork(idx))
687 }
688
689 pub fn active_fork_mut(&mut self) -> Option<&mut Fork> {
691 self.active_fork_ids.map(|(_, idx)| self.inner.get_fork_mut(idx))
692 }
693
694 pub fn active_fork_db(&self) -> Option<&ForkDB> {
696 self.active_fork().map(|f| &f.db)
697 }
698
699 pub fn active_fork_db_mut(&mut self) -> Option<&mut ForkDB> {
701 self.active_fork_mut().map(|f| &mut f.db)
702 }
703
704 pub fn db(&self) -> &dyn Database<Error = DatabaseError> {
706 match self.active_fork_db() {
707 Some(fork_db) => fork_db,
708 None => &self.mem_db,
709 }
710 }
711
712 pub fn db_mut(&mut self) -> &mut dyn Database<Error = DatabaseError> {
714 match self.active_fork_ids.map(|(_, idx)| &mut self.inner.get_fork_mut(idx).db) {
715 Some(fork_db) => fork_db,
716 None => &mut self.mem_db,
717 }
718 }
719
720 pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot {
722 if let Some((id, idx)) = self.active_fork_ids {
723 let fork = self.inner.get_fork(idx).clone();
724 let fork_id = self.inner.ensure_fork_id(id).cloned().expect("Exists; qed");
725 BackendDatabaseSnapshot::Forked(id, fork_id, idx, Box::new(fork))
726 } else {
727 BackendDatabaseSnapshot::InMemory(self.mem_db.clone())
728 }
729 }
730
731 pub fn merged_logs(&self, mut logs: Vec<Log>) -> Vec<Log> {
733 if let Some((_, active)) = self.active_fork_ids {
734 let mut all_logs = Vec::with_capacity(logs.len());
735
736 self.inner
737 .forks
738 .iter()
739 .enumerate()
740 .filter_map(|(idx, f)| f.as_ref().map(|f| (idx, f)))
741 .for_each(|(idx, f)| {
742 if idx == active {
743 all_logs.append(&mut logs);
744 } else {
745 all_logs.extend(f.journaled_state.logs.clone())
746 }
747 });
748 return all_logs;
749 }
750
751 logs
752 }
753
754 pub(crate) fn initialize(&mut self, spec_id: SpecId, caller: Address, tx_kind: TxKind) {
758 self.set_caller(caller);
759 self.set_spec_id(spec_id);
760
761 let test_contract = match tx_kind {
762 TxKind::Call(to) => to,
763 TxKind::Create => {
764 let nonce =
765 self.basic_ref(caller).map(|b| b.unwrap_or_default().nonce).unwrap_or_default();
766 caller.create(nonce)
767 }
768 };
769 self.set_test_contract(test_contract);
770 }
771
772 #[instrument(name = "inspect", level = "debug", skip_all)]
777 pub fn inspect<I: EthInspectorExt>(
778 &mut self,
779 evm_env: &mut EvmEnv,
780 tx_env: &mut TxEnv,
781 inspector: I,
782 ) -> eyre::Result<ResultAndState> {
783 self.initialize(evm_env.cfg_env.spec, tx_env.caller, tx_env.kind);
784 let mut evm = crate::evm::new_eth_evm_with_inspector(
785 self,
786 evm_env.to_owned(),
787 tx_env.to_owned(),
788 inspector,
789 );
790
791 let res = evm.transact(tx_env.clone()).wrap_err("EVM error")?;
792
793 *evm_env = EvmEnv::new(evm.cfg.clone(), evm.block.clone());
794 *tx_env = evm.tx.clone();
795
796 Ok(res)
797 }
798
799 pub fn is_existing_precompile(&self, addr: &Address) -> bool {
801 self.inner.precompiles().contains(addr)
802 }
803
804 #[inline]
806 fn set_init_journaled_state(&mut self, journaled_state: JournaledState) {
807 trace!("recording fork init journaled_state");
808 self.fork_init_journaled_state = journaled_state;
809 }
810
811 fn prepare_init_journal_state(&mut self) -> Result<(), BackendError> {
821 let loaded_accounts = self
822 .fork_init_journaled_state
823 .state
824 .iter()
825 .filter(|(addr, _)| !self.is_existing_precompile(addr) && !self.is_persistent(addr))
826 .map(|(addr, _)| addr)
827 .copied()
828 .collect::<Vec<_>>();
829
830 for fork in self.inner.forks_iter_mut() {
831 let mut journaled_state = self.fork_init_journaled_state.clone();
832 for loaded_account in loaded_accounts.iter().copied() {
833 trace!(?loaded_account, "replacing account on init");
834 let init_account =
835 journaled_state.state.get_mut(&loaded_account).expect("exists; qed");
836
837 if init_account.is_created() {
841 trace!(?loaded_account, "skipping created account");
842 continue;
843 }
844
845 let fork_account = Database::basic(&mut fork.db, loaded_account)?
848 .ok_or(BackendError::MissingAccount(loaded_account))?;
849 init_account.info = fork_account;
850 }
851 fork.journaled_state = journaled_state;
852 }
853 Ok(())
854 }
855
856 fn get_block_number_and_block_for_transaction(
858 &self,
859 id: LocalForkId,
860 transaction: B256,
861 ) -> eyre::Result<(u64, AnyRpcBlock)> {
862 let fork = self.inner.get_fork_by_id(id)?;
863 let tx = fork.backend().get_transaction(transaction)?;
864
865 if let Some(tx_block) = tx.block_number {
867 let block = fork.backend().get_full_block(tx_block)?;
868
869 let fork_block = tx_block - 1;
872 Ok((fork_block, block))
873 } else {
874 let block = fork.backend().get_full_block(BlockNumberOrTag::Latest)?;
875
876 let number = block.header.number();
877
878 Ok((number, block))
879 }
880 }
881
882 pub fn replay_until(
886 &mut self,
887 id: LocalForkId,
888 mut evm_env: EvmEnv,
889 mut tx_env: TxEnv,
890 tx_hash: B256,
891 journaled_state: &mut JournaledState,
892 ) -> eyre::Result<Option<Transaction<AnyTxEnvelope>>> {
893 trace!(?id, ?tx_hash, "replay until transaction");
894
895 let persistent_accounts = self.inner.persistent_accounts.clone();
896 let fork_id = self.ensure_fork_id(id)?.clone();
897
898 let fork = self.inner.get_fork_by_id_mut(id)?;
899 let full_block =
900 fork.backend().get_full_block(evm_env.block_env.number.saturating_to::<u64>())?;
901
902 for tx in full_block.inner.transactions.txns() {
903 if is_known_system_sender(tx.inner().inner.signer())
906 || tx.ty() == SYSTEM_TRANSACTION_TYPE
907 {
908 trace!(tx=?tx.tx_hash(), "skipping system transaction");
909 continue;
910 }
911
912 if tx.tx_hash() == tx_hash {
913 return Ok(Some(tx.inner.clone()));
915 }
916 trace!(tx=?tx.tx_hash(), "committing transaction");
917
918 commit_transaction(
919 tx,
920 &mut evm_env,
921 &mut tx_env,
922 journaled_state,
923 fork,
924 &fork_id,
925 &persistent_accounts,
926 &mut NoOpInspector,
927 )?;
928 }
929
930 Ok(None)
931 }
932}
933
934impl DatabaseExt for Backend {
935 fn snapshot_state(&mut self, journaled_state: &JournaledState, evm_env: &EvmEnv) -> U256 {
936 trace!("create snapshot");
937 let id = self.inner.state_snapshots.insert(BackendStateSnapshot::new(
938 self.create_db_snapshot(),
939 journaled_state.clone(),
940 evm_env.clone(),
941 ));
942 trace!(target: "backend", "Created new snapshot {}", id);
943 id
944 }
945
946 fn revert_state(
947 &mut self,
948 id: U256,
949 current_state: &JournaledState,
950 evm_env: &mut EvmEnv,
951 tx_env: &mut TxEnv,
952 action: RevertStateSnapshotAction,
953 ) -> Option<JournaledState> {
954 trace!(?id, "revert snapshot");
955 if let Some(mut snapshot) = self.inner.state_snapshots.remove_at(id) {
956 if action.is_keep() {
958 self.inner.state_snapshots.insert_at(snapshot.clone(), id);
959 }
960
961 if let Some(account) = current_state.state.get(&CHEATCODE_ADDRESS)
966 && let Some(slot) = account.storage.get(&GLOBAL_FAIL_SLOT)
967 && !slot.present_value.is_zero()
968 {
969 self.set_state_snapshot_failure(true);
970 }
971
972 snapshot.merge(current_state);
974 let BackendStateSnapshot { db, mut journaled_state, snap_evm_env } = snapshot;
975 match db {
976 BackendDatabaseSnapshot::InMemory(mem_db) => {
977 self.mem_db = mem_db;
978 }
979 BackendDatabaseSnapshot::Forked(id, fork_id, idx, mut fork) => {
980 let caller = tx_env.caller;
984 journaled_state.state.entry(caller).or_insert_with(|| {
985 let caller_account = current_state
986 .state
987 .get(&caller)
988 .map(|acc| acc.info.clone())
989 .unwrap_or_default();
990
991 if !fork.db.cache.accounts.contains_key(&caller) {
992 fork.db.insert_account_info(caller, caller_account.clone());
994 }
995 caller_account.into()
996 });
997 self.inner.revert_state_snapshot(id, fork_id, idx, *fork);
998 self.active_fork_ids = Some((id, idx))
999 }
1000 }
1001
1002 update_current_env_with_fork_env(evm_env, tx_env, snap_evm_env);
1003 trace!(target: "backend", "Reverted snapshot {}", id);
1004
1005 Some(journaled_state)
1006 } else {
1007 warn!(target: "backend", "No snapshot to revert for {}", id);
1008 None
1009 }
1010 }
1011
1012 fn delete_state_snapshot(&mut self, id: U256) -> bool {
1013 self.inner.state_snapshots.remove_at(id).is_some()
1014 }
1015
1016 fn delete_state_snapshots(&mut self) {
1017 self.inner.state_snapshots.clear()
1018 }
1019
1020 fn create_fork(&mut self, create_fork: CreateFork) -> eyre::Result<LocalForkId> {
1021 trace!("create fork");
1022 let (fork_id, fork, _) = self.forks.create_fork(create_fork)?;
1023
1024 let fork_db = ForkDB::new(fork);
1025 let (id, _) =
1026 self.inner.insert_new_fork(fork_id, fork_db, self.fork_init_journaled_state.clone());
1027 Ok(id)
1028 }
1029
1030 fn create_fork_at_transaction(
1031 &mut self,
1032 fork: CreateFork,
1033 transaction: B256,
1034 ) -> eyre::Result<LocalForkId> {
1035 trace!(?transaction, "create fork at transaction");
1036 let id = self.create_fork(fork)?;
1037 let fork_id = self.ensure_fork_id(id).cloned()?;
1038 let mut evm_env = self
1039 .forks
1040 .get_evm_env(fork_id)?
1041 .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exist", id))?;
1042
1043 self.roll_fork_to_transaction(
1046 Some(id),
1047 transaction,
1048 &mut evm_env,
1049 &mut TxEnv::default(),
1050 &mut self.inner.new_journaled_state(),
1051 )?;
1052
1053 Ok(id)
1054 }
1055
1056 fn select_fork(
1059 &mut self,
1060 id: LocalForkId,
1061 evm_env: &mut EvmEnv,
1062 tx_env: &mut TxEnv,
1063 active_journaled_state: &mut JournaledState,
1064 ) -> eyre::Result<()> {
1065 trace!(?id, "select fork");
1066 if self.is_active_fork(id) {
1067 return Ok(());
1069 }
1070
1071 if let Some(active_fork_id) = self.active_fork_id() {
1074 self.forks.update_block(
1075 self.ensure_fork_id(active_fork_id).cloned()?,
1076 evm_env.block_env.number,
1077 evm_env.block_env.timestamp,
1078 )?;
1079 }
1080
1081 let fork_id = self.ensure_fork_id(id).cloned()?;
1082 let idx = self.inner.ensure_fork_index(&fork_id)?;
1083 let fork_evm_env = self
1084 .forks
1085 .get_evm_env(fork_id)?
1086 .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exist", id))?;
1087
1088 if let Some(active) = self.active_fork_mut() {
1091 active.journaled_state = active_journaled_state.clone();
1092
1093 let caller = tx_env.caller;
1094 let caller_account = active.journaled_state.state.get(&tx_env.caller).cloned();
1095 let target_fork = self.inner.get_fork_mut(idx);
1096
1097 if target_fork.journaled_state.depth == 0 {
1099 if let Some(mut acc) = caller_account {
1101 let fork_account = Database::basic(&mut target_fork.db, caller)?
1102 .ok_or(BackendError::MissingAccount(caller))?;
1103
1104 acc.info = fork_account;
1105 target_fork.journaled_state.state.insert(caller, acc);
1106 }
1107 }
1108 } else {
1109 self.set_init_journaled_state(active_journaled_state.clone());
1116 self.prepare_init_journal_state()?;
1117
1118 self.fork_init_journaled_state.depth = 0;
1120 }
1121
1122 {
1123 let mut fork = self.inner.take_fork(idx);
1125
1126 let persistent_accounts = self.inner.persistent_accounts.clone();
1134 if let Some(db) = self.active_fork_db_mut() {
1135 for addr in persistent_accounts {
1136 let Ok(db_account) = db.load_account(addr) else { continue };
1137
1138 let Some(fork_account) = fork.journaled_state.state.get_mut(&addr) else {
1139 continue;
1140 };
1141
1142 for (key, val) in &db_account.storage {
1143 if let Some(fork_storage) = fork_account.storage.get_mut(key) {
1144 fork_storage.present_value = *val;
1145 }
1146 }
1147 }
1148 }
1149
1150 fork.journaled_state.depth = active_journaled_state.depth;
1155
1156 let caller = tx_env.caller;
1160 fork.journaled_state.state.entry(caller).or_insert_with(|| {
1161 let caller_account = active_journaled_state
1162 .state
1163 .get(&tx_env.caller)
1164 .map(|acc| acc.info.clone())
1165 .unwrap_or_default();
1166
1167 if !fork.db.cache.accounts.contains_key(&caller) {
1168 fork.db.insert_account_info(caller, caller_account.clone());
1170 }
1171 caller_account.into()
1172 });
1173
1174 self.update_fork_db(active_journaled_state, &mut fork);
1175
1176 self.inner.set_fork(idx, fork);
1178 }
1179
1180 self.active_fork_ids = Some((id, idx));
1181 update_current_env_with_fork_env(evm_env, tx_env, fork_evm_env);
1183
1184 Ok(())
1185 }
1186
1187 fn roll_fork(
1190 &mut self,
1191 id: Option<LocalForkId>,
1192 block_number: u64,
1193 evm_env: &mut EvmEnv,
1194 tx_env: &mut TxEnv,
1195 journaled_state: &mut JournaledState,
1196 ) -> eyre::Result<()> {
1197 trace!(?id, ?block_number, "roll fork");
1198 let id = self.ensure_fork(id)?;
1199 let (fork_id, backend, fork_env) =
1200 self.forks.roll_fork(self.inner.ensure_fork_id(id).cloned()?, block_number)?;
1201 self.inner.roll_fork(id, fork_id, backend)?;
1203
1204 if let Some((active_id, active_idx)) = self.active_fork_ids {
1205 if active_id == id {
1207 update_current_env_with_fork_env(evm_env, tx_env, fork_env);
1210
1211 let mut persistent_addrs = self.inner.persistent_accounts.clone();
1216 persistent_addrs.extend(self.caller_address());
1218
1219 let active = self.inner.get_fork_mut(active_idx);
1220 active.journaled_state = self.fork_init_journaled_state.clone();
1221 active.journaled_state.depth = journaled_state.depth;
1222
1223 for addr in persistent_addrs {
1224 merge_journaled_state_data(addr, journaled_state, &mut active.journaled_state);
1225 }
1226
1227 for (addr, acc) in &journaled_state.state {
1235 if acc.is_created() {
1236 if acc.is_touched() {
1237 merge_journaled_state_data(
1238 *addr,
1239 journaled_state,
1240 &mut active.journaled_state,
1241 );
1242 }
1243 } else {
1244 let _ = active.journaled_state.load_account(&mut active.db, *addr);
1245 }
1246 }
1247
1248 *journaled_state = active.journaled_state.clone();
1249 }
1250 }
1251 Ok(())
1252 }
1253
1254 fn roll_fork_to_transaction(
1255 &mut self,
1256 id: Option<LocalForkId>,
1257 transaction: B256,
1258 evm_env: &mut EvmEnv,
1259 tx_env: &mut TxEnv,
1260 journaled_state: &mut JournaledState,
1261 ) -> eyre::Result<()> {
1262 trace!(?id, ?transaction, "roll fork to transaction");
1263 let id = self.ensure_fork(id)?;
1264
1265 let (fork_block, block) =
1266 self.get_block_number_and_block_for_transaction(id, transaction)?;
1267
1268 self.roll_fork(Some(id), fork_block, evm_env, tx_env, journaled_state)?;
1272
1273 update_env_block(evm_env, block.header());
1275
1276 let _ = self
1279 .forks
1280 .update_block_env(self.inner.ensure_fork_id(id).cloned()?, evm_env.block_env.clone());
1281
1282 self.replay_until(id, evm_env.clone(), tx_env.clone(), transaction, journaled_state)?;
1284
1285 Ok(())
1286 }
1287
1288 fn transact(
1289 &mut self,
1290 maybe_id: Option<LocalForkId>,
1291 transaction: B256,
1292 mut evm_env: EvmEnv,
1293 mut tx_env: TxEnv,
1294 journaled_state: &mut JournaledState,
1295 inspector: &mut dyn EthInspectorExt,
1296 ) -> eyre::Result<()> {
1297 trace!(?maybe_id, ?transaction, "execute transaction");
1298 let persistent_accounts = self.inner.persistent_accounts.clone();
1299 let id = self.ensure_fork(maybe_id)?;
1300 let fork_id = self.ensure_fork_id(id).cloned()?;
1301
1302 let tx = {
1303 let fork = self.inner.get_fork_by_id_mut(id)?;
1304 fork.backend().get_transaction(transaction)?
1305 };
1306
1307 let (_fork_block, block) =
1314 self.get_block_number_and_block_for_transaction(id, transaction)?;
1315 update_env_block(&mut evm_env, block.header());
1316
1317 let fork = self.inner.get_fork_by_id_mut(id)?;
1318 commit_transaction(
1319 &tx,
1320 &mut evm_env,
1321 &mut tx_env,
1322 journaled_state,
1323 fork,
1324 &fork_id,
1325 &persistent_accounts,
1326 inspector,
1327 )
1328 }
1329
1330 fn transact_from_tx(
1331 &mut self,
1332 tx_env: &TxEnv,
1333 evm_env: EvmEnv,
1334 journaled_state: &mut JournaledState,
1335 inspector: &mut dyn EthInspectorExt,
1336 ) -> eyre::Result<()> {
1337 trace!(?tx_env, "execute signed transaction");
1338
1339 self.commit(journaled_state.state.clone());
1340
1341 let res = {
1342 let mut db = self.clone();
1343 let mut evm =
1344 new_eth_evm_with_inspector(&mut db, evm_env, tx_env.to_owned(), inspector);
1345 evm.journaled_state.depth = journaled_state.depth + 1;
1346 evm.transact_raw(tx_env.to_owned())?
1347 };
1348
1349 self.commit(res.state);
1350 update_state(&mut journaled_state.state, self, None)?;
1351
1352 Ok(())
1353 }
1354
1355 fn active_fork_id(&self) -> Option<LocalForkId> {
1356 self.active_fork_ids.map(|(id, _)| id)
1357 }
1358
1359 fn active_fork_url(&self) -> Option<String> {
1360 let fork = self.inner.issued_local_fork_ids.get(&self.active_fork_id()?)?;
1361 self.forks.get_fork_url(fork.clone()).ok()?
1362 }
1363
1364 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
1365 if let Some(id) = id {
1366 if self.inner.issued_local_fork_ids.contains_key(&id) {
1367 return Ok(id);
1368 }
1369 eyre::bail!("Requested fork `{}` does not exist", id)
1370 }
1371 if let Some(id) = self.active_fork_id() { Ok(id) } else { eyre::bail!("No fork active") }
1372 }
1373
1374 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1375 self.inner.ensure_fork_id(id)
1376 }
1377
1378 fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic> {
1379 let active_id = self.active_fork_id()?;
1380 let active_fork = self.active_fork()?;
1381
1382 if self.inner.forks.len() == 1 {
1383 return None;
1386 }
1387
1388 if !active_fork.is_contract(callee) && !is_contract_in_state(evm_state, callee) {
1389 let mut available_on = Vec::new();
1391 for (id, fork) in self.inner.forks_iter().filter(|(id, _)| *id != active_id) {
1392 trace!(?id, address=?callee, "checking if account exists");
1393 if fork.is_contract(callee) {
1394 available_on.push(id);
1395 }
1396 }
1397
1398 return if available_on.is_empty() {
1399 Some(RevertDiagnostic::ContractDoesNotExist {
1400 contract: callee,
1401 active: active_id,
1402 persistent: self.is_persistent(&callee),
1403 })
1404 } else {
1405 Some(RevertDiagnostic::ContractExistsOnOtherForks {
1408 contract: callee,
1409 active: active_id,
1410 available_on,
1411 })
1412 };
1413 }
1414 None
1415 }
1416
1417 fn load_allocs(
1421 &mut self,
1422 allocs: &BTreeMap<Address, GenesisAccount>,
1423 journaled_state: &mut JournaledState,
1424 ) -> Result<(), BackendError> {
1425 for (addr, acc) in allocs {
1427 self.clone_account(acc, addr, journaled_state)?;
1428 }
1429
1430 Ok(())
1431 }
1432
1433 fn clone_account(
1438 &mut self,
1439 source: &GenesisAccount,
1440 target: &Address,
1441 journaled_state: &mut JournaledState,
1442 ) -> Result<(), BackendError> {
1443 let mut state_acc = journaled_state.load_account_mut(self, *target)?;
1446
1447 if let Some(bytecode) = source.code.as_ref() {
1449 let bytecode_hash = keccak256(bytecode);
1450 let bytecode = Bytecode::new_raw(bytecode.0.clone().into());
1451 state_acc.set_code(bytecode_hash, bytecode);
1452 }
1453
1454 state_acc.set_balance(source.balance);
1456
1457 if let Some(acc) = journaled_state.state.get_mut(target) {
1459 if let Some(storage) = source.storage.as_ref() {
1460 for (slot, value) in storage {
1461 let slot = U256::from_be_bytes(slot.0);
1462 acc.storage.insert(
1463 slot,
1464 EvmStorageSlot::new_changed(
1465 acc.storage.get(&slot).map(|s| s.present_value).unwrap_or_default(),
1466 U256::from_be_bytes(value.0),
1467 0,
1468 ),
1469 );
1470 }
1471 }
1472
1473 acc.info.nonce = source.nonce.unwrap_or_default();
1475 };
1476
1477 journaled_state.touch(*target);
1479
1480 Ok(())
1481 }
1482
1483 fn add_persistent_account(&mut self, account: Address) -> bool {
1484 trace!(?account, "add persistent account");
1485 self.inner.persistent_accounts.insert(account)
1486 }
1487
1488 fn remove_persistent_account(&mut self, account: &Address) -> bool {
1489 trace!(?account, "remove persistent account");
1490 self.inner.persistent_accounts.remove(account)
1491 }
1492
1493 fn is_persistent(&self, acc: &Address) -> bool {
1494 self.inner.persistent_accounts.contains(acc)
1495 }
1496
1497 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
1498 trace!(?account, "allow cheatcode access");
1499 self.inner.cheatcode_access_accounts.insert(account)
1500 }
1501
1502 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
1503 trace!(?account, "revoke cheatcode access");
1504 self.inner.cheatcode_access_accounts.remove(account)
1505 }
1506
1507 fn has_cheatcode_access(&self, account: &Address) -> bool {
1508 self.inner.cheatcode_access_accounts.contains(account)
1509 }
1510
1511 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
1512 if let Some(db) = self.active_fork_db_mut() {
1513 db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1514 } else {
1515 self.mem_db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1516 }
1517 }
1518}
1519
1520impl DatabaseRef for Backend {
1521 type Error = DatabaseError;
1522
1523 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1524 if let Some(db) = self.active_fork_db() {
1525 db.basic_ref(address)
1526 } else {
1527 Ok(self.mem_db.basic_ref(address)?)
1528 }
1529 }
1530
1531 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1532 if let Some(db) = self.active_fork_db() {
1533 db.code_by_hash_ref(code_hash)
1534 } else {
1535 Ok(self.mem_db.code_by_hash_ref(code_hash)?)
1536 }
1537 }
1538
1539 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
1540 if let Some(db) = self.active_fork_db() {
1541 DatabaseRef::storage_ref(db, address, index)
1542 } else {
1543 Ok(DatabaseRef::storage_ref(&self.mem_db, address, index)?)
1544 }
1545 }
1546
1547 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
1548 if let Some(db) = self.active_fork_db() {
1549 db.block_hash_ref(number)
1550 } else {
1551 Ok(self.mem_db.block_hash_ref(number)?)
1552 }
1553 }
1554}
1555
1556impl DatabaseCommit for Backend {
1557 fn commit(&mut self, changes: Map<Address, Account>) {
1558 if let Some(db) = self.active_fork_db_mut() {
1559 db.commit(changes)
1560 } else {
1561 self.mem_db.commit(changes)
1562 }
1563 }
1564}
1565
1566impl Database for Backend {
1567 type Error = DatabaseError;
1568 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1569 if let Some(db) = self.active_fork_db_mut() {
1570 Ok(db.basic(address)?)
1571 } else {
1572 Ok(self.mem_db.basic(address)?)
1573 }
1574 }
1575
1576 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1577 if let Some(db) = self.active_fork_db_mut() {
1578 Ok(db.code_by_hash(code_hash)?)
1579 } else {
1580 Ok(self.mem_db.code_by_hash(code_hash)?)
1581 }
1582 }
1583
1584 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
1585 if let Some(db) = self.active_fork_db_mut() {
1586 Ok(Database::storage(db, address, index)?)
1587 } else {
1588 Ok(Database::storage(&mut self.mem_db, address, index)?)
1589 }
1590 }
1591
1592 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
1593 if let Some(db) = self.active_fork_db_mut() {
1594 Ok(db.block_hash(number)?)
1595 } else {
1596 Ok(self.mem_db.block_hash(number)?)
1597 }
1598 }
1599}
1600
1601#[derive(Clone, Debug)]
1603pub enum BackendDatabaseSnapshot {
1604 InMemory(FoundryEvmInMemoryDB),
1606 Forked(LocalForkId, ForkId, ForkLookupIndex, Box<Fork>),
1608}
1609
1610#[derive(Clone, Debug)]
1612pub struct Fork {
1613 db: ForkDB,
1614 journaled_state: JournaledState,
1615}
1616
1617impl Fork {
1618 pub fn backend(&self) -> &SharedBackend {
1620 &self.db.db
1621 }
1622
1623 pub fn is_contract(&self, acc: Address) -> bool {
1625 if let Ok(Some(acc)) = self.db.basic_ref(acc)
1626 && acc.code_hash != KECCAK_EMPTY
1627 {
1628 return true;
1629 }
1630 is_contract_in_state(&self.journaled_state.state, acc)
1631 }
1632}
1633
1634#[derive(Clone, Debug)]
1636pub struct BackendInner {
1637 pub launched_with_fork: Option<(ForkId, LocalForkId, ForkLookupIndex)>,
1642 pub issued_local_fork_ids: HashMap<LocalForkId, ForkId>,
1654 pub created_forks: HashMap<ForkId, ForkLookupIndex>,
1657 pub forks: Vec<Option<Fork>>,
1660 pub state_snapshots: StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>>,
1662 pub has_state_snapshot_failure: bool,
1672 pub caller: Option<Address>,
1674 pub next_fork_id: LocalForkId,
1676 pub persistent_accounts: HashSet<Address>,
1680 pub spec_id: SpecId,
1682 pub cheatcode_access_accounts: HashSet<Address>,
1684}
1685
1686impl BackendInner {
1687 pub fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1688 self.issued_local_fork_ids
1689 .get(&id)
1690 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1691 }
1692
1693 pub fn ensure_fork_index(&self, id: &ForkId) -> eyre::Result<ForkLookupIndex> {
1694 self.created_forks
1695 .get(id)
1696 .copied()
1697 .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1698 }
1699
1700 pub fn ensure_fork_index_by_local_id(&self, id: LocalForkId) -> eyre::Result<ForkLookupIndex> {
1701 self.ensure_fork_index(self.ensure_fork_id(id)?)
1702 }
1703
1704 #[track_caller]
1706 fn get_fork(&self, idx: ForkLookupIndex) -> &Fork {
1707 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1708 self.forks[idx].as_ref().unwrap()
1709 }
1710
1711 #[track_caller]
1713 fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork {
1714 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1715 self.forks[idx].as_mut().unwrap()
1716 }
1717
1718 #[track_caller]
1720 fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> {
1721 let idx = self.ensure_fork_index_by_local_id(id)?;
1722 Ok(self.get_fork_mut(idx))
1723 }
1724
1725 #[track_caller]
1727 fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> {
1728 let idx = self.ensure_fork_index_by_local_id(id)?;
1729 Ok(self.get_fork(idx))
1730 }
1731
1732 fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork {
1734 debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1735 self.forks[idx].take().unwrap()
1736 }
1737
1738 fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) {
1739 self.forks[idx] = Some(fork)
1740 }
1741
1742 pub fn forks_iter(&self) -> impl Iterator<Item = (LocalForkId, &Fork)> + '_ {
1744 self.issued_local_fork_ids
1745 .iter()
1746 .map(|(id, fork_id)| (*id, self.get_fork(self.created_forks[fork_id])))
1747 }
1748
1749 pub fn forks_iter_mut(&mut self) -> impl Iterator<Item = &mut Fork> + '_ {
1751 self.forks.iter_mut().filter_map(|f| f.as_mut())
1752 }
1753
1754 pub fn revert_state_snapshot(
1756 &mut self,
1757 id: LocalForkId,
1758 fork_id: ForkId,
1759 idx: ForkLookupIndex,
1760 fork: Fork,
1761 ) {
1762 self.created_forks.insert(fork_id.clone(), idx);
1763 self.issued_local_fork_ids.insert(id, fork_id);
1764 self.set_fork(idx, fork)
1765 }
1766
1767 pub fn update_fork_mapping(
1769 &mut self,
1770 id: LocalForkId,
1771 fork_id: ForkId,
1772 db: ForkDB,
1773 journaled_state: JournaledState,
1774 ) -> ForkLookupIndex {
1775 let idx = self.forks.len();
1776 self.issued_local_fork_ids.insert(id, fork_id.clone());
1777 self.created_forks.insert(fork_id, idx);
1778
1779 let fork = Fork { db, journaled_state };
1780 self.forks.push(Some(fork));
1781 idx
1782 }
1783
1784 pub fn roll_fork(
1785 &mut self,
1786 id: LocalForkId,
1787 new_fork_id: ForkId,
1788 backend: SharedBackend,
1789 ) -> eyre::Result<ForkLookupIndex> {
1790 let fork_id = self.ensure_fork_id(id)?;
1791 let idx = self.ensure_fork_index(fork_id)?;
1792
1793 if let Some(active) = self.forks[idx].as_mut() {
1794 let mut new_db = ForkDB::new(backend);
1796 for addr in self.persistent_accounts.iter().copied() {
1797 merge_db_account_data(addr, &active.db, &mut new_db);
1798 }
1799 active.db = new_db;
1800 }
1801 self.issued_local_fork_ids.insert(id, new_fork_id.clone());
1803 self.created_forks.insert(new_fork_id, idx);
1804 Ok(idx)
1805 }
1806
1807 pub fn insert_new_fork(
1811 &mut self,
1812 fork_id: ForkId,
1813 db: ForkDB,
1814 journaled_state: JournaledState,
1815 ) -> (LocalForkId, ForkLookupIndex) {
1816 let idx = self.forks.len();
1817 self.created_forks.insert(fork_id.clone(), idx);
1818 let id = self.next_id();
1819 self.issued_local_fork_ids.insert(id, fork_id);
1820 let fork = Fork { db, journaled_state };
1821 self.forks.push(Some(fork));
1822 (id, idx)
1823 }
1824
1825 fn next_id(&mut self) -> U256 {
1826 let id = self.next_fork_id;
1827 self.next_fork_id += U256::from(1);
1828 id
1829 }
1830
1831 pub fn len(&self) -> usize {
1833 self.issued_local_fork_ids.len()
1834 }
1835
1836 pub fn is_empty(&self) -> bool {
1838 self.issued_local_fork_ids.is_empty()
1839 }
1840
1841 pub fn precompiles(&self) -> &'static Precompiles {
1842 Precompiles::new(PrecompileSpecId::from_spec_id(self.spec_id))
1843 }
1844
1845 pub fn new_journaled_state(&self) -> JournaledState {
1847 let mut journal = {
1848 let mut journal_inner = JournalInner::new();
1849 journal_inner.set_spec_id(self.spec_id);
1850 journal_inner
1851 };
1852 journal
1853 .warm_addresses
1854 .set_precompile_addresses(self.precompiles().addresses().copied().collect());
1855 journal
1856 }
1857}
1858
1859impl Default for BackendInner {
1860 fn default() -> Self {
1861 Self {
1862 launched_with_fork: None,
1863 issued_local_fork_ids: Default::default(),
1864 created_forks: Default::default(),
1865 forks: vec![],
1866 state_snapshots: Default::default(),
1867 has_state_snapshot_failure: false,
1868 caller: None,
1869 next_fork_id: Default::default(),
1870 persistent_accounts: Default::default(),
1871 spec_id: SpecId::default(),
1872 cheatcode_access_accounts: HashSet::from([
1875 CHEATCODE_ADDRESS,
1876 TEST_CONTRACT_ADDRESS,
1877 CALLER,
1878 ]),
1879 }
1880 }
1881}
1882
1883pub(crate) fn update_current_env_with_fork_env<
1885 SPEC,
1886 BLOCK: FoundryBlock,
1887 TX: FoundryTransaction,
1888>(
1889 evm_env: &mut EvmEnv<SPEC, BLOCK>,
1890 tx_env: &mut TX,
1891 fork_evm_env: EvmEnv<SPEC, BLOCK>,
1892) {
1893 tx_env.set_chain_id(Some(fork_evm_env.cfg_env.chain_id));
1894 *evm_env = fork_evm_env;
1895}
1896
1897pub(crate) fn merge_account_data<ExtDB: DatabaseRef>(
1900 accounts: impl IntoIterator<Item = Address>,
1901 active: &CacheDB<ExtDB>,
1902 active_journaled_state: &mut JournaledState,
1903 target_fork: &mut Fork,
1904) {
1905 for addr in accounts.into_iter() {
1906 merge_db_account_data(addr, active, &mut target_fork.db);
1907 merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state);
1908 }
1909
1910 *active_journaled_state = target_fork.journaled_state.clone();
1911}
1912
1913fn merge_journaled_state_data(
1915 addr: Address,
1916 active_journaled_state: &JournaledState,
1917 fork_journaled_state: &mut JournaledState,
1918) {
1919 if let Some(mut acc) = active_journaled_state.state.get(&addr).cloned() {
1920 trace!(?addr, "updating journaled_state account data");
1921 if let Some(fork_account) = fork_journaled_state.state.get_mut(&addr) {
1922 fork_account.storage.extend(std::mem::take(&mut acc.storage));
1924 std::mem::swap(&mut fork_account.storage, &mut acc.storage);
1926 }
1927 fork_journaled_state.state.insert(addr, acc);
1928 }
1929}
1930
1931fn merge_db_account_data<ExtDB: DatabaseRef>(
1933 addr: Address,
1934 active: &CacheDB<ExtDB>,
1935 fork_db: &mut ForkDB,
1936) {
1937 trace!(?addr, "merging database data");
1938
1939 let Some(acc) = active.cache.accounts.get(&addr) else { return };
1940
1941 if let Some(code) = active.cache.contracts.get(&acc.info.code_hash) {
1943 trace!("merging contract cache");
1944 fork_db.cache.contracts.insert(acc.info.code_hash, code.clone());
1945 }
1946
1947 use std::collections::hash_map::Entry;
1949 match fork_db.cache.accounts.entry(addr) {
1950 Entry::Vacant(vacant) => {
1951 trace!("target account not present - inserting from active");
1952 vacant.insert(acc.clone());
1955 }
1956 Entry::Occupied(mut occupied) => {
1957 trace!("target account present - merging storage slots");
1958 let fork_account = occupied.get_mut();
1961 fork_account.storage.extend(&acc.storage);
1962 }
1963 }
1964}
1965
1966fn is_contract_in_state(evm_state: &EvmState, acc: Address) -> bool {
1968 evm_state.get(&acc).map(|acc| acc.info.code_hash != KECCAK_EMPTY).unwrap_or_default()
1969}
1970
1971fn update_env_block<SPEC, BLOCK: FoundryBlock>(
1973 evm_env: &mut EvmEnv<SPEC, BLOCK>,
1974 header: &impl BlockHeader,
1975) {
1976 let block_env = &mut evm_env.block_env;
1977 block_env.set_timestamp(U256::from(header.timestamp()));
1978 block_env.set_beneficiary(header.beneficiary());
1979 block_env.set_difficulty(header.difficulty());
1980 block_env.set_prevrandao(header.mix_hash());
1981 block_env.set_basefee(header.base_fee_per_gas().unwrap_or_default());
1982 block_env.set_gas_limit(header.gas_limit());
1983 block_env.set_number(U256::from(header.number()));
1984
1985 if let Some(excess_blob_gas) = header.excess_blob_gas() {
1986 evm_env.block_env.set_blob_excess_gas_and_price(
1987 excess_blob_gas,
1988 get_blob_base_fee_update_fraction(evm_env.cfg_env.chain_id, header.timestamp()),
1989 );
1990 }
1991}
1992
1993#[allow(clippy::too_many_arguments)]
1996fn commit_transaction(
1997 tx: &AnyRpcTransaction,
1998 evm_env: &mut EvmEnv,
1999 tx_env: &mut TxEnv,
2000 journaled_state: &mut JournaledState,
2001 fork: &mut Fork,
2002 fork_id: &ForkId,
2003 persistent_accounts: &HashSet<Address>,
2004 inspector: &mut dyn EthInspectorExt,
2005) -> eyre::Result<()> {
2006 if let Some(tx_envelope) = tx.as_envelope() {
2007 *tx_env = TxEnv::from_recovered_tx(tx_envelope, tx.from());
2008 }
2009
2010 let now = Instant::now();
2011 let res = {
2012 let fork = fork.clone();
2013 let journaled_state = journaled_state.clone();
2014 let depth = journaled_state.depth;
2015 let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?;
2016
2017 let mut evm = crate::evm::new_eth_evm_with_inspector(
2018 &mut db as _,
2019 evm_env.to_owned(),
2020 tx_env.to_owned(),
2021 inspector,
2022 );
2023 evm.journaled_state.depth = depth + 1;
2025 evm.transact(tx_env.clone()).wrap_err("backend: failed committing transaction")?
2026 };
2027 trace!(elapsed = ?now.elapsed(), "transacted transaction");
2028
2029 apply_state_changeset(res.state, journaled_state, fork, persistent_accounts)?;
2030 Ok(())
2031}
2032
2033pub fn update_state<DB: Database>(
2036 state: &mut EvmState,
2037 db: &mut DB,
2038 persistent_accounts: Option<&HashSet<Address>>,
2039) -> Result<(), DB::Error> {
2040 for (addr, acc) in state.iter_mut() {
2041 if !persistent_accounts.is_some_and(|accounts| accounts.contains(addr)) {
2042 acc.info = db.basic(*addr)?.unwrap_or_default();
2043 for (key, val) in &mut acc.storage {
2044 val.present_value = db.storage(*addr, *key)?;
2045 }
2046 }
2047 }
2048
2049 Ok(())
2050}
2051
2052fn apply_state_changeset(
2055 state: Map<revm::primitives::Address, Account>,
2056 journaled_state: &mut JournaledState,
2057 fork: &mut Fork,
2058 persistent_accounts: &HashSet<Address>,
2059) -> Result<(), BackendError> {
2060 fork.db.commit(state);
2062
2063 update_state(&mut journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2064 update_state(&mut fork.journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2065
2066 Ok(())
2067}
2068
2069#[cfg(test)]
2070mod tests {
2071 use crate::{backend::Backend, opts::EvmOpts};
2072 use alloy_primitives::{U256, address};
2073 use alloy_provider::Provider;
2074 use foundry_common::provider::get_http_provider;
2075 use foundry_config::{Config, NamedChain};
2076 use foundry_fork_db::cache::{BlockchainDb, BlockchainDbMeta};
2077 use revm::database::DatabaseRef;
2078
2079 #[tokio::test(flavor = "multi_thread")]
2080 async fn can_read_write_cache() {
2081 let endpoint = &*foundry_test_utils::rpc::next_http_rpc_endpoint();
2082 let provider = get_http_provider(endpoint);
2083
2084 let block_num = provider.get_block_number().await.unwrap();
2085
2086 let mut evm_opts = Config::figment().extract::<EvmOpts>().unwrap();
2087 evm_opts.fork_url = Some(endpoint.to_string());
2088 evm_opts.fork_block_number = Some(block_num);
2089
2090 let (evm_env, _) = evm_opts.env().await.unwrap();
2091
2092 let fork = evm_opts.get_fork(&Config::default(), evm_env.clone()).unwrap();
2093
2094 let backend = Backend::spawn(Some(fork)).unwrap();
2095
2096 let address = address!("0x63091244180ae240c87d1f528f5f269134cb07b3");
2098
2099 let num_slots = 5;
2100 let _account = backend.basic_ref(address);
2101 for idx in 0..num_slots {
2102 let _ = backend.storage_ref(address, U256::from(idx));
2103 }
2104 drop(backend);
2105
2106 let meta = BlockchainDbMeta {
2107 chain: None,
2108 block_env: evm_env.block_env,
2109 hosts: Default::default(),
2110 };
2111
2112 let db = BlockchainDb::new(
2113 meta,
2114 Some(Config::foundry_block_cache_dir(NamedChain::Mainnet, block_num).unwrap()),
2115 );
2116 assert!(db.accounts().read().contains_key(&address));
2117 assert!(db.storage().read().contains_key(&address));
2118 assert_eq!(db.storage().read().get(&address).unwrap().len(), num_slots as usize);
2119 }
2120}