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