1use crate::states::block_hash_cache::BlockHashCache;
2
3use super::{
4 bundle_state::BundleRetention, cache::CacheState, plain_account::PlainStorage, BundleState,
5 CacheAccount, StateBuilder, TransitionAccount, TransitionState,
6};
7use bytecode::Bytecode;
8use database_interface::{
9 bal::{BalState, EvmDatabaseError},
10 Database, DatabaseCommit, DatabaseRef, EmptyDB, OnStateHook,
11};
12use primitives::{hash_map, Address, AddressMap, HashMap, StorageKey, StorageValue, B256};
13use state::{
14 bal::{alloy::AlloyBal, Bal, BlockAccessIndex},
15 Account, AccountId, AccountInfo, EvmStorage,
16};
17use std::{borrow::Cow, boxed::Box, sync::Arc};
18
19pub type DBBox<'a, E> = Box<dyn Database<Error = E> + Send + 'a>;
21
22pub type StateDBBox<'a, E> = State<DBBox<'a, E>>;
26
27#[derive(derive_more::Debug)]
32pub struct State<DB> {
33 pub cache: CacheState,
40 pub database: DB,
46 pub transition_state: Option<TransitionState>,
50 pub bundle_state: BundleState,
56 pub use_preloaded_bundle: bool,
62 pub block_hashes: BlockHashCache,
69 pub bal_state: BalState,
73 #[debug(skip)]
75 pub state_hook: Option<Box<dyn OnStateHook>>,
76}
77
78impl State<EmptyDB> {
80 pub fn builder() -> StateBuilder<EmptyDB> {
82 StateBuilder::default()
83 }
84}
85
86impl<DB: Database> State<DB> {
87 pub fn bundle_size_hint(&self) -> usize {
91 self.bundle_state.size_hint()
92 }
93
94 pub fn insert_not_existing(&mut self, address: Address) {
96 self.cache.insert_not_existing(address)
97 }
98
99 pub fn insert_account(&mut self, address: Address, info: AccountInfo) {
101 self.cache.insert_account(address, info)
102 }
103
104 pub fn insert_account_with_storage(
106 &mut self,
107 address: Address,
108 info: AccountInfo,
109 storage: PlainStorage,
110 ) {
111 self.cache
112 .insert_account_with_storage(address, info, storage)
113 }
114
115 pub fn apply_transition<'a>(
117 &mut self,
118 transitions: impl IntoIterator<Item = (Address, TransitionAccount<Option<Cow<'a, EvmStorage>>>)>,
119 ) {
120 if let Some(s) = self.transition_state.as_mut() {
122 s.add_transitions(transitions)
123 }
124 }
125
126 pub fn merge_transitions(&mut self, retention: BundleRetention) {
132 if let Some(transition_state) = self.transition_state.as_mut().map(TransitionState::take) {
133 self.bundle_state
134 .apply_transitions_and_create_reverts(transition_state, retention);
135 }
136 }
137
138 pub fn load_cache_account(&mut self, address: Address) -> Result<&mut CacheAccount, DB::Error> {
143 Self::load_cache_account_with(
144 &mut self.cache,
145 self.use_preloaded_bundle,
146 &self.bundle_state,
147 &mut self.database,
148 address,
149 )
150 }
151
152 fn load_cache_account_with<'a>(
160 cache: &'a mut CacheState,
161 use_preloaded_bundle: bool,
162 bundle_state: &BundleState,
163 database: &mut DB,
164 address: Address,
165 ) -> Result<&'a mut CacheAccount, DB::Error> {
166 Ok(match cache.accounts.entry(address) {
167 hash_map::Entry::Vacant(entry) => {
168 if use_preloaded_bundle {
169 if let Some(account) = bundle_state.account(&address).map(Into::into) {
171 return Ok(entry.insert(account));
172 }
173 }
174 let info = database.basic(address)?;
176 let account = match info {
177 None => CacheAccount::new_loaded_not_existing(),
178 Some(acc) if acc.is_empty() => {
179 CacheAccount::new_loaded_empty_eip161(HashMap::default())
180 }
181 Some(acc) => CacheAccount::new_loaded(acc, HashMap::default()),
182 };
183 entry.insert(account)
184 }
185 hash_map::Entry::Occupied(entry) => entry.into_mut(),
186 })
187 }
188
189 pub fn take_bundle(&mut self) -> BundleState {
201 core::mem::take(&mut self.bundle_state)
202 }
203
204 #[inline]
206 pub const fn take_built_bal(&mut self) -> Option<Bal> {
207 self.bal_state.take_built_bal()
208 }
209
210 #[inline]
212 pub fn take_built_alloy_bal(&mut self) -> Option<AlloyBal> {
213 self.bal_state.take_built_alloy_bal()
214 }
215
216 #[inline]
218 pub const fn bump_bal_index(&mut self) {
219 self.bal_state.bump_bal_index();
220 }
221
222 #[inline]
224 pub const fn set_bal_index(&mut self, index: BlockAccessIndex) {
225 self.bal_state.bal_index = index;
226 }
227
228 #[inline]
230 pub const fn reset_bal_index(&mut self) {
231 self.bal_state.reset_bal_index();
232 }
233
234 #[inline]
236 pub fn set_bal(&mut self, bal: Option<Arc<Bal>>) {
237 self.bal_state.bal = bal;
238 }
239
240 #[inline]
244 pub const fn set_allow_bal_db_fallback(&mut self, allow: bool) {
245 self.bal_state.allow_db_fallback = allow;
246 }
247
248 #[inline]
250 pub fn set_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {
251 self.state_hook = hook;
252 }
253
254 #[inline]
256 #[must_use]
257 pub fn with_state_hook(mut self, hook: Option<Box<dyn OnStateHook>>) -> Self {
258 self.set_state_hook(hook);
259 self
260 }
261
262 #[inline]
264 pub const fn has_bal(&self) -> bool {
265 self.bal_state.bal.is_some()
266 }
267
268 #[inline]
270 fn storage(&mut self, address: Address, index: StorageKey) -> Result<StorageValue, DB::Error> {
271 let account = Self::load_cache_account_with(
273 &mut self.cache,
274 self.use_preloaded_bundle,
275 &self.bundle_state,
276 &mut self.database,
277 address,
278 )?;
279
280 let is_storage_known = account.status.is_storage_known();
282 Ok(account
283 .account
284 .as_mut()
285 .map(|account| match account.storage.entry(index) {
286 hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
287 hash_map::Entry::Vacant(entry) => {
288 let value = if is_storage_known {
291 StorageValue::ZERO
292 } else {
293 self.database.storage(address, index)?
294 };
295 entry.insert(value);
296 Ok(value)
297 }
298 })
299 .transpose()?
300 .unwrap_or_default())
301 }
302}
303
304impl<DB: Database> Database for State<DB> {
305 type Error = EvmDatabaseError<DB::Error>;
306
307 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
308 let account_id = self
310 .bal_state
311 .get_account_id(&address)
312 .map_err(EvmDatabaseError::Bal)?;
313
314 let mut basic = self
315 .load_cache_account(address)
316 .map(|a| a.account_info())
317 .map_err(EvmDatabaseError::Database)?;
318 if let Some(account_id) = account_id {
321 self.bal_state
322 .basic_by_account_id(account_id, &mut basic)
323 .map_err(EvmDatabaseError::Bal)?;
324 }
325 Ok(basic)
326 }
327
328 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
329 let res = match self.cache.contracts.entry(code_hash) {
330 hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
331 hash_map::Entry::Vacant(entry) => {
332 if self.use_preloaded_bundle {
333 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
334 entry.insert(code.clone());
335 return Ok(code.clone());
336 }
337 }
338 let code = self
340 .database
341 .code_by_hash(code_hash)
342 .map_err(EvmDatabaseError::Database)?;
343 entry.insert(code.clone());
344 Ok(code)
345 }
346 };
347 res
348 }
349
350 fn storage(
351 &mut self,
352 address: Address,
353 index: StorageKey,
354 ) -> Result<StorageValue, Self::Error> {
355 if let Some(storage) = self
356 .bal_state
357 .storage(&address, index)
358 .map_err(EvmDatabaseError::Bal)?
359 {
360 return Ok(storage);
362 }
363 self.storage(address, index)
364 .map_err(EvmDatabaseError::Database)
365 }
366
367 fn storage_by_account_id(
368 &mut self,
369 address: Address,
370 account_id: AccountId,
371 key: StorageKey,
372 ) -> Result<StorageValue, Self::Error> {
373 if let Some(storage) = self.bal_state.storage_by_account_id(account_id, key)? {
374 return Ok(storage);
375 }
376
377 self.storage(address, key)
378 .map_err(EvmDatabaseError::Database)
379 }
380
381 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
382 if let Some(hash) = self.block_hashes.get(number) {
384 return Ok(hash);
385 }
386
387 let hash = self
389 .database
390 .block_hash(number)
391 .map_err(EvmDatabaseError::Database)?;
392
393 self.block_hashes.insert(number, hash);
395
396 Ok(hash)
397 }
398}
399
400impl<DB: Database> DatabaseCommit for State<DB> {
401 fn commit(&mut self, changes: AddressMap<Account>) {
402 self.bal_state.commit(&changes);
403
404 if let Some(hook) = self.state_hook.as_mut() {
405 let transitions = self.cache.apply_evm_state_iter(
406 changes
407 .iter()
408 .map(|(address, account)| (*address, Cow::Borrowed(account))),
409 |_, _| {},
410 );
411
412 if let Some(s) = self.transition_state.as_mut() {
413 s.add_transitions(transitions)
414 } else {
415 transitions.for_each(|_| {});
417 }
418
419 hook.on_state(changes);
420 } else {
421 let transitions = self.cache.apply_evm_state_iter(
422 changes
423 .into_iter()
424 .map(|(address, account)| (address, Cow::Owned(account))),
425 |_, _| {},
426 );
427
428 if let Some(s) = self.transition_state.as_mut() {
429 s.add_transitions(transitions)
430 } else {
431 transitions.for_each(|_| {});
433 }
434 }
435 }
436
437 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
438 if self.state_hook.is_some() {
439 let changes = changes.collect::<AddressMap<_>>();
440 self.commit(changes);
441 return;
442 }
443
444 if let Some(s) = self.transition_state.as_mut() {
445 for (address, account) in changes {
446 self.bal_state.commit_one(address, &account);
447 if let Some(transition) =
448 self.cache.apply_account_state(address, Cow::Owned(account))
449 {
450 s.add_transition(address, transition);
451 }
452 }
453 } else {
454 for (address, account) in changes {
455 self.bal_state.commit_one(address, &account);
456 _ = self.cache.apply_account_state(address, Cow::Owned(account));
457 }
458 }
459 }
460}
461
462impl<DB: DatabaseRef> DatabaseRef for State<DB> {
463 type Error = EvmDatabaseError<DB::Error>;
464
465 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
466 let account_id = self.bal_state.get_account_id(&address)?;
468
469 let mut loaded_account = None;
471 if let Some(account) = self.cache.accounts.get(&address) {
472 loaded_account = Some(account.account_info());
473 };
474
475 if self.use_preloaded_bundle && loaded_account.is_none() {
477 if let Some(account) = self.bundle_state.account(&address) {
478 loaded_account = Some(account.account_info());
479 }
480 }
481
482 if loaded_account.is_none() {
484 loaded_account = Some(
485 self.database
486 .basic_ref(address)
487 .map_err(EvmDatabaseError::Database)?,
488 );
489 }
490
491 let mut account = loaded_account.unwrap();
493
494 if let Some(account_id) = account_id {
496 self.bal_state
497 .basic_by_account_id(account_id, &mut account)
498 .map_err(EvmDatabaseError::Bal)?;
499 }
500 Ok(account)
501 }
502
503 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
504 if let Some(code) = self.cache.contracts.get(&code_hash) {
506 return Ok(code.clone());
507 }
508 if self.use_preloaded_bundle {
510 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
511 return Ok(code.clone());
512 }
513 }
514 self.database
516 .code_by_hash_ref(code_hash)
517 .map_err(EvmDatabaseError::Database)
518 }
519
520 fn storage_ref(
521 &self,
522 address: Address,
523 index: StorageKey,
524 ) -> Result<StorageValue, Self::Error> {
525 if let Some(storage) = self.bal_state.storage(&address, index)? {
527 return Ok(storage);
528 }
529
530 if let Some(account) = self.cache.accounts.get(&address) {
532 if let Some(plain_account) = &account.account {
533 if let Some(storage_value) = plain_account.storage.get(&index) {
535 return Ok(*storage_value);
536 }
537 if account.status.is_storage_known() {
540 return Ok(StorageValue::ZERO);
541 }
542 }
543 }
544
545 self.database
547 .storage_ref(address, index)
548 .map_err(EvmDatabaseError::Database)
549 }
550
551 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
552 if let Some(hash) = self.block_hashes.get(number) {
553 return Ok(hash);
554 }
555 self.database
557 .block_hash_ref(number)
558 .map_err(EvmDatabaseError::Database)
559 }
560}
561
562#[cfg(test)]
563mod tests {
564 use super::*;
565 use crate::{
566 states::{reverts::AccountInfoRevert, StorageSlot},
567 AccountRevert, AccountStatus, BundleAccount, RevertToSlot,
568 };
569 use primitives::{keccak256, Bytes, BLOCK_HASH_HISTORY, U256};
570 use state::{EvmStorageSlot, TransactionId};
571
572 fn evm_storage<const N: usize>(
573 slots: [(StorageKey, EvmStorageSlot); N],
574 ) -> Option<Cow<'static, EvmStorage>> {
575 Some(Cow::Owned(HashMap::from_iter(slots)))
576 }
577
578 #[test]
579 fn has_bal_helper() {
580 let state = State::builder().build();
581 assert!(!state.has_bal());
582
583 let state = State::builder().with_bal(Arc::new(Bal::new())).build();
584 assert!(state.has_bal());
585 }
586
587 #[test]
588 fn block_hash_cache() {
589 let mut state = State::builder().build();
590 state.block_hash(1u64).unwrap();
591 state.block_hash(2u64).unwrap();
592
593 let test_number = BLOCK_HASH_HISTORY + 2;
594
595 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
596 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
597 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
598
599 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
601 assert_eq!(state.block_hashes.get(2), Some(block2_hash));
602
603 state.block_hash(test_number).unwrap();
606
607 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
609 assert_eq!(state.block_hashes.get(2), None);
610 assert_eq!(state.block_hashes.get(test_number), Some(block_test_hash));
611 }
612
613 #[test]
618 fn block_hash_cache_block_zero() {
619 let mut state = State::builder().build();
620
621 assert_eq!(state.block_hashes.get(0), None);
623
624 let block0_hash = state.block_hash(0u64).unwrap();
626
627 let expected_hash = keccak256(U256::from(0).to_string().as_bytes());
629 assert_eq!(block0_hash, expected_hash);
630
631 assert_eq!(state.block_hashes.get(0), Some(expected_hash));
633 }
634
635 #[test]
636 fn created_contract_code_is_available_before_transition_merge() {
637 let bytecode = Bytecode::new_raw(Bytes::from_static(&[0x00]));
638 let code_hash = bytecode.hash_slow();
639 let account = Account::default()
640 .with_info(AccountInfo::default().with_code(bytecode.clone()))
641 .with_touched_mark()
642 .with_created_mark();
643 let mut state = State::builder().with_bundle_update().build();
644
645 state.commit(HashMap::from_iter([(Address::ZERO, account)]));
646
647 assert_eq!(state.code_by_hash(code_hash).unwrap(), bytecode);
648 }
649
650 #[test]
657 fn reverts_preserve_old_values() {
658 let mut state = State::builder().with_bundle_update().build();
659
660 let (slot1, slot2, slot3) = (
661 StorageKey::from(1),
662 StorageKey::from(2),
663 StorageKey::from(3),
664 );
665
666 let new_account_address = Address::from_slice(&[0x1; 20]);
669 let new_account_created_info = AccountInfo {
670 nonce: 1,
671 balance: U256::from(1),
672 ..Default::default()
673 };
674 let new_account_changed_info = AccountInfo {
675 nonce: 2,
676 ..new_account_created_info.clone()
677 };
678 let new_account_changed_info2 = AccountInfo {
679 nonce: 3,
680 ..new_account_changed_info.clone()
681 };
682
683 let existing_account_address = Address::from_slice(&[0x2; 20]);
685 let existing_account_initial_info = AccountInfo {
686 nonce: 1,
687 ..Default::default()
688 };
689 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
690 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
693 let existing_account_changed_info = AccountInfo {
694 nonce: 2,
695 ..existing_account_initial_info.clone()
696 };
697
698 state.apply_transition(Vec::from([
700 (
701 new_account_address,
702 TransitionAccount {
703 status: AccountStatus::InMemoryChange,
704 info: Some(new_account_created_info.clone()),
705 previous_status: AccountStatus::LoadedNotExisting,
706 previous_info: None,
707 storage: None,
708 ..Default::default()
709 },
710 ),
711 (
712 existing_account_address,
713 TransitionAccount {
714 status: AccountStatus::InMemoryChange,
715 info: Some(existing_account_changed_info.clone()),
716 previous_status: AccountStatus::Loaded,
717 previous_info: Some(existing_account_initial_info.clone()),
718 storage: evm_storage([(
719 slot1,
720 EvmStorageSlot::new_changed(
721 *existing_account_initial_storage.get(&slot1).unwrap(),
722 StorageValue::from(1000),
723 TransactionId::ZERO,
724 ),
725 )]),
726 storage_was_destroyed: false,
727 },
728 ),
729 ]));
730
731 state.apply_transition(Vec::from([(
733 new_account_address,
734 TransitionAccount {
735 status: AccountStatus::InMemoryChange,
736 info: Some(new_account_changed_info.clone()),
737 previous_status: AccountStatus::InMemoryChange,
738 previous_info: Some(new_account_created_info.clone()),
739 ..Default::default()
740 },
741 )]));
742
743 state.apply_transition(Vec::from([
745 (
746 new_account_address,
747 TransitionAccount {
748 status: AccountStatus::InMemoryChange,
749 info: Some(new_account_changed_info2.clone()),
750 previous_status: AccountStatus::InMemoryChange,
751 previous_info: Some(new_account_changed_info),
752 storage: evm_storage([(
753 slot1,
754 EvmStorageSlot::new_changed(
755 StorageValue::ZERO,
756 StorageValue::from(1),
757 TransactionId::ZERO,
758 ),
759 )]),
760 storage_was_destroyed: false,
761 },
762 ),
763 (
764 existing_account_address,
765 TransitionAccount {
766 status: AccountStatus::InMemoryChange,
767 info: Some(existing_account_changed_info.clone()),
768 previous_status: AccountStatus::InMemoryChange,
769 previous_info: Some(existing_account_changed_info.clone()),
770 storage: evm_storage([
771 (
772 slot1,
773 EvmStorageSlot::new_changed(
774 StorageValue::from(100),
775 StorageValue::from(1_000),
776 TransactionId::ZERO,
777 ),
778 ),
779 (
780 slot2,
781 EvmStorageSlot::new_changed(
782 *existing_account_initial_storage.get(&slot2).unwrap(),
783 StorageValue::from(2_000),
784 TransactionId::ZERO,
785 ),
786 ),
787 (
789 slot3,
790 EvmStorageSlot::new_changed(
791 StorageValue::ZERO,
792 StorageValue::from(3_000),
793 TransactionId::ZERO,
794 ),
795 ),
796 ]),
797 storage_was_destroyed: false,
798 },
799 ),
800 ]));
801
802 state.merge_transitions(BundleRetention::Reverts);
803 let mut bundle_state = state.take_bundle();
804
805 bundle_state.reverts.sort();
808 assert_eq!(
809 bundle_state.reverts.as_ref(),
810 Vec::from([Vec::from([
811 (
812 new_account_address,
813 AccountRevert {
814 account: AccountInfoRevert::DeleteIt,
815 previous_status: AccountStatus::LoadedNotExisting,
816 storage: HashMap::from_iter([(
817 slot1,
818 RevertToSlot::Some(StorageValue::ZERO)
819 )]),
820 wipe_storage: false,
821 }
822 ),
823 (
824 existing_account_address,
825 AccountRevert {
826 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
827 previous_status: AccountStatus::Loaded,
828 storage: HashMap::from_iter([
829 (
830 slot1,
831 RevertToSlot::Some(
832 *existing_account_initial_storage.get(&slot1).unwrap()
833 )
834 ),
835 (
836 slot2,
837 RevertToSlot::Some(
838 *existing_account_initial_storage.get(&slot2).unwrap()
839 )
840 ),
841 (slot3, RevertToSlot::Some(StorageValue::ZERO))
842 ]),
843 wipe_storage: false,
844 }
845 ),
846 ])]),
847 "The account or storage reverts are incorrect"
848 );
849
850 assert_eq!(
853 bundle_state.account(&new_account_address),
854 Some(&BundleAccount {
855 info: Some(new_account_changed_info2),
856 original_info: None,
857 status: AccountStatus::InMemoryChange,
858 storage: HashMap::from_iter([(
859 slot1,
860 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
861 )]),
862 }),
863 "The latest state of the new account is incorrect"
864 );
865
866 assert_eq!(
869 bundle_state.account(&existing_account_address),
870 Some(&BundleAccount {
871 info: Some(existing_account_changed_info),
872 original_info: Some(existing_account_initial_info),
873 status: AccountStatus::InMemoryChange,
874 storage: HashMap::from_iter([
875 (
876 slot1,
877 StorageSlot::new_changed(
878 *existing_account_initial_storage.get(&slot1).unwrap(),
879 StorageValue::from(1_000)
880 )
881 ),
882 (
883 slot2,
884 StorageSlot::new_changed(
885 *existing_account_initial_storage.get(&slot2).unwrap(),
886 StorageValue::from(2_000)
887 )
888 ),
889 (
891 slot3,
892 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
893 ),
894 ]),
895 }),
896 "The latest state of the existing account is incorrect"
897 );
898 }
899
900 #[test]
903 fn bundle_scoped_reverts_collapse() {
904 let mut state = State::builder().with_bundle_update().build();
905
906 let new_account_address = Address::from_slice(&[0x1; 20]);
908 let new_account_created_info = AccountInfo {
909 nonce: 1,
910 balance: U256::from(1),
911 ..Default::default()
912 };
913
914 let existing_account_address = Address::from_slice(&[0x2; 20]);
916 let existing_account_initial_info = AccountInfo {
917 nonce: 1,
918 ..Default::default()
919 };
920 let existing_account_updated_info = AccountInfo {
921 nonce: 1,
922 balance: U256::from(1),
923 ..Default::default()
924 };
925
926 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
928 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
929 let existing_account_with_storage_info = AccountInfo {
930 nonce: 1,
931 ..Default::default()
932 };
933 state.apply_transition(Vec::from([
935 (
936 new_account_address,
937 TransitionAccount {
938 status: AccountStatus::InMemoryChange,
939 info: Some(new_account_created_info.clone()),
940 previous_status: AccountStatus::LoadedNotExisting,
941 previous_info: None,
942 ..Default::default()
943 },
944 ),
945 (
946 existing_account_address,
947 TransitionAccount {
948 status: AccountStatus::Changed,
949 info: Some(existing_account_updated_info.clone()),
950 previous_status: AccountStatus::Loaded,
951 previous_info: Some(existing_account_initial_info.clone()),
952 ..Default::default()
953 },
954 ),
955 (
956 existing_account_with_storage_address,
957 TransitionAccount {
958 status: AccountStatus::Changed,
959 info: Some(existing_account_with_storage_info.clone()),
960 previous_status: AccountStatus::Loaded,
961 previous_info: Some(existing_account_with_storage_info.clone()),
962 storage: evm_storage([
963 (
964 slot1,
965 EvmStorageSlot::new_changed(
966 StorageValue::from(1),
967 StorageValue::from(10),
968 TransactionId::ZERO,
969 ),
970 ),
971 (
972 slot2,
973 EvmStorageSlot::new_changed(
974 StorageValue::ZERO,
975 StorageValue::from(20),
976 TransactionId::ZERO,
977 ),
978 ),
979 ]),
980 storage_was_destroyed: false,
981 },
982 ),
983 ]));
984
985 state.apply_transition(Vec::from([
987 (
988 new_account_address,
989 TransitionAccount {
990 status: AccountStatus::Destroyed,
991 info: None,
992 previous_status: AccountStatus::InMemoryChange,
993 previous_info: Some(new_account_created_info),
994 ..Default::default()
995 },
996 ),
997 (
998 existing_account_address,
999 TransitionAccount {
1000 status: AccountStatus::Changed,
1001 info: Some(existing_account_initial_info),
1002 previous_status: AccountStatus::Changed,
1003 previous_info: Some(existing_account_updated_info),
1004 ..Default::default()
1005 },
1006 ),
1007 (
1008 existing_account_with_storage_address,
1009 TransitionAccount {
1010 status: AccountStatus::Changed,
1011 info: Some(existing_account_with_storage_info.clone()),
1012 previous_status: AccountStatus::Changed,
1013 previous_info: Some(existing_account_with_storage_info.clone()),
1014 storage: evm_storage([
1015 (
1016 slot1,
1017 EvmStorageSlot::new_changed(
1018 StorageValue::from(10),
1019 StorageValue::from(1),
1020 TransactionId::ZERO,
1021 ),
1022 ),
1023 (
1024 slot2,
1025 EvmStorageSlot::new_changed(
1026 StorageValue::from(20),
1027 StorageValue::ZERO,
1028 TransactionId::ZERO,
1029 ),
1030 ),
1031 ]),
1032 storage_was_destroyed: false,
1033 },
1034 ),
1035 ]));
1036
1037 state.merge_transitions(BundleRetention::Reverts);
1038
1039 let mut bundle_state = state.take_bundle();
1040 bundle_state.reverts.sort();
1041
1042 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
1045 }
1046
1047 #[test]
1049 fn selfdestruct_state_and_reverts() {
1050 let mut state = State::builder().with_bundle_update().build();
1051
1052 let existing_account_address = Address::from_slice(&[0x1; 20]);
1054 let existing_account_info = AccountInfo {
1055 nonce: 1,
1056 ..Default::default()
1057 };
1058
1059 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
1060
1061 state.apply_transition(Vec::from([(
1063 existing_account_address,
1064 TransitionAccount {
1065 status: AccountStatus::Destroyed,
1066 info: None,
1067 previous_status: AccountStatus::Loaded,
1068 previous_info: Some(existing_account_info.clone()),
1069 storage: Some(Cow::Owned(HashMap::default())),
1070 storage_was_destroyed: true,
1071 },
1072 )]));
1073
1074 state.apply_transition(Vec::from([(
1076 existing_account_address,
1077 TransitionAccount {
1078 status: AccountStatus::DestroyedChanged,
1079 info: Some(existing_account_info.clone()),
1080 previous_status: AccountStatus::Destroyed,
1081 previous_info: None,
1082 storage: evm_storage([(
1083 slot1,
1084 EvmStorageSlot::new_changed(
1085 StorageValue::ZERO,
1086 StorageValue::from(1),
1087 TransactionId::ZERO,
1088 ),
1089 )]),
1090 storage_was_destroyed: false,
1091 },
1092 )]));
1093
1094 state.apply_transition(Vec::from([(
1096 existing_account_address,
1097 TransitionAccount {
1098 status: AccountStatus::DestroyedAgain,
1099 info: None,
1100 previous_status: AccountStatus::DestroyedChanged,
1101 previous_info: Some(existing_account_info.clone()),
1102 storage: Some(Cow::Owned(HashMap::default())),
1104 storage_was_destroyed: true,
1105 },
1106 )]));
1107
1108 state.apply_transition(Vec::from([(
1110 existing_account_address,
1111 TransitionAccount {
1112 status: AccountStatus::DestroyedChanged,
1113 info: Some(existing_account_info.clone()),
1114 previous_status: AccountStatus::DestroyedAgain,
1115 previous_info: None,
1116 storage: evm_storage([(
1117 slot2,
1118 EvmStorageSlot::new_changed(
1119 StorageValue::ZERO,
1120 StorageValue::from(2),
1121 TransactionId::ZERO,
1122 ),
1123 )]),
1124 storage_was_destroyed: false,
1125 },
1126 )]));
1127
1128 state.merge_transitions(BundleRetention::Reverts);
1129
1130 let bundle_state = state.take_bundle();
1131
1132 assert_eq!(
1133 bundle_state.state,
1134 HashMap::from_iter([(
1135 existing_account_address,
1136 BundleAccount {
1137 info: Some(existing_account_info.clone()),
1138 original_info: Some(existing_account_info.clone()),
1139 storage: HashMap::from_iter([(
1140 slot2,
1141 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1142 )]),
1143 status: AccountStatus::DestroyedChanged,
1144 }
1145 )])
1146 );
1147
1148 assert_eq!(
1149 bundle_state.reverts.as_ref(),
1150 Vec::from([Vec::from([(
1151 existing_account_address,
1152 AccountRevert {
1153 account: AccountInfoRevert::DoNothing,
1154 previous_status: AccountStatus::Loaded,
1155 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1156 wipe_storage: true,
1157 }
1158 )])])
1159 )
1160 }
1161}