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, 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 #[test]
641 fn reverts_preserve_old_values() {
642 let mut state = State::builder().with_bundle_update().build();
643
644 let (slot1, slot2, slot3) = (
645 StorageKey::from(1),
646 StorageKey::from(2),
647 StorageKey::from(3),
648 );
649
650 let new_account_address = Address::from_slice(&[0x1; 20]);
653 let new_account_created_info = AccountInfo {
654 nonce: 1,
655 balance: U256::from(1),
656 ..Default::default()
657 };
658 let new_account_changed_info = AccountInfo {
659 nonce: 2,
660 ..new_account_created_info.clone()
661 };
662 let new_account_changed_info2 = AccountInfo {
663 nonce: 3,
664 ..new_account_changed_info.clone()
665 };
666
667 let existing_account_address = Address::from_slice(&[0x2; 20]);
669 let existing_account_initial_info = AccountInfo {
670 nonce: 1,
671 ..Default::default()
672 };
673 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
674 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
677 let existing_account_changed_info = AccountInfo {
678 nonce: 2,
679 ..existing_account_initial_info.clone()
680 };
681
682 state.apply_transition(Vec::from([
684 (
685 new_account_address,
686 TransitionAccount {
687 status: AccountStatus::InMemoryChange,
688 info: Some(new_account_created_info.clone()),
689 previous_status: AccountStatus::LoadedNotExisting,
690 previous_info: None,
691 storage: None,
692 ..Default::default()
693 },
694 ),
695 (
696 existing_account_address,
697 TransitionAccount {
698 status: AccountStatus::InMemoryChange,
699 info: Some(existing_account_changed_info.clone()),
700 previous_status: AccountStatus::Loaded,
701 previous_info: Some(existing_account_initial_info.clone()),
702 storage: evm_storage([(
703 slot1,
704 EvmStorageSlot::new_changed(
705 *existing_account_initial_storage.get(&slot1).unwrap(),
706 StorageValue::from(1000),
707 TransactionId::ZERO,
708 ),
709 )]),
710 storage_was_destroyed: false,
711 },
712 ),
713 ]));
714
715 state.apply_transition(Vec::from([(
717 new_account_address,
718 TransitionAccount {
719 status: AccountStatus::InMemoryChange,
720 info: Some(new_account_changed_info.clone()),
721 previous_status: AccountStatus::InMemoryChange,
722 previous_info: Some(new_account_created_info.clone()),
723 ..Default::default()
724 },
725 )]));
726
727 state.apply_transition(Vec::from([
729 (
730 new_account_address,
731 TransitionAccount {
732 status: AccountStatus::InMemoryChange,
733 info: Some(new_account_changed_info2.clone()),
734 previous_status: AccountStatus::InMemoryChange,
735 previous_info: Some(new_account_changed_info),
736 storage: evm_storage([(
737 slot1,
738 EvmStorageSlot::new_changed(
739 StorageValue::ZERO,
740 StorageValue::from(1),
741 TransactionId::ZERO,
742 ),
743 )]),
744 storage_was_destroyed: false,
745 },
746 ),
747 (
748 existing_account_address,
749 TransitionAccount {
750 status: AccountStatus::InMemoryChange,
751 info: Some(existing_account_changed_info.clone()),
752 previous_status: AccountStatus::InMemoryChange,
753 previous_info: Some(existing_account_changed_info.clone()),
754 storage: evm_storage([
755 (
756 slot1,
757 EvmStorageSlot::new_changed(
758 StorageValue::from(100),
759 StorageValue::from(1_000),
760 TransactionId::ZERO,
761 ),
762 ),
763 (
764 slot2,
765 EvmStorageSlot::new_changed(
766 *existing_account_initial_storage.get(&slot2).unwrap(),
767 StorageValue::from(2_000),
768 TransactionId::ZERO,
769 ),
770 ),
771 (
773 slot3,
774 EvmStorageSlot::new_changed(
775 StorageValue::ZERO,
776 StorageValue::from(3_000),
777 TransactionId::ZERO,
778 ),
779 ),
780 ]),
781 storage_was_destroyed: false,
782 },
783 ),
784 ]));
785
786 state.merge_transitions(BundleRetention::Reverts);
787 let mut bundle_state = state.take_bundle();
788
789 bundle_state.reverts.sort();
792 assert_eq!(
793 bundle_state.reverts.as_ref(),
794 Vec::from([Vec::from([
795 (
796 new_account_address,
797 AccountRevert {
798 account: AccountInfoRevert::DeleteIt,
799 previous_status: AccountStatus::LoadedNotExisting,
800 storage: HashMap::from_iter([(
801 slot1,
802 RevertToSlot::Some(StorageValue::ZERO)
803 )]),
804 wipe_storage: false,
805 }
806 ),
807 (
808 existing_account_address,
809 AccountRevert {
810 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
811 previous_status: AccountStatus::Loaded,
812 storage: HashMap::from_iter([
813 (
814 slot1,
815 RevertToSlot::Some(
816 *existing_account_initial_storage.get(&slot1).unwrap()
817 )
818 ),
819 (
820 slot2,
821 RevertToSlot::Some(
822 *existing_account_initial_storage.get(&slot2).unwrap()
823 )
824 ),
825 (slot3, RevertToSlot::Some(StorageValue::ZERO))
826 ]),
827 wipe_storage: false,
828 }
829 ),
830 ])]),
831 "The account or storage reverts are incorrect"
832 );
833
834 assert_eq!(
837 bundle_state.account(&new_account_address),
838 Some(&BundleAccount {
839 info: Some(new_account_changed_info2),
840 original_info: None,
841 status: AccountStatus::InMemoryChange,
842 storage: HashMap::from_iter([(
843 slot1,
844 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
845 )]),
846 }),
847 "The latest state of the new account is incorrect"
848 );
849
850 assert_eq!(
853 bundle_state.account(&existing_account_address),
854 Some(&BundleAccount {
855 info: Some(existing_account_changed_info),
856 original_info: Some(existing_account_initial_info),
857 status: AccountStatus::InMemoryChange,
858 storage: HashMap::from_iter([
859 (
860 slot1,
861 StorageSlot::new_changed(
862 *existing_account_initial_storage.get(&slot1).unwrap(),
863 StorageValue::from(1_000)
864 )
865 ),
866 (
867 slot2,
868 StorageSlot::new_changed(
869 *existing_account_initial_storage.get(&slot2).unwrap(),
870 StorageValue::from(2_000)
871 )
872 ),
873 (
875 slot3,
876 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
877 ),
878 ]),
879 }),
880 "The latest state of the existing account is incorrect"
881 );
882 }
883
884 #[test]
887 fn bundle_scoped_reverts_collapse() {
888 let mut state = State::builder().with_bundle_update().build();
889
890 let new_account_address = Address::from_slice(&[0x1; 20]);
892 let new_account_created_info = AccountInfo {
893 nonce: 1,
894 balance: U256::from(1),
895 ..Default::default()
896 };
897
898 let existing_account_address = Address::from_slice(&[0x2; 20]);
900 let existing_account_initial_info = AccountInfo {
901 nonce: 1,
902 ..Default::default()
903 };
904 let existing_account_updated_info = AccountInfo {
905 nonce: 1,
906 balance: U256::from(1),
907 ..Default::default()
908 };
909
910 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
912 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
913 let existing_account_with_storage_info = AccountInfo {
914 nonce: 1,
915 ..Default::default()
916 };
917 state.apply_transition(Vec::from([
919 (
920 new_account_address,
921 TransitionAccount {
922 status: AccountStatus::InMemoryChange,
923 info: Some(new_account_created_info.clone()),
924 previous_status: AccountStatus::LoadedNotExisting,
925 previous_info: None,
926 ..Default::default()
927 },
928 ),
929 (
930 existing_account_address,
931 TransitionAccount {
932 status: AccountStatus::Changed,
933 info: Some(existing_account_updated_info.clone()),
934 previous_status: AccountStatus::Loaded,
935 previous_info: Some(existing_account_initial_info.clone()),
936 ..Default::default()
937 },
938 ),
939 (
940 existing_account_with_storage_address,
941 TransitionAccount {
942 status: AccountStatus::Changed,
943 info: Some(existing_account_with_storage_info.clone()),
944 previous_status: AccountStatus::Loaded,
945 previous_info: Some(existing_account_with_storage_info.clone()),
946 storage: evm_storage([
947 (
948 slot1,
949 EvmStorageSlot::new_changed(
950 StorageValue::from(1),
951 StorageValue::from(10),
952 TransactionId::ZERO,
953 ),
954 ),
955 (
956 slot2,
957 EvmStorageSlot::new_changed(
958 StorageValue::ZERO,
959 StorageValue::from(20),
960 TransactionId::ZERO,
961 ),
962 ),
963 ]),
964 storage_was_destroyed: false,
965 },
966 ),
967 ]));
968
969 state.apply_transition(Vec::from([
971 (
972 new_account_address,
973 TransitionAccount {
974 status: AccountStatus::Destroyed,
975 info: None,
976 previous_status: AccountStatus::InMemoryChange,
977 previous_info: Some(new_account_created_info),
978 ..Default::default()
979 },
980 ),
981 (
982 existing_account_address,
983 TransitionAccount {
984 status: AccountStatus::Changed,
985 info: Some(existing_account_initial_info),
986 previous_status: AccountStatus::Changed,
987 previous_info: Some(existing_account_updated_info),
988 ..Default::default()
989 },
990 ),
991 (
992 existing_account_with_storage_address,
993 TransitionAccount {
994 status: AccountStatus::Changed,
995 info: Some(existing_account_with_storage_info.clone()),
996 previous_status: AccountStatus::Changed,
997 previous_info: Some(existing_account_with_storage_info.clone()),
998 storage: evm_storage([
999 (
1000 slot1,
1001 EvmStorageSlot::new_changed(
1002 StorageValue::from(10),
1003 StorageValue::from(1),
1004 TransactionId::ZERO,
1005 ),
1006 ),
1007 (
1008 slot2,
1009 EvmStorageSlot::new_changed(
1010 StorageValue::from(20),
1011 StorageValue::ZERO,
1012 TransactionId::ZERO,
1013 ),
1014 ),
1015 ]),
1016 storage_was_destroyed: false,
1017 },
1018 ),
1019 ]));
1020
1021 state.merge_transitions(BundleRetention::Reverts);
1022
1023 let mut bundle_state = state.take_bundle();
1024 bundle_state.reverts.sort();
1025
1026 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
1029 }
1030
1031 #[test]
1033 fn selfdestruct_state_and_reverts() {
1034 let mut state = State::builder().with_bundle_update().build();
1035
1036 let existing_account_address = Address::from_slice(&[0x1; 20]);
1038 let existing_account_info = AccountInfo {
1039 nonce: 1,
1040 ..Default::default()
1041 };
1042
1043 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
1044
1045 state.apply_transition(Vec::from([(
1047 existing_account_address,
1048 TransitionAccount {
1049 status: AccountStatus::Destroyed,
1050 info: None,
1051 previous_status: AccountStatus::Loaded,
1052 previous_info: Some(existing_account_info.clone()),
1053 storage: Some(Cow::Owned(HashMap::default())),
1054 storage_was_destroyed: true,
1055 },
1056 )]));
1057
1058 state.apply_transition(Vec::from([(
1060 existing_account_address,
1061 TransitionAccount {
1062 status: AccountStatus::DestroyedChanged,
1063 info: Some(existing_account_info.clone()),
1064 previous_status: AccountStatus::Destroyed,
1065 previous_info: None,
1066 storage: evm_storage([(
1067 slot1,
1068 EvmStorageSlot::new_changed(
1069 StorageValue::ZERO,
1070 StorageValue::from(1),
1071 TransactionId::ZERO,
1072 ),
1073 )]),
1074 storage_was_destroyed: false,
1075 },
1076 )]));
1077
1078 state.apply_transition(Vec::from([(
1080 existing_account_address,
1081 TransitionAccount {
1082 status: AccountStatus::DestroyedAgain,
1083 info: None,
1084 previous_status: AccountStatus::DestroyedChanged,
1085 previous_info: Some(existing_account_info.clone()),
1086 storage: Some(Cow::Owned(HashMap::default())),
1088 storage_was_destroyed: true,
1089 },
1090 )]));
1091
1092 state.apply_transition(Vec::from([(
1094 existing_account_address,
1095 TransitionAccount {
1096 status: AccountStatus::DestroyedChanged,
1097 info: Some(existing_account_info.clone()),
1098 previous_status: AccountStatus::DestroyedAgain,
1099 previous_info: None,
1100 storage: evm_storage([(
1101 slot2,
1102 EvmStorageSlot::new_changed(
1103 StorageValue::ZERO,
1104 StorageValue::from(2),
1105 TransactionId::ZERO,
1106 ),
1107 )]),
1108 storage_was_destroyed: false,
1109 },
1110 )]));
1111
1112 state.merge_transitions(BundleRetention::Reverts);
1113
1114 let bundle_state = state.take_bundle();
1115
1116 assert_eq!(
1117 bundle_state.state,
1118 HashMap::from_iter([(
1119 existing_account_address,
1120 BundleAccount {
1121 info: Some(existing_account_info.clone()),
1122 original_info: Some(existing_account_info.clone()),
1123 storage: HashMap::from_iter([(
1124 slot2,
1125 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1126 )]),
1127 status: AccountStatus::DestroyedChanged,
1128 }
1129 )])
1130 );
1131
1132 assert_eq!(
1133 bundle_state.reverts.as_ref(),
1134 Vec::from([Vec::from([(
1135 existing_account_address,
1136 AccountRevert {
1137 account: AccountInfoRevert::DoNothing,
1138 previous_status: AccountStatus::Loaded,
1139 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1140 wipe_storage: true,
1141 }
1142 )])])
1143 )
1144 }
1145}