1use revm_interpreter::Eip7702CodeLoad;
2
3use crate::{
4 interpreter::{AccountLoad, InstructionResult, SStoreResult, SelfDestructResult, StateLoad},
5 primitives::{
6 db::Database, hash_map::Entry, Account, Address, Bytecode, EVMError, EvmState,
7 EvmStorageSlot, HashMap, HashSet, Log, SpecId, SpecId::*, TransientStorage, B256,
8 KECCAK_EMPTY, PRECOMPILE3, U256,
9 },
10};
11use core::mem;
12use std::vec::Vec;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct JournaledState {
20 pub state: EvmState,
22 pub transient_storage: TransientStorage,
26 pub logs: Vec<Log>,
28 pub depth: usize,
30 pub journal: Vec<Vec<JournalEntry>>,
32 pub spec: SpecId,
42 pub warm_preloaded_addresses: HashSet<Address>,
49}
50
51impl JournaledState {
52 pub fn new(spec: SpecId, warm_preloaded_addresses: HashSet<Address>) -> JournaledState {
62 Self {
63 state: HashMap::default(),
64 transient_storage: TransientStorage::default(),
65 logs: Vec::new(),
66 journal: vec![vec![]],
67 depth: 0,
68 spec,
69 warm_preloaded_addresses,
70 }
71 }
72
73 #[inline]
75 pub fn state(&mut self) -> &mut EvmState {
76 &mut self.state
77 }
78
79 #[inline]
81 pub fn set_spec_id(&mut self, spec: SpecId) {
82 self.spec = spec;
83 }
84
85 #[inline]
89 pub fn touch(&mut self, address: &Address) {
90 if let Some(account) = self.state.get_mut(address) {
91 Self::touch_account(self.journal.last_mut().unwrap(), address, account);
92 }
93 }
94
95 #[inline]
97 fn touch_account(journal: &mut Vec<JournalEntry>, address: &Address, account: &mut Account) {
98 if !account.is_touched() {
99 journal.push(JournalEntry::AccountTouched { address: *address });
100 account.mark_touch();
101 }
102 }
103
104 pub fn clear(&mut self) {
106 let spec = self.spec;
107 *self = Self::new(spec, HashSet::default());
108 }
109
110 #[inline]
114 pub fn finalize(&mut self) -> (EvmState, Vec<Log>) {
115 let Self {
116 state,
117 transient_storage,
118 logs,
119 depth,
120 journal,
121 spec: _,
123 warm_preloaded_addresses: _,
124 } = self;
125
126 *transient_storage = TransientStorage::default();
127 *journal = vec![vec![]];
128 *depth = 0;
129 let state = mem::take(state);
130 let logs = mem::take(logs);
131
132 (state, logs)
133 }
134
135 #[inline]
143 pub fn account(&self, address: Address) -> &Account {
144 self.state
145 .get(&address)
146 .expect("Account expected to be loaded") }
148
149 #[inline]
151 pub fn depth(&self) -> u64 {
152 self.depth as u64
153 }
154
155 #[inline]
159 pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
160 let account = self.state.get_mut(&address).unwrap();
161 Self::touch_account(self.journal.last_mut().unwrap(), &address, account);
162
163 self.journal
164 .last_mut()
165 .unwrap()
166 .push(JournalEntry::CodeChange { address });
167
168 account.info.code_hash = hash;
169 account.info.code = Some(code);
170 }
171
172 #[inline]
175 pub fn set_code(&mut self, address: Address, code: Bytecode) {
176 let hash = code.hash_slow();
177 self.set_code_with_hash(address, code, hash)
178 }
179
180 #[inline]
181 pub fn inc_nonce(&mut self, address: Address) -> Option<u64> {
182 let account = self.state.get_mut(&address).unwrap();
183 if account.info.nonce == u64::MAX {
185 return None;
186 }
187 Self::touch_account(self.journal.last_mut().unwrap(), &address, account);
188 self.journal
189 .last_mut()
190 .unwrap()
191 .push(JournalEntry::NonceChange { address });
192
193 account.info.nonce += 1;
194
195 Some(account.info.nonce)
196 }
197
198 #[inline]
200 pub fn transfer<DB: Database>(
201 &mut self,
202 from: &Address,
203 to: &Address,
204 balance: U256,
205 db: &mut DB,
206 ) -> Result<Option<InstructionResult>, EVMError<DB::Error>> {
207 self.load_account(*from, db)?;
209 self.load_account(*to, db)?;
210
211 let from_account = &mut self.state.get_mut(from).unwrap();
213 Self::touch_account(self.journal.last_mut().unwrap(), from, from_account);
214 let from_balance = &mut from_account.info.balance;
215
216 let Some(from_balance_incr) = from_balance.checked_sub(balance) else {
217 return Ok(Some(InstructionResult::OutOfFunds));
218 };
219 *from_balance = from_balance_incr;
220
221 let to_account = &mut self.state.get_mut(to).unwrap();
223 Self::touch_account(self.journal.last_mut().unwrap(), to, to_account);
224 let to_balance = &mut to_account.info.balance;
225 let Some(to_balance_decr) = to_balance.checked_add(balance) else {
226 return Ok(Some(InstructionResult::OverflowPayment));
227 };
228 *to_balance = to_balance_decr;
229 self.journal
232 .last_mut()
233 .unwrap()
234 .push(JournalEntry::BalanceTransfer {
235 from: *from,
236 to: *to,
237 balance,
238 });
239
240 Ok(None)
241 }
242
243 #[inline]
259 pub fn create_account_checkpoint(
260 &mut self,
261 caller: Address,
262 address: Address,
263 balance: U256,
264 spec_id: SpecId,
265 ) -> Result<JournalCheckpoint, InstructionResult> {
266 let checkpoint = self.checkpoint();
268
269 let account = self.state.get_mut(&address).unwrap();
271 let last_journal = self.journal.last_mut().unwrap();
272
273 if account.info.code_hash != KECCAK_EMPTY || account.info.nonce != 0 {
278 self.checkpoint_revert(checkpoint);
279 return Err(InstructionResult::CreateCollision);
280 }
281
282 account.mark_created();
284
285 last_journal.push(JournalEntry::AccountCreated { address });
287 account.info.code = None;
288
289 Self::touch_account(last_journal, &address, account);
292
293 let Some(new_balance) = account.info.balance.checked_add(balance) else {
295 self.checkpoint_revert(checkpoint);
296 return Err(InstructionResult::OverflowPayment);
297 };
298 account.info.balance = new_balance;
299
300 if spec_id.is_enabled_in(SPURIOUS_DRAGON) {
302 account.info.nonce = 1;
304 }
305
306 let caller_account = self.state.get_mut(&caller).unwrap();
308 caller_account.info.balance -= balance;
310
311 last_journal.push(JournalEntry::BalanceTransfer {
313 from: caller,
314 to: address,
315 balance,
316 });
317
318 Ok(checkpoint)
319 }
320
321 #[inline]
323 fn journal_revert(
324 state: &mut EvmState,
325 transient_storage: &mut TransientStorage,
326 journal_entries: Vec<JournalEntry>,
327 is_spurious_dragon_enabled: bool,
328 ) {
329 for entry in journal_entries.into_iter().rev() {
330 match entry {
331 JournalEntry::AccountWarmed { address } => {
332 state.get_mut(&address).unwrap().mark_cold();
333 }
334 JournalEntry::AccountTouched { address } => {
335 if is_spurious_dragon_enabled && address == PRECOMPILE3 {
336 continue;
337 }
338 state.get_mut(&address).unwrap().unmark_touch();
340 }
341 JournalEntry::AccountDestroyed {
342 address,
343 target,
344 was_destroyed,
345 had_balance,
346 } => {
347 let account = state.get_mut(&address).unwrap();
348 if was_destroyed {
351 account.mark_selfdestruct();
353 } else {
354 account.unmark_selfdestruct();
356 }
357 account.info.balance += had_balance;
358
359 if address != target {
360 let target = state.get_mut(&target).unwrap();
361 target.info.balance -= had_balance;
362 }
363 }
364 JournalEntry::BalanceTransfer { from, to, balance } => {
365 let from = state.get_mut(&from).unwrap();
367 from.info.balance += balance;
368 let to = state.get_mut(&to).unwrap();
369 to.info.balance -= balance;
370 }
371 JournalEntry::NonceChange { address } => {
372 state.get_mut(&address).unwrap().info.nonce -= 1;
373 }
374 JournalEntry::AccountCreated { address } => {
375 let account = &mut state.get_mut(&address).unwrap();
376 account.unmark_created();
377 account
378 .storage
379 .values_mut()
380 .for_each(|slot| slot.mark_cold());
381 account.info.nonce = 0;
382 }
383 JournalEntry::StorageWarmed { address, key } => {
384 state
385 .get_mut(&address)
386 .unwrap()
387 .storage
388 .get_mut(&key)
389 .unwrap()
390 .mark_cold();
391 }
392 JournalEntry::StorageChanged {
393 address,
394 key,
395 had_value,
396 } => {
397 state
398 .get_mut(&address)
399 .unwrap()
400 .storage
401 .get_mut(&key)
402 .unwrap()
403 .present_value = had_value;
404 }
405 JournalEntry::TransientStorageChange {
406 address,
407 key,
408 had_value,
409 } => {
410 let tkey = (address, key);
411 if had_value.is_zero() {
412 transient_storage.remove(&tkey);
414 } else {
415 transient_storage.insert(tkey, had_value);
417 }
418 }
419 JournalEntry::CodeChange { address } => {
420 let acc = state.get_mut(&address).unwrap();
421 acc.info.code_hash = KECCAK_EMPTY;
422 acc.info.code = None;
423 }
424 }
425 }
426 }
427
428 #[inline]
430 pub fn checkpoint(&mut self) -> JournalCheckpoint {
431 let checkpoint = JournalCheckpoint {
432 log_i: self.logs.len(),
433 journal_i: self.journal.len(),
434 };
435 self.depth += 1;
436 self.journal.push(Default::default());
437 checkpoint
438 }
439
440 #[inline]
442 pub fn checkpoint_commit(&mut self) {
443 self.depth -= 1;
444 }
445
446 #[inline]
448 pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
449 let is_spurious_dragon_enabled = SpecId::enabled(self.spec, SPURIOUS_DRAGON);
450 let state = &mut self.state;
451 let transient_storage = &mut self.transient_storage;
452 self.depth -= 1;
453 let leng = self.journal.len();
455 self.journal
456 .iter_mut()
457 .rev()
458 .take(leng - checkpoint.journal_i)
459 .for_each(|cs| {
460 Self::journal_revert(
461 state,
462 transient_storage,
463 mem::take(cs),
464 is_spurious_dragon_enabled,
465 )
466 });
467
468 self.logs.truncate(checkpoint.log_i);
469 self.journal.truncate(checkpoint.journal_i);
470 }
471
472 #[inline]
484 pub fn selfdestruct<DB: Database>(
485 &mut self,
486 address: Address,
487 target: Address,
488 db: &mut DB,
489 ) -> Result<StateLoad<SelfDestructResult>, EVMError<DB::Error>> {
490 let spec = self.spec;
491 let account_load = self.load_account(target, db)?;
492 let is_cold = account_load.is_cold;
493 let is_empty = account_load.state_clear_aware_is_empty(spec);
494
495 if address != target {
496 let acc_balance = self.state.get_mut(&address).unwrap().info.balance;
499
500 let target_account = self.state.get_mut(&target).unwrap();
501 Self::touch_account(self.journal.last_mut().unwrap(), &target, target_account);
502 target_account.info.balance += acc_balance;
503 }
504
505 let acc = self.state.get_mut(&address).unwrap();
506 let balance = acc.info.balance;
507 let previously_destroyed = acc.is_selfdestructed();
508 let is_cancun_enabled = SpecId::enabled(self.spec, CANCUN);
509
510 let journal_entry = if acc.is_created() || !is_cancun_enabled {
512 acc.mark_selfdestruct();
513 acc.info.balance = U256::ZERO;
514 Some(JournalEntry::AccountDestroyed {
515 address,
516 target,
517 was_destroyed: previously_destroyed,
518 had_balance: balance,
519 })
520 } else if address != target {
521 acc.info.balance = U256::ZERO;
522 Some(JournalEntry::BalanceTransfer {
523 from: address,
524 to: target,
525 balance,
526 })
527 } else {
528 None
533 };
534
535 if let Some(entry) = journal_entry {
536 self.journal.last_mut().unwrap().push(entry);
537 };
538
539 Ok(StateLoad {
540 data: SelfDestructResult {
541 had_value: !balance.is_zero(),
542 target_exists: !is_empty,
543 previously_destroyed,
544 },
545 is_cold,
546 })
547 }
548
549 #[inline]
551 pub fn initial_account_load<DB: Database>(
552 &mut self,
553 address: Address,
554 storage_keys: impl IntoIterator<Item = U256>,
555 db: &mut DB,
556 ) -> Result<&mut Account, EVMError<DB::Error>> {
557 let account = match self.state.entry(address) {
559 Entry::Occupied(entry) => entry.into_mut(),
560 Entry::Vacant(vac) => vac.insert(
561 db.basic(address)
562 .map_err(EVMError::Database)?
563 .map(|i| i.into())
564 .unwrap_or(Account::new_not_existing()),
565 ),
566 };
567 for storage_key in storage_keys.into_iter() {
569 if let Entry::Vacant(entry) = account.storage.entry(storage_key) {
570 let storage = db
571 .storage(address, storage_key)
572 .map_err(EVMError::Database)?;
573 entry.insert(EvmStorageSlot::new(storage));
574 }
575 }
576 Ok(account)
577 }
578
579 #[inline]
581 pub fn load_account<DB: Database>(
582 &mut self,
583 address: Address,
584 db: &mut DB,
585 ) -> Result<StateLoad<&mut Account>, EVMError<DB::Error>> {
586 let load = match self.state.entry(address) {
587 Entry::Occupied(entry) => {
588 let account = entry.into_mut();
589 let is_cold = account.mark_warm();
590 StateLoad {
591 data: account,
592 is_cold,
593 }
594 }
595 Entry::Vacant(vac) => {
596 let account =
597 if let Some(account) = db.basic(address).map_err(EVMError::Database)? {
598 account.into()
599 } else {
600 Account::new_not_existing()
601 };
602
603 let is_cold = !self.warm_preloaded_addresses.contains(&address);
605
606 StateLoad {
607 data: vac.insert(account),
608 is_cold,
609 }
610 }
611 };
612
613 if load.is_cold {
615 self.journal
616 .last_mut()
617 .unwrap()
618 .push(JournalEntry::AccountWarmed { address });
619 }
620
621 Ok(load)
622 }
623
624 #[inline]
625 pub fn load_account_delegated<DB: Database>(
626 &mut self,
627 address: Address,
628 db: &mut DB,
629 ) -> Result<AccountLoad, EVMError<DB::Error>> {
630 let spec = self.spec;
631 let account = self.load_code(address, db)?;
632 let is_empty = account.state_clear_aware_is_empty(spec);
633
634 let mut account_load = AccountLoad {
635 is_empty,
636 load: Eip7702CodeLoad::new_not_delegated((), account.is_cold),
637 };
638 if let Some(Bytecode::Eip7702(code)) = &account.info.code {
640 let address = code.address();
641 let delegate_account = self.load_account(address, db)?;
642 account_load
643 .load
644 .set_delegate_load(delegate_account.is_cold);
645 }
646
647 Ok(account_load)
648 }
649
650 #[inline]
652 pub fn load_code<DB: Database>(
653 &mut self,
654 address: Address,
655 db: &mut DB,
656 ) -> Result<StateLoad<&mut Account>, EVMError<DB::Error>> {
657 let account_load = self.load_account(address, db)?;
658 let acc = &mut account_load.data.info;
659 if acc.code.is_none() {
660 if acc.code_hash == KECCAK_EMPTY {
661 let empty = Bytecode::default();
662 acc.code = Some(empty);
663 } else {
664 let code = db.code_by_hash(acc.code_hash).map_err(EVMError::Database)?;
665 acc.code = Some(code);
666 }
667 }
668 Ok(account_load)
669 }
670
671 #[inline]
677 pub fn sload<DB: Database>(
678 &mut self,
679 address: Address,
680 key: U256,
681 db: &mut DB,
682 ) -> Result<StateLoad<U256>, EVMError<DB::Error>> {
683 let account = self.state.get_mut(&address).unwrap();
685 let is_newly_created = account.is_created();
687 let (value, is_cold) = match account.storage.entry(key) {
688 Entry::Occupied(occ) => {
689 let slot = occ.into_mut();
690 let is_cold = slot.mark_warm();
691 (slot.present_value, is_cold)
692 }
693 Entry::Vacant(vac) => {
694 let value = if is_newly_created {
696 U256::ZERO
697 } else {
698 db.storage(address, key).map_err(EVMError::Database)?
699 };
700
701 vac.insert(EvmStorageSlot::new(value));
702
703 (value, true)
704 }
705 };
706
707 if is_cold {
708 self.journal
710 .last_mut()
711 .unwrap()
712 .push(JournalEntry::StorageWarmed { address, key });
713 }
714
715 Ok(StateLoad::new(value, is_cold))
716 }
717
718 #[inline]
725 pub fn sstore<DB: Database>(
726 &mut self,
727 address: Address,
728 key: U256,
729 new: U256,
730 db: &mut DB,
731 ) -> Result<StateLoad<SStoreResult>, EVMError<DB::Error>> {
732 let present = self.sload(address, key, db)?;
734 let acc = self.state.get_mut(&address).unwrap();
735
736 let slot = acc.storage.get_mut(&key).unwrap();
738
739 if present.data == new {
741 return Ok(StateLoad::new(
742 SStoreResult {
743 original_value: slot.original_value(),
744 present_value: present.data,
745 new_value: new,
746 },
747 present.is_cold,
748 ));
749 }
750
751 self.journal
752 .last_mut()
753 .unwrap()
754 .push(JournalEntry::StorageChanged {
755 address,
756 key,
757 had_value: present.data,
758 });
759 slot.present_value = new;
761 Ok(StateLoad::new(
762 SStoreResult {
763 original_value: slot.original_value(),
764 present_value: present.data,
765 new_value: new,
766 },
767 present.is_cold,
768 ))
769 }
770
771 #[inline]
775 pub fn tload(&mut self, address: Address, key: U256) -> U256 {
776 self.transient_storage
777 .get(&(address, key))
778 .copied()
779 .unwrap_or_default()
780 }
781
782 #[inline]
789 pub fn tstore(&mut self, address: Address, key: U256, new: U256) {
790 let had_value = if new.is_zero() {
791 self.transient_storage.remove(&(address, key))
795 } else {
796 let previous_value = self
798 .transient_storage
799 .insert((address, key), new)
800 .unwrap_or_default();
801
802 if previous_value != new {
804 Some(previous_value)
806 } else {
807 None
808 }
809 };
810
811 if let Some(had_value) = had_value {
812 self.journal
814 .last_mut()
815 .unwrap()
816 .push(JournalEntry::TransientStorageChange {
817 address,
818 key,
819 had_value,
820 });
821 }
822 }
823
824 #[inline]
826 pub fn log(&mut self, log: Log) {
827 self.logs.push(log);
828 }
829}
830
831#[derive(Debug, Clone, PartialEq, Eq, Hash)]
833#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
834pub enum JournalEntry {
835 AccountWarmed { address: Address },
839 AccountDestroyed {
843 address: Address,
844 target: Address,
845 was_destroyed: bool, had_balance: U256,
847 },
848 AccountTouched { address: Address },
853 BalanceTransfer {
857 from: Address,
858 to: Address,
859 balance: U256,
860 },
861 NonceChange {
865 address: Address, },
867 AccountCreated { address: Address },
871 StorageChanged {
875 address: Address,
876 key: U256,
877 had_value: U256,
878 },
879 StorageWarmed { address: Address, key: U256 },
883 TransientStorageChange {
887 address: Address,
888 key: U256,
889 had_value: U256,
890 },
891 CodeChange { address: Address },
895}
896
897#[derive(Debug, Copy, Clone, PartialEq, Eq)]
899#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
900pub struct JournalCheckpoint {
901 log_i: usize,
902 journal_i: usize,
903}