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