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,
11};
12use primitives::{hash_map, Address, AddressMap, HashMap, StorageKey, StorageValue, B256};
13use state::{
14 bal::{alloy::AlloyBal, Bal},
15 Account, 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(Debug)]
33pub struct State<DB> {
34 pub cache: CacheState,
41 pub database: DB,
47 pub transition_state: Option<TransitionState>,
51 pub bundle_state: BundleState,
57 pub use_preloaded_bundle: bool,
63 pub block_hashes: BlockHashCache,
70 pub bal_state: BalState,
74}
75
76impl State<EmptyDB> {
78 pub fn builder() -> StateBuilder<EmptyDB> {
80 StateBuilder::default()
81 }
82}
83
84impl<DB: Database> State<DB> {
85 pub fn bundle_size_hint(&self) -> usize {
89 self.bundle_state.size_hint()
90 }
91
92 pub fn set_state_clear_flag(&mut self, has_state_clear: bool) {
94 self.cache.set_state_clear_flag(has_state_clear);
95 }
96
97 pub fn insert_not_existing(&mut self, address: Address) {
99 self.cache.insert_not_existing(address)
100 }
101
102 pub fn insert_account(&mut self, address: Address, info: AccountInfo) {
104 self.cache.insert_account(address, info)
105 }
106
107 pub fn insert_account_with_storage(
109 &mut self,
110 address: Address,
111 info: AccountInfo,
112 storage: PlainStorage,
113 ) {
114 self.cache
115 .insert_account_with_storage(address, info, storage)
116 }
117
118 pub fn apply_transition(
120 &mut self,
121 transitions: impl IntoIterator<Item = (Address, TransitionAccount)>,
122 ) {
123 if let Some(s) = self.transition_state.as_mut() {
125 s.add_transitions(transitions)
126 }
127 }
128
129 pub fn merge_transitions(&mut self, retention: BundleRetention) {
135 if let Some(transition_state) = self.transition_state.as_mut().map(TransitionState::take) {
136 self.bundle_state
137 .apply_transitions_and_create_reverts(transition_state, retention);
138 }
139 }
140
141 pub fn load_cache_account(&mut self, address: Address) -> Result<&mut CacheAccount, DB::Error> {
146 Self::load_cache_account_with(
147 &mut self.cache,
148 self.use_preloaded_bundle,
149 &self.bundle_state,
150 &mut self.database,
151 address,
152 )
153 }
154
155 fn load_cache_account_with<'a>(
163 cache: &'a mut CacheState,
164 use_preloaded_bundle: bool,
165 bundle_state: &BundleState,
166 database: &mut DB,
167 address: Address,
168 ) -> Result<&'a mut CacheAccount, DB::Error> {
169 Ok(match cache.accounts.entry(address) {
170 hash_map::Entry::Vacant(entry) => {
171 if use_preloaded_bundle {
172 if let Some(account) = bundle_state.account(&address).map(Into::into) {
174 return Ok(entry.insert(account));
175 }
176 }
177 let info = database.basic(address)?;
179 let account = match info {
180 None => CacheAccount::new_loaded_not_existing(),
181 Some(acc) if acc.is_empty() => {
182 CacheAccount::new_loaded_empty_eip161(HashMap::default())
183 }
184 Some(acc) => CacheAccount::new_loaded(acc, HashMap::default()),
185 };
186 entry.insert(account)
187 }
188 hash_map::Entry::Occupied(entry) => entry.into_mut(),
189 })
190 }
191
192 pub fn take_bundle(&mut self) -> BundleState {
204 core::mem::take(&mut self.bundle_state)
205 }
206
207 #[inline]
209 pub fn take_built_bal(&mut self) -> Option<Bal> {
210 self.bal_state.take_built_bal()
211 }
212
213 #[inline]
215 pub fn take_built_alloy_bal(&mut self) -> Option<AlloyBal> {
216 self.bal_state.take_built_alloy_bal()
217 }
218
219 #[inline]
221 pub fn bump_bal_index(&mut self) {
222 self.bal_state.bump_bal_index();
223 }
224
225 #[inline]
227 pub fn set_bal_index(&mut self, index: u64) {
228 self.bal_state.bal_index = index;
229 }
230
231 #[inline]
233 pub fn reset_bal_index(&mut self) {
234 self.bal_state.reset_bal_index();
235 }
236
237 #[inline]
239 pub fn set_bal(&mut self, bal: Option<Arc<Bal>>) {
240 self.bal_state.bal = bal;
241 }
242
243 #[inline]
245 fn storage(&mut self, address: Address, index: StorageKey) -> Result<StorageValue, DB::Error> {
246 let account = Self::load_cache_account_with(
248 &mut self.cache,
249 self.use_preloaded_bundle,
250 &self.bundle_state,
251 &mut self.database,
252 address,
253 )?;
254
255 let is_storage_known = account.status.is_storage_known();
257 Ok(account
258 .account
259 .as_mut()
260 .map(|account| match account.storage.entry(index) {
261 hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
262 hash_map::Entry::Vacant(entry) => {
263 let value = if is_storage_known {
266 StorageValue::ZERO
267 } else {
268 self.database.storage(address, index)?
269 };
270 entry.insert(value);
271 Ok(value)
272 }
273 })
274 .transpose()?
275 .unwrap_or_default())
276 }
277}
278
279impl<DB: Database> Database for State<DB> {
280 type Error = EvmDatabaseError<DB::Error>;
281
282 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
283 let account_id = self
285 .bal_state
286 .get_account_id(&address)
287 .map_err(EvmDatabaseError::Bal)?;
288
289 let mut basic = self
290 .load_cache_account(address)
291 .map(|a| a.account_info())
292 .map_err(EvmDatabaseError::Database)?;
293 if let Some(account_id) = account_id {
296 self.bal_state.basic_by_account_id(account_id, &mut basic);
297 }
298 Ok(basic)
299 }
300
301 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
302 let res = match self.cache.contracts.entry(code_hash) {
303 hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
304 hash_map::Entry::Vacant(entry) => {
305 if self.use_preloaded_bundle {
306 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
307 entry.insert(code.clone());
308 return Ok(code.clone());
309 }
310 }
311 let code = self
313 .database
314 .code_by_hash(code_hash)
315 .map_err(EvmDatabaseError::Database)?;
316 entry.insert(code.clone());
317 Ok(code)
318 }
319 };
320 res
321 }
322
323 fn storage(
324 &mut self,
325 address: Address,
326 index: StorageKey,
327 ) -> Result<StorageValue, Self::Error> {
328 if let Some(storage) = self
329 .bal_state
330 .storage(&address, index)
331 .map_err(EvmDatabaseError::Bal)?
332 {
333 return Ok(storage);
335 }
336 self.storage(address, index)
337 .map_err(EvmDatabaseError::Database)
338 }
339
340 fn storage_by_account_id(
341 &mut self,
342 address: Address,
343 account_id: usize,
344 key: StorageKey,
345 ) -> Result<StorageValue, Self::Error> {
346 if let Some(storage) = self.bal_state.storage_by_account_id(account_id, key)? {
347 return Ok(storage);
348 }
349
350 self.storage(address, key)
351 .map_err(EvmDatabaseError::Database)
352 }
353
354 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
355 if let Some(hash) = self.block_hashes.get(number) {
357 return Ok(hash);
358 }
359
360 let hash = self
362 .database
363 .block_hash(number)
364 .map_err(EvmDatabaseError::Database)?;
365
366 self.block_hashes.insert(number, hash);
368
369 Ok(hash)
370 }
371}
372
373impl<DB: Database> DatabaseCommit for State<DB> {
374 fn commit(&mut self, changes: AddressMap<Account>) {
375 self.bal_state.commit(&changes);
376 let transitions = self.cache.apply_evm_state_iter(changes, |_, _| {});
377 if let Some(s) = self.transition_state.as_mut() {
378 s.add_transitions(transitions)
379 } else {
380 transitions.for_each(|_| {});
382 }
383 }
384
385 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
386 let transitions = self
387 .cache
388 .apply_evm_state_iter(changes, |address, account| {
389 self.bal_state.commit_one(*address, account);
390 });
391 if let Some(s) = self.transition_state.as_mut() {
392 s.add_transitions(transitions)
393 } else {
394 transitions.for_each(|_| {});
396 }
397 }
398}
399
400impl<DB: DatabaseRef> DatabaseRef for State<DB> {
401 type Error = EvmDatabaseError<DB::Error>;
402
403 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
404 let account_id = self.bal_state.get_account_id(&address)?;
406
407 let mut loaded_account = None;
409 if let Some(account) = self.cache.accounts.get(&address) {
410 loaded_account = Some(account.account_info());
411 };
412
413 if self.use_preloaded_bundle && loaded_account.is_none() {
415 if let Some(account) = self.bundle_state.account(&address) {
416 loaded_account = Some(account.account_info());
417 }
418 }
419
420 if loaded_account.is_none() {
422 loaded_account = Some(
423 self.database
424 .basic_ref(address)
425 .map_err(EvmDatabaseError::Database)?,
426 );
427 }
428
429 let mut account = loaded_account.unwrap();
431
432 if let Some(account_id) = account_id {
434 self.bal_state.basic_by_account_id(account_id, &mut account);
435 }
436 Ok(account)
437 }
438
439 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
440 if let Some(code) = self.cache.contracts.get(&code_hash) {
442 return Ok(code.clone());
443 }
444 if self.use_preloaded_bundle {
446 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
447 return Ok(code.clone());
448 }
449 }
450 self.database
452 .code_by_hash_ref(code_hash)
453 .map_err(EvmDatabaseError::Database)
454 }
455
456 fn storage_ref(
457 &self,
458 address: Address,
459 index: StorageKey,
460 ) -> Result<StorageValue, Self::Error> {
461 if let Some(storage) = self.bal_state.storage(&address, index)? {
463 return Ok(storage);
464 }
465
466 if let Some(account) = self.cache.accounts.get(&address) {
468 if let Some(plain_account) = &account.account {
469 if let Some(storage_value) = plain_account.storage.get(&index) {
471 return Ok(*storage_value);
472 }
473 if account.status.is_storage_known() {
476 return Ok(StorageValue::ZERO);
477 }
478 }
479 }
480
481 self.database
483 .storage_ref(address, index)
484 .map_err(EvmDatabaseError::Database)
485 }
486
487 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
488 if let Some(hash) = self.block_hashes.get(number) {
489 return Ok(hash);
490 }
491 self.database
493 .block_hash_ref(number)
494 .map_err(EvmDatabaseError::Database)
495 }
496}
497
498#[cfg(test)]
499mod tests {
500 use super::*;
501 use crate::{
502 states::{reverts::AccountInfoRevert, StorageSlot},
503 AccountRevert, AccountStatus, BundleAccount, RevertToSlot,
504 };
505 use primitives::{keccak256, BLOCK_HASH_HISTORY, U256};
506 #[test]
507 fn block_hash_cache() {
508 let mut state = State::builder().build();
509 state.block_hash(1u64).unwrap();
510 state.block_hash(2u64).unwrap();
511
512 let test_number = BLOCK_HASH_HISTORY + 2;
513
514 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
515 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
516 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
517
518 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
520 assert_eq!(state.block_hashes.get(2), Some(block2_hash));
521
522 state.block_hash(test_number).unwrap();
525
526 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
528 assert_eq!(state.block_hashes.get(2), None);
529 assert_eq!(state.block_hashes.get(test_number), Some(block_test_hash));
530 }
531
532 #[test]
537 fn block_hash_cache_block_zero() {
538 let mut state = State::builder().build();
539
540 assert_eq!(state.block_hashes.get(0), None);
542
543 let block0_hash = state.block_hash(0u64).unwrap();
545
546 let expected_hash = keccak256(U256::from(0).to_string().as_bytes());
548 assert_eq!(block0_hash, expected_hash);
549
550 assert_eq!(state.block_hashes.get(0), Some(expected_hash));
552 }
553 #[test]
560 fn reverts_preserve_old_values() {
561 let mut state = State::builder().with_bundle_update().build();
562
563 let (slot1, slot2, slot3) = (
564 StorageKey::from(1),
565 StorageKey::from(2),
566 StorageKey::from(3),
567 );
568
569 let new_account_address = Address::from_slice(&[0x1; 20]);
572 let new_account_created_info = AccountInfo {
573 nonce: 1,
574 balance: U256::from(1),
575 ..Default::default()
576 };
577 let new_account_changed_info = AccountInfo {
578 nonce: 2,
579 ..new_account_created_info.clone()
580 };
581 let new_account_changed_info2 = AccountInfo {
582 nonce: 3,
583 ..new_account_changed_info.clone()
584 };
585
586 let existing_account_address = Address::from_slice(&[0x2; 20]);
588 let existing_account_initial_info = AccountInfo {
589 nonce: 1,
590 ..Default::default()
591 };
592 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
593 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
596 let existing_account_changed_info = AccountInfo {
597 nonce: 2,
598 ..existing_account_initial_info.clone()
599 };
600
601 state.apply_transition(Vec::from([
603 (
604 new_account_address,
605 TransitionAccount {
606 status: AccountStatus::InMemoryChange,
607 info: Some(new_account_created_info.clone()),
608 previous_status: AccountStatus::LoadedNotExisting,
609 previous_info: None,
610 ..Default::default()
611 },
612 ),
613 (
614 existing_account_address,
615 TransitionAccount {
616 status: AccountStatus::InMemoryChange,
617 info: Some(existing_account_changed_info.clone()),
618 previous_status: AccountStatus::Loaded,
619 previous_info: Some(existing_account_initial_info.clone()),
620 storage: HashMap::from_iter([(
621 slot1,
622 StorageSlot::new_changed(
623 *existing_account_initial_storage.get(&slot1).unwrap(),
624 StorageValue::from(1000),
625 ),
626 )]),
627 storage_was_destroyed: false,
628 },
629 ),
630 ]));
631
632 state.apply_transition(Vec::from([(
634 new_account_address,
635 TransitionAccount {
636 status: AccountStatus::InMemoryChange,
637 info: Some(new_account_changed_info.clone()),
638 previous_status: AccountStatus::InMemoryChange,
639 previous_info: Some(new_account_created_info.clone()),
640 ..Default::default()
641 },
642 )]));
643
644 state.apply_transition(Vec::from([
646 (
647 new_account_address,
648 TransitionAccount {
649 status: AccountStatus::InMemoryChange,
650 info: Some(new_account_changed_info2.clone()),
651 previous_status: AccountStatus::InMemoryChange,
652 previous_info: Some(new_account_changed_info),
653 storage: HashMap::from_iter([(
654 slot1,
655 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
656 )]),
657 storage_was_destroyed: false,
658 },
659 ),
660 (
661 existing_account_address,
662 TransitionAccount {
663 status: AccountStatus::InMemoryChange,
664 info: Some(existing_account_changed_info.clone()),
665 previous_status: AccountStatus::InMemoryChange,
666 previous_info: Some(existing_account_changed_info.clone()),
667 storage: HashMap::from_iter([
668 (
669 slot1,
670 StorageSlot::new_changed(
671 StorageValue::from(100),
672 StorageValue::from(1_000),
673 ),
674 ),
675 (
676 slot2,
677 StorageSlot::new_changed(
678 *existing_account_initial_storage.get(&slot2).unwrap(),
679 StorageValue::from(2_000),
680 ),
681 ),
682 (
684 slot3,
685 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)),
686 ),
687 ]),
688 storage_was_destroyed: false,
689 },
690 ),
691 ]));
692
693 state.merge_transitions(BundleRetention::Reverts);
694 let mut bundle_state = state.take_bundle();
695
696 bundle_state.reverts.sort();
699 assert_eq!(
700 bundle_state.reverts.as_ref(),
701 Vec::from([Vec::from([
702 (
703 new_account_address,
704 AccountRevert {
705 account: AccountInfoRevert::DeleteIt,
706 previous_status: AccountStatus::LoadedNotExisting,
707 storage: HashMap::from_iter([(
708 slot1,
709 RevertToSlot::Some(StorageValue::ZERO)
710 )]),
711 wipe_storage: false,
712 }
713 ),
714 (
715 existing_account_address,
716 AccountRevert {
717 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
718 previous_status: AccountStatus::Loaded,
719 storage: HashMap::from_iter([
720 (
721 slot1,
722 RevertToSlot::Some(
723 *existing_account_initial_storage.get(&slot1).unwrap()
724 )
725 ),
726 (
727 slot2,
728 RevertToSlot::Some(
729 *existing_account_initial_storage.get(&slot2).unwrap()
730 )
731 ),
732 (slot3, RevertToSlot::Some(StorageValue::ZERO))
733 ]),
734 wipe_storage: false,
735 }
736 ),
737 ])]),
738 "The account or storage reverts are incorrect"
739 );
740
741 assert_eq!(
744 bundle_state.account(&new_account_address),
745 Some(&BundleAccount {
746 info: Some(new_account_changed_info2),
747 original_info: None,
748 status: AccountStatus::InMemoryChange,
749 storage: HashMap::from_iter([(
750 slot1,
751 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
752 )]),
753 }),
754 "The latest state of the new account is incorrect"
755 );
756
757 assert_eq!(
760 bundle_state.account(&existing_account_address),
761 Some(&BundleAccount {
762 info: Some(existing_account_changed_info),
763 original_info: Some(existing_account_initial_info),
764 status: AccountStatus::InMemoryChange,
765 storage: HashMap::from_iter([
766 (
767 slot1,
768 StorageSlot::new_changed(
769 *existing_account_initial_storage.get(&slot1).unwrap(),
770 StorageValue::from(1_000)
771 )
772 ),
773 (
774 slot2,
775 StorageSlot::new_changed(
776 *existing_account_initial_storage.get(&slot2).unwrap(),
777 StorageValue::from(2_000)
778 )
779 ),
780 (
782 slot3,
783 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
784 ),
785 ]),
786 }),
787 "The latest state of the existing account is incorrect"
788 );
789 }
790
791 #[test]
794 fn bundle_scoped_reverts_collapse() {
795 let mut state = State::builder().with_bundle_update().build();
796
797 let new_account_address = Address::from_slice(&[0x1; 20]);
799 let new_account_created_info = AccountInfo {
800 nonce: 1,
801 balance: U256::from(1),
802 ..Default::default()
803 };
804
805 let existing_account_address = Address::from_slice(&[0x2; 20]);
807 let existing_account_initial_info = AccountInfo {
808 nonce: 1,
809 ..Default::default()
810 };
811 let existing_account_updated_info = AccountInfo {
812 nonce: 1,
813 balance: U256::from(1),
814 ..Default::default()
815 };
816
817 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
819 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
820 let existing_account_with_storage_info = AccountInfo {
821 nonce: 1,
822 ..Default::default()
823 };
824 state.apply_transition(Vec::from([
826 (
827 new_account_address,
828 TransitionAccount {
829 status: AccountStatus::InMemoryChange,
830 info: Some(new_account_created_info.clone()),
831 previous_status: AccountStatus::LoadedNotExisting,
832 previous_info: None,
833 ..Default::default()
834 },
835 ),
836 (
837 existing_account_address,
838 TransitionAccount {
839 status: AccountStatus::Changed,
840 info: Some(existing_account_updated_info.clone()),
841 previous_status: AccountStatus::Loaded,
842 previous_info: Some(existing_account_initial_info.clone()),
843 ..Default::default()
844 },
845 ),
846 (
847 existing_account_with_storage_address,
848 TransitionAccount {
849 status: AccountStatus::Changed,
850 info: Some(existing_account_with_storage_info.clone()),
851 previous_status: AccountStatus::Loaded,
852 previous_info: Some(existing_account_with_storage_info.clone()),
853 storage: HashMap::from_iter([
854 (
855 slot1,
856 StorageSlot::new_changed(StorageValue::from(1), StorageValue::from(10)),
857 ),
858 (
859 slot2,
860 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(20)),
861 ),
862 ]),
863 storage_was_destroyed: false,
864 },
865 ),
866 ]));
867
868 state.apply_transition(Vec::from([
870 (
871 new_account_address,
872 TransitionAccount {
873 status: AccountStatus::Destroyed,
874 info: None,
875 previous_status: AccountStatus::InMemoryChange,
876 previous_info: Some(new_account_created_info),
877 ..Default::default()
878 },
879 ),
880 (
881 existing_account_address,
882 TransitionAccount {
883 status: AccountStatus::Changed,
884 info: Some(existing_account_initial_info),
885 previous_status: AccountStatus::Changed,
886 previous_info: Some(existing_account_updated_info),
887 ..Default::default()
888 },
889 ),
890 (
891 existing_account_with_storage_address,
892 TransitionAccount {
893 status: AccountStatus::Changed,
894 info: Some(existing_account_with_storage_info.clone()),
895 previous_status: AccountStatus::Changed,
896 previous_info: Some(existing_account_with_storage_info.clone()),
897 storage: HashMap::from_iter([
898 (
899 slot1,
900 StorageSlot::new_changed(StorageValue::from(10), StorageValue::from(1)),
901 ),
902 (
903 slot2,
904 StorageSlot::new_changed(StorageValue::from(20), StorageValue::ZERO),
905 ),
906 ]),
907 storage_was_destroyed: false,
908 },
909 ),
910 ]));
911
912 state.merge_transitions(BundleRetention::Reverts);
913
914 let mut bundle_state = state.take_bundle();
915 bundle_state.reverts.sort();
916
917 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
920 }
921
922 #[test]
924 fn selfdestruct_state_and_reverts() {
925 let mut state = State::builder().with_bundle_update().build();
926
927 let existing_account_address = Address::from_slice(&[0x1; 20]);
929 let existing_account_info = AccountInfo {
930 nonce: 1,
931 ..Default::default()
932 };
933
934 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
935
936 state.apply_transition(Vec::from([(
938 existing_account_address,
939 TransitionAccount {
940 status: AccountStatus::Destroyed,
941 info: None,
942 previous_status: AccountStatus::Loaded,
943 previous_info: Some(existing_account_info.clone()),
944 storage: HashMap::default(),
945 storage_was_destroyed: true,
946 },
947 )]));
948
949 state.apply_transition(Vec::from([(
951 existing_account_address,
952 TransitionAccount {
953 status: AccountStatus::DestroyedChanged,
954 info: Some(existing_account_info.clone()),
955 previous_status: AccountStatus::Destroyed,
956 previous_info: None,
957 storage: HashMap::from_iter([(
958 slot1,
959 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
960 )]),
961 storage_was_destroyed: false,
962 },
963 )]));
964
965 state.apply_transition(Vec::from([(
967 existing_account_address,
968 TransitionAccount {
969 status: AccountStatus::DestroyedAgain,
970 info: None,
971 previous_status: AccountStatus::DestroyedChanged,
972 previous_info: Some(existing_account_info.clone()),
973 storage: HashMap::default(),
975 storage_was_destroyed: true,
976 },
977 )]));
978
979 state.apply_transition(Vec::from([(
981 existing_account_address,
982 TransitionAccount {
983 status: AccountStatus::DestroyedChanged,
984 info: Some(existing_account_info.clone()),
985 previous_status: AccountStatus::DestroyedAgain,
986 previous_info: None,
987 storage: HashMap::from_iter([(
988 slot2,
989 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)),
990 )]),
991 storage_was_destroyed: false,
992 },
993 )]));
994
995 state.merge_transitions(BundleRetention::Reverts);
996
997 let bundle_state = state.take_bundle();
998
999 assert_eq!(
1000 bundle_state.state,
1001 HashMap::from_iter([(
1002 existing_account_address,
1003 BundleAccount {
1004 info: Some(existing_account_info.clone()),
1005 original_info: Some(existing_account_info.clone()),
1006 storage: HashMap::from_iter([(
1007 slot2,
1008 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1009 )]),
1010 status: AccountStatus::DestroyedChanged,
1011 }
1012 )])
1013 );
1014
1015 assert_eq!(
1016 bundle_state.reverts.as_ref(),
1017 Vec::from([Vec::from([(
1018 existing_account_address,
1019 AccountRevert {
1020 account: AccountInfoRevert::DoNothing,
1021 previous_status: AccountStatus::Loaded,
1022 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1023 wipe_storage: true,
1024 }
1025 )])])
1026 )
1027 }
1028}