revm_context_interface/
journaled_state.rs

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