1use super::{
2 bundle_state::BundleRetention, cache::CacheState, plain_account::PlainStorage, BundleState,
3 CacheAccount, StateBuilder, TransitionAccount, TransitionState,
4};
5use bytecode::Bytecode;
6use database_interface::{
7 bal::{BalState, EvmDatabaseError},
8 Database, DatabaseCommit, DatabaseRef, EmptyDB,
9};
10use primitives::{hash_map, Address, HashMap, StorageKey, StorageValue, B256, BLOCK_HASH_HISTORY};
11use state::{
12 bal::{alloy::AlloyBal, Bal},
13 Account, AccountInfo,
14};
15use std::{
16 boxed::Box,
17 collections::{btree_map, BTreeMap},
18 sync::Arc,
19};
20
21pub type DBBox<'a, E> = Box<dyn Database<Error = E> + Send + 'a>;
23
24pub type StateDBBox<'a, E> = State<DBBox<'a, E>>;
28
29#[derive(Debug)]
35pub struct State<DB> {
36 pub cache: CacheState,
43 pub database: DB,
49 pub transition_state: Option<TransitionState>,
53 pub bundle_state: BundleState,
59 pub use_preloaded_bundle: bool,
65 pub block_hashes: BTreeMap<u64, B256>,
72 pub bal_state: BalState,
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 set_state_clear_flag(&mut self, has_state_clear: bool) {
96 self.cache.set_state_clear_flag(has_state_clear);
97 }
98
99 pub fn insert_not_existing(&mut self, address: Address) {
101 self.cache.insert_not_existing(address)
102 }
103
104 pub fn insert_account(&mut self, address: Address, info: AccountInfo) {
106 self.cache.insert_account(address, info)
107 }
108
109 pub fn insert_account_with_storage(
111 &mut self,
112 address: Address,
113 info: AccountInfo,
114 storage: PlainStorage,
115 ) {
116 self.cache
117 .insert_account_with_storage(address, info, storage)
118 }
119
120 pub fn apply_transition(
122 &mut self,
123 transitions: impl IntoIterator<Item = (Address, TransitionAccount)>,
124 ) {
125 if let Some(s) = self.transition_state.as_mut() {
127 s.add_transitions(transitions)
128 }
129 }
130
131 pub fn merge_transitions(&mut self, retention: BundleRetention) {
137 if let Some(transition_state) = self.transition_state.as_mut().map(TransitionState::take) {
138 self.bundle_state
139 .apply_transitions_and_create_reverts(transition_state, retention);
140 }
141 }
142
143 pub fn load_cache_account(&mut self, address: Address) -> Result<&mut CacheAccount, DB::Error> {
148 Self::load_cache_account_with(
149 &mut self.cache,
150 self.use_preloaded_bundle,
151 &self.bundle_state,
152 &mut self.database,
153 address,
154 )
155 }
156
157 fn load_cache_account_with<'a>(
165 cache: &'a mut CacheState,
166 use_preloaded_bundle: bool,
167 bundle_state: &BundleState,
168 database: &mut DB,
169 address: Address,
170 ) -> Result<&'a mut CacheAccount, DB::Error> {
171 Ok(match cache.accounts.entry(address) {
172 hash_map::Entry::Vacant(entry) => {
173 if use_preloaded_bundle {
174 if let Some(account) = bundle_state.account(&address).map(Into::into) {
176 return Ok(entry.insert(account));
177 }
178 }
179 let info = database.basic(address)?;
181 let account = match info {
182 None => CacheAccount::new_loaded_not_existing(),
183 Some(acc) if acc.is_empty() => {
184 CacheAccount::new_loaded_empty_eip161(HashMap::default())
185 }
186 Some(acc) => CacheAccount::new_loaded(acc, HashMap::default()),
187 };
188 entry.insert(account)
189 }
190 hash_map::Entry::Occupied(entry) => entry.into_mut(),
191 })
192 }
193
194 pub fn take_bundle(&mut self) -> BundleState {
206 core::mem::take(&mut self.bundle_state)
207 }
208
209 #[inline]
211 pub fn take_built_bal(&mut self) -> Option<Bal> {
212 self.bal_state.take_built_bal()
213 }
214
215 #[inline]
217 pub fn take_built_alloy_bal(&mut self) -> Option<AlloyBal> {
218 self.bal_state.take_built_alloy_bal()
219 }
220
221 #[inline]
223 pub fn bump_bal_index(&mut self) {
224 self.bal_state.bump_bal_index();
225 }
226
227 #[inline]
229 pub fn set_bal_index(&mut self, index: u64) {
230 self.bal_state.bal_index = index;
231 }
232
233 #[inline]
235 pub fn reset_bal_index(&mut self) {
236 self.bal_state.reset_bal_index();
237 }
238
239 #[inline]
241 pub fn set_bal(&mut self, bal: Option<Arc<Bal>>) {
242 self.bal_state.bal = bal;
243 }
244
245 #[inline]
247 fn storage(&mut self, address: Address, index: StorageKey) -> Result<StorageValue, DB::Error> {
248 let account = Self::load_cache_account_with(
250 &mut self.cache,
251 self.use_preloaded_bundle,
252 &self.bundle_state,
253 &mut self.database,
254 address,
255 )?;
256
257 let is_storage_known = account.status.is_storage_known();
259 Ok(account
260 .account
261 .as_mut()
262 .map(|account| match account.storage.entry(index) {
263 hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
264 hash_map::Entry::Vacant(entry) => {
265 let value = if is_storage_known {
268 StorageValue::ZERO
269 } else {
270 self.database.storage(address, index)?
271 };
272 entry.insert(value);
273 Ok(value)
274 }
275 })
276 .transpose()?
277 .unwrap_or_default())
278 }
279}
280
281impl<DB: Database> Database for State<DB> {
282 type Error = EvmDatabaseError<DB::Error>;
283
284 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
285 let account_id = self
287 .bal_state
288 .get_account_id(&address)
289 .map_err(EvmDatabaseError::Bal)?;
290
291 let mut basic = self
292 .load_cache_account(address)
293 .map(|a| a.account_info())
294 .map_err(EvmDatabaseError::Database)?;
295 if let Some(account_id) = account_id {
298 self.bal_state.basic_by_account_id(account_id, &mut basic);
299 }
300 Ok(basic)
301 }
302
303 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
304 let res = match self.cache.contracts.entry(code_hash) {
305 hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
306 hash_map::Entry::Vacant(entry) => {
307 if self.use_preloaded_bundle {
308 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
309 entry.insert(code.clone());
310 return Ok(code.clone());
311 }
312 }
313 let code = self
315 .database
316 .code_by_hash(code_hash)
317 .map_err(EvmDatabaseError::Database)?;
318 entry.insert(code.clone());
319 Ok(code)
320 }
321 };
322 res
323 }
324
325 fn storage(
326 &mut self,
327 address: Address,
328 index: StorageKey,
329 ) -> Result<StorageValue, Self::Error> {
330 if let Some(storage) = self
331 .bal_state
332 .storage(&address, index)
333 .map_err(EvmDatabaseError::Bal)?
334 {
335 return Ok(storage);
337 }
338 self.storage(address, index)
339 .map_err(EvmDatabaseError::Database)
340 }
341
342 fn storage_by_account_id(
343 &mut self,
344 address: Address,
345 account_id: usize,
346 key: StorageKey,
347 ) -> Result<StorageValue, Self::Error> {
348 if let Some(storage) = self.bal_state.storage_by_account_id(account_id, key)? {
349 return Ok(storage);
350 }
351
352 self.database
353 .storage(address, key)
354 .map_err(EvmDatabaseError::Database)
355 }
356
357 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
358 match self.block_hashes.entry(number) {
359 btree_map::Entry::Occupied(entry) => Ok(*entry.get()),
360 btree_map::Entry::Vacant(entry) => {
361 let ret = *entry.insert(
362 self.database
363 .block_hash(number)
364 .map_err(EvmDatabaseError::Database)?,
365 );
366
367 let last_block = number.saturating_sub(BLOCK_HASH_HISTORY);
369 while let Some(entry) = self.block_hashes.first_entry() {
370 if *entry.key() < last_block {
371 entry.remove();
372 } else {
373 break;
374 }
375 }
376
377 Ok(ret)
378 }
379 }
380 }
381}
382
383impl<DB: Database> DatabaseCommit for State<DB> {
384 fn commit(&mut self, changes: HashMap<Address, Account>) {
385 self.bal_state.commit(&changes);
386 let transitions = self.cache.apply_evm_state_iter(changes, |_, _| {});
387 if let Some(s) = self.transition_state.as_mut() {
388 s.add_transitions(transitions)
389 } else {
390 transitions.for_each(|_| {});
392 }
393 }
394
395 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
396 let transitions = self
397 .cache
398 .apply_evm_state_iter(changes, |address, account| {
399 self.bal_state.commit_one(*address, account);
400 });
401 if let Some(s) = self.transition_state.as_mut() {
402 s.add_transitions(transitions)
403 } else {
404 transitions.for_each(|_| {});
406 }
407 }
408}
409
410impl<DB: DatabaseRef> DatabaseRef for State<DB> {
411 type Error = EvmDatabaseError<DB::Error>;
412
413 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
414 let account_id = self.bal_state.get_account_id(&address)?;
416
417 let mut loaded_account = None;
419 if let Some(account) = self.cache.accounts.get(&address) {
420 loaded_account = Some(account.account_info());
421 };
422
423 if self.use_preloaded_bundle && loaded_account.is_none() {
425 if let Some(account) = self.bundle_state.account(&address) {
426 loaded_account = Some(account.account_info());
427 }
428 }
429
430 if loaded_account.is_none() {
432 loaded_account = Some(
433 self.database
434 .basic_ref(address)
435 .map_err(EvmDatabaseError::Database)?,
436 );
437 }
438
439 let mut account = loaded_account.unwrap();
441
442 if let Some(account_id) = account_id {
444 self.bal_state.basic_by_account_id(account_id, &mut account);
445 }
446 Ok(account)
447 }
448
449 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
450 if let Some(code) = self.cache.contracts.get(&code_hash) {
452 return Ok(code.clone());
453 }
454 if self.use_preloaded_bundle {
456 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
457 return Ok(code.clone());
458 }
459 }
460 self.database
462 .code_by_hash_ref(code_hash)
463 .map_err(EvmDatabaseError::Database)
464 }
465
466 fn storage_ref(
467 &self,
468 address: Address,
469 index: StorageKey,
470 ) -> Result<StorageValue, Self::Error> {
471 if let Some(storage) = self.bal_state.storage(&address, index)? {
473 return Ok(storage);
474 }
475
476 if let Some(account) = self.cache.accounts.get(&address) {
478 if let Some(plain_account) = &account.account {
479 if let Some(storage_value) = plain_account.storage.get(&index) {
481 return Ok(*storage_value);
482 }
483 if account.status.is_storage_known() {
486 return Ok(StorageValue::ZERO);
487 }
488 }
489 }
490
491 self.database
493 .storage_ref(address, index)
494 .map_err(EvmDatabaseError::Database)
495 }
496
497 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
498 if let Some(entry) = self.block_hashes.get(&number) {
499 return Ok(*entry);
500 }
501 self.database
503 .block_hash_ref(number)
504 .map_err(EvmDatabaseError::Database)
505 }
506}
507
508#[cfg(test)]
509mod tests {
510 use super::*;
511 use crate::{
512 states::{reverts::AccountInfoRevert, StorageSlot},
513 AccountRevert, AccountStatus, BundleAccount, RevertToSlot,
514 };
515 use primitives::{keccak256, U256};
516
517 #[test]
518 fn block_hash_cache() {
519 let mut state = State::builder().build();
520 state.block_hash(1u64).unwrap();
521 state.block_hash(2u64).unwrap();
522
523 let test_number = BLOCK_HASH_HISTORY + 2;
524
525 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
526 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
527 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
528
529 assert_eq!(
530 state.block_hashes,
531 BTreeMap::from([(1, block1_hash), (2, block2_hash)])
532 );
533
534 state.block_hash(test_number).unwrap();
535 assert_eq!(
536 state.block_hashes,
537 BTreeMap::from([(test_number, block_test_hash), (2, block2_hash)])
538 );
539 }
540
541 #[test]
548 fn reverts_preserve_old_values() {
549 let mut state = State::builder().with_bundle_update().build();
550
551 let (slot1, slot2, slot3) = (
552 StorageKey::from(1),
553 StorageKey::from(2),
554 StorageKey::from(3),
555 );
556
557 let new_account_address = Address::from_slice(&[0x1; 20]);
560 let new_account_created_info = AccountInfo {
561 nonce: 1,
562 balance: U256::from(1),
563 ..Default::default()
564 };
565 let new_account_changed_info = AccountInfo {
566 nonce: 2,
567 ..new_account_created_info.clone()
568 };
569 let new_account_changed_info2 = AccountInfo {
570 nonce: 3,
571 ..new_account_changed_info.clone()
572 };
573
574 let existing_account_address = Address::from_slice(&[0x2; 20]);
576 let existing_account_initial_info = AccountInfo {
577 nonce: 1,
578 ..Default::default()
579 };
580 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
581 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
584 let existing_account_changed_info = AccountInfo {
585 nonce: 2,
586 ..existing_account_initial_info.clone()
587 };
588
589 state.apply_transition(Vec::from([
591 (
592 new_account_address,
593 TransitionAccount {
594 status: AccountStatus::InMemoryChange,
595 info: Some(new_account_created_info.clone()),
596 previous_status: AccountStatus::LoadedNotExisting,
597 previous_info: None,
598 ..Default::default()
599 },
600 ),
601 (
602 existing_account_address,
603 TransitionAccount {
604 status: AccountStatus::InMemoryChange,
605 info: Some(existing_account_changed_info.clone()),
606 previous_status: AccountStatus::Loaded,
607 previous_info: Some(existing_account_initial_info.clone()),
608 storage: HashMap::from_iter([(
609 slot1,
610 StorageSlot::new_changed(
611 *existing_account_initial_storage.get(&slot1).unwrap(),
612 StorageValue::from(1000),
613 ),
614 )]),
615 storage_was_destroyed: false,
616 },
617 ),
618 ]));
619
620 state.apply_transition(Vec::from([(
622 new_account_address,
623 TransitionAccount {
624 status: AccountStatus::InMemoryChange,
625 info: Some(new_account_changed_info.clone()),
626 previous_status: AccountStatus::InMemoryChange,
627 previous_info: Some(new_account_created_info.clone()),
628 ..Default::default()
629 },
630 )]));
631
632 state.apply_transition(Vec::from([
634 (
635 new_account_address,
636 TransitionAccount {
637 status: AccountStatus::InMemoryChange,
638 info: Some(new_account_changed_info2.clone()),
639 previous_status: AccountStatus::InMemoryChange,
640 previous_info: Some(new_account_changed_info),
641 storage: HashMap::from_iter([(
642 slot1,
643 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
644 )]),
645 storage_was_destroyed: false,
646 },
647 ),
648 (
649 existing_account_address,
650 TransitionAccount {
651 status: AccountStatus::InMemoryChange,
652 info: Some(existing_account_changed_info.clone()),
653 previous_status: AccountStatus::InMemoryChange,
654 previous_info: Some(existing_account_changed_info.clone()),
655 storage: HashMap::from_iter([
656 (
657 slot1,
658 StorageSlot::new_changed(
659 StorageValue::from(100),
660 StorageValue::from(1_000),
661 ),
662 ),
663 (
664 slot2,
665 StorageSlot::new_changed(
666 *existing_account_initial_storage.get(&slot2).unwrap(),
667 StorageValue::from(2_000),
668 ),
669 ),
670 (
672 slot3,
673 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)),
674 ),
675 ]),
676 storage_was_destroyed: false,
677 },
678 ),
679 ]));
680
681 state.merge_transitions(BundleRetention::Reverts);
682 let mut bundle_state = state.take_bundle();
683
684 bundle_state.reverts.sort();
687 assert_eq!(
688 bundle_state.reverts.as_ref(),
689 Vec::from([Vec::from([
690 (
691 new_account_address,
692 AccountRevert {
693 account: AccountInfoRevert::DeleteIt,
694 previous_status: AccountStatus::LoadedNotExisting,
695 storage: HashMap::from_iter([(
696 slot1,
697 RevertToSlot::Some(StorageValue::ZERO)
698 )]),
699 wipe_storage: false,
700 }
701 ),
702 (
703 existing_account_address,
704 AccountRevert {
705 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
706 previous_status: AccountStatus::Loaded,
707 storage: HashMap::from_iter([
708 (
709 slot1,
710 RevertToSlot::Some(
711 *existing_account_initial_storage.get(&slot1).unwrap()
712 )
713 ),
714 (
715 slot2,
716 RevertToSlot::Some(
717 *existing_account_initial_storage.get(&slot2).unwrap()
718 )
719 ),
720 (slot3, RevertToSlot::Some(StorageValue::ZERO))
721 ]),
722 wipe_storage: false,
723 }
724 ),
725 ])]),
726 "The account or storage reverts are incorrect"
727 );
728
729 assert_eq!(
732 bundle_state.account(&new_account_address),
733 Some(&BundleAccount {
734 info: Some(new_account_changed_info2),
735 original_info: None,
736 status: AccountStatus::InMemoryChange,
737 storage: HashMap::from_iter([(
738 slot1,
739 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
740 )]),
741 }),
742 "The latest state of the new account is incorrect"
743 );
744
745 assert_eq!(
748 bundle_state.account(&existing_account_address),
749 Some(&BundleAccount {
750 info: Some(existing_account_changed_info),
751 original_info: Some(existing_account_initial_info),
752 status: AccountStatus::InMemoryChange,
753 storage: HashMap::from_iter([
754 (
755 slot1,
756 StorageSlot::new_changed(
757 *existing_account_initial_storage.get(&slot1).unwrap(),
758 StorageValue::from(1_000)
759 )
760 ),
761 (
762 slot2,
763 StorageSlot::new_changed(
764 *existing_account_initial_storage.get(&slot2).unwrap(),
765 StorageValue::from(2_000)
766 )
767 ),
768 (
770 slot3,
771 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
772 ),
773 ]),
774 }),
775 "The latest state of the existing account is incorrect"
776 );
777 }
778
779 #[test]
782 fn bundle_scoped_reverts_collapse() {
783 let mut state = State::builder().with_bundle_update().build();
784
785 let new_account_address = Address::from_slice(&[0x1; 20]);
787 let new_account_created_info = AccountInfo {
788 nonce: 1,
789 balance: U256::from(1),
790 ..Default::default()
791 };
792
793 let existing_account_address = Address::from_slice(&[0x2; 20]);
795 let existing_account_initial_info = AccountInfo {
796 nonce: 1,
797 ..Default::default()
798 };
799 let existing_account_updated_info = AccountInfo {
800 nonce: 1,
801 balance: U256::from(1),
802 ..Default::default()
803 };
804
805 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
807 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
808 let existing_account_with_storage_info = AccountInfo {
809 nonce: 1,
810 ..Default::default()
811 };
812 state.apply_transition(Vec::from([
814 (
815 new_account_address,
816 TransitionAccount {
817 status: AccountStatus::InMemoryChange,
818 info: Some(new_account_created_info.clone()),
819 previous_status: AccountStatus::LoadedNotExisting,
820 previous_info: None,
821 ..Default::default()
822 },
823 ),
824 (
825 existing_account_address,
826 TransitionAccount {
827 status: AccountStatus::Changed,
828 info: Some(existing_account_updated_info.clone()),
829 previous_status: AccountStatus::Loaded,
830 previous_info: Some(existing_account_initial_info.clone()),
831 ..Default::default()
832 },
833 ),
834 (
835 existing_account_with_storage_address,
836 TransitionAccount {
837 status: AccountStatus::Changed,
838 info: Some(existing_account_with_storage_info.clone()),
839 previous_status: AccountStatus::Loaded,
840 previous_info: Some(existing_account_with_storage_info.clone()),
841 storage: HashMap::from_iter([
842 (
843 slot1,
844 StorageSlot::new_changed(StorageValue::from(1), StorageValue::from(10)),
845 ),
846 (
847 slot2,
848 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(20)),
849 ),
850 ]),
851 storage_was_destroyed: false,
852 },
853 ),
854 ]));
855
856 state.apply_transition(Vec::from([
858 (
859 new_account_address,
860 TransitionAccount {
861 status: AccountStatus::Destroyed,
862 info: None,
863 previous_status: AccountStatus::InMemoryChange,
864 previous_info: Some(new_account_created_info),
865 ..Default::default()
866 },
867 ),
868 (
869 existing_account_address,
870 TransitionAccount {
871 status: AccountStatus::Changed,
872 info: Some(existing_account_initial_info),
873 previous_status: AccountStatus::Changed,
874 previous_info: Some(existing_account_updated_info),
875 ..Default::default()
876 },
877 ),
878 (
879 existing_account_with_storage_address,
880 TransitionAccount {
881 status: AccountStatus::Changed,
882 info: Some(existing_account_with_storage_info.clone()),
883 previous_status: AccountStatus::Changed,
884 previous_info: Some(existing_account_with_storage_info.clone()),
885 storage: HashMap::from_iter([
886 (
887 slot1,
888 StorageSlot::new_changed(StorageValue::from(10), StorageValue::from(1)),
889 ),
890 (
891 slot2,
892 StorageSlot::new_changed(StorageValue::from(20), StorageValue::ZERO),
893 ),
894 ]),
895 storage_was_destroyed: false,
896 },
897 ),
898 ]));
899
900 state.merge_transitions(BundleRetention::Reverts);
901
902 let mut bundle_state = state.take_bundle();
903 bundle_state.reverts.sort();
904
905 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
908 }
909
910 #[test]
912 fn selfdestruct_state_and_reverts() {
913 let mut state = State::builder().with_bundle_update().build();
914
915 let existing_account_address = Address::from_slice(&[0x1; 20]);
917 let existing_account_info = AccountInfo {
918 nonce: 1,
919 ..Default::default()
920 };
921
922 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
923
924 state.apply_transition(Vec::from([(
926 existing_account_address,
927 TransitionAccount {
928 status: AccountStatus::Destroyed,
929 info: None,
930 previous_status: AccountStatus::Loaded,
931 previous_info: Some(existing_account_info.clone()),
932 storage: HashMap::default(),
933 storage_was_destroyed: true,
934 },
935 )]));
936
937 state.apply_transition(Vec::from([(
939 existing_account_address,
940 TransitionAccount {
941 status: AccountStatus::DestroyedChanged,
942 info: Some(existing_account_info.clone()),
943 previous_status: AccountStatus::Destroyed,
944 previous_info: None,
945 storage: HashMap::from_iter([(
946 slot1,
947 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
948 )]),
949 storage_was_destroyed: false,
950 },
951 )]));
952
953 state.apply_transition(Vec::from([(
955 existing_account_address,
956 TransitionAccount {
957 status: AccountStatus::DestroyedAgain,
958 info: None,
959 previous_status: AccountStatus::DestroyedChanged,
960 previous_info: Some(existing_account_info.clone()),
961 storage: HashMap::default(),
963 storage_was_destroyed: true,
964 },
965 )]));
966
967 state.apply_transition(Vec::from([(
969 existing_account_address,
970 TransitionAccount {
971 status: AccountStatus::DestroyedChanged,
972 info: Some(existing_account_info.clone()),
973 previous_status: AccountStatus::DestroyedAgain,
974 previous_info: None,
975 storage: HashMap::from_iter([(
976 slot2,
977 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)),
978 )]),
979 storage_was_destroyed: false,
980 },
981 )]));
982
983 state.merge_transitions(BundleRetention::Reverts);
984
985 let bundle_state = state.take_bundle();
986
987 assert_eq!(
988 bundle_state.state,
989 HashMap::from_iter([(
990 existing_account_address,
991 BundleAccount {
992 info: Some(existing_account_info.clone()),
993 original_info: Some(existing_account_info.clone()),
994 storage: HashMap::from_iter([(
995 slot2,
996 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
997 )]),
998 status: AccountStatus::DestroyedChanged,
999 }
1000 )])
1001 );
1002
1003 assert_eq!(
1004 bundle_state.reverts.as_ref(),
1005 Vec::from([Vec::from([(
1006 existing_account_address,
1007 AccountRevert {
1008 account: AccountInfoRevert::DoNothing,
1009 previous_status: AccountStatus::Loaded,
1010 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1011 wipe_storage: true,
1012 }
1013 )])])
1014 )
1015 }
1016}