1use super::{JournalEntryTr, JournalOutput};
3use bytecode::Bytecode;
4use context_interface::{
5 context::{SStoreResult, SelfDestructResult, StateLoad},
6 journaled_state::{AccountLoad, JournalCheckpoint, TransferError},
7};
8use core::mem;
9use database_interface::Database;
10use primitives::{
11 hardfork::SpecId::{self, *},
12 hash_map::Entry,
13 Address, HashMap, HashSet, Log, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256,
14};
15use state::{Account, EvmState, EvmStorageSlot, TransientStorage};
16use std::vec::Vec;
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<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::new(),
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.clone_from(precompiles);
107
108 let state = mem::take(state);
109 let logs = mem::take(logs);
110 transient_storage.clear();
111 journal.clear();
112 *depth = 0;
113
114 JournalOutput { state, logs }
115 }
116
117 #[inline]
119 pub fn state(&mut self) -> &mut EvmState {
120 &mut self.state
121 }
122
123 #[inline]
125 pub fn set_spec_id(&mut self, spec: SpecId) {
126 self.spec = spec;
127 }
128
129 #[inline]
133 pub fn touch(&mut self, address: Address) {
134 if let Some(account) = self.state.get_mut(&address) {
135 Self::touch_account(&mut self.journal, address, account);
136 }
137 }
138
139 #[inline]
141 fn touch_account(journal: &mut Vec<ENTRY>, address: Address, account: &mut Account) {
142 if !account.is_touched() {
143 journal.push(ENTRY::account_touched(address));
144 account.mark_touch();
145 }
146 }
147
148 #[inline]
156 pub fn account(&self, address: Address) -> &Account {
157 self.state
158 .get(&address)
159 .expect("Account expected to be loaded") }
161
162 #[inline]
166 pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
167 let account = self.state.get_mut(&address).unwrap();
168 Self::touch_account(&mut self.journal, address, account);
169
170 self.journal.push(ENTRY::code_changed(address));
171
172 account.info.code_hash = hash;
173 account.info.code = Some(code);
174 }
175
176 #[inline]
182 pub fn set_code(&mut self, address: Address, code: Bytecode) {
183 if let Bytecode::Eip7702(eip7702_bytecode) = &code {
184 if eip7702_bytecode.address().is_zero() {
185 self.set_code_with_hash(address, Bytecode::default(), KECCAK_EMPTY);
186 return;
187 }
188 }
189
190 let hash = code.hash_slow();
191 self.set_code_with_hash(address, code, hash)
192 }
193
194 #[inline]
200 pub fn inc_nonce(&mut self, address: Address) -> Option<u64> {
201 let account = self.state.get_mut(&address).unwrap();
202 if account.info.nonce == u64::MAX {
204 return None;
205 }
206 Self::touch_account(&mut self.journal, address, account);
207 self.journal.push(ENTRY::nonce_changed(address));
208
209 account.info.nonce += 1;
210
211 Some(account.info.nonce)
212 }
213
214 #[inline]
216 pub fn transfer<DB: Database>(
217 &mut self,
218 db: &mut DB,
219 from: Address,
220 to: Address,
221 balance: U256,
222 ) -> Result<Option<TransferError>, DB::Error> {
223 if balance.is_zero() {
224 self.load_account(db, to)?;
225 let to_account = self.state.get_mut(&to).unwrap();
226 Self::touch_account(&mut self.journal, to, to_account);
227 return Ok(None);
228 }
229 self.load_account(db, from)?;
231 self.load_account(db, to)?;
232
233 let from_account = self.state.get_mut(&from).unwrap();
235 Self::touch_account(&mut self.journal, from, from_account);
236 let from_balance = &mut from_account.info.balance;
237
238 let Some(from_balance_decr) = from_balance.checked_sub(balance) else {
239 return Ok(Some(TransferError::OutOfFunds));
240 };
241 *from_balance = from_balance_decr;
242
243 let to_account = &mut self.state.get_mut(&to).unwrap();
245 Self::touch_account(&mut self.journal, to, to_account);
246 let to_balance = &mut to_account.info.balance;
247 let Some(to_balance_incr) = to_balance.checked_add(balance) else {
248 return Ok(Some(TransferError::OverflowPayment));
249 };
250 *to_balance = to_balance_incr;
251 self.journal
254 .push(ENTRY::balance_transfer(from, to, balance));
255
256 Ok(None)
257 }
258
259 #[inline]
275 pub fn create_account_checkpoint(
276 &mut self,
277 caller: Address,
278 target_address: Address,
279 balance: U256,
280 spec_id: SpecId,
281 ) -> Result<JournalCheckpoint, TransferError> {
282 let checkpoint = self.checkpoint();
284
285 let caller_balance = self.state.get(&caller).unwrap().info.balance;
287 if caller_balance < balance {
289 self.checkpoint_revert(checkpoint);
290 return Err(TransferError::OutOfFunds);
291 }
292
293 let target_acc = self.state.get_mut(&target_address).unwrap();
295 let last_journal = &mut self.journal;
296
297 if target_acc.info.code_hash != KECCAK_EMPTY || target_acc.info.nonce != 0 {
302 self.checkpoint_revert(checkpoint);
303 return Err(TransferError::CreateCollision);
304 }
305
306 target_acc.mark_created();
308
309 last_journal.push(ENTRY::account_created(target_address));
311 target_acc.info.code = None;
312 if spec_id.is_enabled_in(SPURIOUS_DRAGON) {
314 target_acc.info.nonce = 1;
316 }
317
318 Self::touch_account(last_journal, target_address, target_acc);
321
322 let Some(new_balance) = target_acc.info.balance.checked_add(balance) else {
324 self.checkpoint_revert(checkpoint);
325 return Err(TransferError::OverflowPayment);
326 };
327 target_acc.info.balance = new_balance;
328
329 self.state.get_mut(&caller).unwrap().info.balance -= balance;
331
332 last_journal.push(ENTRY::balance_transfer(caller, target_address, balance));
334
335 Ok(checkpoint)
336 }
337
338 #[inline]
340 pub fn checkpoint(&mut self) -> JournalCheckpoint {
341 let checkpoint = JournalCheckpoint {
342 log_i: self.logs.len(),
343 journal_i: self.journal.len(),
344 };
345 self.depth += 1;
346 checkpoint
347 }
348
349 #[inline]
351 pub fn checkpoint_commit(&mut self) {
352 self.depth -= 1;
353 }
354
355 #[inline]
357 pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
358 let is_spurious_dragon_enabled = self.spec.is_enabled_in(SPURIOUS_DRAGON);
359 let state = &mut self.state;
360 let transient_storage = &mut self.transient_storage;
361 self.depth -= 1;
362 self.logs.truncate(checkpoint.log_i);
363
364 self.journal
366 .drain(checkpoint.journal_i..)
367 .rev()
368 .for_each(|entry| {
369 entry.revert(state, transient_storage, is_spurious_dragon_enabled);
370 });
371 }
372
373 #[inline]
385 pub fn selfdestruct<DB: Database>(
386 &mut self,
387 db: &mut DB,
388 address: Address,
389 target: Address,
390 ) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
391 let spec = self.spec;
392 let account_load = self.load_account(db, target)?;
393 let is_cold = account_load.is_cold;
394 let is_empty = account_load.state_clear_aware_is_empty(spec);
395
396 if address != target {
397 let acc_balance = self.state.get(&address).unwrap().info.balance;
400
401 let target_account = self.state.get_mut(&target).unwrap();
402 Self::touch_account(&mut self.journal, target, target_account);
403 target_account.info.balance += acc_balance;
404 }
405
406 let acc = self.state.get_mut(&address).unwrap();
407 let balance = acc.info.balance;
408 let previously_destroyed = acc.is_selfdestructed();
409 let is_cancun_enabled = spec.is_enabled_in(CANCUN);
410
411 let journal_entry = if acc.is_created() || !is_cancun_enabled {
413 acc.mark_selfdestruct();
414 acc.info.balance = U256::ZERO;
415 Some(ENTRY::account_destroyed(
416 address,
417 target,
418 previously_destroyed,
419 balance,
420 ))
421 } else if address != target {
422 acc.info.balance = U256::ZERO;
423 Some(ENTRY::balance_transfer(address, target, balance))
424 } else {
425 None
430 };
431
432 if let Some(entry) = journal_entry {
433 self.journal.push(entry);
434 };
435
436 Ok(StateLoad {
437 data: SelfDestructResult {
438 had_value: !balance.is_zero(),
439 target_exists: !is_empty,
440 previously_destroyed,
441 },
442 is_cold,
443 })
444 }
445
446 #[inline]
448 pub fn initial_account_load<DB: Database>(
449 &mut self,
450 db: &mut DB,
451 address: Address,
452 storage_keys: impl IntoIterator<Item = StorageKey>,
453 ) -> Result<&mut Account, DB::Error> {
454 let account = match self.state.entry(address) {
456 Entry::Occupied(entry) => entry.into_mut(),
457 Entry::Vacant(vac) => vac.insert(
458 db.basic(address)?
459 .map(|i| i.into())
460 .unwrap_or(Account::new_not_existing()),
461 ),
462 };
463 for storage_key in storage_keys.into_iter() {
465 if let Entry::Vacant(entry) = account.storage.entry(storage_key) {
466 let storage = db.storage(address, storage_key)?;
467 entry.insert(EvmStorageSlot::new(storage));
468 }
469 }
470 Ok(account)
471 }
472
473 #[inline]
475 pub fn load_account<DB: Database>(
476 &mut self,
477 db: &mut DB,
478 address: Address,
479 ) -> Result<StateLoad<&mut Account>, DB::Error> {
480 self.load_account_optional(db, address, false)
481 }
482
483 #[inline]
491 pub fn load_account_delegated<DB: Database>(
492 &mut self,
493 db: &mut DB,
494 address: Address,
495 ) -> Result<StateLoad<AccountLoad>, DB::Error> {
496 let spec = self.spec;
497 let is_eip7702_enabled = spec.is_enabled_in(SpecId::PRAGUE);
498 let account = self.load_account_optional(db, address, is_eip7702_enabled)?;
499 let is_empty = account.state_clear_aware_is_empty(spec);
500
501 let mut account_load = StateLoad::new(
502 AccountLoad {
503 is_delegate_account_cold: None,
504 is_empty,
505 },
506 account.is_cold,
507 );
508
509 if let Some(Bytecode::Eip7702(code)) = &account.info.code {
511 let address = code.address();
512 let delegate_account = self.load_account(db, address)?;
513 account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
514 }
515
516 Ok(account_load)
517 }
518
519 #[inline]
526 pub fn load_code<DB: Database>(
527 &mut self,
528 db: &mut DB,
529 address: Address,
530 ) -> Result<StateLoad<&mut Account>, DB::Error> {
531 self.load_account_optional(db, address, true)
532 }
533
534 #[inline]
536 pub fn load_account_optional<DB: Database>(
537 &mut self,
538 db: &mut DB,
539 address: Address,
540 load_code: bool,
541 ) -> Result<StateLoad<&mut Account>, DB::Error> {
542 let load = match self.state.entry(address) {
543 Entry::Occupied(entry) => {
544 let account = entry.into_mut();
545 let is_cold = account.mark_warm();
546 StateLoad {
547 data: account,
548 is_cold,
549 }
550 }
551 Entry::Vacant(vac) => {
552 let account = if let Some(account) = db.basic(address)? {
553 account.into()
554 } else {
555 Account::new_not_existing()
556 };
557
558 let is_cold = !self.warm_preloaded_addresses.contains(&address);
560
561 StateLoad {
562 data: vac.insert(account),
563 is_cold,
564 }
565 }
566 };
567 if load.is_cold {
569 self.journal.push(ENTRY::account_warmed(address));
570 }
571 if load_code {
572 let info = &mut load.data.info;
573 if info.code.is_none() {
574 let code = if info.code_hash == KECCAK_EMPTY {
575 Bytecode::default()
576 } else {
577 db.code_by_hash(info.code_hash)?
578 };
579 info.code = Some(code);
580 }
581 }
582
583 Ok(load)
584 }
585
586 #[inline]
592 pub fn sload<DB: Database>(
593 &mut self,
594 db: &mut DB,
595 address: Address,
596 key: StorageKey,
597 ) -> Result<StateLoad<StorageValue>, DB::Error> {
598 let account = self.state.get_mut(&address).unwrap();
600 let is_newly_created = account.is_created();
602 let (value, is_cold) = match account.storage.entry(key) {
603 Entry::Occupied(occ) => {
604 let slot = occ.into_mut();
605 let is_cold = slot.mark_warm();
606 (slot.present_value, is_cold)
607 }
608 Entry::Vacant(vac) => {
609 let value = if is_newly_created {
611 StorageValue::ZERO
612 } else {
613 db.storage(address, key)?
614 };
615
616 vac.insert(EvmStorageSlot::new(value));
617
618 (value, true)
619 }
620 };
621
622 if is_cold {
623 self.journal.push(ENTRY::storage_warmed(address, key));
625 }
626
627 Ok(StateLoad::new(value, is_cold))
628 }
629
630 #[inline]
636 pub fn sstore<DB: Database>(
637 &mut self,
638 db: &mut DB,
639 address: Address,
640 key: StorageKey,
641 new: StorageValue,
642 ) -> Result<StateLoad<SStoreResult>, DB::Error> {
643 let present = self.sload(db, address, key)?;
645 let acc = self.state.get_mut(&address).unwrap();
646
647 let slot = acc.storage.get_mut(&key).unwrap();
649
650 if present.data == new {
652 return Ok(StateLoad::new(
653 SStoreResult {
654 original_value: slot.original_value(),
655 present_value: present.data,
656 new_value: new,
657 },
658 present.is_cold,
659 ));
660 }
661
662 self.journal
663 .push(ENTRY::storage_changed(address, key, present.data));
664 slot.present_value = new;
666 Ok(StateLoad::new(
667 SStoreResult {
668 original_value: slot.original_value(),
669 present_value: present.data,
670 new_value: new,
671 },
672 present.is_cold,
673 ))
674 }
675
676 #[inline]
680 pub fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
681 self.transient_storage
682 .get(&(address, key))
683 .copied()
684 .unwrap_or_default()
685 }
686
687 #[inline]
694 pub fn tstore(&mut self, address: Address, key: StorageKey, new: StorageValue) {
695 let had_value = if new.is_zero() {
696 self.transient_storage.remove(&(address, key))
700 } else {
701 let previous_value = self
703 .transient_storage
704 .insert((address, key), new)
705 .unwrap_or_default();
706
707 if previous_value != new {
709 Some(previous_value)
711 } else {
712 None
713 }
714 };
715
716 if let Some(had_value) = had_value {
717 self.journal
719 .push(ENTRY::transient_storage_changed(address, key, had_value));
720 }
721 }
722
723 #[inline]
725 pub fn log(&mut self, log: Log) {
726 self.logs.push(log);
727 }
728}