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, 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.database
351 .storage(address, key)
352 .map_err(EvmDatabaseError::Database)
353 }
354
355 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
356 if let Some(hash) = self.block_hashes.get(number) {
358 return Ok(hash);
359 }
360
361 let hash = self
363 .database
364 .block_hash(number)
365 .map_err(EvmDatabaseError::Database)?;
366
367 self.block_hashes.insert(number, hash);
369
370 Ok(hash)
371 }
372}
373
374impl<DB: Database> DatabaseCommit for State<DB> {
375 fn commit(&mut self, changes: HashMap<Address, Account>) {
376 self.bal_state.commit(&changes);
377 let transitions = self.cache.apply_evm_state_iter(changes, |_, _| {});
378 if let Some(s) = self.transition_state.as_mut() {
379 s.add_transitions(transitions)
380 } else {
381 transitions.for_each(|_| {});
383 }
384 }
385
386 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
387 let transitions = self
388 .cache
389 .apply_evm_state_iter(changes, |address, account| {
390 self.bal_state.commit_one(*address, account);
391 });
392 if let Some(s) = self.transition_state.as_mut() {
393 s.add_transitions(transitions)
394 } else {
395 transitions.for_each(|_| {});
397 }
398 }
399}
400
401impl<DB: DatabaseRef> DatabaseRef for State<DB> {
402 type Error = EvmDatabaseError<DB::Error>;
403
404 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
405 let account_id = self.bal_state.get_account_id(&address)?;
407
408 let mut loaded_account = None;
410 if let Some(account) = self.cache.accounts.get(&address) {
411 loaded_account = Some(account.account_info());
412 };
413
414 if self.use_preloaded_bundle && loaded_account.is_none() {
416 if let Some(account) = self.bundle_state.account(&address) {
417 loaded_account = Some(account.account_info());
418 }
419 }
420
421 if loaded_account.is_none() {
423 loaded_account = Some(
424 self.database
425 .basic_ref(address)
426 .map_err(EvmDatabaseError::Database)?,
427 );
428 }
429
430 let mut account = loaded_account.unwrap();
432
433 if let Some(account_id) = account_id {
435 self.bal_state.basic_by_account_id(account_id, &mut account);
436 }
437 Ok(account)
438 }
439
440 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
441 if let Some(code) = self.cache.contracts.get(&code_hash) {
443 return Ok(code.clone());
444 }
445 if self.use_preloaded_bundle {
447 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
448 return Ok(code.clone());
449 }
450 }
451 self.database
453 .code_by_hash_ref(code_hash)
454 .map_err(EvmDatabaseError::Database)
455 }
456
457 fn storage_ref(
458 &self,
459 address: Address,
460 index: StorageKey,
461 ) -> Result<StorageValue, Self::Error> {
462 if let Some(storage) = self.bal_state.storage(&address, index)? {
464 return Ok(storage);
465 }
466
467 if let Some(account) = self.cache.accounts.get(&address) {
469 if let Some(plain_account) = &account.account {
470 if let Some(storage_value) = plain_account.storage.get(&index) {
472 return Ok(*storage_value);
473 }
474 if account.status.is_storage_known() {
477 return Ok(StorageValue::ZERO);
478 }
479 }
480 }
481
482 self.database
484 .storage_ref(address, index)
485 .map_err(EvmDatabaseError::Database)
486 }
487
488 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
489 if let Some(hash) = self.block_hashes.get(number) {
490 return Ok(hash);
491 }
492 self.database
494 .block_hash_ref(number)
495 .map_err(EvmDatabaseError::Database)
496 }
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502 use crate::{
503 states::{reverts::AccountInfoRevert, StorageSlot},
504 AccountRevert, AccountStatus, BundleAccount, RevertToSlot,
505 };
506 use primitives::{keccak256, BLOCK_HASH_HISTORY, U256};
507 #[test]
508 fn block_hash_cache() {
509 let mut state = State::builder().build();
510 state.block_hash(1u64).unwrap();
511 state.block_hash(2u64).unwrap();
512
513 let test_number = BLOCK_HASH_HISTORY + 2;
514
515 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
516 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
517 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
518
519 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
521 assert_eq!(state.block_hashes.get(2), Some(block2_hash));
522
523 state.block_hash(test_number).unwrap();
526
527 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
529 assert_eq!(state.block_hashes.get(2), None);
530 assert_eq!(state.block_hashes.get(test_number), Some(block_test_hash));
531 }
532
533 #[test]
538 fn block_hash_cache_block_zero() {
539 let mut state = State::builder().build();
540
541 assert_eq!(state.block_hashes.get(0), None);
543
544 let block0_hash = state.block_hash(0u64).unwrap();
546
547 let expected_hash = keccak256(U256::from(0).to_string().as_bytes());
549 assert_eq!(block0_hash, expected_hash);
550
551 assert_eq!(state.block_hashes.get(0), Some(expected_hash));
553 }
554 #[test]
561 fn reverts_preserve_old_values() {
562 let mut state = State::builder().with_bundle_update().build();
563
564 let (slot1, slot2, slot3) = (
565 StorageKey::from(1),
566 StorageKey::from(2),
567 StorageKey::from(3),
568 );
569
570 let new_account_address = Address::from_slice(&[0x1; 20]);
573 let new_account_created_info = AccountInfo {
574 nonce: 1,
575 balance: U256::from(1),
576 ..Default::default()
577 };
578 let new_account_changed_info = AccountInfo {
579 nonce: 2,
580 ..new_account_created_info.clone()
581 };
582 let new_account_changed_info2 = AccountInfo {
583 nonce: 3,
584 ..new_account_changed_info.clone()
585 };
586
587 let existing_account_address = Address::from_slice(&[0x2; 20]);
589 let existing_account_initial_info = AccountInfo {
590 nonce: 1,
591 ..Default::default()
592 };
593 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
594 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
597 let existing_account_changed_info = AccountInfo {
598 nonce: 2,
599 ..existing_account_initial_info.clone()
600 };
601
602 state.apply_transition(Vec::from([
604 (
605 new_account_address,
606 TransitionAccount {
607 status: AccountStatus::InMemoryChange,
608 info: Some(new_account_created_info.clone()),
609 previous_status: AccountStatus::LoadedNotExisting,
610 previous_info: None,
611 ..Default::default()
612 },
613 ),
614 (
615 existing_account_address,
616 TransitionAccount {
617 status: AccountStatus::InMemoryChange,
618 info: Some(existing_account_changed_info.clone()),
619 previous_status: AccountStatus::Loaded,
620 previous_info: Some(existing_account_initial_info.clone()),
621 storage: HashMap::from_iter([(
622 slot1,
623 StorageSlot::new_changed(
624 *existing_account_initial_storage.get(&slot1).unwrap(),
625 StorageValue::from(1000),
626 ),
627 )]),
628 storage_was_destroyed: false,
629 },
630 ),
631 ]));
632
633 state.apply_transition(Vec::from([(
635 new_account_address,
636 TransitionAccount {
637 status: AccountStatus::InMemoryChange,
638 info: Some(new_account_changed_info.clone()),
639 previous_status: AccountStatus::InMemoryChange,
640 previous_info: Some(new_account_created_info.clone()),
641 ..Default::default()
642 },
643 )]));
644
645 state.apply_transition(Vec::from([
647 (
648 new_account_address,
649 TransitionAccount {
650 status: AccountStatus::InMemoryChange,
651 info: Some(new_account_changed_info2.clone()),
652 previous_status: AccountStatus::InMemoryChange,
653 previous_info: Some(new_account_changed_info),
654 storage: HashMap::from_iter([(
655 slot1,
656 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
657 )]),
658 storage_was_destroyed: false,
659 },
660 ),
661 (
662 existing_account_address,
663 TransitionAccount {
664 status: AccountStatus::InMemoryChange,
665 info: Some(existing_account_changed_info.clone()),
666 previous_status: AccountStatus::InMemoryChange,
667 previous_info: Some(existing_account_changed_info.clone()),
668 storage: HashMap::from_iter([
669 (
670 slot1,
671 StorageSlot::new_changed(
672 StorageValue::from(100),
673 StorageValue::from(1_000),
674 ),
675 ),
676 (
677 slot2,
678 StorageSlot::new_changed(
679 *existing_account_initial_storage.get(&slot2).unwrap(),
680 StorageValue::from(2_000),
681 ),
682 ),
683 (
685 slot3,
686 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)),
687 ),
688 ]),
689 storage_was_destroyed: false,
690 },
691 ),
692 ]));
693
694 state.merge_transitions(BundleRetention::Reverts);
695 let mut bundle_state = state.take_bundle();
696
697 bundle_state.reverts.sort();
700 assert_eq!(
701 bundle_state.reverts.as_ref(),
702 Vec::from([Vec::from([
703 (
704 new_account_address,
705 AccountRevert {
706 account: AccountInfoRevert::DeleteIt,
707 previous_status: AccountStatus::LoadedNotExisting,
708 storage: HashMap::from_iter([(
709 slot1,
710 RevertToSlot::Some(StorageValue::ZERO)
711 )]),
712 wipe_storage: false,
713 }
714 ),
715 (
716 existing_account_address,
717 AccountRevert {
718 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
719 previous_status: AccountStatus::Loaded,
720 storage: HashMap::from_iter([
721 (
722 slot1,
723 RevertToSlot::Some(
724 *existing_account_initial_storage.get(&slot1).unwrap()
725 )
726 ),
727 (
728 slot2,
729 RevertToSlot::Some(
730 *existing_account_initial_storage.get(&slot2).unwrap()
731 )
732 ),
733 (slot3, RevertToSlot::Some(StorageValue::ZERO))
734 ]),
735 wipe_storage: false,
736 }
737 ),
738 ])]),
739 "The account or storage reverts are incorrect"
740 );
741
742 assert_eq!(
745 bundle_state.account(&new_account_address),
746 Some(&BundleAccount {
747 info: Some(new_account_changed_info2),
748 original_info: None,
749 status: AccountStatus::InMemoryChange,
750 storage: HashMap::from_iter([(
751 slot1,
752 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
753 )]),
754 }),
755 "The latest state of the new account is incorrect"
756 );
757
758 assert_eq!(
761 bundle_state.account(&existing_account_address),
762 Some(&BundleAccount {
763 info: Some(existing_account_changed_info),
764 original_info: Some(existing_account_initial_info),
765 status: AccountStatus::InMemoryChange,
766 storage: HashMap::from_iter([
767 (
768 slot1,
769 StorageSlot::new_changed(
770 *existing_account_initial_storage.get(&slot1).unwrap(),
771 StorageValue::from(1_000)
772 )
773 ),
774 (
775 slot2,
776 StorageSlot::new_changed(
777 *existing_account_initial_storage.get(&slot2).unwrap(),
778 StorageValue::from(2_000)
779 )
780 ),
781 (
783 slot3,
784 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
785 ),
786 ]),
787 }),
788 "The latest state of the existing account is incorrect"
789 );
790 }
791
792 #[test]
795 fn bundle_scoped_reverts_collapse() {
796 let mut state = State::builder().with_bundle_update().build();
797
798 let new_account_address = Address::from_slice(&[0x1; 20]);
800 let new_account_created_info = AccountInfo {
801 nonce: 1,
802 balance: U256::from(1),
803 ..Default::default()
804 };
805
806 let existing_account_address = Address::from_slice(&[0x2; 20]);
808 let existing_account_initial_info = AccountInfo {
809 nonce: 1,
810 ..Default::default()
811 };
812 let existing_account_updated_info = AccountInfo {
813 nonce: 1,
814 balance: U256::from(1),
815 ..Default::default()
816 };
817
818 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
820 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
821 let existing_account_with_storage_info = AccountInfo {
822 nonce: 1,
823 ..Default::default()
824 };
825 state.apply_transition(Vec::from([
827 (
828 new_account_address,
829 TransitionAccount {
830 status: AccountStatus::InMemoryChange,
831 info: Some(new_account_created_info.clone()),
832 previous_status: AccountStatus::LoadedNotExisting,
833 previous_info: None,
834 ..Default::default()
835 },
836 ),
837 (
838 existing_account_address,
839 TransitionAccount {
840 status: AccountStatus::Changed,
841 info: Some(existing_account_updated_info.clone()),
842 previous_status: AccountStatus::Loaded,
843 previous_info: Some(existing_account_initial_info.clone()),
844 ..Default::default()
845 },
846 ),
847 (
848 existing_account_with_storage_address,
849 TransitionAccount {
850 status: AccountStatus::Changed,
851 info: Some(existing_account_with_storage_info.clone()),
852 previous_status: AccountStatus::Loaded,
853 previous_info: Some(existing_account_with_storage_info.clone()),
854 storage: HashMap::from_iter([
855 (
856 slot1,
857 StorageSlot::new_changed(StorageValue::from(1), StorageValue::from(10)),
858 ),
859 (
860 slot2,
861 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(20)),
862 ),
863 ]),
864 storage_was_destroyed: false,
865 },
866 ),
867 ]));
868
869 state.apply_transition(Vec::from([
871 (
872 new_account_address,
873 TransitionAccount {
874 status: AccountStatus::Destroyed,
875 info: None,
876 previous_status: AccountStatus::InMemoryChange,
877 previous_info: Some(new_account_created_info),
878 ..Default::default()
879 },
880 ),
881 (
882 existing_account_address,
883 TransitionAccount {
884 status: AccountStatus::Changed,
885 info: Some(existing_account_initial_info),
886 previous_status: AccountStatus::Changed,
887 previous_info: Some(existing_account_updated_info),
888 ..Default::default()
889 },
890 ),
891 (
892 existing_account_with_storage_address,
893 TransitionAccount {
894 status: AccountStatus::Changed,
895 info: Some(existing_account_with_storage_info.clone()),
896 previous_status: AccountStatus::Changed,
897 previous_info: Some(existing_account_with_storage_info.clone()),
898 storage: HashMap::from_iter([
899 (
900 slot1,
901 StorageSlot::new_changed(StorageValue::from(10), StorageValue::from(1)),
902 ),
903 (
904 slot2,
905 StorageSlot::new_changed(StorageValue::from(20), StorageValue::ZERO),
906 ),
907 ]),
908 storage_was_destroyed: false,
909 },
910 ),
911 ]));
912
913 state.merge_transitions(BundleRetention::Reverts);
914
915 let mut bundle_state = state.take_bundle();
916 bundle_state.reverts.sort();
917
918 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
921 }
922
923 #[test]
925 fn selfdestruct_state_and_reverts() {
926 let mut state = State::builder().with_bundle_update().build();
927
928 let existing_account_address = Address::from_slice(&[0x1; 20]);
930 let existing_account_info = AccountInfo {
931 nonce: 1,
932 ..Default::default()
933 };
934
935 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
936
937 state.apply_transition(Vec::from([(
939 existing_account_address,
940 TransitionAccount {
941 status: AccountStatus::Destroyed,
942 info: None,
943 previous_status: AccountStatus::Loaded,
944 previous_info: Some(existing_account_info.clone()),
945 storage: HashMap::default(),
946 storage_was_destroyed: true,
947 },
948 )]));
949
950 state.apply_transition(Vec::from([(
952 existing_account_address,
953 TransitionAccount {
954 status: AccountStatus::DestroyedChanged,
955 info: Some(existing_account_info.clone()),
956 previous_status: AccountStatus::Destroyed,
957 previous_info: None,
958 storage: HashMap::from_iter([(
959 slot1,
960 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
961 )]),
962 storage_was_destroyed: false,
963 },
964 )]));
965
966 state.apply_transition(Vec::from([(
968 existing_account_address,
969 TransitionAccount {
970 status: AccountStatus::DestroyedAgain,
971 info: None,
972 previous_status: AccountStatus::DestroyedChanged,
973 previous_info: Some(existing_account_info.clone()),
974 storage: HashMap::default(),
976 storage_was_destroyed: true,
977 },
978 )]));
979
980 state.apply_transition(Vec::from([(
982 existing_account_address,
983 TransitionAccount {
984 status: AccountStatus::DestroyedChanged,
985 info: Some(existing_account_info.clone()),
986 previous_status: AccountStatus::DestroyedAgain,
987 previous_info: None,
988 storage: HashMap::from_iter([(
989 slot2,
990 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)),
991 )]),
992 storage_was_destroyed: false,
993 },
994 )]));
995
996 state.merge_transitions(BundleRetention::Reverts);
997
998 let bundle_state = state.take_bundle();
999
1000 assert_eq!(
1001 bundle_state.state,
1002 HashMap::from_iter([(
1003 existing_account_address,
1004 BundleAccount {
1005 info: Some(existing_account_info.clone()),
1006 original_info: Some(existing_account_info.clone()),
1007 storage: HashMap::from_iter([(
1008 slot2,
1009 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1010 )]),
1011 status: AccountStatus::DestroyedChanged,
1012 }
1013 )])
1014 );
1015
1016 assert_eq!(
1017 bundle_state.reverts.as_ref(),
1018 Vec::from([Vec::from([(
1019 existing_account_address,
1020 AccountRevert {
1021 account: AccountInfoRevert::DoNothing,
1022 previous_status: AccountStatus::Loaded,
1023 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1024 wipe_storage: true,
1025 }
1026 )])])
1027 )
1028 }
1029}