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}