1use bytecode::Bytecode;
2use context_interface::{
3    context::{SStoreResult, SelfDestructResult, StateLoad},
4    journaled_state::{AccountLoad, JournalCheckpoint, TransferError},
5};
6use core::mem;
7use database_interface::Database;
8use primitives::{
9    hardfork::{SpecId, SpecId::*},
10    hash_map::Entry,
11    Address, HashMap, HashSet, Log, B256, KECCAK_EMPTY, U256,
12};
13use state::{Account, EvmState, EvmStorageSlot, TransientStorage};
14use std::{vec, vec::Vec};
15
16use super::{JournalEntryTr, JournalOutput};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct JournalInner<ENTRY> {
24    pub state: EvmState,
26    pub transient_storage: TransientStorage,
30    pub logs: Vec<Log>,
32    pub depth: usize,
34    pub journal: Vec<Vec<ENTRY>>,
36    pub spec: SpecId,
49    pub warm_preloaded_addresses: HashSet<Address>,
56    pub precompiles: HashSet<Address>,
58}
59
60impl<ENTRY: JournalEntryTr> Default for JournalInner<ENTRY> {
61    fn default() -> Self {
62        Self::new()
63    }
64}
65
66impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
67    pub fn new() -> JournalInner<ENTRY> {
72        Self {
73            state: HashMap::default(),
74            transient_storage: TransientStorage::default(),
75            logs: Vec::new(),
76            journal: vec![vec![]],
77            depth: 0,
78            spec: SpecId::default(),
79            warm_preloaded_addresses: HashSet::default(),
80            precompiles: HashSet::default(),
81        }
82    }
83
84    #[inline]
90    pub fn clear_and_take_output(&mut self) -> JournalOutput {
91        let Self {
94            state,
95            transient_storage,
96            logs,
97            depth,
98            journal,
99            spec,
100            warm_preloaded_addresses,
101            precompiles,
102        } = self;
103        let _ = spec;
105        *warm_preloaded_addresses = precompiles.clone();
107
108        let state = mem::take(state);
109        let logs = mem::take(logs);
110        transient_storage.clear();
111        journal.clear();
112        journal.push(vec![]);
113        *depth = 0;
114
115        JournalOutput { state, logs }
116    }
117
118    #[inline]
120    pub fn state(&mut self) -> &mut EvmState {
121        &mut self.state
122    }
123
124    #[inline]
126    pub fn set_spec_id(&mut self, spec: SpecId) {
127        self.spec = spec;
128    }
129
130    #[inline]
134    pub fn touch(&mut self, address: Address) {
135        if let Some(account) = self.state.get_mut(&address) {
136            Self::touch_account(self.journal.last_mut().unwrap(), address, account);
137        }
138    }
139
140    #[inline]
142    fn touch_account(journal: &mut Vec<ENTRY>, address: Address, account: &mut Account) {
143        if !account.is_touched() {
144            journal.push(ENTRY::account_touched(address));
145            account.mark_touch();
146        }
147    }
148
149    #[inline]
157    pub fn account(&self, address: Address) -> &Account {
158        self.state
159            .get(&address)
160            .expect("Account expected to be loaded") }
162
163    #[inline]
167    pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
168        let account = self.state.get_mut(&address).unwrap();
169        Self::touch_account(self.journal.last_mut().unwrap(), address, account);
170
171        self.journal
172            .last_mut()
173            .unwrap()
174            .push(ENTRY::code_changed(address));
175
176        account.info.code_hash = hash;
177        account.info.code = Some(code);
178    }
179
180    #[inline]
184    pub fn set_code(&mut self, address: Address, code: Bytecode) {
185        let hash = code.hash_slow();
186        self.set_code_with_hash(address, code, hash)
187    }
188
189    #[inline]
190    pub fn inc_nonce(&mut self, address: Address) -> Option<u64> {
191        let account = self.state.get_mut(&address).unwrap();
192        if account.info.nonce == u64::MAX {
194            return None;
195        }
196        Self::touch_account(self.journal.last_mut().unwrap(), address, account);
197        self.journal
198            .last_mut()
199            .unwrap()
200            .push(ENTRY::nonce_changed(address));
201
202        account.info.nonce += 1;
203
204        Some(account.info.nonce)
205    }
206
207    #[inline]
209    pub fn transfer<DB: Database>(
210        &mut self,
211        db: &mut DB,
212        from: Address,
213        to: Address,
214        balance: U256,
215    ) -> Result<Option<TransferError>, DB::Error> {
216        if balance.is_zero() {
217            self.load_account(db, to)?;
218            let to_account = self.state.get_mut(&to).unwrap();
219            Self::touch_account(self.journal.last_mut().unwrap(), to, to_account);
220            return Ok(None);
221        }
222        self.load_account(db, from)?;
224        self.load_account(db, to)?;
225
226        let from_account = self.state.get_mut(&from).unwrap();
228        Self::touch_account(self.journal.last_mut().unwrap(), from, from_account);
229        let from_balance = &mut from_account.info.balance;
230
231        let Some(from_balance_decr) = from_balance.checked_sub(balance) else {
232            return Ok(Some(TransferError::OutOfFunds));
233        };
234        *from_balance = from_balance_decr;
235
236        let to_account = &mut self.state.get_mut(&to).unwrap();
238        Self::touch_account(self.journal.last_mut().unwrap(), to, to_account);
239        let to_balance = &mut to_account.info.balance;
240        let Some(to_balance_incr) = to_balance.checked_add(balance) else {
241            return Ok(Some(TransferError::OverflowPayment));
242        };
243        *to_balance = to_balance_incr;
244        self.journal
247            .last_mut()
248            .unwrap()
249            .push(ENTRY::balance_transfer(from, to, balance));
250
251        Ok(None)
252    }
253
254    #[inline]
270    pub fn create_account_checkpoint(
271        &mut self,
272        caller: Address,
273        target_address: Address,
274        balance: U256,
275        spec_id: SpecId,
276    ) -> Result<JournalCheckpoint, TransferError> {
277        let checkpoint = self.checkpoint();
279
280        let caller_balance = self.state.get(&caller).unwrap().info.balance;
282        if caller_balance < balance {
284            self.checkpoint_revert(checkpoint);
285            return Err(TransferError::OutOfFunds);
286        }
287
288        let target_acc = self.state.get_mut(&target_address).unwrap();
290        let last_journal = self.journal.last_mut().unwrap();
291
292        if target_acc.info.code_hash != KECCAK_EMPTY || target_acc.info.nonce != 0 {
297            self.checkpoint_revert(checkpoint);
298            return Err(TransferError::CreateCollision);
299        }
300
301        target_acc.mark_created();
303
304        last_journal.push(ENTRY::account_created(target_address));
306        target_acc.info.code = None;
307        if spec_id.is_enabled_in(SPURIOUS_DRAGON) {
309            target_acc.info.nonce = 1;
311        }
312
313        Self::touch_account(last_journal, target_address, target_acc);
316
317        let Some(new_balance) = target_acc.info.balance.checked_add(balance) else {
319            self.checkpoint_revert(checkpoint);
320            return Err(TransferError::OverflowPayment);
321        };
322        target_acc.info.balance = new_balance;
323
324        self.state.get_mut(&caller).unwrap().info.balance -= balance;
326
327        last_journal.push(ENTRY::balance_transfer(caller, target_address, balance));
329
330        Ok(checkpoint)
331    }
332
333    #[inline]
335    pub fn checkpoint(&mut self) -> JournalCheckpoint {
336        let checkpoint = JournalCheckpoint {
337            log_i: self.logs.len(),
338            journal_i: self.journal.len(),
339        };
340        self.depth += 1;
341        self.journal.push(Default::default());
342        checkpoint
343    }
344
345    #[inline]
347    pub fn checkpoint_commit(&mut self) {
348        self.depth -= 1;
349    }
350
351    #[inline]
353    pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
354        let is_spurious_dragon_enabled = self.spec.is_enabled_in(SPURIOUS_DRAGON);
355        let state = &mut self.state;
356        let transient_storage = &mut self.transient_storage;
357        self.depth -= 1;
358        let len = self.journal.len();
360        self.journal
361            .iter_mut()
362            .rev()
363            .take(len - checkpoint.journal_i)
364            .for_each(|cs| {
365                for entry in mem::take(cs).into_iter().rev() {
366                    entry.revert(state, transient_storage, is_spurious_dragon_enabled);
367                }
368            });
369
370        self.logs.truncate(checkpoint.log_i);
371        self.journal.truncate(checkpoint.journal_i);
372    }
373
374    #[inline]
386    pub fn selfdestruct<DB: Database>(
387        &mut self,
388        db: &mut DB,
389        address: Address,
390        target: Address,
391    ) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
392        let spec = self.spec;
393        let account_load = self.load_account(db, target)?;
394        let is_cold = account_load.is_cold;
395        let is_empty = account_load.state_clear_aware_is_empty(spec);
396
397        if address != target {
398            let acc_balance = self.state.get(&address).unwrap().info.balance;
401
402            let target_account = self.state.get_mut(&target).unwrap();
403            Self::touch_account(self.journal.last_mut().unwrap(), target, target_account);
404            target_account.info.balance += acc_balance;
405        }
406
407        let acc = self.state.get_mut(&address).unwrap();
408        let balance = acc.info.balance;
409        let previously_destroyed = acc.is_selfdestructed();
410        let is_cancun_enabled = spec.is_enabled_in(CANCUN);
411
412        let journal_entry = if acc.is_created() || !is_cancun_enabled {
414            acc.mark_selfdestruct();
415            acc.info.balance = U256::ZERO;
416            Some(ENTRY::account_destroyed(
417                address,
418                target,
419                previously_destroyed,
420                balance,
421            ))
422        } else if address != target {
423            acc.info.balance = U256::ZERO;
424            Some(ENTRY::balance_transfer(address, target, balance))
425        } else {
426            None
431        };
432
433        if let Some(entry) = journal_entry {
434            self.journal.last_mut().unwrap().push(entry);
435        };
436
437        Ok(StateLoad {
438            data: SelfDestructResult {
439                had_value: !balance.is_zero(),
440                target_exists: !is_empty,
441                previously_destroyed,
442            },
443            is_cold,
444        })
445    }
446
447    #[inline]
449    pub fn initial_account_load<DB: Database>(
450        &mut self,
451        db: &mut DB,
452        address: Address,
453        storage_keys: impl IntoIterator<Item = U256>,
454    ) -> Result<&mut Account, DB::Error> {
455        let account = match self.state.entry(address) {
457            Entry::Occupied(entry) => entry.into_mut(),
458            Entry::Vacant(vac) => vac.insert(
459                db.basic(address)?
460                    .map(|i| i.into())
461                    .unwrap_or(Account::new_not_existing()),
462            ),
463        };
464        for storage_key in storage_keys.into_iter() {
466            if let Entry::Vacant(entry) = account.storage.entry(storage_key) {
467                let storage = db.storage(address, storage_key)?;
468                entry.insert(EvmStorageSlot::new(storage));
469            }
470        }
471        Ok(account)
472    }
473
474    #[inline]
476    pub fn load_account<DB: Database>(
477        &mut self,
478        db: &mut DB,
479        address: Address,
480    ) -> Result<StateLoad<&mut Account>, DB::Error> {
481        self.load_account_optional(db, address, false)
482    }
483
484    #[inline]
485    pub fn load_account_delegated<DB: Database>(
486        &mut self,
487        db: &mut DB,
488        address: Address,
489    ) -> Result<StateLoad<AccountLoad>, DB::Error> {
490        let spec = self.spec;
491        let is_eip7702_enabled = spec.is_enabled_in(SpecId::PRAGUE);
492        let account = self.load_account_optional(db, address, is_eip7702_enabled)?;
493        let is_empty = account.state_clear_aware_is_empty(spec);
494
495        let mut account_load = StateLoad::new(
496            AccountLoad {
497                is_delegate_account_cold: None,
498                is_empty,
499            },
500            account.is_cold,
501        );
502
503        if let Some(Bytecode::Eip7702(code)) = &account.info.code {
505            let address = code.address();
506            let delegate_account = self.load_account(db, address)?;
507            account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
508        }
509
510        Ok(account_load)
511    }
512
513    pub fn load_code<DB: Database>(
514        &mut self,
515        db: &mut DB,
516        address: Address,
517    ) -> Result<StateLoad<&mut Account>, DB::Error> {
518        self.load_account_optional(db, address, true)
519    }
520
521    #[inline]
523    pub fn load_account_optional<DB: Database>(
524        &mut self,
525        db: &mut DB,
526        address: Address,
527        load_code: bool,
528    ) -> Result<StateLoad<&mut Account>, DB::Error> {
529        let load = match self.state.entry(address) {
530            Entry::Occupied(entry) => {
531                let account = entry.into_mut();
532                let is_cold = account.mark_warm();
533                StateLoad {
534                    data: account,
535                    is_cold,
536                }
537            }
538            Entry::Vacant(vac) => {
539                let account = if let Some(account) = db.basic(address)? {
540                    account.into()
541                } else {
542                    Account::new_not_existing()
543                };
544
545                let is_cold = !self.warm_preloaded_addresses.contains(&address);
547
548                StateLoad {
549                    data: vac.insert(account),
550                    is_cold,
551                }
552            }
553        };
554        if load.is_cold {
556            self.journal
557                .last_mut()
558                .unwrap()
559                .push(ENTRY::account_warmed(address));
560        }
561        if load_code {
562            let info = &mut load.data.info;
563            if info.code.is_none() {
564                let code = if info.code_hash == KECCAK_EMPTY {
565                    Bytecode::default()
566                } else {
567                    db.code_by_hash(info.code_hash)?
568                };
569                info.code = Some(code);
570            }
571        }
572
573        Ok(load)
574    }
575
576    #[inline]
582    pub fn sload<DB: Database>(
583        &mut self,
584        db: &mut DB,
585        address: Address,
586        key: U256,
587    ) -> Result<StateLoad<U256>, DB::Error> {
588        let account = self.state.get_mut(&address).unwrap();
590        let is_newly_created = account.is_created();
592        let (value, is_cold) = match account.storage.entry(key) {
593            Entry::Occupied(occ) => {
594                let slot = occ.into_mut();
595                let is_cold = slot.mark_warm();
596                (slot.present_value, is_cold)
597            }
598            Entry::Vacant(vac) => {
599                let value = if is_newly_created {
601                    U256::ZERO
602                } else {
603                    db.storage(address, key)?
604                };
605
606                vac.insert(EvmStorageSlot::new(value));
607
608                (value, true)
609            }
610        };
611
612        if is_cold {
613            self.journal
615                .last_mut()
616                .unwrap()
617                .push(ENTRY::storage_warmed(address, key));
618        }
619
620        Ok(StateLoad::new(value, is_cold))
621    }
622
623    #[inline]
629    pub fn sstore<DB: Database>(
630        &mut self,
631        db: &mut DB,
632        address: Address,
633        key: U256,
634        new: U256,
635    ) -> Result<StateLoad<SStoreResult>, DB::Error> {
636        let present = self.sload(db, address, key)?;
638        let acc = self.state.get_mut(&address).unwrap();
639
640        let slot = acc.storage.get_mut(&key).unwrap();
642
643        if present.data == new {
645            return Ok(StateLoad::new(
646                SStoreResult {
647                    original_value: slot.original_value(),
648                    present_value: present.data,
649                    new_value: new,
650                },
651                present.is_cold,
652            ));
653        }
654
655        self.journal
656            .last_mut()
657            .unwrap()
658            .push(ENTRY::storage_changed(address, key, present.data));
659        slot.present_value = new;
661        Ok(StateLoad::new(
662            SStoreResult {
663                original_value: slot.original_value(),
664                present_value: present.data,
665                new_value: new,
666            },
667            present.is_cold,
668        ))
669    }
670
671    #[inline]
675    pub fn tload(&mut self, address: Address, key: U256) -> U256 {
676        self.transient_storage
677            .get(&(address, key))
678            .copied()
679            .unwrap_or_default()
680    }
681
682    #[inline]
689    pub fn tstore(&mut self, address: Address, key: U256, new: U256) {
690        let had_value = if new.is_zero() {
691            self.transient_storage.remove(&(address, key))
695        } else {
696            let previous_value = self
698                .transient_storage
699                .insert((address, key), new)
700                .unwrap_or_default();
701
702            if previous_value != new {
704                Some(previous_value)
706            } else {
707                None
708            }
709        };
710
711        if let Some(had_value) = had_value {
712            self.journal
714                .last_mut()
715                .unwrap()
716                .push(ENTRY::transient_storage_changed(address, key, had_value));
717        }
718    }
719
720    #[inline]
722    pub fn log(&mut self, log: Log) {
723        self.logs.push(log);
724    }
725}