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::{JournalCfg, 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.cfg.spec = spec_id;
200    }
201
202    #[inline]
203    fn set_eip7708_config(&mut self, disabled: bool, delayed_burn_disabled: bool) {
204        self.inner
205            .set_eip7708_config(disabled, delayed_burn_disabled);
206    }
207
208    #[inline]
209    fn transfer(
210        &mut self,
211        from: Address,
212        to: Address,
213        balance: U256,
214    ) -> Result<Option<TransferError>, DB::Error> {
215        self.inner.transfer(&mut self.database, from, to, balance)
216    }
217
218    #[inline]
219    fn transfer_loaded(
220        &mut self,
221        from: Address,
222        to: Address,
223        balance: U256,
224    ) -> Option<TransferError> {
225        self.inner.transfer_loaded(from, to, balance)
226    }
227
228    #[inline]
229    fn touch_account(&mut self, address: Address) {
230        self.inner.touch(address);
231    }
232
233    #[inline]
234    #[allow(deprecated)]
235    fn caller_accounting_journal_entry(
236        &mut self,
237        address: Address,
238        old_balance: U256,
239        bump_nonce: bool,
240    ) {
241        self.inner
242            .caller_accounting_journal_entry(address, old_balance, bump_nonce);
243    }
244
245    /// Increments the balance of the account.
246    #[inline]
247    fn balance_incr(
248        &mut self,
249        address: Address,
250        balance: U256,
251    ) -> Result<(), <Self::Database as Database>::Error> {
252        self.inner
253            .balance_incr(&mut self.database, address, balance)
254    }
255
256    /// Increments the nonce of the account.
257    #[inline]
258    #[allow(deprecated)]
259    fn nonce_bump_journal_entry(&mut self, address: Address) {
260        self.inner.nonce_bump_journal_entry(address)
261    }
262
263    #[inline]
264    fn load_account(&mut self, address: Address) -> Result<StateLoad<&Account>, DB::Error> {
265        self.inner.load_account(&mut self.database, address)
266    }
267
268    #[inline]
269    fn load_account_mut_skip_cold_load(
270        &mut self,
271        address: Address,
272        skip_cold_load: bool,
273    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, DB::Error> {
274        self.inner
275            .load_account_mut_optional(&mut self.database, address, skip_cold_load)
276            .map_err(JournalLoadError::unwrap_db_error)
277    }
278
279    #[inline]
280    fn load_account_mut_optional_code(
281        &mut self,
282        address: Address,
283        load_code: bool,
284    ) -> Result<StateLoad<Self::JournaledAccount<'_>>, DB::Error> {
285        self.inner
286            .load_account_mut_optional_code(&mut self.database, address, load_code, false)
287            .map_err(JournalLoadError::unwrap_db_error)
288    }
289
290    #[inline]
291    fn load_account_with_code(
292        &mut self,
293        address: Address,
294    ) -> Result<StateLoad<&Account>, DB::Error> {
295        self.inner.load_code(&mut self.database, address)
296    }
297
298    #[inline]
299    fn load_account_delegated(
300        &mut self,
301        address: Address,
302    ) -> Result<StateLoad<AccountLoad>, DB::Error> {
303        self.inner
304            .load_account_delegated(&mut self.database, address)
305    }
306
307    #[inline]
308    fn checkpoint(&mut self) -> JournalCheckpoint {
309        self.inner.checkpoint()
310    }
311
312    #[inline]
313    fn checkpoint_commit(&mut self) {
314        self.inner.checkpoint_commit()
315    }
316
317    #[inline]
318    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
319        self.inner.checkpoint_revert(checkpoint)
320    }
321
322    #[inline]
323    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
324        self.inner.set_code_with_hash(address, code, hash);
325    }
326
327    #[inline]
328    fn create_account_checkpoint(
329        &mut self,
330        caller: Address,
331        address: Address,
332        balance: U256,
333        spec_id: SpecId,
334    ) -> Result<JournalCheckpoint, TransferError> {
335        // Ignore error.
336        self.inner
337            .create_account_checkpoint(caller, address, balance, spec_id)
338    }
339
340    #[inline]
341    fn commit_tx(&mut self) {
342        self.inner.commit_tx()
343    }
344
345    #[inline]
346    fn discard_tx(&mut self) {
347        self.inner.discard_tx();
348    }
349
350    /// Clear current journal resetting it to initial state and return changes state.
351    #[inline]
352    fn finalize(&mut self) -> Self::State {
353        self.inner.finalize()
354    }
355
356    #[inline]
357    fn sload_skip_cold_load(
358        &mut self,
359        address: Address,
360        key: StorageKey,
361        skip_cold_load: bool,
362    ) -> Result<StateLoad<StorageValue>, JournalLoadError<<Self::Database as Database>::Error>>
363    {
364        self.inner
365            .sload_assume_account_present(&mut self.database, address, key, skip_cold_load)
366    }
367
368    #[inline]
369    fn sstore_skip_cold_load(
370        &mut self,
371        address: Address,
372        key: StorageKey,
373        value: StorageValue,
374        skip_cold_load: bool,
375    ) -> Result<StateLoad<SStoreResult>, JournalLoadError<<Self::Database as Database>::Error>>
376    {
377        self.inner.sstore_assume_account_present(
378            &mut self.database,
379            address,
380            key,
381            value,
382            skip_cold_load,
383        )
384    }
385
386    #[inline]
387    fn load_account_info_skip_cold_load(
388        &mut self,
389        address: Address,
390        load_code: bool,
391        skip_cold_load: bool,
392    ) -> Result<AccountInfoLoad<'_>, JournalLoadError<<Self::Database as Database>::Error>> {
393        let spec = self.inner.cfg.spec;
394        self.inner
395            .load_account_optional(&mut self.database, address, load_code, skip_cold_load)
396            .map(|a| {
397                AccountInfoLoad::new(&a.data.info, a.is_cold, a.state_clear_aware_is_empty(spec))
398            })
399    }
400}