1mod entry;
2mod init;
3
4pub use entry::{JournalEntry, JournalEntryTr};
5pub use init::JournalInit;
6
7use bytecode::Bytecode;
8use context_interface::{
9 context::{SStoreResult, SelfDestructResult, StateLoad},
10 journaled_state::{AccountLoad, JournalCheckpoint, JournalTr, TransferError},
11};
12use core::mem;
13use database_interface::Database;
14use primitives::{
15 hardfork::{SpecId, SpecId::*},
16 hash_map::Entry,
17 Address, HashMap, HashSet, Log, B256, KECCAK_EMPTY, U256,
18};
19use state::{Account, EvmState, EvmStorageSlot, TransientStorage};
20use std::{vec, vec::Vec};
21
22#[derive(Debug, Clone, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct Journal<DB, ENTRY = JournalEntry>
30where
31 ENTRY: JournalEntryTr,
32{
33 pub database: DB,
35 pub state: EvmState,
37 pub transient_storage: TransientStorage,
41 pub logs: Vec<Log>,
43 pub depth: usize,
45 pub journal: Vec<Vec<ENTRY>>,
47 pub spec: SpecId,
57 pub warm_preloaded_addresses: HashSet<Address>,
64 pub precompiles: HashSet<Address>,
66}
67
68pub struct JournalOutput {
70 pub state: EvmState,
72 pub logs: Vec<Log>,
74}
75
76impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
77 type Database = DB;
78 type FinalOutput = JournalOutput;
79
80 fn new(database: DB) -> Journal<DB, ENTRY> {
81 Self::new(SpecId::LATEST, database)
82 }
83
84 fn db_ref(&self) -> &Self::Database {
85 &self.database
86 }
87
88 fn db(&mut self) -> &mut Self::Database {
89 &mut self.database
90 }
91
92 fn sload(
93 &mut self,
94 address: Address,
95 key: U256,
96 ) -> Result<StateLoad<U256>, <Self::Database as Database>::Error> {
97 self.sload(address, key)
98 }
99
100 fn sstore(
101 &mut self,
102 address: Address,
103 key: U256,
104 value: U256,
105 ) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
106 self.sstore(address, key, value)
107 }
108
109 fn tload(&mut self, address: Address, key: U256) -> U256 {
110 self.tload(address, key)
111 }
112
113 fn tstore(&mut self, address: Address, key: U256, value: U256) {
114 self.tstore(address, key, value)
115 }
116
117 fn log(&mut self, log: Log) {
118 self.log(log)
119 }
120
121 fn selfdestruct(
122 &mut self,
123 address: Address,
124 target: Address,
125 ) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
126 self.selfdestruct(address, target)
127 }
128
129 fn warm_account(&mut self, address: Address) {
130 self.warm_preloaded_addresses.insert(address);
131 }
132
133 fn warm_precompiles(&mut self, address: HashSet<Address>) {
134 self.precompiles = address;
135 self.warm_preloaded_addresses
136 .extend(self.precompiles.iter());
137 }
138
139 #[inline]
140 fn precompile_addresses(&self) -> &HashSet<Address> {
141 &self.precompiles
142 }
143
144 #[inline]
146 fn depth(&self) -> usize {
147 self.depth
148 }
149
150 fn warm_account_and_storage(
151 &mut self,
152 address: Address,
153 storage_keys: impl IntoIterator<Item = U256>,
154 ) -> Result<(), <Self::Database as Database>::Error> {
155 self.initial_account_load(address, storage_keys)?;
156 Ok(())
157 }
158
159 fn set_spec_id(&mut self, spec_id: SpecId) {
160 self.spec = spec_id;
161 }
162
163 fn transfer(
164 &mut self,
165 from: &Address,
166 to: &Address,
167 balance: U256,
168 ) -> Result<Option<TransferError>, DB::Error> {
169 self.transfer(from, to, balance)
170 }
171
172 fn touch_account(&mut self, address: Address) {
173 self.touch(&address);
174 }
175
176 fn inc_account_nonce(&mut self, address: Address) -> Result<Option<u64>, DB::Error> {
177 Ok(self.inc_nonce(address))
178 }
179
180 fn load_account(&mut self, address: Address) -> Result<StateLoad<&mut Account>, DB::Error> {
181 self.load_account(address)
182 }
183
184 fn load_account_code(
185 &mut self,
186 address: Address,
187 ) -> Result<StateLoad<&mut Account>, DB::Error> {
188 self.load_code(address)
189 }
190
191 fn load_account_delegated(
192 &mut self,
193 address: Address,
194 ) -> Result<StateLoad<AccountLoad>, DB::Error> {
195 self.load_account_delegated(address)
196 }
197
198 fn checkpoint(&mut self) -> JournalCheckpoint {
199 self.checkpoint()
200 }
201
202 fn checkpoint_commit(&mut self) {
203 self.checkpoint_commit()
204 }
205
206 fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
207 self.checkpoint_revert(checkpoint)
208 }
209
210 fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
211 self.set_code_with_hash(address, code, hash);
212 }
213
214 fn clear(&mut self) {
215 self.state.clear();
217 self.transient_storage.clear();
218 self.logs.clear();
219 self.journal = vec![vec![]];
220 self.depth = 0;
221 self.warm_preloaded_addresses.clear();
222 }
223
224 fn create_account_checkpoint(
225 &mut self,
226 caller: Address,
227 address: Address,
228 balance: U256,
229 spec_id: SpecId,
230 ) -> Result<JournalCheckpoint, TransferError> {
231 self.create_account_checkpoint(caller, address, balance, spec_id)
233 }
234
235 fn finalize(&mut self) -> Self::FinalOutput {
236 let Self {
237 state,
238 transient_storage,
239 logs,
240 depth,
241 journal,
242 spec: _,
244 database: _,
245 warm_preloaded_addresses: _,
246 precompiles: _,
247 } = self;
248
249 *transient_storage = TransientStorage::default();
250 *journal = vec![vec![]];
251 *depth = 0;
252 let state = mem::take(state);
253 let logs = mem::take(logs);
254
255 JournalOutput { state, logs }
256 }
257}
258
259impl<DB: Database, ENTRY: JournalEntryTr> Journal<DB, ENTRY> {
260 pub fn new(spec: SpecId, database: DB) -> Journal<DB, ENTRY> {
269 Self {
270 database,
271 state: HashMap::default(),
272 transient_storage: TransientStorage::default(),
273 logs: Vec::new(),
274 journal: vec![vec![]],
275 depth: 0,
276 spec,
277 warm_preloaded_addresses: HashSet::default(),
278 precompiles: HashSet::default(),
279 }
280 }
281
282 #[inline]
284 pub fn state(&mut self) -> &mut EvmState {
285 &mut self.state
286 }
287
288 #[inline]
290 pub fn set_spec_id(&mut self, spec: SpecId) {
291 self.spec = spec;
292 }
293
294 #[inline]
298 pub fn touch(&mut self, address: &Address) {
299 if let Some(account) = self.state.get_mut(address) {
300 Self::touch_account(self.journal.last_mut().unwrap(), address, account);
301 }
302 }
303
304 #[inline]
306 fn touch_account(journal: &mut Vec<ENTRY>, address: &Address, account: &mut Account) {
307 if !account.is_touched() {
308 journal.push(ENTRY::account_touched(*address));
309 account.mark_touch();
310 }
311 }
312
313 #[inline]
321 pub fn account(&self, address: Address) -> &Account {
322 self.state
323 .get(&address)
324 .expect("Account expected to be loaded") }
326
327 #[inline]
331 pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
332 let account = self.state.get_mut(&address).unwrap();
333 Self::touch_account(self.journal.last_mut().unwrap(), &address, account);
334
335 self.journal
336 .last_mut()
337 .unwrap()
338 .push(ENTRY::code_changed(address));
339
340 account.info.code_hash = hash;
341 account.info.code = Some(code);
342 }
343
344 #[inline]
348 pub fn set_code(&mut self, address: Address, code: Bytecode) {
349 let hash = code.hash_slow();
350 self.set_code_with_hash(address, code, hash)
351 }
352
353 #[inline]
354 pub fn inc_nonce(&mut self, address: Address) -> Option<u64> {
355 let account = self.state.get_mut(&address).unwrap();
356 if account.info.nonce == u64::MAX {
358 return None;
359 }
360 Self::touch_account(self.journal.last_mut().unwrap(), &address, account);
361 self.journal
362 .last_mut()
363 .unwrap()
364 .push(ENTRY::nonce_changed(address));
365
366 account.info.nonce += 1;
367
368 Some(account.info.nonce)
369 }
370
371 #[inline]
373 pub fn transfer(
374 &mut self,
375 from: &Address,
376 to: &Address,
377 balance: U256,
378 ) -> Result<Option<TransferError>, DB::Error> {
379 if balance.is_zero() {
380 self.load_account(*to)?;
381 let to_account = self.state.get_mut(to).unwrap();
382 Self::touch_account(self.journal.last_mut().unwrap(), to, to_account);
383 return Ok(None);
384 }
385 self.load_account(*from)?;
387 self.load_account(*to)?;
388
389 let from_account = self.state.get_mut(from).unwrap();
391 Self::touch_account(self.journal.last_mut().unwrap(), from, from_account);
392 let from_balance = &mut from_account.info.balance;
393
394 let Some(from_balance_decr) = from_balance.checked_sub(balance) else {
395 return Ok(Some(TransferError::OutOfFunds));
396 };
397 *from_balance = from_balance_decr;
398
399 let to_account = &mut self.state.get_mut(to).unwrap();
401 Self::touch_account(self.journal.last_mut().unwrap(), to, to_account);
402 let to_balance = &mut to_account.info.balance;
403 let Some(to_balance_incr) = to_balance.checked_add(balance) else {
404 return Ok(Some(TransferError::OverflowPayment));
405 };
406 *to_balance = to_balance_incr;
407 self.journal
410 .last_mut()
411 .unwrap()
412 .push(ENTRY::balance_transfer(*from, *to, balance));
413
414 Ok(None)
415 }
416
417 #[inline]
433 pub fn create_account_checkpoint(
434 &mut self,
435 caller: Address,
436 target_address: Address,
437 balance: U256,
438 spec_id: SpecId,
439 ) -> Result<JournalCheckpoint, TransferError> {
440 let checkpoint = self.checkpoint();
442
443 let caller_balance = self.state.get(&caller).unwrap().info.balance;
445 if caller_balance < balance {
447 self.checkpoint_revert(checkpoint);
448 return Err(TransferError::OutOfFunds);
449 }
450
451 let target_acc = self.state.get_mut(&target_address).unwrap();
453 let last_journal = self.journal.last_mut().unwrap();
454
455 if target_acc.info.code_hash != KECCAK_EMPTY || target_acc.info.nonce != 0 {
460 self.checkpoint_revert(checkpoint);
461 return Err(TransferError::CreateCollision);
462 }
463
464 target_acc.mark_created();
466
467 last_journal.push(ENTRY::account_created(target_address));
469 target_acc.info.code = None;
470 if spec_id.is_enabled_in(SPURIOUS_DRAGON) {
472 target_acc.info.nonce = 1;
474 }
475
476 Self::touch_account(last_journal, &target_address, target_acc);
479
480 let Some(new_balance) = target_acc.info.balance.checked_add(balance) else {
482 self.checkpoint_revert(checkpoint);
483 return Err(TransferError::OverflowPayment);
484 };
485 target_acc.info.balance = new_balance;
486
487 self.state.get_mut(&caller).unwrap().info.balance -= balance;
489
490 last_journal.push(ENTRY::balance_transfer(caller, target_address, balance));
492
493 Ok(checkpoint)
494 }
495
496 #[inline]
498 pub fn checkpoint(&mut self) -> JournalCheckpoint {
499 let checkpoint = JournalCheckpoint {
500 log_i: self.logs.len(),
501 journal_i: self.journal.len(),
502 };
503 self.depth += 1;
504 self.journal.push(Default::default());
505 checkpoint
506 }
507
508 #[inline]
510 pub fn checkpoint_commit(&mut self) {
511 self.depth -= 1;
512 }
513
514 #[inline]
516 pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
517 let is_spurious_dragon_enabled = self.spec.is_enabled_in(SPURIOUS_DRAGON);
518 let state = &mut self.state;
519 let transient_storage = &mut self.transient_storage;
520 self.depth -= 1;
521 let len = self.journal.len();
523 self.journal
524 .iter_mut()
525 .rev()
526 .take(len - checkpoint.journal_i)
527 .for_each(|cs| {
528 for entry in mem::take(cs).into_iter().rev() {
529 entry.revert(state, transient_storage, is_spurious_dragon_enabled);
530 }
531 });
532
533 self.logs.truncate(checkpoint.log_i);
534 self.journal.truncate(checkpoint.journal_i);
535 }
536
537 #[inline]
549 pub fn selfdestruct(
550 &mut self,
551 address: Address,
552 target: Address,
553 ) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
554 let spec = self.spec;
555 let account_load = self.load_account(target)?;
556 let is_cold = account_load.is_cold;
557 let is_empty = account_load.state_clear_aware_is_empty(spec);
558
559 if address != target {
560 let acc_balance = self.state.get(&address).unwrap().info.balance;
563
564 let target_account = self.state.get_mut(&target).unwrap();
565 Self::touch_account(self.journal.last_mut().unwrap(), &target, target_account);
566 target_account.info.balance += acc_balance;
567 }
568
569 let acc = self.state.get_mut(&address).unwrap();
570 let balance = acc.info.balance;
571 let previously_destroyed = acc.is_selfdestructed();
572 let is_cancun_enabled = self.spec.is_enabled_in(CANCUN);
573
574 let journal_entry = if acc.is_created() || !is_cancun_enabled {
576 acc.mark_selfdestruct();
577 acc.info.balance = U256::ZERO;
578 Some(ENTRY::account_destroyed(
579 address,
580 target,
581 previously_destroyed,
582 balance,
583 ))
584 } else if address != target {
585 acc.info.balance = U256::ZERO;
586 Some(ENTRY::balance_transfer(address, target, balance))
587 } else {
588 None
593 };
594
595 if let Some(entry) = journal_entry {
596 self.journal.last_mut().unwrap().push(entry);
597 };
598
599 Ok(StateLoad {
600 data: SelfDestructResult {
601 had_value: !balance.is_zero(),
602 target_exists: !is_empty,
603 previously_destroyed,
604 },
605 is_cold,
606 })
607 }
608
609 #[inline]
611 pub fn initial_account_load(
612 &mut self,
613 address: Address,
614 storage_keys: impl IntoIterator<Item = U256>,
615 ) -> Result<&mut Account, DB::Error> {
616 let account = match self.state.entry(address) {
618 Entry::Occupied(entry) => entry.into_mut(),
619 Entry::Vacant(vac) => vac.insert(
620 self.database
621 .basic(address)?
622 .map(|i| i.into())
623 .unwrap_or(Account::new_not_existing()),
624 ),
625 };
626 for storage_key in storage_keys.into_iter() {
628 if let Entry::Vacant(entry) = account.storage.entry(storage_key) {
629 let storage = self.database.storage(address, storage_key)?;
630 entry.insert(EvmStorageSlot::new(storage));
631 }
632 }
633 Ok(account)
634 }
635
636 #[inline]
638 pub fn load_account(&mut self, address: Address) -> Result<StateLoad<&mut Account>, DB::Error> {
639 self.load_account_optional(address, false)
640 }
641
642 #[inline]
643 pub fn load_account_delegated(
644 &mut self,
645 address: Address,
646 ) -> Result<StateLoad<AccountLoad>, DB::Error> {
647 let spec = self.spec;
648 let is_eip7702_enabled = spec.is_enabled_in(SpecId::PRAGUE);
649 let account = self.load_account_optional(address, is_eip7702_enabled)?;
650 let is_empty = account.state_clear_aware_is_empty(spec);
651
652 let mut account_load = StateLoad::new(
653 AccountLoad {
654 is_delegate_account_cold: None,
655 is_empty,
656 },
657 account.is_cold,
658 );
659
660 if let Some(Bytecode::Eip7702(code)) = &account.info.code {
662 let address = code.address();
663 let delegate_account = self.load_account(address)?;
664 account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
665 }
666
667 Ok(account_load)
668 }
669
670 pub fn load_code(&mut self, address: Address) -> Result<StateLoad<&mut Account>, DB::Error> {
671 self.load_account_optional(address, true)
672 }
673
674 #[inline]
676 pub fn load_account_optional(
677 &mut self,
678 address: Address,
679 load_code: bool,
680 ) -> Result<StateLoad<&mut Account>, DB::Error> {
681 let load = match self.state.entry(address) {
682 Entry::Occupied(entry) => {
683 let account = entry.into_mut();
684 let is_cold = account.mark_warm();
685 StateLoad {
686 data: account,
687 is_cold,
688 }
689 }
690 Entry::Vacant(vac) => {
691 let account = if let Some(account) = self.database.basic(address)? {
692 account.into()
693 } else {
694 Account::new_not_existing()
695 };
696
697 let is_cold = !self.warm_preloaded_addresses.contains(&address);
699
700 StateLoad {
701 data: vac.insert(account),
702 is_cold,
703 }
704 }
705 };
706 if load.is_cold {
708 self.journal
709 .last_mut()
710 .unwrap()
711 .push(ENTRY::account_warmed(address));
712 }
713 if load_code {
714 let info = &mut load.data.info;
715 if info.code.is_none() {
716 let code = if info.code_hash == KECCAK_EMPTY {
717 Bytecode::default()
718 } else {
719 self.database.code_by_hash(info.code_hash)?
720 };
721 info.code = Some(code);
722 }
723 }
724
725 Ok(load)
726 }
727
728 #[inline]
734 pub fn sload(&mut self, address: Address, key: U256) -> Result<StateLoad<U256>, DB::Error> {
735 let account = self.state.get_mut(&address).unwrap();
737 let is_newly_created = account.is_created();
739 let (value, is_cold) = match account.storage.entry(key) {
740 Entry::Occupied(occ) => {
741 let slot = occ.into_mut();
742 let is_cold = slot.mark_warm();
743 (slot.present_value, is_cold)
744 }
745 Entry::Vacant(vac) => {
746 let value = if is_newly_created {
748 U256::ZERO
749 } else {
750 self.database.storage(address, key)?
751 };
752
753 vac.insert(EvmStorageSlot::new(value));
754
755 (value, true)
756 }
757 };
758
759 if is_cold {
760 self.journal
762 .last_mut()
763 .unwrap()
764 .push(ENTRY::storage_warmed(address, key));
765 }
766
767 Ok(StateLoad::new(value, is_cold))
768 }
769
770 #[inline]
776 pub fn sstore(
777 &mut self,
778 address: Address,
779 key: U256,
780 new: U256,
781 ) -> Result<StateLoad<SStoreResult>, DB::Error> {
782 let present = self.sload(address, key)?;
784 let acc = self.state.get_mut(&address).unwrap();
785
786 let slot = acc.storage.get_mut(&key).unwrap();
788
789 if present.data == new {
791 return Ok(StateLoad::new(
792 SStoreResult {
793 original_value: slot.original_value(),
794 present_value: present.data,
795 new_value: new,
796 },
797 present.is_cold,
798 ));
799 }
800
801 self.journal
802 .last_mut()
803 .unwrap()
804 .push(ENTRY::storage_changed(address, key, present.data));
805 slot.present_value = new;
807 Ok(StateLoad::new(
808 SStoreResult {
809 original_value: slot.original_value(),
810 present_value: present.data,
811 new_value: new,
812 },
813 present.is_cold,
814 ))
815 }
816
817 #[inline]
821 pub fn tload(&mut self, address: Address, key: U256) -> U256 {
822 self.transient_storage
823 .get(&(address, key))
824 .copied()
825 .unwrap_or_default()
826 }
827
828 #[inline]
835 pub fn tstore(&mut self, address: Address, key: U256, new: U256) {
836 let had_value = if new.is_zero() {
837 self.transient_storage.remove(&(address, key))
841 } else {
842 let previous_value = self
844 .transient_storage
845 .insert((address, key), new)
846 .unwrap_or_default();
847
848 if previous_value != new {
850 Some(previous_value)
852 } else {
853 None
854 }
855 };
856
857 if let Some(had_value) = had_value {
858 self.journal
860 .last_mut()
861 .unwrap()
862 .push(ENTRY::transient_storage_changed(address, key, had_value));
863 }
864 }
865
866 #[inline]
868 pub fn log(&mut self, log: Log) {
869 self.logs.push(log);
870 }
871}
872
873impl<DB> Journal<DB> {
874 pub fn from_init(init: &JournalInit, database: DB) -> Self {
878 Self {
879 database,
880 state: init.state.clone(),
881 transient_storage: init.transient_storage.clone(),
882 logs: init.logs.clone(),
883 depth: init.depth,
884 journal: init.journal.clone(),
885 spec: init.spec,
886 warm_preloaded_addresses: init.warm_preloaded_addresses.clone(),
887 precompiles: init.precompiles.clone(),
888 }
889 }
890}