revm_context_interface/
journaled_state.rs

1use crate::context::{SStoreResult, SelfDestructResult};
2use core::ops::{Deref, DerefMut};
3use database_interface::Database;
4use primitives::{hardfork::SpecId, Address, Bytes, HashSet, Log, B256, U256};
5use state::{
6    bytecode::{EOF_MAGIC_BYTES, EOF_MAGIC_HASH},
7    Account, Bytecode,
8};
9
10pub trait JournalTr {
11    type Database: Database;
12    type FinalOutput;
13
14    /// Creates new Journaled state.
15    ///
16    /// Dont forget to set spec_id.
17    fn new(database: Self::Database) -> Self;
18
19    /// Returns the database.
20    fn db_ref(&self) -> &Self::Database;
21
22    /// Returns the mutable database.
23    fn db(&mut self) -> &mut Self::Database;
24
25    /// Returns the storage value from Journal state.
26    ///
27    /// Loads the storage from database if not found in Journal state.
28    fn sload(
29        &mut self,
30        address: Address,
31        key: U256,
32    ) -> Result<StateLoad<U256>, <Self::Database as Database>::Error>;
33
34    /// Stores the storage value in Journal state.
35    fn sstore(
36        &mut self,
37        address: Address,
38        key: U256,
39        value: U256,
40    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error>;
41
42    /// Loads transient storage value.
43    fn tload(&mut self, address: Address, key: U256) -> U256;
44
45    /// Stores transient storage value.
46    fn tstore(&mut self, address: Address, key: U256, value: U256);
47
48    /// Logs the log in Journal state.
49    fn log(&mut self, log: Log);
50
51    /// Marks the account for selfdestruction and transfers all the balance to the target.
52    fn selfdestruct(
53        &mut self,
54        address: Address,
55        target: Address,
56    ) -> Result<StateLoad<SelfDestructResult>, <Self::Database as Database>::Error>;
57
58    fn warm_account_and_storage(
59        &mut self,
60        address: Address,
61        storage_keys: impl IntoIterator<Item = U256>,
62    ) -> Result<(), <Self::Database as Database>::Error>;
63
64    fn warm_account(&mut self, address: Address);
65
66    fn warm_precompiles(&mut self, addresses: HashSet<Address>);
67
68    fn precompile_addresses(&self) -> &HashSet<Address>;
69
70    fn set_spec_id(&mut self, spec_id: SpecId);
71
72    fn touch_account(&mut self, address: Address);
73
74    fn transfer(
75        &mut self,
76        from: &Address,
77        to: &Address,
78        balance: U256,
79    ) -> Result<Option<TransferError>, <Self::Database as Database>::Error>;
80
81    fn inc_account_nonce(
82        &mut self,
83        address: Address,
84    ) -> Result<Option<u64>, <Self::Database as Database>::Error>;
85
86    fn load_account(
87        &mut self,
88        address: Address,
89    ) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
90
91    fn load_account_code(
92        &mut self,
93        address: Address,
94    ) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
95
96    fn load_account_delegated(
97        &mut self,
98        address: Address,
99    ) -> Result<StateLoad<AccountLoad>, <Self::Database as Database>::Error>;
100
101    /// Sets bytecode with hash. Assume that account is warm.
102    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
103
104    /// Sets bytecode and calculates hash.
105    ///
106    /// Assume account is warm.
107    #[inline]
108    fn set_code(&mut self, address: Address, code: Bytecode) {
109        let hash = code.hash_slow();
110        self.set_code_with_hash(address, code, hash);
111    }
112
113    /// Returns account code bytes and if address is cold loaded.
114    ///
115    /// In case of EOF account it will return `EOF_MAGIC` (0xEF00) as code.
116    #[inline]
117    fn code(
118        &mut self,
119        address: Address,
120    ) -> Result<StateLoad<Bytes>, <Self::Database as Database>::Error> {
121        let a = self.load_account_code(address)?;
122        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
123        let code = a.info.code.as_ref().unwrap();
124
125        let code = if code.is_eof() {
126            EOF_MAGIC_BYTES.clone()
127        } else {
128            code.original_bytes()
129        };
130
131        Ok(StateLoad::new(code, a.is_cold))
132    }
133
134    /// Gets code hash of account.
135    ///
136    /// In case of EOF account it will return `EOF_MAGIC_HASH`
137    /// (the hash of `0xEF00`).
138    fn code_hash(
139        &mut self,
140        address: Address,
141    ) -> Result<StateLoad<B256>, <Self::Database as Database>::Error> {
142        let acc = self.load_account_code(address)?;
143        if acc.is_empty() {
144            return Ok(StateLoad::new(B256::ZERO, acc.is_cold));
145        }
146        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
147        let code = acc.info.code.as_ref().unwrap();
148
149        let hash = if code.is_eof() {
150            EOF_MAGIC_HASH
151        } else {
152            acc.info.code_hash
153        };
154
155        Ok(StateLoad::new(hash, acc.is_cold))
156    }
157
158    /// Called at the end of the transaction to clean all residue data from journal.
159    fn clear(&mut self);
160
161    fn checkpoint(&mut self) -> JournalCheckpoint;
162
163    fn checkpoint_commit(&mut self);
164
165    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint);
166
167    fn create_account_checkpoint(
168        &mut self,
169        caller: Address,
170        address: Address,
171        balance: U256,
172        spec_id: SpecId,
173    ) -> Result<JournalCheckpoint, TransferError>;
174
175    fn depth(&self) -> usize;
176
177    /// Does cleanup and returns modified state.
178    ///
179    /// This resets the [JournalTr] to its initial state.
180    fn finalize(&mut self) -> Self::FinalOutput;
181}
182
183/// Transfer and creation result
184#[derive(Copy, Clone, Debug, PartialEq, Eq)]
185pub enum TransferError {
186    /// Caller does not have enough funds
187    OutOfFunds,
188    /// Overflow in target account
189    OverflowPayment,
190    /// Create collision.
191    CreateCollision,
192}
193
194/// SubRoutine checkpoint that will help us to go back from this
195#[derive(Debug, Copy, Clone, PartialEq, Eq)]
196#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
197pub struct JournalCheckpoint {
198    pub log_i: usize,
199    pub journal_i: usize,
200}
201
202/// State load information that contains the data and if the account or storage is cold loaded
203#[derive(Clone, Debug, Default, PartialEq, Eq)]
204#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
205pub struct StateLoad<T> {
206    /// Returned data
207    pub data: T,
208    /// Is account is cold loaded
209    pub is_cold: bool,
210}
211
212impl<T> Deref for StateLoad<T> {
213    type Target = T;
214
215    fn deref(&self) -> &Self::Target {
216        &self.data
217    }
218}
219
220impl<T> DerefMut for StateLoad<T> {
221    fn deref_mut(&mut self) -> &mut Self::Target {
222        &mut self.data
223    }
224}
225
226impl<T> StateLoad<T> {
227    /// Returns a new [`StateLoad`] with the given data and cold load status.
228    pub fn new(data: T, is_cold: bool) -> Self {
229        Self { data, is_cold }
230    }
231
232    /// Maps the data of the [`StateLoad`] to a new value.
233    ///
234    /// Useful for transforming the data of the [`StateLoad`] without changing the cold load status.
235    pub fn map<B, F>(self, f: F) -> StateLoad<B>
236    where
237        F: FnOnce(T) -> B,
238    {
239        StateLoad::new(f(self.data), self.is_cold)
240    }
241}
242
243/// Result of the account load from Journal state
244#[derive(Clone, Debug, Default, PartialEq, Eq)]
245#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
246pub struct AccountLoad {
247    /// Does account have delegate code and delegated account is cold loaded
248    pub is_delegate_account_cold: Option<bool>,
249    /// Is account empty, if `true` account is not created
250    pub is_empty: bool,
251}