Skip to main content

revm_context/
journal.rs

1//! This module contains [`Journal`] struct and implements [`JournalTr`] trait for it.
2//!
3//! Entry submodule contains [`JournalEntry`] and [`JournalEntryTr`] traits.
4//! and inner submodule contains [`JournalInner`] struct that contains state.
5pub mod inner;
6pub mod warm_addresses;
7
8pub use context_interface::journaled_state::entry::{JournalEntry, JournalEntryTr};
9pub use inner::{JournalCfg, JournalInner};
10
11use bytecode::Bytecode;
12use context_interface::{
13    context::{SStoreResult, SelfDestructResult, StateLoad},
14    journaled_state::{
15        account::JournaledAccount, AccountInfoLoad, AccountLoad, JournalCheckpoint,
16        JournalLoadError, JournalTr, TransferError,
17    },
18};
19use core::ops::{Deref, DerefMut};
20use database_interface::Database;
21use primitives::{
22    hardfork::SpecId, Address, AddressMap, AddressSet, HashSet, Log, StorageKey, StorageValue,
23    B256, U256,
24};
25use state::{Account, EvmState};
26use std::vec::Vec;
27
28/// A journal of state changes internal to the EVM
29///
30/// On each additional call, the depth of the journaled state is increased (`depth`) and a new journal is added.
31///
32/// The journal contains every state change that happens within that call, making it possible to revert changes made in a specific call.
33#[derive(Debug, Clone, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub struct Journal<DB, ENTRY = JournalEntry>
36where
37    ENTRY: JournalEntryTr,
38{
39    /// Database
40    pub database: DB,
41    /// Inner journal state.
42    pub inner: JournalInner<ENTRY>,
43}
44
45impl<DB, ENTRY> Deref for Journal<DB, ENTRY>
46where
47    ENTRY: JournalEntryTr,
48{
49    type Target = JournalInner<ENTRY>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.inner
53    }
54}
55
56impl<DB, ENTRY> DerefMut for Journal<DB, ENTRY>
57where
58    ENTRY: JournalEntryTr,
59{
60    fn deref_mut(&mut self) -> &mut Self::Target {
61        &mut self.inner
62    }
63}
64
65impl<DB, ENTRY: JournalEntryTr> Journal<DB, ENTRY> {
66    /// Creates a new JournaledState by copying state data from a JournalInit and provided database.
67    /// This allows reusing the state, logs, and other data from a previous execution context while
68    /// connecting it to a different database backend.
69    pub const fn new_with_inner(database: DB, inner: JournalInner<ENTRY>) -> Self {
70        Self { database, inner }
71    }
72
73    /// Consumes the [`Journal`] and returns [`JournalInner`].
74    ///
75    /// If you need to preserve the original journal, use [`Self::to_inner`] instead which clones the state.
76    pub fn into_init(self) -> JournalInner<ENTRY> {
77        self.inner
78    }
79}
80
81impl<DB, ENTRY: JournalEntryTr + Clone> Journal<DB, ENTRY> {
82    /// Creates a new [`JournalInner`] by cloning all internal state data (state, storage, logs, etc)
83    /// This allows creating a new journaled state with the same state data but without
84    /// carrying over the original database.
85    ///
86    /// This is useful when you want to reuse the current state for a new transaction or
87    /// execution context, but want to start with a fresh database.
88    pub fn to_inner(&self) -> JournalInner<ENTRY> {
89        self.inner.clone()
90    }
91}
92
93impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
94    type Database = DB;
95    type State = EvmState;
96    type JournaledAccount<'a>
97        = JournaledAccount<'a, DB, ENTRY>
98    where
99        ENTRY: 'a,
100        DB: 'a;
101
102    fn new(database: DB) -> Journal<DB, ENTRY> {
103        Self {
104            inner: JournalInner::new(),
105            database,
106        }
107    }
108
109    fn db_and_state(&self) -> (&Self::Database, &Self::State) {
110        (&self.database, &self.inner.state)
111    }
112
113    #[inline]
114    fn db_and_state_mut(&mut self) -> (&mut Self::Database, &mut Self::State) {
115        (&mut self.database, &mut self.inner.state)
116    }
117
118    fn sload(
119        &mut self,
120        address: Address,
121        key: StorageKey,
122    ) -> Result<StateLoad<StorageValue>, <Self::Database as Database>::Error> {
123        self.inner
124            .sload_assume_account_present(&mut self.database, address, key, false)
125            .map_err(JournalLoadError::unwrap_db_error)
126    }
127
128    fn sstore(
129        &mut self,
130        address: Address,
131        key: StorageKey,
132        value: StorageValue,
133    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
134        self.inner
135            .sstore_assume_account_present(&mut self.database, address, key, value, false)
136            .map_err(JournalLoadError::unwrap_db_error)
137    }
138
139    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
140        self.inner.tload(address, key)
141    }
142
143    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) {
144        self.inner.tstore(address, key, value)
145    }
146
147    fn log(&mut self, log: Log) {
148        self.inner.log(log)
149    }
150
151    #[inline]
152    fn logs(&self) -> &[Log] {
153        &self.inner.logs
154    }
155
156    #[inline]
157    fn take_logs(&mut self) -> Vec<Log> {
158        self.inner.take_logs()
159    }
160
161    fn selfdestruct(
162        &mut self,
163        address: Address,
164        target: Address,
165        skip_cold_load: bool,
166    ) -> Result<StateLoad<SelfDestructResult>, JournalLoadError<<Self::Database as Database>::Error>>
167    {
168        self.inner
169            .selfdestruct(&mut self.database, address, target, skip_cold_load)
170    }
171
172    #[inline]
173    fn warm_access_list(&mut self, access_list: AddressMap<HashSet<StorageKey>>) {
174        self.inner.warm_addresses.set_access_list(access_list);
175    }
176
177    #[inline]
178    fn warm_coinbase_account(&mut self, address: Address) {
179        self.inner.warm_addresses.set_coinbase(address);
180    }
181
182    #[inline]
183    fn warm_precompiles(&mut self, precompiles: &AddressSet) {
184        self.inner
185            .warm_addresses
186            .set_precompile_addresses(precompiles);
187    }
188
189    #[inline]
190    fn precompile_addresses(&self) -> &AddressSet {
191        self.inner.warm_addresses.precompiles()
192    }
193
194    /// Returns call depth.
195    #[inline]
196    fn depth(&self) -> usize {
197        self.inner.depth
198    }
199
200    #[inline]
201    fn set_spec_id(&mut self, spec_id: SpecId) {
202        self.inner.cfg.spec = spec_id;
203    }
204
205    #[inline]
206    fn set_eip7708_config(&mut self, disabled: bool, delayed_burn_disabled: bool) {
207        self.inner
208            .set_eip7708_config(disabled, delayed_burn_disabled);
209    }
210
211    #[inline]
212    fn transfer(
213        &mut self,
214        from: Address,
215        to: Address,
216        balance: U256,
217    ) -> Result<Option<TransferError>, DB::Error> {
218        self.inner.transfer(&mut self.database, from, to, balance)
219    }
220
221    #[inline]
222    fn transfer_loaded(
223        &mut self,
224        from: Address,
225        to: Address,
226        balance: U256,
227    ) -> Option<TransferError> {
228        self.inner.transfer_loaded(from, to, balance)
229    }
230
231    #[inline]
232    fn touch_account(&mut self, address: Address) {
233        self.inner.touch(address);
234    }
235
236    #[inline]
237    #[expect(deprecated)]
238    fn caller_accounting_journal_entry(
239        &mut self,
240        address: Address,
241        old_balance: U256,
242        bump_nonce: bool,
243    ) {
244        self.inner
245            .caller_accounting_journal_entry(address, old_balance, bump_nonce);
246    }
247
248    /// Increments the balance of the account.
249    #[inline]
250    fn balance_incr(
251        &mut self,
252        address: Address,
253        balance: U256,
254    ) -> Result<(), <Self::Database as Database>::Error> {
255        self.inner
256            .balance_incr(&mut self.database, address, balance)
257    }
258
259    /// Increments the nonce of the account.
260    #[inline]
261    #[expect(deprecated)]
262    fn nonce_bump_journal_entry(&mut self, address: Address) {
263        self.inner.nonce_bump_journal_entry(address)
264    }
265
266    #[inline]
267    fn load_account(&mut self, address: Address) -> Result<StateLoad<&Account>, DB::Error> {
268        self.inner.load_account(&mut self.database, address)
269    }
270
271    #[inline]
272    fn load_account_mut_skip_cold_load(
273        &mut self,
274        address: Address,
275        skip_cold_load: bool,
276    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, JournalLoadError<DB::Error>> {
277        self.inner
278            .load_account_mut_optional(&mut self.database, address, skip_cold_load)
279    }
280
281    #[inline]
282    fn load_account_mut_optional_code(
283        &mut self,
284        address: Address,
285        load_code: bool,
286    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, DB::Error> {
287        self.inner
288            .load_account_mut_optional_code(&mut self.database, address, load_code, false)
289            .map_err(JournalLoadError::unwrap_db_error)
290    }
291
292    #[inline]
293    fn load_account_with_code(
294        &mut self,
295        address: Address,
296    ) -> Result<StateLoad<&Account>, DB::Error> {
297        self.inner.load_code(&mut self.database, address)
298    }
299
300    #[inline]
301    fn load_account_delegated(
302        &mut self,
303        address: Address,
304    ) -> Result<StateLoad<AccountLoad>, DB::Error> {
305        self.inner
306            .load_account_delegated(&mut self.database, address)
307    }
308
309    #[inline]
310    fn checkpoint(&mut self) -> JournalCheckpoint {
311        self.inner.checkpoint()
312    }
313
314    #[inline]
315    fn checkpoint_commit(&mut self) {
316        self.inner.checkpoint_commit()
317    }
318
319    #[inline]
320    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
321        self.inner.checkpoint_revert(checkpoint)
322    }
323
324    #[inline]
325    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
326        self.inner.set_code_with_hash(address, code, hash);
327    }
328
329    #[inline]
330    fn create_account_checkpoint(
331        &mut self,
332        caller: Address,
333        address: Address,
334        balance: U256,
335        spec_id: SpecId,
336    ) -> Result<JournalCheckpoint, TransferError> {
337        // Ignore error.
338        self.inner
339            .create_account_checkpoint(caller, address, balance, spec_id)
340    }
341
342    #[inline]
343    fn commit_tx(&mut self) {
344        self.inner.commit_tx()
345    }
346
347    #[inline]
348    fn discard_tx(&mut self) {
349        self.inner.discard_tx();
350    }
351
352    /// Clear current journal resetting it to initial state and return changes state.
353    #[inline]
354    fn finalize(&mut self) -> Self::State {
355        self.inner.finalize()
356    }
357
358    #[inline]
359    fn sload_skip_cold_load(
360        &mut self,
361        address: Address,
362        key: StorageKey,
363        skip_cold_load: bool,
364    ) -> Result<StateLoad<StorageValue>, JournalLoadError<<Self::Database as Database>::Error>>
365    {
366        self.inner
367            .sload_assume_account_present(&mut self.database, address, key, skip_cold_load)
368    }
369
370    #[inline]
371    fn sstore_skip_cold_load(
372        &mut self,
373        address: Address,
374        key: StorageKey,
375        value: StorageValue,
376        skip_cold_load: bool,
377    ) -> Result<StateLoad<SStoreResult>, JournalLoadError<<Self::Database as Database>::Error>>
378    {
379        self.inner.sstore_assume_account_present(
380            &mut self.database,
381            address,
382            key,
383            value,
384            skip_cold_load,
385        )
386    }
387
388    #[inline]
389    fn load_account_info_skip_cold_load(
390        &mut self,
391        address: Address,
392        load_code: bool,
393        skip_cold_load: bool,
394    ) -> Result<AccountInfoLoad<'_>, JournalLoadError<<Self::Database as Database>::Error>> {
395        let spec = self.inner.cfg.spec;
396        self.inner
397            .load_account_optional(&mut self.database, address, load_code, skip_cold_load)
398            .map(|a| {
399                AccountInfoLoad::new(&a.data.info, a.is_cold, a.state_clear_aware_is_empty(spec))
400            })
401    }
402}