revm_context/
journaled_state.rs

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