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