revm/
journaled_state.rs

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