foundry_evm_core/backend/snapshot.rs
1use alloy_primitives::{map::AddressHashMap, B256, U256};
2use revm::{
3 primitives::{AccountInfo, Env, HashMap},
4 JournaledState,
5};
6use serde::{Deserialize, Serialize};
7
8/// A minimal abstraction of a state at a certain point in time
9#[derive(Clone, Debug, Default, Serialize, Deserialize)]
10pub struct StateSnapshot {
11 pub accounts: AddressHashMap<AccountInfo>,
12 pub storage: AddressHashMap<HashMap<U256, U256>>,
13 pub block_hashes: HashMap<U256, B256>,
14}
15
16/// Represents a state snapshot taken during evm execution
17#[derive(Clone, Debug)]
18pub struct BackendStateSnapshot<T> {
19 pub db: T,
20 /// The journaled_state state at a specific point
21 pub journaled_state: JournaledState,
22 /// Contains the env at the time of the snapshot
23 pub env: Env,
24}
25
26impl<T> BackendStateSnapshot<T> {
27 /// Takes a new state snapshot.
28 pub fn new(db: T, journaled_state: JournaledState, env: Env) -> Self {
29 Self { db, journaled_state, env }
30 }
31
32 /// Called when this state snapshot is reverted.
33 ///
34 /// Since we want to keep all additional logs that were emitted since the snapshot was taken
35 /// we'll merge additional logs into the snapshot's `revm::JournaledState`. Additional logs are
36 /// those logs that are missing in the snapshot's journaled_state, since the current
37 /// journaled_state includes the same logs, we can simply replace use that See also
38 /// `DatabaseExt::revert`.
39 pub fn merge(&mut self, current: &JournaledState) {
40 self.journaled_state.logs.clone_from(¤t.logs);
41 }
42}
43
44/// What to do when reverting a state snapshot.
45///
46/// Whether to remove the state snapshot or keep it.
47#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
48pub enum RevertStateSnapshotAction {
49 /// Remove the state snapshot after reverting.
50 #[default]
51 RevertRemove,
52 /// Keep the state snapshot after reverting.
53 RevertKeep,
54}
55
56impl RevertStateSnapshotAction {
57 /// Returns `true` if the action is to keep the state snapshot.
58 pub fn is_keep(&self) -> bool {
59 matches!(self, Self::RevertKeep)
60 }
61}