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