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