revm_context_interface/
journaled_state.rs

1//! Journaled state trait [`JournalTr`] and related types.
2use crate::context::{SStoreResult, SelfDestructResult};
3use core::ops::{Deref, DerefMut};
4use database_interface::Database;
5use primitives::{
6    hardfork::SpecId, Address, Bytes, HashSet, Log, StorageKey, StorageValue, B256, U256,
7};
8use state::{Account, Bytecode};
9use std::vec::Vec;
10
11/// Trait that contains database and journal of all changes that were made to the state.
12pub trait JournalTr {
13    /// Database type that is used in the journal.
14    type Database: Database;
15    /// State type that is returned by the journal after finalization.
16    type State;
17
18    /// Creates new Journaled state.
19    ///
20    /// Dont forget to set spec_id.
21    fn new(database: Self::Database) -> Self;
22
23    /// Returns a mutable reference to the database.
24    fn db_mut(&mut self) -> &mut Self::Database;
25
26    /// Returns an immutable reference to the database.
27    fn db(&self) -> &Self::Database;
28
29    /// Returns the storage value from Journal state.
30    ///
31    /// Loads the storage from database if not found in Journal state.
32    fn sload(
33        &mut self,
34        address: Address,
35        key: StorageKey,
36    ) -> Result<StateLoad<StorageValue>, <Self::Database as Database>::Error>;
37
38    /// Stores the storage value in Journal state.
39    fn sstore(
40        &mut self,
41        address: Address,
42        key: StorageKey,
43        value: StorageValue,
44    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error>;
45
46    /// Loads transient storage value.
47    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
48
49    /// Stores transient storage value.
50    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
51
52    /// Logs the log in Journal state.
53    fn log(&mut self, log: Log);
54
55    /// Marks the account for selfdestruction and transfers all the balance to the target.
56    fn selfdestruct(
57        &mut self,
58        address: Address,
59        target: Address,
60    ) -> Result<StateLoad<SelfDestructResult>, <Self::Database as Database>::Error>;
61
62    /// Warms the account and storage.
63    fn warm_account_and_storage(
64        &mut self,
65        address: Address,
66        storage_keys: impl IntoIterator<Item = StorageKey>,
67    ) -> Result<(), <Self::Database as Database>::Error>;
68
69    /// Warms the account. Internally calls [`JournalTr::warm_account_and_storage`] with empty storage keys.
70    fn warm_account(
71        &mut self,
72        address: Address,
73    ) -> Result<(), <Self::Database as Database>::Error> {
74        self.warm_account_and_storage(address, [])
75    }
76
77    /// Warms the coinbase account.
78    fn warm_coinbase_account(&mut self, address: Address);
79
80    /// Warms the precompiles.
81    fn warm_precompiles(&mut self, addresses: HashSet<Address>);
82
83    /// Returns the addresses of the precompiles.
84    fn precompile_addresses(&self) -> &HashSet<Address>;
85
86    /// Sets the spec id.
87    fn set_spec_id(&mut self, spec_id: SpecId);
88
89    /// Touches the account.
90    fn touch_account(&mut self, address: Address);
91
92    /// Transfers the balance from one account to another.
93    fn transfer(
94        &mut self,
95        from: Address,
96        to: Address,
97        balance: U256,
98    ) -> Result<Option<TransferError>, <Self::Database as Database>::Error>;
99
100    /// Increments the balance of the account.
101    fn caller_accounting_journal_entry(
102        &mut self,
103        address: Address,
104        old_balance: U256,
105        bump_nonce: bool,
106    );
107
108    /// Increments the balance of the account.
109    fn balance_incr(
110        &mut self,
111        address: Address,
112        balance: U256,
113    ) -> Result<(), <Self::Database as Database>::Error>;
114
115    /// Increments the nonce of the account.
116    fn nonce_bump_journal_entry(&mut self, address: Address);
117
118    /// Loads the account.
119    fn load_account(
120        &mut self,
121        address: Address,
122    ) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
123
124    /// Loads the account code.
125    fn load_account_code(
126        &mut self,
127        address: Address,
128    ) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
129
130    /// Loads the account delegated.
131    fn load_account_delegated(
132        &mut self,
133        address: Address,
134    ) -> Result<StateLoad<AccountLoad>, <Self::Database as Database>::Error>;
135
136    /// Sets bytecode with hash. Assume that account is warm.
137    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
138
139    /// Sets bytecode and calculates hash.
140    ///
141    /// Assume account is warm.
142    #[inline]
143    fn set_code(&mut self, address: Address, code: Bytecode) {
144        let hash = code.hash_slow();
145        self.set_code_with_hash(address, code, hash);
146    }
147
148    /// Returns account code bytes and if address is cold loaded.
149    #[inline]
150    fn code(
151        &mut self,
152        address: Address,
153    ) -> Result<StateLoad<Bytes>, <Self::Database as Database>::Error> {
154        let a = self.load_account_code(address)?;
155        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
156        let code = a.info.code.as_ref().unwrap();
157        let code = code.original_bytes();
158
159        Ok(StateLoad::new(code, a.is_cold))
160    }
161
162    /// Gets code hash of account.
163    fn code_hash(
164        &mut self,
165        address: Address,
166    ) -> Result<StateLoad<B256>, <Self::Database as Database>::Error> {
167        let acc = self.load_account_code(address)?;
168        if acc.is_empty() {
169            return Ok(StateLoad::new(B256::ZERO, acc.is_cold));
170        }
171        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
172        let _code = acc.info.code.as_ref().unwrap();
173
174        let hash = acc.info.code_hash;
175
176        Ok(StateLoad::new(hash, acc.is_cold))
177    }
178
179    /// Called at the end of the transaction to clean all residue data from journal.
180    fn clear(&mut self) {
181        let _ = self.finalize();
182    }
183
184    /// Creates a checkpoint of the current state. State can be revert to this point
185    /// if needed.
186    fn checkpoint(&mut self) -> JournalCheckpoint;
187
188    /// Commits the changes made since the last checkpoint.
189    fn checkpoint_commit(&mut self);
190
191    /// Reverts the changes made since the last checkpoint.
192    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint);
193
194    /// Creates a checkpoint of the account creation.
195    fn create_account_checkpoint(
196        &mut self,
197        caller: Address,
198        address: Address,
199        balance: U256,
200        spec_id: SpecId,
201    ) -> Result<JournalCheckpoint, TransferError>;
202
203    /// Returns the depth of the journal.
204    fn depth(&self) -> usize;
205
206    /// Take logs from journal.
207    fn take_logs(&mut self) -> Vec<Log>;
208
209    /// Commit current transaction journal and returns transaction logs.
210    fn commit_tx(&mut self);
211
212    /// Discard current transaction journal by removing journal entries and logs and incrementing the transaction id.
213    ///
214    /// This function is useful to discard intermediate state that is interrupted by error and it will not revert
215    /// any already committed changes and it is safe to call it multiple times.
216    fn discard_tx(&mut self);
217
218    /// Clear current journal resetting it to initial state and return changes state.
219    fn finalize(&mut self) -> Self::State;
220}
221
222/// Transfer and creation result
223#[derive(Copy, Clone, Debug, PartialEq, Eq)]
224pub enum TransferError {
225    /// Caller does not have enough funds
226    OutOfFunds,
227    /// Overflow in target account
228    OverflowPayment,
229    /// Create collision.
230    CreateCollision,
231}
232
233/// SubRoutine checkpoint that will help us to go back from this
234#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
235#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
236pub struct JournalCheckpoint {
237    /// Checkpoint to where on revert we will go back to.
238    pub log_i: usize,
239    /// Checkpoint to where on revert we will go back to and revert other journal entries.
240    pub journal_i: usize,
241}
242
243/// State load information that contains the data and if the account or storage is cold loaded
244#[derive(Clone, Debug, Default, PartialEq, Eq)]
245#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
246pub struct StateLoad<T> {
247    /// Returned data
248    pub data: T,
249    /// Is account is cold loaded
250    pub is_cold: bool,
251}
252
253impl<T> Deref for StateLoad<T> {
254    type Target = T;
255
256    fn deref(&self) -> &Self::Target {
257        &self.data
258    }
259}
260
261impl<T> DerefMut for StateLoad<T> {
262    fn deref_mut(&mut self) -> &mut Self::Target {
263        &mut self.data
264    }
265}
266
267impl<T> StateLoad<T> {
268    /// Returns a new [`StateLoad`] with the given data and cold load status.
269    pub fn new(data: T, is_cold: bool) -> Self {
270        Self { data, is_cold }
271    }
272
273    /// Maps the data of the [`StateLoad`] to a new value.
274    ///
275    /// Useful for transforming the data of the [`StateLoad`] without changing the cold load status.
276    pub fn map<B, F>(self, f: F) -> StateLoad<B>
277    where
278        F: FnOnce(T) -> B,
279    {
280        StateLoad::new(f(self.data), self.is_cold)
281    }
282}
283
284/// Result of the account load from Journal state
285#[derive(Clone, Debug, Default, PartialEq, Eq)]
286#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
287pub struct AccountLoad {
288    /// Does account have delegate code and delegated account is cold loaded
289    pub is_delegate_account_cold: Option<bool>,
290    /// Is account empty, if `true` account is not created
291    pub is_empty: bool,
292}