Skip to main content

revm_context/
journal.rs

1//! This module contains [`Journal`] struct and implements [`JournalTr`] trait for it.
2//!
3//! Entry submodule contains [`JournalEntry`] and [`JournalEntryTr`] traits.
4//! and inner submodule contains [`JournalInner`] struct that contains state.
5pub mod inner;
6pub mod warm_addresses;
7
8pub use context_interface::journaled_state::entry::{JournalEntry, JournalEntryTr};
9pub use inner::JournalInner;
10
11use bytecode::Bytecode;
12use context_interface::{
13    context::{SStoreResult, SelfDestructResult, StateLoad},
14    journaled_state::{
15        account::JournaledAccount, AccountInfoLoad, AccountLoad, JournalCheckpoint,
16        JournalLoadError, JournalTr, TransferError,
17    },
18};
19use core::ops::{Deref, DerefMut};
20use database_interface::Database;
21use primitives::{
22    hardfork::SpecId, Address, AddressMap, AddressSet, HashSet, Log, StorageKey, StorageValue,
23    B256, U256,
24};
25use state::{Account, EvmState};
26use std::vec::Vec;
27
28/// A journal of state changes internal to the EVM
29///
30/// On each additional call, the depth of the journaled state is increased (`depth`) and a new journal is added.
31///
32/// The journal contains every state change that happens within that call, making it possible to revert changes made in a specific call.
33#[derive(Debug, Clone, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub struct Journal<DB, ENTRY = JournalEntry>
36where
37    ENTRY: JournalEntryTr,
38{
39    /// Database
40    pub database: DB,
41    /// Inner journal state.
42    pub inner: JournalInner<ENTRY>,
43}
44
45impl<DB, ENTRY> Deref for Journal<DB, ENTRY>
46where
47    ENTRY: JournalEntryTr,
48{
49    type Target = JournalInner<ENTRY>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.inner
53    }
54}
55
56impl<DB, ENTRY> DerefMut for Journal<DB, ENTRY>
57where
58    ENTRY: JournalEntryTr,
59{
60    fn deref_mut(&mut self) -> &mut Self::Target {
61        &mut self.inner
62    }
63}
64
65impl<DB, ENTRY: JournalEntryTr> Journal<DB, ENTRY> {
66    /// Creates a new JournaledState by copying state data from a JournalInit and provided database.
67    /// This allows reusing the state, logs, and other data from a previous execution context while
68    /// connecting it to a different database backend.
69    pub fn new_with_inner(database: DB, inner: JournalInner<ENTRY>) -> Self {
70        Self { database, inner }
71    }
72
73    /// Consumes the [`Journal`] and returns [`JournalInner`].
74    ///
75    /// If you need to preserve the original journal, use [`Self::to_inner`] instead which clones the state.
76    pub fn into_init(self) -> JournalInner<ENTRY> {
77        self.inner
78    }
79}
80
81impl<DB, ENTRY: JournalEntryTr + Clone> Journal<DB, ENTRY> {
82    /// Creates a new [`JournalInner`] by cloning all internal state data (state, storage, logs, etc)
83    /// This allows creating a new journaled state with the same state data but without
84    /// carrying over the original database.
85    ///
86    /// This is useful when you want to reuse the current state for a new transaction or
87    /// execution context, but want to start with a fresh database.
88    pub fn to_inner(&self) -> JournalInner<ENTRY> {
89        self.inner.clone()
90    }
91}
92
93impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
94    type Database = DB;
95    type State = EvmState;
96    type JournaledAccount<'a>
97        = JournaledAccount<'a, DB, ENTRY>
98    where
99        ENTRY: 'a,
100        DB: 'a;
101
102    fn new(database: DB) -> Journal<DB, ENTRY> {
103        Self {
104            inner: JournalInner::new(),
105            database,
106        }
107    }
108
109    fn db(&self) -> &Self::Database {
110        &self.database
111    }
112
113    fn db_mut(&mut self) -> &mut Self::Database {
114        &mut self.database
115    }
116
117    fn sload(
118        &mut self,
119        address: Address,
120        key: StorageKey,
121    ) -> Result<StateLoad<StorageValue>, <Self::Database as Database>::Error> {
122        self.inner
123            .sload_assume_account_present(&mut self.database, address, key, false)
124            .map_err(JournalLoadError::unwrap_db_error)
125    }
126
127    fn sstore(
128        &mut self,
129        address: Address,
130        key: StorageKey,
131        value: StorageValue,
132    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
133        self.inner
134            .sstore_assume_account_present(&mut self.database, address, key, value, false)
135            .map_err(JournalLoadError::unwrap_db_error)
136    }
137
138    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
139        self.inner.tload(address, key)
140    }
141
142    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) {
143        self.inner.tstore(address, key, value)
144    }
145
146    fn log(&mut self, log: Log) {
147        self.inner.log(log)
148    }
149
150    #[inline]
151    fn logs(&self) -> &[Log] {
152        &self.inner.logs
153    }
154
155    #[inline]
156    fn take_logs(&mut self) -> Vec<Log> {
157        self.inner.take_logs()
158    }
159
160    fn selfdestruct(
161        &mut self,
162        address: Address,
163        target: Address,
164        skip_cold_load: bool,
165    ) -> Result<StateLoad<SelfDestructResult>, JournalLoadError<<Self::Database as Database>::Error>>
166    {
167        self.inner
168            .selfdestruct(&mut self.database, address, target, skip_cold_load)
169    }
170
171    #[inline]
172    fn warm_access_list(&mut self, access_list: AddressMap<HashSet<StorageKey>>) {
173        self.inner.warm_addresses.set_access_list(access_list);
174    }
175
176    fn warm_coinbase_account(&mut self, address: Address) {
177        self.inner.warm_addresses.set_coinbase(address);
178    }
179
180    fn warm_precompiles(&mut self, precompiles: AddressSet) {
181        self.inner
182            .warm_addresses
183            .set_precompile_addresses(precompiles);
184    }
185
186    #[inline]
187    fn precompile_addresses(&self) -> &AddressSet {
188        self.inner.warm_addresses.precompiles()
189    }
190
191    /// Returns call depth.
192    #[inline]
193    fn depth(&self) -> usize {
194        self.inner.depth
195    }
196
197    #[inline]
198    fn set_spec_id(&mut self, spec_id: SpecId) {
199        self.inner.spec = spec_id;
200    }
201
202    #[inline]
203    fn transfer(
204        &mut self,
205        from: Address,
206        to: Address,
207        balance: U256,
208    ) -> Result<Option<TransferError>, DB::Error> {
209        self.inner.transfer(&mut self.database, from, to, balance)
210    }
211
212    #[inline]
213    fn transfer_loaded(
214        &mut self,
215        from: Address,
216        to: Address,
217        balance: U256,
218    ) -> Option<TransferError> {
219        self.inner.transfer_loaded(from, to, balance)
220    }
221
222    #[inline]
223    fn touch_account(&mut self, address: Address) {
224        self.inner.touch(address);
225    }
226
227    #[inline]
228    #[allow(deprecated)]
229    fn caller_accounting_journal_entry(
230        &mut self,
231        address: Address,
232        old_balance: U256,
233        bump_nonce: bool,
234    ) {
235        self.inner
236            .caller_accounting_journal_entry(address, old_balance, bump_nonce);
237    }
238
239    /// Increments the balance of the account.
240    #[inline]
241    fn balance_incr(
242        &mut self,
243        address: Address,
244        balance: U256,
245    ) -> Result<(), <Self::Database as Database>::Error> {
246        self.inner
247            .balance_incr(&mut self.database, address, balance)
248    }
249
250    /// Increments the nonce of the account.
251    #[inline]
252    #[allow(deprecated)]
253    fn nonce_bump_journal_entry(&mut self, address: Address) {
254        self.inner.nonce_bump_journal_entry(address)
255    }
256
257    #[inline]
258    fn load_account(&mut self, address: Address) -> Result<StateLoad<&Account>, DB::Error> {
259        self.inner.load_account(&mut self.database, address)
260    }
261
262    #[inline]
263    fn load_account_mut_skip_cold_load(
264        &mut self,
265        address: Address,
266        skip_cold_load: bool,
267    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, DB::Error> {
268        self.inner
269            .load_account_mut_optional(&mut self.database, address, skip_cold_load)
270            .map_err(JournalLoadError::unwrap_db_error)
271    }
272
273    #[inline]
274    fn load_account_mut_optional_code(
275        &mut self,
276        address: Address,
277        load_code: bool,
278    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, DB::Error> {
279        self.inner
280            .load_account_mut_optional_code(&mut self.database, address, load_code, false)
281            .map_err(JournalLoadError::unwrap_db_error)
282    }
283
284    #[inline]
285    fn load_account_with_code(
286        &mut self,
287        address: Address,
288    ) -> Result<StateLoad<&Account>, DB::Error> {
289        self.inner.load_code(&mut self.database, address)
290    }
291
292    #[inline]
293    fn load_account_delegated(
294        &mut self,
295        address: Address,
296    ) -> Result<StateLoad<AccountLoad>, DB::Error> {
297        self.inner
298            .load_account_delegated(&mut self.database, address)
299    }
300
301    #[inline]
302    fn checkpoint(&mut self) -> JournalCheckpoint {
303        self.inner.checkpoint()
304    }
305
306    #[inline]
307    fn checkpoint_commit(&mut self) {
308        self.inner.checkpoint_commit()
309    }
310
311    #[inline]
312    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
313        self.inner.checkpoint_revert(checkpoint)
314    }
315
316    #[inline]
317    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
318        self.inner.set_code_with_hash(address, code, hash);
319    }
320
321    #[inline]
322    fn create_account_checkpoint(
323        &mut self,
324        caller: Address,
325        address: Address,
326        balance: U256,
327        spec_id: SpecId,
328    ) -> Result<JournalCheckpoint, TransferError> {
329        // Ignore error.
330        self.inner
331            .create_account_checkpoint(caller, address, balance, spec_id)
332    }
333
334    #[inline]
335    fn commit_tx(&mut self) {
336        self.inner.commit_tx()
337    }
338
339    #[inline]
340    fn discard_tx(&mut self) {
341        self.inner.discard_tx();
342    }
343
344    /// Clear current journal resetting it to initial state and return changes state.
345    #[inline]
346    fn finalize(&mut self) -> Self::State {
347        self.inner.finalize()
348    }
349
350    #[inline]
351    fn sload_skip_cold_load(
352        &mut self,
353        address: Address,
354        key: StorageKey,
355        skip_cold_load: bool,
356    ) -> Result<StateLoad<StorageValue>, JournalLoadError<<Self::Database as Database>::Error>>
357    {
358        self.inner
359            .sload_assume_account_present(&mut self.database, address, key, skip_cold_load)
360    }
361
362    #[inline]
363    fn sstore_skip_cold_load(
364        &mut self,
365        address: Address,
366        key: StorageKey,
367        value: StorageValue,
368        skip_cold_load: bool,
369    ) -> Result<StateLoad<SStoreResult>, JournalLoadError<<Self::Database as Database>::Error>>
370    {
371        self.inner.sstore_assume_account_present(
372            &mut self.database,
373            address,
374            key,
375            value,
376            skip_cold_load,
377        )
378    }
379
380    #[inline]
381    fn load_account_info_skip_cold_load(
382        &mut self,
383        address: Address,
384        load_code: bool,
385        skip_cold_load: bool,
386    ) -> Result<AccountInfoLoad<'_>, JournalLoadError<<Self::Database as Database>::Error>> {
387        let spec = self.inner.spec;
388        self.inner
389            .load_account_optional(&mut self.database, address, load_code, skip_cold_load)
390            .map(|a| {
391                AccountInfoLoad::new(&a.data.info, a.is_cold, a.state_clear_aware_is_empty(spec))
392            })
393    }
394}