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