revm_context/
journaled_state.rs

1use bytecode::{Bytecode, EOF_MAGIC_BYTES, EOF_MAGIC_HASH};
2use context_interface::journaled_state::{AccountLoad, Journal, JournalCheckpoint, TransferError};
3use database_interface::Database;
4use interpreter::{SStoreResult, SelfDestructResult, StateLoad};
5use primitives::{
6    hash_map::Entry, Address, Bytes, HashMap, HashSet, Log, B256, KECCAK_EMPTY, PRECOMPILE3, U256,
7};
8use specification::hardfork::{SpecId, SpecId::*};
9use state::{Account, EvmState, EvmStorageSlot, TransientStorage};
10
11use core::mem;
12use std::{vec, vec::Vec};
13
14use crate::JournalInit;
15
16/// A journal of state changes internal to the EVM
17///
18/// On each additional call, the depth of the journaled state is increased (`depth`) and a new journal is added.
19///
20/// The journal contains every state change that happens within that call, making it possible to revert changes made in a specific call.
21#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct JournaledState<DB> {
24    /// Database
25    pub database: DB,
26    /// The current state
27    pub state: EvmState,
28    /// Transient storage that is discarded after every transaction.
29    ///
30    /// See [EIP-1153](https://eips.ethereum.org/EIPS/eip-1153).
31    pub transient_storage: TransientStorage,
32    /// Emitted logs
33    pub logs: Vec<Log>,
34    /// The current call stack depth
35    pub depth: usize,
36    /// The journal of state changes, one for each call
37    pub journal: Vec<Vec<JournalEntry>>,
38    /// The spec ID for the EVM
39    ///
40    /// This spec is used for two things:
41    ///
42    /// - [EIP-161]: Prior to this EIP, Ethereum had separate definitions for empty and non-existing accounts.
43    /// - [EIP-6780]: `SELFDESTRUCT` only in same transaction
44    ///
45    /// [EIP-161]: https://eips.ethereum.org/EIPS/eip-161
46    /// [EIP-6780]: https://eips.ethereum.org/EIPS/eip-6780
47    pub spec: SpecId,
48    /// Warm loaded addresses are used to check if loaded address
49    /// should be considered cold or warm loaded when the account
50    /// is first accessed.
51    ///
52    /// Note that this not include newly loaded accounts, account and storage
53    /// is considered warm if it is found in the `State`.
54    pub warm_preloaded_addresses: HashSet<Address>,
55    /// Precompile addresses
56    pub precompiles: HashSet<Address>,
57}
58
59impl<DB: Database> Journal for JournaledState<DB> {
60    type Database = DB;
61    // TODO : Make a struck here.
62    type FinalOutput = (EvmState, Vec<Log>);
63
64    fn new(database: DB) -> JournaledState<DB> {
65        Self::new(SpecId::LATEST, database)
66    }
67
68    fn db_ref(&self) -> &Self::Database {
69        &self.database
70    }
71
72    fn db(&mut self) -> &mut Self::Database {
73        &mut self.database
74    }
75
76    fn sload(
77        &mut self,
78        address: Address,
79        key: U256,
80    ) -> Result<StateLoad<U256>, <Self::Database as Database>::Error> {
81        self.sload(address, key)
82    }
83
84    fn sstore(
85        &mut self,
86        address: Address,
87        key: U256,
88        value: U256,
89    ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
90        self.sstore(address, key, value)
91    }
92
93    fn tload(&mut self, address: Address, key: U256) -> U256 {
94        self.tload(address, key)
95    }
96
97    fn tstore(&mut self, address: Address, key: U256, value: U256) {
98        self.tstore(address, key, value)
99    }
100
101    fn log(&mut self, log: Log) {
102        self.log(log)
103    }
104
105    fn selfdestruct(
106        &mut self,
107        address: Address,
108        target: Address,
109    ) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
110        self.selfdestruct(address, target)
111    }
112
113    fn warm_account(&mut self, address: Address) {
114        self.warm_preloaded_addresses.insert(address);
115    }
116
117    fn warm_precompiles(&mut self, address: HashSet<Address>) {
118        self.precompiles = address;
119        self.warm_preloaded_addresses
120            .extend(self.precompiles.iter());
121    }
122
123    #[inline]
124    fn precompile_addresses(&self) -> &HashSet<Address> {
125        &self.precompiles
126    }
127
128    /// Returns call depth.
129    #[inline]
130    fn depth(&self) -> usize {
131        self.depth
132    }
133
134    fn warm_account_and_storage(
135        &mut self,
136        address: Address,
137        storage_keys: impl IntoIterator<Item = U256>,
138    ) -> Result<(), <Self::Database as Database>::Error> {
139        self.initial_account_load(address, storage_keys)?;
140        Ok(())
141    }
142
143    fn set_spec_id(&mut self, spec_id: SpecId) {
144        self.spec = spec_id;
145    }
146
147    fn code(
148        &mut self,
149        address: Address,
150    ) -> Result<StateLoad<primitives::Bytes>, <Self::Database as Database>::Error> {
151        self.code(address)
152    }
153
154    fn code_hash(
155        &mut self,
156        address: Address,
157    ) -> Result<StateLoad<B256>, <Self::Database as Database>::Error> {
158        self.code_hash(address)
159    }
160
161    fn transfer(
162        &mut self,
163        from: &Address,
164        to: &Address,
165        balance: U256,
166    ) -> Result<Option<TransferError>, DB::Error> {
167        self.transfer(from, to, balance)
168    }
169
170    fn touch_account(&mut self, address: Address) {
171        self.touch(&address);
172    }
173
174    fn inc_account_nonce(&mut self, address: Address) -> Result<Option<u64>, DB::Error> {
175        Ok(self.inc_nonce(address))
176    }
177
178    fn load_account(&mut self, address: Address) -> Result<StateLoad<&mut Account>, DB::Error> {
179        self.load_account(address)
180    }
181
182    fn load_account_code(
183        &mut self,
184        address: Address,
185    ) -> Result<StateLoad<&mut Account>, DB::Error> {
186        self.load_code(address)
187    }
188
189    fn load_account_delegated(
190        &mut self,
191        address: Address,
192    ) -> Result<StateLoad<AccountLoad>, DB::Error> {
193        self.load_account_delegated(address)
194    }
195
196    fn checkpoint(&mut self) -> JournalCheckpoint {
197        self.checkpoint()
198    }
199
200    fn checkpoint_commit(&mut self) {
201        self.checkpoint_commit()
202    }
203
204    fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
205        self.checkpoint_revert(checkpoint)
206    }
207
208    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
209        self.set_code_with_hash(address, code, hash);
210    }
211
212    fn clear(&mut self) {
213        // Clears the JournaledState. Preserving only the spec.
214        self.state.clear();
215        self.transient_storage.clear();
216        self.logs.clear();
217        self.journal = vec![vec![]];
218        self.depth = 0;
219        self.warm_preloaded_addresses.clear();
220    }
221
222    fn create_account_checkpoint(
223        &mut self,
224        caller: Address,
225        address: Address,
226        balance: U256,
227        spec_id: SpecId,
228    ) -> Result<JournalCheckpoint, TransferError> {
229        // Ignore error.
230        self.create_account_checkpoint(caller, address, balance, spec_id)
231    }
232
233    fn finalize(&mut self) -> Self::FinalOutput {
234        let Self {
235            state,
236            transient_storage,
237            logs,
238            depth,
239            journal,
240            // kept, see [Self::new]
241            spec: _,
242            database: _,
243            warm_preloaded_addresses: _,
244            precompiles: _,
245        } = self;
246
247        *transient_storage = TransientStorage::default();
248        *journal = vec![vec![]];
249        *depth = 0;
250        let state = mem::take(state);
251        let logs = mem::take(logs);
252
253        (state, logs)
254    }
255}
256
257impl<DB: Database> JournaledState<DB> {
258    /// Creates new JournaledState.
259    ///
260    /// `warm_preloaded_addresses` is used to determine if address is considered warm loaded.
261    /// In ordinary case this is precompile or beneficiary.
262    ///
263    /// # Note
264    /// This function will journal state after Spurious Dragon fork.
265    /// And will not take into account if account is not existing or empty.
266    pub fn new(spec: SpecId, database: DB) -> JournaledState<DB> {
267        Self {
268            database,
269            state: HashMap::default(),
270            transient_storage: TransientStorage::default(),
271            logs: Vec::new(),
272            journal: vec![vec![]],
273            depth: 0,
274            spec,
275            warm_preloaded_addresses: HashSet::default(),
276            precompiles: HashSet::default(),
277        }
278    }
279
280    /// Return reference to state.
281    #[inline]
282    pub fn state(&mut self) -> &mut EvmState {
283        &mut self.state
284    }
285
286    /// Sets SpecId.
287    #[inline]
288    pub fn set_spec_id(&mut self, spec: SpecId) {
289        self.spec = spec;
290    }
291
292    /// Mark account as touched as only touched accounts will be added to state.
293    /// This is especially important for state clear where touched empty accounts needs to
294    /// be removed from state.
295    #[inline]
296    pub fn touch(&mut self, address: &Address) {
297        if let Some(account) = self.state.get_mut(address) {
298            Self::touch_account(self.journal.last_mut().unwrap(), address, account);
299        }
300    }
301
302    /// Mark account as touched.
303    #[inline]
304    fn touch_account(journal: &mut Vec<JournalEntry>, address: &Address, account: &mut Account) {
305        if !account.is_touched() {
306            journal.push(JournalEntry::AccountTouched { address: *address });
307            account.mark_touch();
308        }
309    }
310
311    /// Returns the _loaded_ [Account] for the given address.
312    ///
313    /// This assumes that the account has already been loaded.
314    ///
315    /// # Panics
316    ///
317    /// Panics if the account has not been loaded and is missing from the state set.
318    #[inline]
319    pub fn account(&self, address: Address) -> &Account {
320        self.state
321            .get(&address)
322            .expect("Account expected to be loaded") // Always assume that acc is already loaded
323    }
324
325    /// Set code and its hash to the account.
326    ///
327    /// Note: Assume account is warm and that hash is calculated from code.
328    #[inline]
329    pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
330        let account = self.state.get_mut(&address).unwrap();
331        Self::touch_account(self.journal.last_mut().unwrap(), &address, account);
332
333        self.journal
334            .last_mut()
335            .unwrap()
336            .push(JournalEntry::CodeChange { address });
337
338        account.info.code_hash = hash;
339        account.info.code = Some(code);
340    }
341
342    /// Use it only if you know that acc is warm.
343    ///
344    /// Assume account is warm.
345    #[inline]
346    pub fn set_code(&mut self, address: Address, code: Bytecode) {
347        let hash = code.hash_slow();
348        self.set_code_with_hash(address, code, hash)
349    }
350
351    #[inline]
352    pub fn inc_nonce(&mut self, address: Address) -> Option<u64> {
353        let account = self.state.get_mut(&address).unwrap();
354        // Check if nonce is going to overflow.
355        if account.info.nonce == u64::MAX {
356            return None;
357        }
358        Self::touch_account(self.journal.last_mut().unwrap(), &address, account);
359        self.journal
360            .last_mut()
361            .unwrap()
362            .push(JournalEntry::NonceChange { address });
363
364        account.info.nonce += 1;
365
366        Some(account.info.nonce)
367    }
368
369    /// Transfers balance from two accounts. Returns error if sender balance is not enough.
370    #[inline]
371    pub fn transfer(
372        &mut self,
373        from: &Address,
374        to: &Address,
375        balance: U256,
376    ) -> Result<Option<TransferError>, DB::Error> {
377        if balance.is_zero() {
378            self.load_account(*to)?;
379            let _ = self.load_account(*to)?;
380            let to_account = self.state.get_mut(to).unwrap();
381            Self::touch_account(self.journal.last_mut().unwrap(), to, to_account);
382            return Ok(None);
383        }
384        // load accounts
385        self.load_account(*from)?;
386        self.load_account(*to)?;
387
388        // sub balance from
389        let from_account = &mut self.state.get_mut(from).unwrap();
390        Self::touch_account(self.journal.last_mut().unwrap(), from, from_account);
391        let from_balance = &mut from_account.info.balance;
392
393        let Some(from_balance_decr) = from_balance.checked_sub(balance) else {
394            return Ok(Some(TransferError::OutOfFunds));
395        };
396        *from_balance = from_balance_decr;
397
398        // add balance to
399        let to_account = &mut self.state.get_mut(to).unwrap();
400        Self::touch_account(self.journal.last_mut().unwrap(), to, to_account);
401        let to_balance = &mut to_account.info.balance;
402        let Some(to_balance_incr) = to_balance.checked_add(balance) else {
403            return Ok(Some(TransferError::OverflowPayment));
404        };
405        *to_balance = to_balance_incr;
406        // Overflow of U256 balance is not possible to happen on mainnet. We don't bother to return funds from from_acc.
407
408        self.journal
409            .last_mut()
410            .unwrap()
411            .push(JournalEntry::BalanceTransfer {
412                from: *from,
413                to: *to,
414                balance,
415            });
416
417        Ok(None)
418    }
419
420    /// Returns account code bytes and if address is cold loaded.
421    ///
422    /// In case of EOF account it will return `EOF_MAGIC` (0xEF00) as code.
423    ///
424    // TODO : Move this in Journaled state
425    #[inline]
426    pub fn code(&mut self, address: Address) -> Result<StateLoad<Bytes>, <DB as Database>::Error> {
427        let a = self.load_account_code(address)?;
428        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
429        let code = a.info.code.as_ref().unwrap();
430
431        let code = if code.is_eof() {
432            EOF_MAGIC_BYTES.clone()
433        } else {
434            code.original_bytes()
435        };
436
437        Ok(StateLoad::new(code, a.is_cold))
438    }
439
440    /// Gets code hash of address.
441    ///
442    /// In case of EOF account it will return `EOF_MAGIC_HASH`
443    /// (the hash of `0xEF00`).
444    #[inline]
445    pub fn code_hash(
446        &mut self,
447        address: Address,
448    ) -> Result<StateLoad<B256>, <DB as Database>::Error> {
449        let acc = self.load_account_code(address)?;
450        if acc.is_empty() {
451            return Ok(StateLoad::new(B256::ZERO, acc.is_cold));
452        }
453        // SAFETY: Safe to unwrap as load_code will insert code if it is empty.
454        let code = acc.info.code.as_ref().unwrap();
455
456        let hash = if code.is_eof() {
457            EOF_MAGIC_HASH
458        } else {
459            acc.info.code_hash
460        };
461
462        Ok(StateLoad::new(hash, acc.is_cold))
463    }
464
465    /// Creates account or returns false if collision is detected.
466    ///
467    /// There are few steps done:
468    /// 1. Make created account warm loaded (AccessList) and this should
469    ///     be done before subroutine checkpoint is created.
470    /// 2. Check if there is collision of newly created account with existing one.
471    /// 3. Mark created account as created.
472    /// 4. Add fund to created account
473    /// 5. Increment nonce of created account if SpuriousDragon is active
474    /// 6. Decrease balance of caller account.
475    ///
476    /// # Panics
477    ///
478    /// Panics if the caller is not loaded inside of the EVM state.
479    /// This is should have been done inside `create_inner`.
480    #[inline]
481    pub fn create_account_checkpoint(
482        &mut self,
483        caller: Address,
484        target_address: Address,
485        balance: U256,
486        spec_id: SpecId,
487    ) -> Result<JournalCheckpoint, TransferError> {
488        // Enter subroutine
489        let checkpoint = self.checkpoint();
490
491        // Fetch balance of caller.
492        let caller_acc = self.state.get_mut(&caller).unwrap();
493        // Check if caller has enough balance to send to the created contract.
494        if caller_acc.info.balance < balance {
495            self.checkpoint_revert(checkpoint);
496            return Err(TransferError::OutOfFunds);
497        }
498
499        // Newly created account is present, as we just loaded it.
500        let target_acc = self.state.get_mut(&target_address).unwrap();
501        let last_journal = self.journal.last_mut().unwrap();
502
503        // New account can be created if:
504        // Bytecode is not empty.
505        // Nonce is not zero
506        // Account is not precompile.
507        if target_acc.info.code_hash != KECCAK_EMPTY || target_acc.info.nonce != 0 {
508            self.checkpoint_revert(checkpoint);
509            return Err(TransferError::CreateCollision);
510        }
511
512        // set account status to created.
513        target_acc.mark_created();
514
515        // this entry will revert set nonce.
516        last_journal.push(JournalEntry::AccountCreated {
517            address: target_address,
518        });
519        target_acc.info.code = None;
520        // EIP-161: State trie clearing (invariant-preserving alternative)
521        if spec_id.is_enabled_in(SPURIOUS_DRAGON) {
522            // nonce is going to be reset to zero in AccountCreated journal entry.
523            target_acc.info.nonce = 1;
524        }
525
526        // touch account. This is important as for pre SpuriousDragon account could be
527        // saved even empty.
528        Self::touch_account(last_journal, &target_address, target_acc);
529
530        // Add balance to created account, as we already have target here.
531        let Some(new_balance) = target_acc.info.balance.checked_add(balance) else {
532            self.checkpoint_revert(checkpoint);
533            return Err(TransferError::OverflowPayment);
534        };
535        target_acc.info.balance = new_balance;
536
537        // safe to decrement for the caller as balance check is already done.
538        self.state.get_mut(&caller).unwrap().info.balance -= balance;
539
540        // add journal entry of transferred balance
541        last_journal.push(JournalEntry::BalanceTransfer {
542            from: caller,
543            to: target_address,
544            balance,
545        });
546
547        Ok(checkpoint)
548    }
549
550    /// Reverts all changes that happened in given journal entries.
551    #[inline]
552    fn journal_revert(
553        state: &mut EvmState,
554        transient_storage: &mut TransientStorage,
555        journal_entries: Vec<JournalEntry>,
556        is_spurious_dragon_enabled: bool,
557    ) {
558        for entry in journal_entries.into_iter().rev() {
559            match entry {
560                JournalEntry::AccountWarmed { address } => {
561                    state.get_mut(&address).unwrap().mark_cold();
562                }
563                JournalEntry::AccountTouched { address } => {
564                    if is_spurious_dragon_enabled && address == PRECOMPILE3 {
565                        continue;
566                    }
567                    // remove touched status
568                    state.get_mut(&address).unwrap().unmark_touch();
569                }
570                JournalEntry::AccountDestroyed {
571                    address,
572                    target,
573                    was_destroyed,
574                    had_balance,
575                } => {
576                    let account = state.get_mut(&address).unwrap();
577                    // set previous state of selfdestructed flag, as there could be multiple
578                    // selfdestructs in one transaction.
579                    if was_destroyed {
580                        // flag is still selfdestructed
581                        account.mark_selfdestruct();
582                    } else {
583                        // flag that is not selfdestructed
584                        account.unmark_selfdestruct();
585                    }
586                    account.info.balance += had_balance;
587
588                    if address != target {
589                        let target = state.get_mut(&target).unwrap();
590                        target.info.balance -= had_balance;
591                    }
592                }
593                JournalEntry::BalanceTransfer { from, to, balance } => {
594                    // we don't need to check overflow and underflow when adding and subtracting the balance.
595                    let from = state.get_mut(&from).unwrap();
596                    from.info.balance += balance;
597                    let to = state.get_mut(&to).unwrap();
598                    to.info.balance -= balance;
599                }
600                JournalEntry::NonceChange { address } => {
601                    state.get_mut(&address).unwrap().info.nonce -= 1;
602                }
603                JournalEntry::AccountCreated { address } => {
604                    let account = &mut state.get_mut(&address).unwrap();
605                    account.unmark_created();
606                    account
607                        .storage
608                        .values_mut()
609                        .for_each(|slot| slot.mark_cold());
610                    account.info.nonce = 0;
611                }
612                JournalEntry::StorageWarmed { address, key } => {
613                    state
614                        .get_mut(&address)
615                        .unwrap()
616                        .storage
617                        .get_mut(&key)
618                        .unwrap()
619                        .mark_cold();
620                }
621                JournalEntry::StorageChanged {
622                    address,
623                    key,
624                    had_value,
625                } => {
626                    state
627                        .get_mut(&address)
628                        .unwrap()
629                        .storage
630                        .get_mut(&key)
631                        .unwrap()
632                        .present_value = had_value;
633                }
634                JournalEntry::TransientStorageChange {
635                    address,
636                    key,
637                    had_value,
638                } => {
639                    let tkey = (address, key);
640                    if had_value.is_zero() {
641                        // if previous value is zero, remove it
642                        transient_storage.remove(&tkey);
643                    } else {
644                        // if not zero, reinsert old value to transient storage.
645                        transient_storage.insert(tkey, had_value);
646                    }
647                }
648                JournalEntry::CodeChange { address } => {
649                    let acc = state.get_mut(&address).unwrap();
650                    acc.info.code_hash = KECCAK_EMPTY;
651                    acc.info.code = None;
652                }
653            }
654        }
655    }
656
657    /// Makes a checkpoint that in case of Revert can bring back state to this point.
658    #[inline]
659    pub fn checkpoint(&mut self) -> JournalCheckpoint {
660        let checkpoint = JournalCheckpoint {
661            log_i: self.logs.len(),
662            journal_i: self.journal.len(),
663        };
664        self.depth += 1;
665        self.journal.push(Default::default());
666        checkpoint
667    }
668
669    /// Commits the checkpoint.
670    #[inline]
671    pub fn checkpoint_commit(&mut self) {
672        self.depth -= 1;
673    }
674
675    /// Reverts all changes to state until given checkpoint.
676    #[inline]
677    pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
678        let is_spurious_dragon_enabled = self.spec.is_enabled_in(SPURIOUS_DRAGON);
679        let state = &mut self.state;
680        let transient_storage = &mut self.transient_storage;
681        self.depth -= 1;
682        // iterate over last N journals sets and revert our global state
683        let leng = self.journal.len();
684        self.journal
685            .iter_mut()
686            .rev()
687            .take(leng - checkpoint.journal_i)
688            .for_each(|cs| {
689                Self::journal_revert(
690                    state,
691                    transient_storage,
692                    mem::take(cs),
693                    is_spurious_dragon_enabled,
694                )
695            });
696
697        self.logs.truncate(checkpoint.log_i);
698        self.journal.truncate(checkpoint.journal_i);
699    }
700
701    /// Performs selfdestruct action.
702    /// Transfers balance from address to target. Check if target exist/is_cold
703    ///
704    /// Note: Balance will be lost if address and target are the same BUT when
705    /// current spec enables Cancun, this happens only when the account associated to address
706    /// is created in the same tx
707    ///
708    /// # References:
709    ///  * <https://github.com/ethereum/go-ethereum/blob/141cd425310b503c5678e674a8c3872cf46b7086/core/vm/instructions.go#L832-L833>
710    ///  * <https://github.com/ethereum/go-ethereum/blob/141cd425310b503c5678e674a8c3872cf46b7086/core/state/statedb.go#L449>
711    ///  * <https://eips.ethereum.org/EIPS/eip-6780>
712    #[inline]
713    pub fn selfdestruct(
714        &mut self,
715        address: Address,
716        target: Address,
717    ) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
718        let spec = self.spec;
719        let account_load = self.load_account(target)?;
720        let is_cold = account_load.is_cold;
721        let is_empty = account_load.state_clear_aware_is_empty(spec);
722
723        if address != target {
724            // Both accounts are loaded before this point, `address` as we execute its contract.
725            // and `target` at the beginning of the function.
726            let acc_balance = self.state.get_mut(&address).unwrap().info.balance;
727
728            let target_account = self.state.get_mut(&target).unwrap();
729            Self::touch_account(self.journal.last_mut().unwrap(), &target, target_account);
730            target_account.info.balance += acc_balance;
731        }
732
733        let acc = self.state.get_mut(&address).unwrap();
734        let balance = acc.info.balance;
735        let previously_destroyed = acc.is_selfdestructed();
736        let is_cancun_enabled = self.spec.is_enabled_in(CANCUN);
737
738        // EIP-6780 (Cancun hard-fork): selfdestruct only if contract is created in the same tx
739        let journal_entry = if acc.is_created() || !is_cancun_enabled {
740            acc.mark_selfdestruct();
741            acc.info.balance = U256::ZERO;
742            Some(JournalEntry::AccountDestroyed {
743                address,
744                target,
745                was_destroyed: previously_destroyed,
746                had_balance: balance,
747            })
748        } else if address != target {
749            acc.info.balance = U256::ZERO;
750            Some(JournalEntry::BalanceTransfer {
751                from: address,
752                to: target,
753                balance,
754            })
755        } else {
756            // State is not changed:
757            // * if we are after Cancun upgrade and
758            // * Selfdestruct account that is created in the same transaction and
759            // * Specify the target is same as selfdestructed account. The balance stays unchanged.
760            None
761        };
762
763        if let Some(entry) = journal_entry {
764            self.journal.last_mut().unwrap().push(entry);
765        };
766
767        Ok(StateLoad {
768            data: SelfDestructResult {
769                had_value: !balance.is_zero(),
770                target_exists: !is_empty,
771                previously_destroyed,
772            },
773            is_cold,
774        })
775    }
776
777    /// Initial load of account. This load will not be tracked inside journal
778    #[inline]
779    pub fn initial_account_load(
780        &mut self,
781        address: Address,
782        storage_keys: impl IntoIterator<Item = U256>,
783    ) -> Result<&mut Account, DB::Error> {
784        // load or get account.
785        let account = match self.state.entry(address) {
786            Entry::Occupied(entry) => entry.into_mut(),
787            Entry::Vacant(vac) => vac.insert(
788                self.database
789                    .basic(address)?
790                    .map(|i| i.into())
791                    .unwrap_or(Account::new_not_existing()),
792            ),
793        };
794        // preload storages.
795        for storage_key in storage_keys.into_iter() {
796            if let Entry::Vacant(entry) = account.storage.entry(storage_key) {
797                let storage = self.database.storage(address, storage_key)?;
798                entry.insert(EvmStorageSlot::new(storage));
799            }
800        }
801        Ok(account)
802    }
803
804    /// Loads account into memory. return if it is cold or warm accessed
805    #[inline]
806    pub fn load_account(&mut self, address: Address) -> Result<StateLoad<&mut Account>, DB::Error> {
807        self.load_account_optional(address, false)
808    }
809
810    #[inline]
811    pub fn load_account_delegated(
812        &mut self,
813        address: Address,
814    ) -> Result<StateLoad<AccountLoad>, DB::Error> {
815        let spec = self.spec;
816        let account = self.load_code(address)?;
817        let is_empty = account.state_clear_aware_is_empty(spec);
818
819        let mut account_load = StateLoad::new(
820            AccountLoad {
821                is_delegate_account_cold: None,
822                is_empty,
823            },
824            account.is_cold,
825        );
826
827        // load delegate code if account is EIP-7702
828        if let Some(Bytecode::Eip7702(code)) = &account.info.code {
829            let address = code.address();
830            let delegate_account = self.load_account(address)?;
831            account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
832        }
833
834        Ok(account_load)
835    }
836
837    pub fn load_code(&mut self, address: Address) -> Result<StateLoad<&mut Account>, DB::Error> {
838        self.load_account_optional(address, true)
839    }
840
841    /// Loads code
842    #[inline]
843    pub fn load_account_optional(
844        &mut self,
845        address: Address,
846        load_code: bool,
847    ) -> Result<StateLoad<&mut Account>, DB::Error> {
848        let load = match self.state.entry(address) {
849            Entry::Occupied(entry) => {
850                let account = entry.into_mut();
851                let is_cold = account.mark_warm();
852                StateLoad {
853                    data: account,
854                    is_cold,
855                }
856            }
857            Entry::Vacant(vac) => {
858                let account = if let Some(account) = self.database.basic(address)? {
859                    account.into()
860                } else {
861                    Account::new_not_existing()
862                };
863
864                // precompiles are warm loaded so we need to take that into account
865                let is_cold = !self.warm_preloaded_addresses.contains(&address);
866
867                StateLoad {
868                    data: vac.insert(account),
869                    is_cold,
870                }
871            }
872        };
873        // journal loading of cold account.
874        if load.is_cold {
875            self.journal
876                .last_mut()
877                .unwrap()
878                .push(JournalEntry::AccountWarmed { address });
879        }
880        if load_code {
881            let info = &mut load.data.info;
882            if info.code.is_none() {
883                if info.code_hash == KECCAK_EMPTY {
884                    let empty = Bytecode::default();
885                    info.code = Some(empty);
886                } else {
887                    let code = self.database.code_by_hash(info.code_hash)?;
888                    info.code = Some(code);
889                }
890            }
891        }
892
893        Ok(load)
894    }
895
896    /// Loads storage slot.
897    ///
898    /// # Panics
899    ///
900    /// Panics if the account is not present in the state.
901    #[inline]
902    pub fn sload(&mut self, address: Address, key: U256) -> Result<StateLoad<U256>, DB::Error> {
903        // assume acc is warm
904        let account = self.state.get_mut(&address).unwrap();
905        // only if account is created in this tx we can assume that storage is empty.
906        let is_newly_created = account.is_created();
907        let (value, is_cold) = match account.storage.entry(key) {
908            Entry::Occupied(occ) => {
909                let slot = occ.into_mut();
910                let is_cold = slot.mark_warm();
911                (slot.present_value, is_cold)
912            }
913            Entry::Vacant(vac) => {
914                // if storage was cleared, we don't need to ping db.
915                let value = if is_newly_created {
916                    U256::ZERO
917                } else {
918                    self.database.storage(address, key)?
919                };
920
921                vac.insert(EvmStorageSlot::new(value));
922
923                (value, true)
924            }
925        };
926
927        if is_cold {
928            // add it to journal as cold loaded.
929            self.journal
930                .last_mut()
931                .unwrap()
932                .push(JournalEntry::StorageWarmed { address, key });
933        }
934
935        Ok(StateLoad::new(value, is_cold))
936    }
937
938    /// Stores storage slot.
939    ///
940    /// And returns (original,present,new) slot value.
941    ///
942    /// **Note**: Account should already be present in our state.
943    #[inline]
944    pub fn sstore(
945        &mut self,
946        address: Address,
947        key: U256,
948        new: U256,
949    ) -> Result<StateLoad<SStoreResult>, DB::Error> {
950        // assume that acc exists and load the slot.
951        let present = self.sload(address, key)?;
952        let acc = self.state.get_mut(&address).unwrap();
953
954        // if there is no original value in dirty return present value, that is our original.
955        let slot = acc.storage.get_mut(&key).unwrap();
956
957        // new value is same as present, we don't need to do anything
958        if present.data == new {
959            return Ok(StateLoad::new(
960                SStoreResult {
961                    original_value: slot.original_value(),
962                    present_value: present.data,
963                    new_value: new,
964                },
965                present.is_cold,
966            ));
967        }
968
969        self.journal
970            .last_mut()
971            .unwrap()
972            .push(JournalEntry::StorageChanged {
973                address,
974                key,
975                had_value: present.data,
976            });
977        // insert value into present state.
978        slot.present_value = new;
979        Ok(StateLoad::new(
980            SStoreResult {
981                original_value: slot.original_value(),
982                present_value: present.data,
983                new_value: new,
984            },
985            present.is_cold,
986        ))
987    }
988
989    /// Read transient storage tied to the account.
990    ///
991    /// EIP-1153: Transient storage opcodes
992    #[inline]
993    pub fn tload(&mut self, address: Address, key: U256) -> U256 {
994        self.transient_storage
995            .get(&(address, key))
996            .copied()
997            .unwrap_or_default()
998    }
999
1000    /// Store transient storage tied to the account.
1001    ///
1002    /// If values is different add entry to the journal
1003    /// so that old state can be reverted if that action is needed.
1004    ///
1005    /// EIP-1153: Transient storage opcodes
1006    #[inline]
1007    pub fn tstore(&mut self, address: Address, key: U256, new: U256) {
1008        let had_value = if new.is_zero() {
1009            // if new values is zero, remove entry from transient storage.
1010            // if previous values was some insert it inside journal.
1011            // If it is none nothing should be inserted.
1012            self.transient_storage.remove(&(address, key))
1013        } else {
1014            // insert values
1015            let previous_value = self
1016                .transient_storage
1017                .insert((address, key), new)
1018                .unwrap_or_default();
1019
1020            // check if previous value is same
1021            if previous_value != new {
1022                // if it is different, insert previous values inside journal.
1023                Some(previous_value)
1024            } else {
1025                None
1026            }
1027        };
1028
1029        if let Some(had_value) = had_value {
1030            // insert in journal only if value was changed.
1031            self.journal
1032                .last_mut()
1033                .unwrap()
1034                .push(JournalEntry::TransientStorageChange {
1035                    address,
1036                    key,
1037                    had_value,
1038                });
1039        }
1040    }
1041
1042    /// Pushes log into subroutine.
1043    #[inline]
1044    pub fn log(&mut self, log: Log) {
1045        self.logs.push(log);
1046    }
1047}
1048
1049/// Journal entries that are used to track changes to the state and are used to revert it.
1050#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1051#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1052pub enum JournalEntry {
1053    /// Used to mark account that is warm inside EVM in regards to EIP-2929 AccessList.
1054    /// Action: We will add Account to state.
1055    /// Revert: we will remove account from state.
1056    AccountWarmed { address: Address },
1057    /// Mark account to be destroyed and journal balance to be reverted
1058    /// Action: Mark account and transfer the balance
1059    /// Revert: Unmark the account and transfer balance back
1060    AccountDestroyed {
1061        address: Address,
1062        target: Address,
1063        was_destroyed: bool, // if account had already been destroyed before this journal entry
1064        had_balance: U256,
1065    },
1066    /// Loading account does not mean that account will need to be added to MerkleTree (touched).
1067    /// Only when account is called (to execute contract or transfer balance) only then account is made touched.
1068    /// Action: Mark account touched
1069    /// Revert: Unmark account touched
1070    AccountTouched { address: Address },
1071    /// Transfer balance between two accounts
1072    /// Action: Transfer balance
1073    /// Revert: Transfer balance back
1074    BalanceTransfer {
1075        from: Address,
1076        to: Address,
1077        balance: U256,
1078    },
1079    /// Increment nonce
1080    /// Action: Increment nonce by one
1081    /// Revert: Decrement nonce by one
1082    NonceChange {
1083        address: Address, //geth has nonce value,
1084    },
1085    /// Create account:
1086    /// Actions: Mark account as created
1087    /// Revert: Unmart account as created and reset nonce to zero.
1088    AccountCreated { address: Address },
1089    /// Entry used to track storage changes
1090    /// Action: Storage change
1091    /// Revert: Revert to previous value
1092    StorageChanged {
1093        address: Address,
1094        key: U256,
1095        had_value: U256,
1096    },
1097    /// Entry used to track storage warming introduced by EIP-2929.
1098    /// Action: Storage warmed
1099    /// Revert: Revert to cold state
1100    StorageWarmed { address: Address, key: U256 },
1101    /// It is used to track an EIP-1153 transient storage change.
1102    /// Action: Transient storage changed.
1103    /// Revert: Revert to previous value.
1104    TransientStorageChange {
1105        address: Address,
1106        key: U256,
1107        had_value: U256,
1108    },
1109    /// Code changed
1110    /// Action: Account code changed
1111    /// Revert: Revert to previous bytecode.
1112    CodeChange { address: Address },
1113}
1114
1115impl<DB> JournaledState<DB> {
1116    /// Initialize a new JournaledState from JournalInit with a database
1117    pub fn from_init(init: &JournalInit, database: DB) -> Self {
1118        Self {
1119            database,
1120            state: init.state.clone(),
1121            transient_storage: init.transient_storage.clone(),
1122            logs: init.logs.clone(),
1123            depth: init.depth,
1124            journal: init.journal.clone(),
1125            spec: init.spec,
1126            warm_preloaded_addresses: init.warm_preloaded_addresses.clone(),
1127            precompiles: init.precompiles.clone(),
1128        }
1129    }
1130}