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