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