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