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,
16};
17use std::{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(
117 &mut self,
118 transitions: impl IntoIterator<Item = (Address, TransitionAccount)>,
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]
242 pub fn set_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {
243 self.state_hook = hook;
244 }
245
246 #[inline]
248 #[must_use]
249 pub fn with_state_hook(mut self, hook: Option<Box<dyn OnStateHook>>) -> Self {
250 self.set_state_hook(hook);
251 self
252 }
253
254 #[inline]
256 pub const fn has_bal(&self) -> bool {
257 self.bal_state.bal.is_some()
258 }
259
260 #[inline]
262 fn storage(&mut self, address: Address, index: StorageKey) -> Result<StorageValue, DB::Error> {
263 let account = Self::load_cache_account_with(
265 &mut self.cache,
266 self.use_preloaded_bundle,
267 &self.bundle_state,
268 &mut self.database,
269 address,
270 )?;
271
272 let is_storage_known = account.status.is_storage_known();
274 Ok(account
275 .account
276 .as_mut()
277 .map(|account| match account.storage.entry(index) {
278 hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
279 hash_map::Entry::Vacant(entry) => {
280 let value = if is_storage_known {
283 StorageValue::ZERO
284 } else {
285 self.database.storage(address, index)?
286 };
287 entry.insert(value);
288 Ok(value)
289 }
290 })
291 .transpose()?
292 .unwrap_or_default())
293 }
294}
295
296impl<DB: Database> Database for State<DB> {
297 type Error = EvmDatabaseError<DB::Error>;
298
299 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
300 let account_id = self
302 .bal_state
303 .get_account_id(&address)
304 .map_err(EvmDatabaseError::Bal)?;
305
306 let mut basic = self
307 .load_cache_account(address)
308 .map(|a| a.account_info())
309 .map_err(EvmDatabaseError::Database)?;
310 if let Some(account_id) = account_id {
313 self.bal_state
314 .basic_by_account_id(account_id, &mut basic)
315 .map_err(EvmDatabaseError::Bal)?;
316 }
317 Ok(basic)
318 }
319
320 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
321 let res = match self.cache.contracts.entry(code_hash) {
322 hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
323 hash_map::Entry::Vacant(entry) => {
324 if self.use_preloaded_bundle {
325 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
326 entry.insert(code.clone());
327 return Ok(code.clone());
328 }
329 }
330 let code = self
332 .database
333 .code_by_hash(code_hash)
334 .map_err(EvmDatabaseError::Database)?;
335 entry.insert(code.clone());
336 Ok(code)
337 }
338 };
339 res
340 }
341
342 fn storage(
343 &mut self,
344 address: Address,
345 index: StorageKey,
346 ) -> Result<StorageValue, Self::Error> {
347 if let Some(storage) = self
348 .bal_state
349 .storage(&address, index)
350 .map_err(EvmDatabaseError::Bal)?
351 {
352 return Ok(storage);
354 }
355 self.storage(address, index)
356 .map_err(EvmDatabaseError::Database)
357 }
358
359 fn storage_by_account_id(
360 &mut self,
361 address: Address,
362 account_id: AccountId,
363 key: StorageKey,
364 ) -> Result<StorageValue, Self::Error> {
365 if let Some(storage) = self.bal_state.storage_by_account_id(account_id, key)? {
366 return Ok(storage);
367 }
368
369 self.storage(address, key)
370 .map_err(EvmDatabaseError::Database)
371 }
372
373 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
374 if let Some(hash) = self.block_hashes.get(number) {
376 return Ok(hash);
377 }
378
379 let hash = self
381 .database
382 .block_hash(number)
383 .map_err(EvmDatabaseError::Database)?;
384
385 self.block_hashes.insert(number, hash);
387
388 Ok(hash)
389 }
390}
391
392impl<DB: Database> DatabaseCommit for State<DB> {
393 fn commit(&mut self, changes: AddressMap<Account>) {
394 if let Some(hook) = self.state_hook.as_mut() {
395 hook.on_state(&changes);
396 }
397 self.bal_state.commit(&changes);
398 let transitions = self.cache.apply_evm_state_iter(changes, |_, _| {});
399 if let Some(s) = self.transition_state.as_mut() {
400 s.add_transitions(transitions)
401 } else {
402 transitions.for_each(|_| {});
404 }
405 }
406
407 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
408 if self.state_hook.is_some() {
409 let changes = changes.collect::<AddressMap<_>>();
410 self.commit(changes);
411 return;
412 }
413
414 let transitions = self
415 .cache
416 .apply_evm_state_iter(changes, |address, account| {
417 self.bal_state.commit_one(*address, account);
418 });
419 if let Some(s) = self.transition_state.as_mut() {
420 s.add_transitions(transitions)
421 } else {
422 transitions.for_each(|_| {});
424 }
425 }
426}
427
428impl<DB: DatabaseRef> DatabaseRef for State<DB> {
429 type Error = EvmDatabaseError<DB::Error>;
430
431 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
432 let account_id = self.bal_state.get_account_id(&address)?;
434
435 let mut loaded_account = None;
437 if let Some(account) = self.cache.accounts.get(&address) {
438 loaded_account = Some(account.account_info());
439 };
440
441 if self.use_preloaded_bundle && loaded_account.is_none() {
443 if let Some(account) = self.bundle_state.account(&address) {
444 loaded_account = Some(account.account_info());
445 }
446 }
447
448 if loaded_account.is_none() {
450 loaded_account = Some(
451 self.database
452 .basic_ref(address)
453 .map_err(EvmDatabaseError::Database)?,
454 );
455 }
456
457 let mut account = loaded_account.unwrap();
459
460 if let Some(account_id) = account_id {
462 self.bal_state
463 .basic_by_account_id(account_id, &mut account)
464 .map_err(EvmDatabaseError::Bal)?;
465 }
466 Ok(account)
467 }
468
469 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
470 if let Some(code) = self.cache.contracts.get(&code_hash) {
472 return Ok(code.clone());
473 }
474 if self.use_preloaded_bundle {
476 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
477 return Ok(code.clone());
478 }
479 }
480 self.database
482 .code_by_hash_ref(code_hash)
483 .map_err(EvmDatabaseError::Database)
484 }
485
486 fn storage_ref(
487 &self,
488 address: Address,
489 index: StorageKey,
490 ) -> Result<StorageValue, Self::Error> {
491 if let Some(storage) = self.bal_state.storage(&address, index)? {
493 return Ok(storage);
494 }
495
496 if let Some(account) = self.cache.accounts.get(&address) {
498 if let Some(plain_account) = &account.account {
499 if let Some(storage_value) = plain_account.storage.get(&index) {
501 return Ok(*storage_value);
502 }
503 if account.status.is_storage_known() {
506 return Ok(StorageValue::ZERO);
507 }
508 }
509 }
510
511 self.database
513 .storage_ref(address, index)
514 .map_err(EvmDatabaseError::Database)
515 }
516
517 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
518 if let Some(hash) = self.block_hashes.get(number) {
519 return Ok(hash);
520 }
521 self.database
523 .block_hash_ref(number)
524 .map_err(EvmDatabaseError::Database)
525 }
526}
527
528#[cfg(test)]
529mod tests {
530 use super::*;
531 use crate::{
532 states::{reverts::AccountInfoRevert, StorageSlot},
533 AccountRevert, AccountStatus, BundleAccount, RevertToSlot,
534 };
535 use primitives::{keccak256, BLOCK_HASH_HISTORY, U256};
536 #[test]
537 fn has_bal_helper() {
538 let state = State::builder().build();
539 assert!(!state.has_bal());
540
541 let state = State::builder().with_bal(Arc::new(Bal::new())).build();
542 assert!(state.has_bal());
543 }
544
545 #[test]
546 fn block_hash_cache() {
547 let mut state = State::builder().build();
548 state.block_hash(1u64).unwrap();
549 state.block_hash(2u64).unwrap();
550
551 let test_number = BLOCK_HASH_HISTORY + 2;
552
553 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
554 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
555 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
556
557 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
559 assert_eq!(state.block_hashes.get(2), Some(block2_hash));
560
561 state.block_hash(test_number).unwrap();
564
565 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
567 assert_eq!(state.block_hashes.get(2), None);
568 assert_eq!(state.block_hashes.get(test_number), Some(block_test_hash));
569 }
570
571 #[test]
576 fn block_hash_cache_block_zero() {
577 let mut state = State::builder().build();
578
579 assert_eq!(state.block_hashes.get(0), None);
581
582 let block0_hash = state.block_hash(0u64).unwrap();
584
585 let expected_hash = keccak256(U256::from(0).to_string().as_bytes());
587 assert_eq!(block0_hash, expected_hash);
588
589 assert_eq!(state.block_hashes.get(0), Some(expected_hash));
591 }
592 #[test]
599 fn reverts_preserve_old_values() {
600 let mut state = State::builder().with_bundle_update().build();
601
602 let (slot1, slot2, slot3) = (
603 StorageKey::from(1),
604 StorageKey::from(2),
605 StorageKey::from(3),
606 );
607
608 let new_account_address = Address::from_slice(&[0x1; 20]);
611 let new_account_created_info = AccountInfo {
612 nonce: 1,
613 balance: U256::from(1),
614 ..Default::default()
615 };
616 let new_account_changed_info = AccountInfo {
617 nonce: 2,
618 ..new_account_created_info.clone()
619 };
620 let new_account_changed_info2 = AccountInfo {
621 nonce: 3,
622 ..new_account_changed_info.clone()
623 };
624
625 let existing_account_address = Address::from_slice(&[0x2; 20]);
627 let existing_account_initial_info = AccountInfo {
628 nonce: 1,
629 ..Default::default()
630 };
631 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
632 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
635 let existing_account_changed_info = AccountInfo {
636 nonce: 2,
637 ..existing_account_initial_info.clone()
638 };
639
640 state.apply_transition(Vec::from([
642 (
643 new_account_address,
644 TransitionAccount {
645 status: AccountStatus::InMemoryChange,
646 info: Some(new_account_created_info.clone()),
647 previous_status: AccountStatus::LoadedNotExisting,
648 previous_info: None,
649 ..Default::default()
650 },
651 ),
652 (
653 existing_account_address,
654 TransitionAccount {
655 status: AccountStatus::InMemoryChange,
656 info: Some(existing_account_changed_info.clone()),
657 previous_status: AccountStatus::Loaded,
658 previous_info: Some(existing_account_initial_info.clone()),
659 storage: HashMap::from_iter([(
660 slot1,
661 StorageSlot::new_changed(
662 *existing_account_initial_storage.get(&slot1).unwrap(),
663 StorageValue::from(1000),
664 ),
665 )]),
666 storage_was_destroyed: false,
667 },
668 ),
669 ]));
670
671 state.apply_transition(Vec::from([(
673 new_account_address,
674 TransitionAccount {
675 status: AccountStatus::InMemoryChange,
676 info: Some(new_account_changed_info.clone()),
677 previous_status: AccountStatus::InMemoryChange,
678 previous_info: Some(new_account_created_info.clone()),
679 ..Default::default()
680 },
681 )]));
682
683 state.apply_transition(Vec::from([
685 (
686 new_account_address,
687 TransitionAccount {
688 status: AccountStatus::InMemoryChange,
689 info: Some(new_account_changed_info2.clone()),
690 previous_status: AccountStatus::InMemoryChange,
691 previous_info: Some(new_account_changed_info),
692 storage: HashMap::from_iter([(
693 slot1,
694 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
695 )]),
696 storage_was_destroyed: false,
697 },
698 ),
699 (
700 existing_account_address,
701 TransitionAccount {
702 status: AccountStatus::InMemoryChange,
703 info: Some(existing_account_changed_info.clone()),
704 previous_status: AccountStatus::InMemoryChange,
705 previous_info: Some(existing_account_changed_info.clone()),
706 storage: HashMap::from_iter([
707 (
708 slot1,
709 StorageSlot::new_changed(
710 StorageValue::from(100),
711 StorageValue::from(1_000),
712 ),
713 ),
714 (
715 slot2,
716 StorageSlot::new_changed(
717 *existing_account_initial_storage.get(&slot2).unwrap(),
718 StorageValue::from(2_000),
719 ),
720 ),
721 (
723 slot3,
724 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)),
725 ),
726 ]),
727 storage_was_destroyed: false,
728 },
729 ),
730 ]));
731
732 state.merge_transitions(BundleRetention::Reverts);
733 let mut bundle_state = state.take_bundle();
734
735 bundle_state.reverts.sort();
738 assert_eq!(
739 bundle_state.reverts.as_ref(),
740 Vec::from([Vec::from([
741 (
742 new_account_address,
743 AccountRevert {
744 account: AccountInfoRevert::DeleteIt,
745 previous_status: AccountStatus::LoadedNotExisting,
746 storage: HashMap::from_iter([(
747 slot1,
748 RevertToSlot::Some(StorageValue::ZERO)
749 )]),
750 wipe_storage: false,
751 }
752 ),
753 (
754 existing_account_address,
755 AccountRevert {
756 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
757 previous_status: AccountStatus::Loaded,
758 storage: HashMap::from_iter([
759 (
760 slot1,
761 RevertToSlot::Some(
762 *existing_account_initial_storage.get(&slot1).unwrap()
763 )
764 ),
765 (
766 slot2,
767 RevertToSlot::Some(
768 *existing_account_initial_storage.get(&slot2).unwrap()
769 )
770 ),
771 (slot3, RevertToSlot::Some(StorageValue::ZERO))
772 ]),
773 wipe_storage: false,
774 }
775 ),
776 ])]),
777 "The account or storage reverts are incorrect"
778 );
779
780 assert_eq!(
783 bundle_state.account(&new_account_address),
784 Some(&BundleAccount {
785 info: Some(new_account_changed_info2),
786 original_info: None,
787 status: AccountStatus::InMemoryChange,
788 storage: HashMap::from_iter([(
789 slot1,
790 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
791 )]),
792 }),
793 "The latest state of the new account is incorrect"
794 );
795
796 assert_eq!(
799 bundle_state.account(&existing_account_address),
800 Some(&BundleAccount {
801 info: Some(existing_account_changed_info),
802 original_info: Some(existing_account_initial_info),
803 status: AccountStatus::InMemoryChange,
804 storage: HashMap::from_iter([
805 (
806 slot1,
807 StorageSlot::new_changed(
808 *existing_account_initial_storage.get(&slot1).unwrap(),
809 StorageValue::from(1_000)
810 )
811 ),
812 (
813 slot2,
814 StorageSlot::new_changed(
815 *existing_account_initial_storage.get(&slot2).unwrap(),
816 StorageValue::from(2_000)
817 )
818 ),
819 (
821 slot3,
822 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
823 ),
824 ]),
825 }),
826 "The latest state of the existing account is incorrect"
827 );
828 }
829
830 #[test]
833 fn bundle_scoped_reverts_collapse() {
834 let mut state = State::builder().with_bundle_update().build();
835
836 let new_account_address = Address::from_slice(&[0x1; 20]);
838 let new_account_created_info = AccountInfo {
839 nonce: 1,
840 balance: U256::from(1),
841 ..Default::default()
842 };
843
844 let existing_account_address = Address::from_slice(&[0x2; 20]);
846 let existing_account_initial_info = AccountInfo {
847 nonce: 1,
848 ..Default::default()
849 };
850 let existing_account_updated_info = AccountInfo {
851 nonce: 1,
852 balance: U256::from(1),
853 ..Default::default()
854 };
855
856 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
858 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
859 let existing_account_with_storage_info = AccountInfo {
860 nonce: 1,
861 ..Default::default()
862 };
863 state.apply_transition(Vec::from([
865 (
866 new_account_address,
867 TransitionAccount {
868 status: AccountStatus::InMemoryChange,
869 info: Some(new_account_created_info.clone()),
870 previous_status: AccountStatus::LoadedNotExisting,
871 previous_info: None,
872 ..Default::default()
873 },
874 ),
875 (
876 existing_account_address,
877 TransitionAccount {
878 status: AccountStatus::Changed,
879 info: Some(existing_account_updated_info.clone()),
880 previous_status: AccountStatus::Loaded,
881 previous_info: Some(existing_account_initial_info.clone()),
882 ..Default::default()
883 },
884 ),
885 (
886 existing_account_with_storage_address,
887 TransitionAccount {
888 status: AccountStatus::Changed,
889 info: Some(existing_account_with_storage_info.clone()),
890 previous_status: AccountStatus::Loaded,
891 previous_info: Some(existing_account_with_storage_info.clone()),
892 storage: HashMap::from_iter([
893 (
894 slot1,
895 StorageSlot::new_changed(StorageValue::from(1), StorageValue::from(10)),
896 ),
897 (
898 slot2,
899 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(20)),
900 ),
901 ]),
902 storage_was_destroyed: false,
903 },
904 ),
905 ]));
906
907 state.apply_transition(Vec::from([
909 (
910 new_account_address,
911 TransitionAccount {
912 status: AccountStatus::Destroyed,
913 info: None,
914 previous_status: AccountStatus::InMemoryChange,
915 previous_info: Some(new_account_created_info),
916 ..Default::default()
917 },
918 ),
919 (
920 existing_account_address,
921 TransitionAccount {
922 status: AccountStatus::Changed,
923 info: Some(existing_account_initial_info),
924 previous_status: AccountStatus::Changed,
925 previous_info: Some(existing_account_updated_info),
926 ..Default::default()
927 },
928 ),
929 (
930 existing_account_with_storage_address,
931 TransitionAccount {
932 status: AccountStatus::Changed,
933 info: Some(existing_account_with_storage_info.clone()),
934 previous_status: AccountStatus::Changed,
935 previous_info: Some(existing_account_with_storage_info.clone()),
936 storage: HashMap::from_iter([
937 (
938 slot1,
939 StorageSlot::new_changed(StorageValue::from(10), StorageValue::from(1)),
940 ),
941 (
942 slot2,
943 StorageSlot::new_changed(StorageValue::from(20), StorageValue::ZERO),
944 ),
945 ]),
946 storage_was_destroyed: false,
947 },
948 ),
949 ]));
950
951 state.merge_transitions(BundleRetention::Reverts);
952
953 let mut bundle_state = state.take_bundle();
954 bundle_state.reverts.sort();
955
956 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
959 }
960
961 #[test]
963 fn selfdestruct_state_and_reverts() {
964 let mut state = State::builder().with_bundle_update().build();
965
966 let existing_account_address = Address::from_slice(&[0x1; 20]);
968 let existing_account_info = AccountInfo {
969 nonce: 1,
970 ..Default::default()
971 };
972
973 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
974
975 state.apply_transition(Vec::from([(
977 existing_account_address,
978 TransitionAccount {
979 status: AccountStatus::Destroyed,
980 info: None,
981 previous_status: AccountStatus::Loaded,
982 previous_info: Some(existing_account_info.clone()),
983 storage: HashMap::default(),
984 storage_was_destroyed: true,
985 },
986 )]));
987
988 state.apply_transition(Vec::from([(
990 existing_account_address,
991 TransitionAccount {
992 status: AccountStatus::DestroyedChanged,
993 info: Some(existing_account_info.clone()),
994 previous_status: AccountStatus::Destroyed,
995 previous_info: None,
996 storage: HashMap::from_iter([(
997 slot1,
998 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
999 )]),
1000 storage_was_destroyed: false,
1001 },
1002 )]));
1003
1004 state.apply_transition(Vec::from([(
1006 existing_account_address,
1007 TransitionAccount {
1008 status: AccountStatus::DestroyedAgain,
1009 info: None,
1010 previous_status: AccountStatus::DestroyedChanged,
1011 previous_info: Some(existing_account_info.clone()),
1012 storage: HashMap::default(),
1014 storage_was_destroyed: true,
1015 },
1016 )]));
1017
1018 state.apply_transition(Vec::from([(
1020 existing_account_address,
1021 TransitionAccount {
1022 status: AccountStatus::DestroyedChanged,
1023 info: Some(existing_account_info.clone()),
1024 previous_status: AccountStatus::DestroyedAgain,
1025 previous_info: None,
1026 storage: HashMap::from_iter([(
1027 slot2,
1028 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)),
1029 )]),
1030 storage_was_destroyed: false,
1031 },
1032 )]));
1033
1034 state.merge_transitions(BundleRetention::Reverts);
1035
1036 let bundle_state = state.take_bundle();
1037
1038 assert_eq!(
1039 bundle_state.state,
1040 HashMap::from_iter([(
1041 existing_account_address,
1042 BundleAccount {
1043 info: Some(existing_account_info.clone()),
1044 original_info: Some(existing_account_info.clone()),
1045 storage: HashMap::from_iter([(
1046 slot2,
1047 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1048 )]),
1049 status: AccountStatus::DestroyedChanged,
1050 }
1051 )])
1052 );
1053
1054 assert_eq!(
1055 bundle_state.reverts.as_ref(),
1056 Vec::from([Vec::from([(
1057 existing_account_address,
1058 AccountRevert {
1059 account: AccountInfoRevert::DoNothing,
1060 previous_status: AccountStatus::Loaded,
1061 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1062 wipe_storage: true,
1063 }
1064 )])])
1065 )
1066 }
1067}