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::JournaledAccount, entry::JournalEntryTr},
10};
11use core::ops::{Deref, DerefMut};
12use database_interface::Database;
13use primitives::{
14    hardfork::SpecId, Address, Bytes, HashMap, HashSet, Log, StorageKey, StorageValue, B256, U256,
15};
16use state::{Account, AccountInfo, Bytecode};
17use std::{borrow::Cow, vec::Vec};
18
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 Entry type that is used in the journal.
26    type JournalEntry: JournalEntryTr;
27
28    /// Creates new Journaled state.
29    ///
30    /// Dont forget to set spec_id.
31    fn new(database: Self::Database) -> Self;
32
33    /// Returns a mutable reference to the database.
34    fn db_mut(&mut self) -> &mut Self::Database;
35
36    /// Returns an immutable reference to the database.
37    fn db(&self) -> &Self::Database;
38
39    /// Returns the storage value from Journal state.
40    ///
41    /// Loads the storage from database if not found in Journal state.
42    fn sload(
43        &mut self,
44        address: Address,
45        key: StorageKey,
46    ) -> Result<StateLoad<StorageValue>, <Self::Database as Database>::Error> {
47        // unwrapping is safe as we only can get DBError
48        self.sload_skip_cold_load(address, key, false)
49            .map_err(JournalLoadError::unwrap_db_error)
50    }
51
52    /// Loads the storage value from Journal state.
53    fn sload_skip_cold_load(
54        &mut self,
55        _address: Address,
56        _key: StorageKey,
57        _skip_cold_load: bool,
58    ) -> Result<StateLoad<StorageValue>, JournalLoadError<<Self::Database as Database>::Error>>;
59
60    /// Stores the storage value in Journal state.
61    fn sstore(
62        &mut self,
63        address: Address,
64        key: StorageKey,
65        value: StorageValue,
66    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
67        // unwrapping is safe as we only can get DBError
68        self.sstore_skip_cold_load(address, key, value, false)
69            .map_err(JournalLoadError::unwrap_db_error)
70    }
71
72    /// Stores the storage value in Journal state.
73    fn sstore_skip_cold_load(
74        &mut self,
75        _address: Address,
76        _key: StorageKey,
77        _value: StorageValue,
78        _skip_cold_load: bool,
79    ) -> Result<StateLoad<SStoreResult>, JournalLoadError<<Self::Database as Database>::Error>>;
80
81    /// Loads transient storage value.
82    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
83
84    /// Stores transient storage value.
85    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
86
87    /// Logs the log in Journal state.
88    fn log(&mut self, log: Log);
89
90    /// Take logs from journal.
91    fn take_logs(&mut self) -> Vec<Log>;
92
93    /// Returns the logs from journal.
94    fn logs(&self) -> &[Log];
95
96    /// Marks the account for selfdestruction and transfers all the balance to the target.
97    fn selfdestruct(
98        &mut self,
99        address: Address,
100        target: Address,
101        skip_cold_load: bool,
102    ) -> Result<StateLoad<SelfDestructResult>, JournalLoadError<<Self::Database as Database>::Error>>;
103
104    /// Sets access list inside journal.
105    fn warm_access_list(&mut self, access_list: HashMap<Address, HashSet<StorageKey>>);
106
107    /// Warms the coinbase account.
108    fn warm_coinbase_account(&mut self, address: Address);
109
110    /// Warms the precompiles.
111    fn warm_precompiles(&mut self, addresses: HashSet<Address>);
112
113    /// Returns the addresses of the precompiles.
114    fn precompile_addresses(&self) -> &HashSet<Address>;
115
116    /// Sets the spec id.
117    fn set_spec_id(&mut self, spec_id: SpecId);
118
119    /// Touches the account.
120    fn touch_account(&mut self, address: Address);
121
122    /// Transfers the balance from one account to another.
123    fn transfer(
124        &mut self,
125        from: Address,
126        to: Address,
127        balance: U256,
128    ) -> Result<Option<TransferError>, <Self::Database as Database>::Error>;
129
130    /// Transfers the balance from one account to another. Assume form and to are loaded.
131    fn transfer_loaded(
132        &mut self,
133        from: Address,
134        to: Address,
135        balance: U256,
136    ) -> Option<TransferError>;
137
138    /// Increments the balance of the account.
139    fn caller_accounting_journal_entry(
140        &mut self,
141        address: Address,
142        old_balance: U256,
143        bump_nonce: bool,
144    );
145
146    /// Increments the balance of the account.
147    fn balance_incr(
148        &mut self,
149        address: Address,
150        balance: U256,
151    ) -> Result<(), <Self::Database as Database>::Error>;
152
153    /// Increments the nonce of the account.
154    fn nonce_bump_journal_entry(&mut self, address: Address);
155
156    /// Loads the account.
157    fn load_account(
158        &mut self,
159        address: Address,
160    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error>;
161
162    /// Loads the account code, use `load_account_with_code` instead.
163    #[inline]
164    #[deprecated(note = "Use `load_account_with_code` instead")]
165    fn load_account_code(
166        &mut self,
167        address: Address,
168    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error> {
169        self.load_account_with_code(address)
170    }
171
172    /// Loads the account with code.
173    fn load_account_with_code(
174        &mut self,
175        address: Address,
176    ) -> Result<StateLoad<&Account>, <Self::Database as Database>::Error>;
177
178    /// Loads the account delegated.
179    fn load_account_delegated(
180        &mut self,
181        address: Address,
182    ) -> Result<StateLoad<AccountLoad>, <Self::Database as Database>::Error>;
183
184    /// Loads the journaled account.
185    #[inline]
186    fn load_account_mut(
187        &mut self,
188        address: Address,
189    ) -> Result<
190        StateLoad<JournaledAccount<'_, Self::JournalEntry>>,
191        <Self::Database as Database>::Error,
192    > {
193        self.load_account_mut_optional_code(address, false)
194    }
195
196    /// Loads the journaled account.
197    #[inline]
198    fn load_account_with_code_mut(
199        &mut self,
200        address: Address,
201    ) -> Result<
202        StateLoad<JournaledAccount<'_, Self::JournalEntry>>,
203        <Self::Database as Database>::Error,
204    > {
205        self.load_account_mut_optional_code(address, true)
206    }
207
208    /// Loads the journaled account.
209    fn load_account_mut_optional_code(
210        &mut self,
211        address: Address,
212        load_code: bool,
213    ) -> Result<
214        StateLoad<JournaledAccount<'_, Self::JournalEntry>>,
215        <Self::Database as Database>::Error,
216    >;
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
314impl<E> JournalLoadError<E> {
315    /// Returns true if the error is a database error.
316    #[inline]
317    pub fn is_db_error(&self) -> bool {
318        matches!(self, JournalLoadError::DBError(_))
319    }
320
321    /// Returns true if the error is a cold load skipped.
322    #[inline]
323    pub fn is_cold_load_skipped(&self) -> bool {
324        matches!(self, JournalLoadError::ColdLoadSkipped)
325    }
326
327    /// Takes the error if it is a database error.
328    #[inline]
329    pub fn take_db_error(self) -> Option<E> {
330        if let JournalLoadError::DBError(e) = self {
331            Some(e)
332        } else {
333            None
334        }
335    }
336
337    /// Unwraps the error if it is a database error.
338    #[inline]
339    pub fn unwrap_db_error(self) -> E {
340        if let JournalLoadError::DBError(e) = self {
341            e
342        } else {
343            panic!("Expected DBError");
344        }
345    }
346
347    /// Converts the error to a load error.
348    #[inline]
349    pub fn into_parts(self) -> (LoadError, Option<E>) {
350        match self {
351            JournalLoadError::DBError(e) => (LoadError::DBError, Some(e)),
352            JournalLoadError::ColdLoadSkipped => (LoadError::ColdLoadSkipped, None),
353        }
354    }
355}
356
357impl<E> From<E> for JournalLoadError<E> {
358    fn from(e: E) -> Self {
359        JournalLoadError::DBError(e)
360    }
361}
362
363impl<E> From<JournalLoadError<E>> for LoadError {
364    fn from(e: JournalLoadError<E>) -> Self {
365        match e {
366            JournalLoadError::DBError(_) => LoadError::DBError,
367            JournalLoadError::ColdLoadSkipped => LoadError::ColdLoadSkipped,
368        }
369    }
370}
371
372/// Transfer and creation result
373#[derive(Copy, Clone, Debug, PartialEq, Eq)]
374pub enum TransferError {
375    /// Caller does not have enough funds
376    OutOfFunds,
377    /// Overflow in target account
378    OverflowPayment,
379    /// Create collision.
380    CreateCollision,
381}
382
383/// SubRoutine checkpoint that will help us to go back from this
384#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
385#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
386pub struct JournalCheckpoint {
387    /// Checkpoint to where on revert we will go back to.
388    pub log_i: usize,
389    /// Checkpoint to where on revert we will go back to and revert other journal entries.
390    pub journal_i: usize,
391}
392
393/// State load information that contains the data and if the account or storage is cold loaded
394#[derive(Clone, Debug, Default, PartialEq, Eq)]
395#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
396pub struct StateLoad<T> {
397    /// Returned data
398    pub data: T,
399    /// Is account is cold loaded
400    pub is_cold: bool,
401}
402
403impl<T> Deref for StateLoad<T> {
404    type Target = T;
405
406    fn deref(&self) -> &Self::Target {
407        &self.data
408    }
409}
410
411impl<T> DerefMut for StateLoad<T> {
412    fn deref_mut(&mut self) -> &mut Self::Target {
413        &mut self.data
414    }
415}
416
417impl<T> StateLoad<T> {
418    /// Returns a new [`StateLoad`] with the given data and cold load status.
419    #[inline]
420    pub fn new(data: T, is_cold: bool) -> Self {
421        Self { data, is_cold }
422    }
423
424    /// Maps the data of the [`StateLoad`] to a new value.
425    ///
426    /// Useful for transforming the data of the [`StateLoad`] without changing the cold load status.
427    #[inline]
428    pub fn map<B, F>(self, f: F) -> StateLoad<B>
429    where
430        F: FnOnce(T) -> B,
431    {
432        StateLoad::new(f(self.data), self.is_cold)
433    }
434}
435
436/// Result of the account load from Journal state
437#[derive(Clone, Debug, Default, PartialEq, Eq)]
438#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
439pub struct AccountLoad {
440    /// Does account have delegate code and delegated account is cold loaded
441    pub is_delegate_account_cold: Option<bool>,
442    /// Is account empty, if `true` account is not created
443    pub is_empty: bool,
444}
445
446/// Result of the account load from Journal state
447#[derive(Clone, Debug, Default, PartialEq, Eq)]
448#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
449pub struct AccountInfoLoad<'a> {
450    /// Account info
451    pub account: Cow<'a, AccountInfo>,
452    /// Is account cold loaded
453    pub is_cold: bool,
454    /// Is account empty, if `true` account is not created
455    pub is_empty: bool,
456}
457
458impl<'a> AccountInfoLoad<'a> {
459    /// Creates new [`AccountInfoLoad`] with the given account info, cold load status and empty status.
460    pub fn new(account: &'a AccountInfo, is_cold: bool, is_empty: bool) -> Self {
461        Self {
462            account: Cow::Borrowed(account),
463            is_cold,
464            is_empty,
465        }
466    }
467
468    /// Maps the account info of the [`AccountInfoLoad`] to a new [`StateLoad`].
469    ///
470    /// Useful for transforming the account info of the [`AccountInfoLoad`] and preserving the cold load status.
471    pub fn into_state_load<F, O>(self, f: F) -> StateLoad<O>
472    where
473        F: FnOnce(Cow<'a, AccountInfo>) -> O,
474    {
475        StateLoad::new(f(self.account), self.is_cold)
476    }
477}
478
479impl<'a> Deref for AccountInfoLoad<'a> {
480    type Target = AccountInfo;
481
482    fn deref(&self) -> &Self::Target {
483        &self.account
484    }
485}