Skip to main content

revm_context_interface/
journaled_state.rs

1//! Journaled state trait [`JournalTr`] and related types.
2
3pub mod account;
4pub mod entry;
5
6use crate::{
7    context::{SStoreResult, SelfDestructResult},
8    host::LoadError,
9    journaled_state::account::JournaledAccountTr,
10    ErasedError,
11};
12use core::ops::{Deref, DerefMut};
13use database_interface::Database;
14use primitives::{
15    hardfork::SpecId, Address, AddressMap, AddressSet, Bytes, HashSet, Log, StorageKey,
16    StorageValue, B256, U256,
17};
18use state::{Account, AccountInfo, Bytecode};
19use std::{borrow::Cow, vec::Vec};
20/// Trait that contains database and journal of all changes that were made to the state.
21pub trait JournalTr {
22    /// Database type that is used in the journal.
23    type Database: Database;
24    /// State type that is returned by the journal after finalization.
25    type State;
26    /// Journal account allows modification of account with all needed changes.
27    type JournaledAccount<'a>: JournaledAccountTr
28    where
29        Self: 'a;
30
31    /// Creates new Journaled state.
32    ///
33    /// Dont forget to set spec_id.
34    fn new(database: Self::Database) -> Self;
35
36    /// Returns a mutable reference to the database.
37    fn db_mut(&mut self) -> &mut Self::Database {
38        self.db_and_state_mut().0
39    }
40
41    /// Returns an immutable reference to the database.
42    fn db(&self) -> &Self::Database {
43        self.db_and_state().0
44    }
45
46    /// Return the mutable current Journaled state.
47    fn evm_state_mut(&mut self) -> &mut Self::State {
48        self.db_and_state_mut().1
49    }
50
51    /// Return the current Journaled state.
52    fn evm_state(&self) -> &Self::State {
53        self.db_and_state().1
54    }
55
56    /// Returns immutable reference to the database and state.
57    fn db_and_state(&self) -> (&Self::Database, &Self::State);
58
59    /// Returns mutable reference to the database and state.
60    fn db_and_state_mut(&mut self) -> (&mut Self::Database, &mut Self::State);
61
62    /// Returns the storage value from Journal state.
63    ///
64    /// Loads the storage from database if not found in Journal state.
65    fn sload(
66        &mut self,
67        address: Address,
68        key: StorageKey,
69    ) -> Result<StateLoad<StorageValue>, <Self::Database as Database>::Error> {
70        // unwrapping is safe as we only can get DBError
71        self.sload_skip_cold_load(address, key, false)
72            .map_err(JournalLoadError::unwrap_db_error)
73    }
74
75    /// Loads the storage value from Journal state.
76    fn sload_skip_cold_load(
77        &mut self,
78        _address: Address,
79        _key: StorageKey,
80        _skip_cold_load: bool,
81    ) -> Result<StateLoad<StorageValue>, JournalLoadError<<Self::Database as Database>::Error>>;
82
83    /// Stores the storage value in Journal state.
84    fn sstore(
85        &mut self,
86        address: Address,
87        key: StorageKey,
88        value: StorageValue,
89    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
90        // unwrapping is safe as we only can get DBError
91        self.sstore_skip_cold_load(address, key, value, false)
92            .map_err(JournalLoadError::unwrap_db_error)
93    }
94
95    /// Stores the storage value in Journal state.
96    fn sstore_skip_cold_load(
97        &mut self,
98        _address: Address,
99        _key: StorageKey,
100        _value: StorageValue,
101        _skip_cold_load: bool,
102    ) -> Result<StateLoad<SStoreResult>, JournalLoadError<<Self::Database as Database>::Error>>;
103
104    /// Loads transient storage value.
105    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
106
107    /// Stores transient storage value.
108    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
109
110    /// Logs the log in Journal state.
111    fn log(&mut self, log: Log);
112
113    /// Take logs from journal.
114    fn take_logs(&mut self) -> Vec<Log>;
115
116    /// Returns the logs from journal.
117    fn logs(&self) -> &[Log];
118
119    /// Marks the account for selfdestruction and transfers all the balance to the target.
120    fn selfdestruct(
121        &mut self,
122        address: Address,
123        target: Address,
124        skip_cold_load: bool,
125    ) -> Result<StateLoad<SelfDestructResult>, JournalLoadError<<Self::Database as Database>::Error>>;
126
127    /// Sets access list inside journal.
128    fn warm_access_list(&mut self, access_list: AddressMap<HashSet<StorageKey>>);
129
130    /// Warms the coinbase account.
131    fn warm_coinbase_account(&mut self, address: Address);
132
133    /// Warms the precompiles.
134    fn warm_precompiles(&mut self, addresses: &AddressSet);
135
136    /// Returns the addresses of the precompiles.
137    fn precompile_addresses(&self) -> &AddressSet;
138
139    /// Sets the spec id.
140    fn set_spec_id(&mut self, spec_id: SpecId);
141
142    /// Sets EIP-7708 configuration flags.
143    ///
144    /// - `disabled`: Whether EIP-7708 (ETH transfers emit logs) is completely disabled.
145    /// - `delayed_burn_disabled`: Whether delayed burn logging is disabled. When enabled,
146    ///   revm tracks all self-destructed addresses and emits logs for accounts that still
147    ///   have remaining balance at the end of the transaction. This can be disabled for
148    ///   performance reasons as it requires storing and iterating over all self-destructed
149    ///   accounts. When disabled, the logging can be done outside of revm when applying
150    ///   accounts to database state.
151    fn set_eip7708_config(&mut self, disabled: bool, delayed_burn_disabled: bool);
152
153    /// Touches the account.
154    fn touch_account(&mut self, address: Address);
155
156    /// Transfers the balance from one account to another.
157    fn transfer(
158        &mut self,
159        from: Address,
160        to: Address,
161        balance: U256,
162    ) -> Result<Option<TransferError>, <Self::Database as Database>::Error>;
163
164    /// Transfers the balance from one account to another. Assume form and to are loaded.
165    fn transfer_loaded(
166        &mut self,
167        from: Address,
168        to: Address,
169        balance: U256,
170    ) -> Option<TransferError>;
171
172    /// Increments the balance of the account.
173    #[deprecated]
174    fn caller_accounting_journal_entry(
175        &mut self,
176        address: Address,
177        old_balance: U256,
178        bump_nonce: bool,
179    );
180
181    /// Increments the balance of the account.
182    fn balance_incr(
183        &mut self,
184        address: Address,
185        balance: U256,
186    ) -> Result<(), <Self::Database as Database>::Error>;
187
188    /// Increments the nonce of the account.
189    #[deprecated]
190    fn nonce_bump_journal_entry(&mut self, address: Address);
191
192    /// Loads the account.
193    fn load_account(
194        &mut self,
195        address: Address,
196    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error>;
197
198    /// Loads the account code, use `load_account_with_code` instead.
199    #[inline]
200    #[deprecated(note = "Use `load_account_with_code` instead")]
201    fn load_account_code(
202        &mut self,
203        address: Address,
204    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error> {
205        self.load_account_with_code(address)
206    }
207
208    /// Loads the account with code.
209    fn load_account_with_code(
210        &mut self,
211        address: Address,
212    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error>;
213
214    /// Loads the account delegated.
215    fn load_account_delegated(
216        &mut self,
217        address: Address,
218    ) -> Result<StateLoad<AccountLoad>, <Self::Database as Database>::Error>;
219
220    /// Loads the journaled account.
221    #[inline]
222    fn load_account_mut(
223        &mut self,
224        address: Address,
225    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error> {
226        self.load_account_mut_skip_cold_load(address, false)
227            .map_err(JournalLoadError::unwrap_db_error)
228    }
229
230    /// Loads the journaled account.
231    fn load_account_mut_skip_cold_load(
232        &mut self,
233        address: Address,
234        skip_cold_load: bool,
235    ) -> Result<
236        StateLoad<Self::JournaledAccount<'_>>,
237        JournalLoadError<<Self::Database as Database>::Error>,
238    >;
239
240    /// Loads the journaled account.
241    #[inline]
242    fn load_account_with_code_mut(
243        &mut self,
244        address: Address,
245    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error> {
246        self.load_account_mut_optional_code(address, true)
247    }
248
249    /// Loads the journaled account.
250    fn load_account_mut_optional_code(
251        &mut self,
252        address: Address,
253        load_code: bool,
254    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error>;
255
256    /// Sets bytecode with hash. Assume that account is warm.
257    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
258
259    /// Sets bytecode and calculates hash.
260    ///
261    /// Assume account is warm.
262    #[inline]
263    fn set_code(&mut self, address: Address, code: Bytecode) {
264        let hash = code.hash_slow();
265        self.set_code_with_hash(address, code, hash);
266    }
267
268    /// Returns account code bytes and if address is cold loaded.
269    #[inline]
270    fn code(
271        &mut self,
272        address: Address,
273    ) -> Result<StateLoad<Bytes>, <Self::Database as Database>::Error> {
274        let a = self.load_account_with_code(address)?;
275        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
276        let code = a.info.code.as_ref().unwrap().original_bytes();
277
278        Ok(StateLoad::new(code, a.is_cold))
279    }
280
281    /// Gets code hash of account.
282    fn code_hash(
283        &mut self,
284        address: Address,
285    ) -> Result<StateLoad<B256>, <Self::Database as Database>::Error> {
286        let acc = self.load_account_with_code(address)?;
287        if acc.is_empty() {
288            return Ok(StateLoad::new(B256::ZERO, acc.is_cold));
289        }
290        let hash = acc.info.code_hash;
291        Ok(StateLoad::new(hash, acc.is_cold))
292    }
293
294    /// Called at the end of the transaction to clean all residue data from journal.
295    fn clear(&mut self) {
296        let _ = self.finalize();
297    }
298
299    /// Creates a checkpoint of the current state. State can be revert to this point
300    /// if needed.
301    fn checkpoint(&mut self) -> JournalCheckpoint;
302
303    /// Commits the changes made since the last checkpoint.
304    fn checkpoint_commit(&mut self);
305
306    /// Reverts the changes made since the last checkpoint.
307    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint);
308
309    /// Creates a checkpoint of the account creation.
310    fn create_account_checkpoint(
311        &mut self,
312        caller: Address,
313        address: Address,
314        balance: U256,
315        spec_id: SpecId,
316    ) -> Result<JournalCheckpoint, TransferError>;
317
318    /// Returns the depth of the journal.
319    fn depth(&self) -> usize;
320
321    /// Commit current transaction journal and returns transaction logs.
322    fn commit_tx(&mut self);
323
324    /// Discard current transaction journal by removing journal entries and logs and incrementing the transaction id.
325    ///
326    /// This function is useful to discard intermediate state that is interrupted by error and it will not revert
327    /// any already committed changes and it is safe to call it multiple times.
328    fn discard_tx(&mut self);
329
330    /// Clear current journal resetting it to initial state and return changes state.
331    fn finalize(&mut self) -> Self::State;
332
333    /// Loads the account info from Journal state.
334    fn load_account_info_skip_cold_load(
335        &mut self,
336        _address: Address,
337        _load_code: bool,
338        _skip_cold_load: bool,
339    ) -> Result<AccountInfoLoad<'_>, JournalLoadError<<Self::Database as Database>::Error>>;
340}
341
342/// Error that can happen when loading account info.
343#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
344#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
345pub enum JournalLoadError<E> {
346    /// Database error.
347    DBError(E),
348    /// Cold load skipped.
349    ColdLoadSkipped,
350}
351
352/// Journal error on loading of storage or account with Boxed Database error.
353pub type JournalLoadErasedError = JournalLoadError<ErasedError>;
354
355impl<E> JournalLoadError<E> {
356    /// Returns true if the error is a database error.
357    #[inline]
358    pub const fn is_db_error(&self) -> bool {
359        matches!(self, JournalLoadError::DBError(_))
360    }
361
362    /// Returns true if the error is a cold load skipped.
363    #[inline]
364    pub const fn is_cold_load_skipped(&self) -> bool {
365        matches!(self, JournalLoadError::ColdLoadSkipped)
366    }
367
368    /// Takes the error if it is a database error.
369    #[inline]
370    pub fn take_db_error(self) -> Option<E> {
371        if let JournalLoadError::DBError(e) = self {
372            Some(e)
373        } else {
374            None
375        }
376    }
377
378    /// Unwraps the error if it is a database error.
379    #[inline]
380    pub fn unwrap_db_error(self) -> E {
381        if let JournalLoadError::DBError(e) = self {
382            e
383        } else {
384            panic!("Expected DBError");
385        }
386    }
387
388    /// Converts the error to a load error.
389    #[inline]
390    pub fn into_parts(self) -> (LoadError, Option<E>) {
391        match self {
392            JournalLoadError::DBError(e) => (LoadError::DBError, Some(e)),
393            JournalLoadError::ColdLoadSkipped => (LoadError::ColdLoadSkipped, None),
394        }
395    }
396
397    /// Maps the database error to a new error.
398    #[inline]
399    pub fn map<B, F>(self, f: F) -> JournalLoadError<B>
400    where
401        F: FnOnce(E) -> B,
402    {
403        match self {
404            JournalLoadError::DBError(e) => JournalLoadError::DBError(f(e)),
405            JournalLoadError::ColdLoadSkipped => JournalLoadError::ColdLoadSkipped,
406        }
407    }
408}
409
410impl<E> From<E> for JournalLoadError<E> {
411    fn from(e: E) -> Self {
412        JournalLoadError::DBError(e)
413    }
414}
415
416impl<E> From<JournalLoadError<E>> for LoadError {
417    fn from(e: JournalLoadError<E>) -> Self {
418        match e {
419            JournalLoadError::DBError(_) => LoadError::DBError,
420            JournalLoadError::ColdLoadSkipped => LoadError::ColdLoadSkipped,
421        }
422    }
423}
424
425/// Transfer and creation result
426#[derive(Copy, Clone, Debug, PartialEq, Eq)]
427pub enum TransferError {
428    /// Caller does not have enough funds
429    OutOfFunds,
430    /// Overflow in target account
431    OverflowPayment,
432    /// Create collision.
433    CreateCollision,
434}
435
436/// SubRoutine checkpoint that will help us to go back from this
437#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
438#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
439pub struct JournalCheckpoint {
440    /// Checkpoint to where on revert we will go back to.
441    pub log_i: usize,
442    /// Checkpoint to where on revert we will go back to and revert other journal entries.
443    pub journal_i: usize,
444    /// Checkpoint for self-destructed addresses tracking (EIP-7708).
445    pub selfdestructed_i: usize,
446}
447
448/// State load information that contains the data and if the account or storage is cold loaded
449#[derive(Clone, Debug, Default, PartialEq, Eq)]
450#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
451pub struct StateLoad<T> {
452    /// Returned data
453    pub data: T,
454    /// Is account is cold loaded
455    pub is_cold: bool,
456}
457
458impl<T> Deref for StateLoad<T> {
459    type Target = T;
460
461    fn deref(&self) -> &Self::Target {
462        &self.data
463    }
464}
465
466impl<T> DerefMut for StateLoad<T> {
467    fn deref_mut(&mut self) -> &mut Self::Target {
468        &mut self.data
469    }
470}
471
472impl<T> StateLoad<T> {
473    /// Returns a new [`StateLoad`] with the given data and cold load status.
474    #[inline]
475    pub const fn new(data: T, is_cold: bool) -> Self {
476        Self { data, is_cold }
477    }
478
479    /// Maps the data of the [`StateLoad`] to a new value.
480    ///
481    /// Useful for transforming the data of the [`StateLoad`] without changing the cold load status.
482    #[inline]
483    pub fn map<B, F>(self, f: F) -> StateLoad<B>
484    where
485        F: FnOnce(T) -> B,
486    {
487        StateLoad::new(f(self.data), self.is_cold)
488    }
489}
490
491/// Result of the account load from Journal state
492#[derive(Clone, Debug, Default, PartialEq, Eq)]
493#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
494pub struct AccountLoad {
495    /// Does account have delegate code and delegated account is cold loaded
496    pub is_delegate_account_cold: Option<bool>,
497    /// Is account empty, if `true` account is not created
498    pub is_empty: bool,
499}
500
501/// Result of the account load from Journal state
502#[derive(Clone, Debug, Default, PartialEq, Eq)]
503#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
504pub struct AccountInfoLoad<'a> {
505    /// Account info
506    pub account: Cow<'a, AccountInfo>,
507    /// Is account cold loaded
508    pub is_cold: bool,
509    /// Is account empty, if `true` account is not created
510    pub is_empty: bool,
511}
512
513impl<'a> AccountInfoLoad<'a> {
514    /// Creates new [`AccountInfoLoad`] with the given account info, cold load status and empty status.
515    #[inline]
516    pub const fn new(account: &'a AccountInfo, is_cold: bool, is_empty: bool) -> Self {
517        Self {
518            account: Cow::Borrowed(account),
519            is_cold,
520            is_empty,
521        }
522    }
523
524    /// Maps the account info of the [`AccountInfoLoad`] to a new [`StateLoad`].
525    ///
526    /// Useful for transforming the account info of the [`AccountInfoLoad`] and preserving the cold load status.
527    #[inline]
528    pub fn into_state_load<F, O>(self, f: F) -> StateLoad<O>
529    where
530        F: FnOnce(Cow<'a, AccountInfo>) -> O,
531    {
532        StateLoad::new(f(self.account), self.is_cold)
533    }
534}
535
536impl<'a> Deref for AccountInfoLoad<'a> {
537    type Target = AccountInfo;
538
539    fn deref(&self) -> &Self::Target {
540        &self.account
541    }
542}