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 and EIP-8246 configuration flags.
143    ///
144    /// - `disabled`: Whether EIP-7708 (ETH transfers emit logs) is completely disabled.
145    /// - `eip8246_delayed_clear_disabled`: Whether the EIP-8246 delayed clearing of
146    ///   self-destructed accounts is disabled. When enabled, revm tracks all self-destructed
147    ///   addresses and, at the end of the transaction, clears the code, storage and nonce of
148    ///   any that still have a remaining balance while preserving the balance. This can be
149    ///   disabled for performance reasons as it requires storing and iterating over all
150    ///   self-destructed accounts. When disabled, this clearing can be done outside of revm
151    ///   when applying accounts to database state.
152    fn set_eip7708_config(&mut self, disabled: bool, eip8246_delayed_clear_disabled: bool);
153
154    /// Touches the account.
155    fn touch_account(&mut self, address: Address);
156
157    /// Transfers the balance from one account to another.
158    fn transfer(
159        &mut self,
160        from: Address,
161        to: Address,
162        balance: U256,
163    ) -> Result<Option<TransferError>, <Self::Database as Database>::Error>;
164
165    /// Transfers the balance from one account to another. Assume form and to are loaded.
166    fn transfer_loaded(
167        &mut self,
168        from: Address,
169        to: Address,
170        balance: U256,
171    ) -> Option<TransferError>;
172
173    /// Increments the balance of the account.
174    #[deprecated]
175    fn caller_accounting_journal_entry(
176        &mut self,
177        address: Address,
178        old_balance: U256,
179        bump_nonce: bool,
180    );
181
182    /// Increments the balance of the account.
183    fn balance_incr(
184        &mut self,
185        address: Address,
186        balance: U256,
187    ) -> Result<(), <Self::Database as Database>::Error>;
188
189    /// Increments the nonce of the account.
190    #[deprecated]
191    fn nonce_bump_journal_entry(&mut self, address: Address);
192
193    /// Loads the account.
194    fn load_account(
195        &mut self,
196        address: Address,
197    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error>;
198
199    /// Loads the account code, use `load_account_with_code` instead.
200    #[inline]
201    #[deprecated(note = "Use `load_account_with_code` instead")]
202    fn load_account_code(
203        &mut self,
204        address: Address,
205    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error> {
206        self.load_account_with_code(address)
207    }
208
209    /// Loads the account with code.
210    fn load_account_with_code(
211        &mut self,
212        address: Address,
213    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error>;
214
215    /// Loads the account delegated.
216    fn load_account_delegated(
217        &mut self,
218        address: Address,
219    ) -> Result<StateLoad<AccountLoad>, <Self::Database as Database>::Error>;
220
221    /// Loads the journaled account.
222    #[inline]
223    fn load_account_mut(
224        &mut self,
225        address: Address,
226    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error> {
227        self.load_account_mut_skip_cold_load(address, false)
228            .map_err(JournalLoadError::unwrap_db_error)
229    }
230
231    /// Loads the journaled account.
232    fn load_account_mut_skip_cold_load(
233        &mut self,
234        address: Address,
235        skip_cold_load: bool,
236    ) -> Result<
237        StateLoad<Self::JournaledAccount<'_>>,
238        JournalLoadError<<Self::Database as Database>::Error>,
239    >;
240
241    /// Loads the journaled account.
242    #[inline]
243    fn load_account_with_code_mut(
244        &mut self,
245        address: Address,
246    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error> {
247        self.load_account_mut_optional_code(address, true)
248    }
249
250    /// Loads the journaled account.
251    fn load_account_mut_optional_code(
252        &mut self,
253        address: Address,
254        load_code: bool,
255    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error>;
256
257    /// Sets bytecode with hash. Assume that account is warm.
258    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
259
260    /// Sets bytecode and calculates hash.
261    ///
262    /// Assume account is warm.
263    #[inline]
264    fn set_code(&mut self, address: Address, code: Bytecode) {
265        let hash = code.hash_slow();
266        self.set_code_with_hash(address, code, hash);
267    }
268
269    /// Returns account code bytes and if address is cold loaded.
270    #[inline]
271    fn code(
272        &mut self,
273        address: Address,
274    ) -> Result<StateLoad<Bytes>, <Self::Database as Database>::Error> {
275        let a = self.load_account_with_code(address)?;
276        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
277        let code = a.info.code.as_ref().unwrap().original_bytes();
278
279        Ok(StateLoad::new(code, a.is_cold))
280    }
281
282    /// Gets code hash of account.
283    fn code_hash(
284        &mut self,
285        address: Address,
286    ) -> Result<StateLoad<B256>, <Self::Database as Database>::Error> {
287        let acc = self.load_account_with_code(address)?;
288        if acc.is_empty() {
289            return Ok(StateLoad::new(B256::ZERO, acc.is_cold));
290        }
291        let hash = acc.info.code_hash;
292        Ok(StateLoad::new(hash, acc.is_cold))
293    }
294
295    /// Called at the end of the transaction to clean all residue data from journal.
296    fn clear(&mut self) {
297        let _ = self.finalize();
298    }
299
300    /// Creates a checkpoint of the current state. State can be revert to this point
301    /// if needed.
302    fn checkpoint(&mut self) -> JournalCheckpoint;
303
304    /// Commits the changes made since the last checkpoint.
305    fn checkpoint_commit(&mut self);
306
307    /// Reverts the changes made since the last checkpoint.
308    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint);
309
310    /// Creates a checkpoint of the account creation.
311    fn create_account_checkpoint(
312        &mut self,
313        caller: Address,
314        address: Address,
315        balance: U256,
316        spec_id: SpecId,
317    ) -> Result<JournalCheckpoint, TransferError>;
318
319    /// Returns the depth of the journal.
320    fn depth(&self) -> usize;
321
322    /// Commit current transaction journal and returns transaction logs.
323    fn commit_tx(&mut self);
324
325    /// Discard current transaction journal by removing journal entries and logs and incrementing the transaction id.
326    ///
327    /// This function is useful to discard intermediate state that is interrupted by error and it will not revert
328    /// any already committed changes and it is safe to call it multiple times.
329    fn discard_tx(&mut self);
330
331    /// Clear current journal resetting it to initial state and return changes state.
332    fn finalize(&mut self) -> Self::State;
333
334    /// Loads the account info from Journal state.
335    fn load_account_info_skip_cold_load(
336        &mut self,
337        _address: Address,
338        _load_code: bool,
339        _skip_cold_load: bool,
340    ) -> Result<AccountInfoLoad<'_>, JournalLoadError<<Self::Database as Database>::Error>>;
341}
342
343/// Error that can happen when loading account info.
344#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
345#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
346pub enum JournalLoadError<E> {
347    /// Database error.
348    DBError(E),
349    /// Cold load skipped.
350    ColdLoadSkipped,
351}
352
353/// Journal error on loading of storage or account with Boxed Database error.
354pub type JournalLoadErasedError = JournalLoadError<ErasedError>;
355
356impl<E> JournalLoadError<E> {
357    /// Returns true if the error is a database error.
358    #[inline]
359    pub const fn is_db_error(&self) -> bool {
360        matches!(self, JournalLoadError::DBError(_))
361    }
362
363    /// Returns true if the error is a cold load skipped.
364    #[inline]
365    pub const fn is_cold_load_skipped(&self) -> bool {
366        matches!(self, JournalLoadError::ColdLoadSkipped)
367    }
368
369    /// Takes the error if it is a database error.
370    #[inline]
371    pub fn take_db_error(self) -> Option<E> {
372        if let JournalLoadError::DBError(e) = self {
373            Some(e)
374        } else {
375            None
376        }
377    }
378
379    /// Unwraps the error if it is a database error.
380    #[inline]
381    pub fn unwrap_db_error(self) -> E {
382        if let JournalLoadError::DBError(e) = self {
383            e
384        } else {
385            panic!("Expected DBError");
386        }
387    }
388
389    /// Converts the error to a load error.
390    #[inline]
391    pub fn into_parts(self) -> (LoadError, Option<E>) {
392        match self {
393            JournalLoadError::DBError(e) => (LoadError::DBError, Some(e)),
394            JournalLoadError::ColdLoadSkipped => (LoadError::ColdLoadSkipped, None),
395        }
396    }
397
398    /// Maps the database error to a new error.
399    #[inline]
400    pub fn map<B, F>(self, f: F) -> JournalLoadError<B>
401    where
402        F: FnOnce(E) -> B,
403    {
404        match self {
405            JournalLoadError::DBError(e) => JournalLoadError::DBError(f(e)),
406            JournalLoadError::ColdLoadSkipped => JournalLoadError::ColdLoadSkipped,
407        }
408    }
409}
410
411impl<E> From<E> for JournalLoadError<E> {
412    fn from(e: E) -> Self {
413        JournalLoadError::DBError(e)
414    }
415}
416
417impl<E> From<JournalLoadError<E>> for LoadError {
418    fn from(e: JournalLoadError<E>) -> Self {
419        match e {
420            JournalLoadError::DBError(_) => LoadError::DBError,
421            JournalLoadError::ColdLoadSkipped => LoadError::ColdLoadSkipped,
422        }
423    }
424}
425
426/// Transfer and creation result
427#[derive(Copy, Clone, Debug, PartialEq, Eq)]
428pub enum TransferError {
429    /// Caller does not have enough funds
430    OutOfFunds,
431    /// Overflow in target account
432    OverflowPayment,
433    /// Create collision.
434    CreateCollision,
435}
436
437/// SubRoutine checkpoint that will help us to go back from this
438#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
439#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
440pub struct JournalCheckpoint {
441    /// Checkpoint to where on revert we will go back to.
442    pub log_i: usize,
443    /// Checkpoint to where on revert we will go back to and revert other journal entries.
444    pub journal_i: usize,
445    /// Checkpoint for self-destructed addresses tracking (EIP-7708).
446    pub selfdestructed_i: usize,
447}
448
449/// State load information that contains the data and if the account or storage is cold loaded
450#[derive(Clone, Debug, Default, PartialEq, Eq)]
451#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
452pub struct StateLoad<T> {
453    /// Returned data
454    pub data: T,
455    /// Is account is cold loaded
456    pub is_cold: bool,
457}
458
459impl<T> Deref for StateLoad<T> {
460    type Target = T;
461
462    fn deref(&self) -> &Self::Target {
463        &self.data
464    }
465}
466
467impl<T> DerefMut for StateLoad<T> {
468    fn deref_mut(&mut self) -> &mut Self::Target {
469        &mut self.data
470    }
471}
472
473impl<T> StateLoad<T> {
474    /// Returns a new [`StateLoad`] with the given data and cold load status.
475    #[inline]
476    pub const fn new(data: T, is_cold: bool) -> Self {
477        Self { data, is_cold }
478    }
479
480    /// Maps the data of the [`StateLoad`] to a new value.
481    ///
482    /// Useful for transforming the data of the [`StateLoad`] without changing the cold load status.
483    #[inline]
484    pub fn map<B, F>(self, f: F) -> StateLoad<B>
485    where
486        F: FnOnce(T) -> B,
487    {
488        StateLoad::new(f(self.data), self.is_cold)
489    }
490}
491
492/// Result of the account load from Journal state
493#[derive(Clone, Debug, Default, PartialEq, Eq)]
494#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
495pub struct AccountLoad {
496    /// Does account have delegate code and delegated account is cold loaded
497    pub is_delegate_account_cold: Option<bool>,
498    /// Is account empty, if `true` account is not created
499    pub is_empty: bool,
500}
501
502/// Result of the account load from Journal state
503#[derive(Clone, Debug, Default, PartialEq, Eq)]
504#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
505pub struct AccountInfoLoad<'a> {
506    /// Account info
507    pub account: Cow<'a, AccountInfo>,
508    /// Is account cold loaded
509    pub is_cold: bool,
510    /// Is account empty, if `true` account is not created
511    pub is_empty: bool,
512}
513
514impl<'a> AccountInfoLoad<'a> {
515    /// Creates new [`AccountInfoLoad`] with the given account info, cold load status and empty status.
516    #[inline]
517    pub const fn new(account: &'a AccountInfo, is_cold: bool, is_empty: bool) -> Self {
518        Self {
519            account: Cow::Borrowed(account),
520            is_cold,
521            is_empty,
522        }
523    }
524
525    /// Maps the account info of the [`AccountInfoLoad`] to a new [`StateLoad`].
526    ///
527    /// Useful for transforming the account info of the [`AccountInfoLoad`] and preserving the cold load status.
528    #[inline]
529    pub fn into_state_load<F, O>(self, f: F) -> StateLoad<O>
530    where
531        F: FnOnce(Cow<'a, AccountInfo>) -> O,
532    {
533        StateLoad::new(f(self.account), self.is_cold)
534    }
535}
536
537impl<'a> Deref for AccountInfoLoad<'a> {
538    type Target = AccountInfo;
539
540    fn deref(&self) -> &Self::Target {
541        &self.account
542    }
543}