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 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(&self) -> &Self::Database {
110        &self.database
111    }
112
113    fn db_mut(&mut self) -> &mut Self::Database {
114        &mut self.database
115    }
116
117    fn sload(
118        &mut self,
119        address: Address,
120        key: StorageKey,
121    ) -> Result<StateLoad<StorageValue>, <Self::Database as Database>::Error> {
122        self.inner
123            .sload_assume_account_present(&mut self.database, address, key, false)
124            .map_err(JournalLoadError::unwrap_db_error)
125    }
126
127    fn sstore(
128        &mut self,
129        address: Address,
130        key: StorageKey,
131        value: StorageValue,
132    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
133        self.inner
134            .sstore_assume_account_present(&mut self.database, address, key, value, false)
135            .map_err(JournalLoadError::unwrap_db_error)
136    }
137
138    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
139        self.inner.tload(address, key)
140    }
141
142    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) {
143        self.inner.tstore(address, key, value)
144    }
145
146    fn log(&mut self, log: Log) {
147        self.inner.log(log)
148    }
149
150    #[inline]
151    fn logs(&self) -> &[Log] {
152        &self.inner.logs
153    }
154
155    #[inline]
156    fn take_logs(&mut self) -> Vec<Log> {
157        self.inner.take_logs()
158    }
159
160    fn selfdestruct(
161        &mut self,
162        address: Address,
163        target: Address,
164        skip_cold_load: bool,
165    ) -> Result<StateLoad<SelfDestructResult>, JournalLoadError<<Self::Database as Database>::Error>>
166    {
167        self.inner
168            .selfdestruct(&mut self.database, address, target, skip_cold_load)
169    }
170
171    #[inline]
172    fn warm_access_list(&mut self, access_list: AddressMap<HashSet<StorageKey>>) {
173        self.inner.warm_addresses.set_access_list(access_list);
174    }
175
176    fn warm_coinbase_account(&mut self, address: Address) {
177        self.inner.warm_addresses.set_coinbase(address);
178    }
179
180    fn warm_precompiles(&mut self, precompiles: AddressSet) {
181        self.inner
182            .warm_addresses
183            .set_precompile_addresses(precompiles);
184    }
185
186    #[inline]
187    fn precompile_addresses(&self) -> &AddressSet {
188        self.inner.warm_addresses.precompiles()
189    }
190
191    /// Returns call depth.
192    #[inline]
193    fn depth(&self) -> usize {
194        self.inner.depth
195    }
196
197    #[inline]
198    fn set_spec_id(&mut self, spec_id: SpecId) {
199        self.inner.cfg.spec = spec_id;
200    }
201
202    #[inline]
203    fn set_eip7708_config(&mut self, disabled: bool, delayed_burn_disabled: bool) {
204        self.inner
205            .set_eip7708_config(disabled, delayed_burn_disabled);
206    }
207
208    #[inline]
209    fn transfer(
210        &mut self,
211        from: Address,
212        to: Address,
213        balance: U256,
214    ) -> Result<Option<TransferError>, DB::Error> {
215        self.inner.transfer(&mut self.database, from, to, balance)
216    }
217
218    #[inline]
219    fn transfer_loaded(
220        &mut self,
221        from: Address,
222        to: Address,
223        balance: U256,
224    ) -> Option<TransferError> {
225        self.inner.transfer_loaded(from, to, balance)
226    }
227
228    #[inline]
229    fn touch_account(&mut self, address: Address) {
230        self.inner.touch(address);
231    }
232
233    #[inline]
234    #[allow(deprecated)]
235    fn caller_accounting_journal_entry(
236        &mut self,
237        address: Address,
238        old_balance: U256,
239        bump_nonce: bool,
240    ) {
241        self.inner
242            .caller_accounting_journal_entry(address, old_balance, bump_nonce);
243    }
244
245    /// Increments the balance of the account.
246    #[inline]
247    fn balance_incr(
248        &mut self,
249        address: Address,
250        balance: U256,
251    ) -> Result<(), <Self::Database as Database>::Error> {
252        self.inner
253            .balance_incr(&mut self.database, address, balance)
254    }
255
256    /// Increments the nonce of the account.
257    #[inline]
258    #[allow(deprecated)]
259    fn nonce_bump_journal_entry(&mut self, address: Address) {
260        self.inner.nonce_bump_journal_entry(address)
261    }
262
263    #[inline]
264    fn load_account(&mut self, address: Address) -> Result<StateLoad<&Account>, DB::Error> {
265        self.inner.load_account(&mut self.database, address)
266    }
267
268    #[inline]
269    fn load_account_mut_skip_cold_load(
270        &mut self,
271        address: Address,
272        skip_cold_load: bool,
273    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, JournalLoadError<DB::Error>> {
274        self.inner
275            .load_account_mut_optional(&mut self.database, address, skip_cold_load)
276    }
277
278    #[inline]
279    fn load_account_mut_optional_code(
280        &mut self,
281        address: Address,
282        load_code: bool,
283    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, DB::Error> {
284        self.inner
285            .load_account_mut_optional_code(&mut self.database, address, load_code, false)
286            .map_err(JournalLoadError::unwrap_db_error)
287    }
288
289    #[inline]
290    fn load_account_with_code(
291        &mut self,
292        address: Address,
293    ) -> Result<StateLoad<&Account>, DB::Error> {
294        self.inner.load_code(&mut self.database, address)
295    }
296
297    #[inline]
298    fn load_account_delegated(
299        &mut self,
300        address: Address,
301    ) -> Result<StateLoad<AccountLoad>, DB::Error> {
302        self.inner
303            .load_account_delegated(&mut self.database, address)
304    }
305
306    #[inline]
307    fn checkpoint(&mut self) -> JournalCheckpoint {
308        self.inner.checkpoint()
309    }
310
311    #[inline]
312    fn checkpoint_commit(&mut self) {
313        self.inner.checkpoint_commit()
314    }
315
316    #[inline]
317    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
318        self.inner.checkpoint_revert(checkpoint)
319    }
320
321    #[inline]
322    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
323        self.inner.set_code_with_hash(address, code, hash);
324    }
325
326    #[inline]
327    fn create_account_checkpoint(
328        &mut self,
329        caller: Address,
330        address: Address,
331        balance: U256,
332        spec_id: SpecId,
333    ) -> Result<JournalCheckpoint, TransferError> {
334        // Ignore error.
335        self.inner
336            .create_account_checkpoint(caller, address, balance, spec_id)
337    }
338
339    #[inline]
340    fn commit_tx(&mut self) {
341        self.inner.commit_tx()
342    }
343
344    #[inline]
345    fn discard_tx(&mut self) {
346        self.inner.discard_tx();
347    }
348
349    /// Clear current journal resetting it to initial state and return changes state.
350    #[inline]
351    fn finalize(&mut self) -> Self::State {
352        self.inner.finalize()
353    }
354
355    #[inline]
356    fn sload_skip_cold_load(
357        &mut self,
358        address: Address,
359        key: StorageKey,
360        skip_cold_load: bool,
361    ) -> Result<StateLoad<StorageValue>, JournalLoadError<<Self::Database as Database>::Error>>
362    {
363        self.inner
364            .sload_assume_account_present(&mut self.database, address, key, skip_cold_load)
365    }
366
367    #[inline]
368    fn sstore_skip_cold_load(
369        &mut self,
370        address: Address,
371        key: StorageKey,
372        value: StorageValue,
373        skip_cold_load: bool,
374    ) -> Result<StateLoad<SStoreResult>, JournalLoadError<<Self::Database as Database>::Error>>
375    {
376        self.inner.sstore_assume_account_present(
377            &mut self.database,
378            address,
379            key,
380            value,
381            skip_cold_load,
382        )
383    }
384
385    #[inline]
386    fn load_account_info_skip_cold_load(
387        &mut self,
388        address: Address,
389        load_code: bool,
390        skip_cold_load: bool,
391    ) -> Result<AccountInfoLoad<'_>, JournalLoadError<<Self::Database as Database>::Error>> {
392        let spec = self.inner.cfg.spec;
393        self.inner
394            .load_account_optional(&mut self.database, address, load_code, skip_cold_load)
395            .map(|a| {
396                AccountInfoLoad::new(&a.data.info, a.is_cold, a.state_clear_aware_is_empty(spec))
397            })
398    }
399}