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, SpecId::*},
12 hash_map::Entry,
13 Address, HashMap, HashSet, Log, 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]
180 pub fn set_code(&mut self, address: Address, code: Bytecode) {
181 let hash = code.hash_slow();
182 self.set_code_with_hash(address, code, hash)
183 }
184
185 #[inline]
191 pub fn inc_nonce(&mut self, address: Address) -> Option<u64> {
192 let account = self.state.get_mut(&address).unwrap();
193 if account.info.nonce == u64::MAX {
195 return None;
196 }
197 Self::touch_account(&mut self.journal, address, account);
198 self.journal.push(ENTRY::nonce_changed(address));
199
200 account.info.nonce += 1;
201
202 Some(account.info.nonce)
203 }
204
205 #[inline]
207 pub fn transfer<DB: Database>(
208 &mut self,
209 db: &mut DB,
210 from: Address,
211 to: Address,
212 balance: U256,
213 ) -> Result<Option<TransferError>, DB::Error> {
214 if balance.is_zero() {
215 self.load_account(db, to)?;
216 let to_account = self.state.get_mut(&to).unwrap();
217 Self::touch_account(&mut self.journal, to, to_account);
218 return Ok(None);
219 }
220 self.load_account(db, from)?;
222 self.load_account(db, to)?;
223
224 let from_account = self.state.get_mut(&from).unwrap();
226 Self::touch_account(&mut self.journal, from, from_account);
227 let from_balance = &mut from_account.info.balance;
228
229 let Some(from_balance_decr) = from_balance.checked_sub(balance) else {
230 return Ok(Some(TransferError::OutOfFunds));
231 };
232 *from_balance = from_balance_decr;
233
234 let to_account = &mut self.state.get_mut(&to).unwrap();
236 Self::touch_account(&mut self.journal, to, to_account);
237 let to_balance = &mut to_account.info.balance;
238 let Some(to_balance_incr) = to_balance.checked_add(balance) else {
239 return Ok(Some(TransferError::OverflowPayment));
240 };
241 *to_balance = to_balance_incr;
242 self.journal
245 .push(ENTRY::balance_transfer(from, to, balance));
246
247 Ok(None)
248 }
249
250 #[inline]
266 pub fn create_account_checkpoint(
267 &mut self,
268 caller: Address,
269 target_address: Address,
270 balance: U256,
271 spec_id: SpecId,
272 ) -> Result<JournalCheckpoint, TransferError> {
273 let checkpoint = self.checkpoint();
275
276 let caller_balance = self.state.get(&caller).unwrap().info.balance;
278 if caller_balance < balance {
280 self.checkpoint_revert(checkpoint);
281 return Err(TransferError::OutOfFunds);
282 }
283
284 let target_acc = self.state.get_mut(&target_address).unwrap();
286 let last_journal = &mut self.journal;
287
288 if target_acc.info.code_hash != KECCAK_EMPTY || target_acc.info.nonce != 0 {
293 self.checkpoint_revert(checkpoint);
294 return Err(TransferError::CreateCollision);
295 }
296
297 target_acc.mark_created();
299
300 last_journal.push(ENTRY::account_created(target_address));
302 target_acc.info.code = None;
303 if spec_id.is_enabled_in(SPURIOUS_DRAGON) {
305 target_acc.info.nonce = 1;
307 }
308
309 Self::touch_account(last_journal, target_address, target_acc);
312
313 let Some(new_balance) = target_acc.info.balance.checked_add(balance) else {
315 self.checkpoint_revert(checkpoint);
316 return Err(TransferError::OverflowPayment);
317 };
318 target_acc.info.balance = new_balance;
319
320 self.state.get_mut(&caller).unwrap().info.balance -= balance;
322
323 last_journal.push(ENTRY::balance_transfer(caller, target_address, balance));
325
326 Ok(checkpoint)
327 }
328
329 #[inline]
331 pub fn checkpoint(&mut self) -> JournalCheckpoint {
332 let checkpoint = JournalCheckpoint {
333 log_i: self.logs.len(),
334 journal_i: self.journal.len(),
335 };
336 self.depth += 1;
337 checkpoint
338 }
339
340 #[inline]
342 pub fn checkpoint_commit(&mut self) {
343 self.depth -= 1;
344 }
345
346 #[inline]
348 pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
349 let is_spurious_dragon_enabled = self.spec.is_enabled_in(SPURIOUS_DRAGON);
350 let state = &mut self.state;
351 let transient_storage = &mut self.transient_storage;
352 self.depth -= 1;
353 self.logs.truncate(checkpoint.log_i);
354
355 self.journal
357 .drain(checkpoint.journal_i..)
358 .rev()
359 .for_each(|entry| {
360 entry.revert(state, transient_storage, is_spurious_dragon_enabled);
361 });
362 }
363
364 #[inline]
376 pub fn selfdestruct<DB: Database>(
377 &mut self,
378 db: &mut DB,
379 address: Address,
380 target: Address,
381 ) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
382 let spec = self.spec;
383 let account_load = self.load_account(db, target)?;
384 let is_cold = account_load.is_cold;
385 let is_empty = account_load.state_clear_aware_is_empty(spec);
386
387 if address != target {
388 let acc_balance = self.state.get(&address).unwrap().info.balance;
391
392 let target_account = self.state.get_mut(&target).unwrap();
393 Self::touch_account(&mut self.journal, target, target_account);
394 target_account.info.balance += acc_balance;
395 }
396
397 let acc = self.state.get_mut(&address).unwrap();
398 let balance = acc.info.balance;
399 let previously_destroyed = acc.is_selfdestructed();
400 let is_cancun_enabled = spec.is_enabled_in(CANCUN);
401
402 let journal_entry = if acc.is_created() || !is_cancun_enabled {
404 acc.mark_selfdestruct();
405 acc.info.balance = U256::ZERO;
406 Some(ENTRY::account_destroyed(
407 address,
408 target,
409 previously_destroyed,
410 balance,
411 ))
412 } else if address != target {
413 acc.info.balance = U256::ZERO;
414 Some(ENTRY::balance_transfer(address, target, balance))
415 } else {
416 None
421 };
422
423 if let Some(entry) = journal_entry {
424 self.journal.push(entry);
425 };
426
427 Ok(StateLoad {
428 data: SelfDestructResult {
429 had_value: !balance.is_zero(),
430 target_exists: !is_empty,
431 previously_destroyed,
432 },
433 is_cold,
434 })
435 }
436
437 #[inline]
439 pub fn initial_account_load<DB: Database>(
440 &mut self,
441 db: &mut DB,
442 address: Address,
443 storage_keys: impl IntoIterator<Item = U256>,
444 ) -> Result<&mut Account, DB::Error> {
445 let account = match self.state.entry(address) {
447 Entry::Occupied(entry) => entry.into_mut(),
448 Entry::Vacant(vac) => vac.insert(
449 db.basic(address)?
450 .map(|i| i.into())
451 .unwrap_or(Account::new_not_existing()),
452 ),
453 };
454 for storage_key in storage_keys.into_iter() {
456 if let Entry::Vacant(entry) = account.storage.entry(storage_key) {
457 let storage = db.storage(address, storage_key)?;
458 entry.insert(EvmStorageSlot::new(storage));
459 }
460 }
461 Ok(account)
462 }
463
464 #[inline]
466 pub fn load_account<DB: Database>(
467 &mut self,
468 db: &mut DB,
469 address: Address,
470 ) -> Result<StateLoad<&mut Account>, DB::Error> {
471 self.load_account_optional(db, address, false)
472 }
473
474 #[inline]
482 pub fn load_account_delegated<DB: Database>(
483 &mut self,
484 db: &mut DB,
485 address: Address,
486 ) -> Result<StateLoad<AccountLoad>, DB::Error> {
487 let spec = self.spec;
488 let is_eip7702_enabled = spec.is_enabled_in(SpecId::PRAGUE);
489 let account = self.load_account_optional(db, address, is_eip7702_enabled)?;
490 let is_empty = account.state_clear_aware_is_empty(spec);
491
492 let mut account_load = StateLoad::new(
493 AccountLoad {
494 is_delegate_account_cold: None,
495 is_empty,
496 },
497 account.is_cold,
498 );
499
500 if let Some(Bytecode::Eip7702(code)) = &account.info.code {
502 let address = code.address();
503 let delegate_account = self.load_account(db, address)?;
504 account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
505 }
506
507 Ok(account_load)
508 }
509
510 #[inline]
517 pub fn load_code<DB: Database>(
518 &mut self,
519 db: &mut DB,
520 address: Address,
521 ) -> Result<StateLoad<&mut Account>, DB::Error> {
522 self.load_account_optional(db, address, true)
523 }
524
525 #[inline]
527 pub fn load_account_optional<DB: Database>(
528 &mut self,
529 db: &mut DB,
530 address: Address,
531 load_code: bool,
532 ) -> Result<StateLoad<&mut Account>, DB::Error> {
533 let load = match self.state.entry(address) {
534 Entry::Occupied(entry) => {
535 let account = entry.into_mut();
536 let is_cold = account.mark_warm();
537 StateLoad {
538 data: account,
539 is_cold,
540 }
541 }
542 Entry::Vacant(vac) => {
543 let account = if let Some(account) = db.basic(address)? {
544 account.into()
545 } else {
546 Account::new_not_existing()
547 };
548
549 let is_cold = !self.warm_preloaded_addresses.contains(&address);
551
552 StateLoad {
553 data: vac.insert(account),
554 is_cold,
555 }
556 }
557 };
558 if load.is_cold {
560 self.journal.push(ENTRY::account_warmed(address));
561 }
562 if load_code {
563 let info = &mut load.data.info;
564 if info.code.is_none() {
565 let code = if info.code_hash == KECCAK_EMPTY {
566 Bytecode::default()
567 } else {
568 db.code_by_hash(info.code_hash)?
569 };
570 info.code = Some(code);
571 }
572 }
573
574 Ok(load)
575 }
576
577 #[inline]
583 pub fn sload<DB: Database>(
584 &mut self,
585 db: &mut DB,
586 address: Address,
587 key: U256,
588 ) -> Result<StateLoad<U256>, DB::Error> {
589 let account = self.state.get_mut(&address).unwrap();
591 let is_newly_created = account.is_created();
593 let (value, is_cold) = match account.storage.entry(key) {
594 Entry::Occupied(occ) => {
595 let slot = occ.into_mut();
596 let is_cold = slot.mark_warm();
597 (slot.present_value, is_cold)
598 }
599 Entry::Vacant(vac) => {
600 let value = if is_newly_created {
602 U256::ZERO
603 } else {
604 db.storage(address, key)?
605 };
606
607 vac.insert(EvmStorageSlot::new(value));
608
609 (value, true)
610 }
611 };
612
613 if is_cold {
614 self.journal.push(ENTRY::storage_warmed(address, key));
616 }
617
618 Ok(StateLoad::new(value, is_cold))
619 }
620
621 #[inline]
627 pub fn sstore<DB: Database>(
628 &mut self,
629 db: &mut DB,
630 address: Address,
631 key: U256,
632 new: U256,
633 ) -> Result<StateLoad<SStoreResult>, DB::Error> {
634 let present = self.sload(db, address, key)?;
636 let acc = self.state.get_mut(&address).unwrap();
637
638 let slot = acc.storage.get_mut(&key).unwrap();
640
641 if present.data == new {
643 return Ok(StateLoad::new(
644 SStoreResult {
645 original_value: slot.original_value(),
646 present_value: present.data,
647 new_value: new,
648 },
649 present.is_cold,
650 ));
651 }
652
653 self.journal
654 .push(ENTRY::storage_changed(address, key, present.data));
655 slot.present_value = new;
657 Ok(StateLoad::new(
658 SStoreResult {
659 original_value: slot.original_value(),
660 present_value: present.data,
661 new_value: new,
662 },
663 present.is_cold,
664 ))
665 }
666
667 #[inline]
671 pub fn tload(&mut self, address: Address, key: U256) -> U256 {
672 self.transient_storage
673 .get(&(address, key))
674 .copied()
675 .unwrap_or_default()
676 }
677
678 #[inline]
685 pub fn tstore(&mut self, address: Address, key: U256, new: U256) {
686 let had_value = if new.is_zero() {
687 self.transient_storage.remove(&(address, key))
691 } else {
692 let previous_value = self
694 .transient_storage
695 .insert((address, key), new)
696 .unwrap_or_default();
697
698 if previous_value != new {
700 Some(previous_value)
702 } else {
703 None
704 }
705 };
706
707 if let Some(had_value) = had_value {
708 self.journal
710 .push(ENTRY::transient_storage_changed(address, key, had_value));
711 }
712 }
713
714 #[inline]
716 pub fn log(&mut self, log: Log) {
717 self.logs.push(log);
718 }
719}