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 const 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 const fn bump_bal_index(&mut self) {
216 self.bal_state.bump_bal_index();
217 }
218
219 #[inline]
221 pub const fn set_bal_index(&mut self, index: u64) {
222 self.bal_state.bal_index = index;
223 }
224
225 #[inline]
227 pub const 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 pub const fn has_bal(&self) -> bool {
240 self.bal_state.bal.is_some()
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 has_bal_helper() {
508 let state = State::builder().build();
509 assert!(!state.has_bal());
510
511 let state = State::builder().with_bal(Arc::new(Bal::new())).build();
512 assert!(state.has_bal());
513 }
514
515 #[test]
516 fn block_hash_cache() {
517 let mut state = State::builder().build();
518 state.block_hash(1u64).unwrap();
519 state.block_hash(2u64).unwrap();
520
521 let test_number = BLOCK_HASH_HISTORY + 2;
522
523 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
524 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
525 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
526
527 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
529 assert_eq!(state.block_hashes.get(2), Some(block2_hash));
530
531 state.block_hash(test_number).unwrap();
534
535 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
537 assert_eq!(state.block_hashes.get(2), None);
538 assert_eq!(state.block_hashes.get(test_number), Some(block_test_hash));
539 }
540
541 #[test]
546 fn block_hash_cache_block_zero() {
547 let mut state = State::builder().build();
548
549 assert_eq!(state.block_hashes.get(0), None);
551
552 let block0_hash = state.block_hash(0u64).unwrap();
554
555 let expected_hash = keccak256(U256::from(0).to_string().as_bytes());
557 assert_eq!(block0_hash, expected_hash);
558
559 assert_eq!(state.block_hashes.get(0), Some(expected_hash));
561 }
562 #[test]
569 fn reverts_preserve_old_values() {
570 let mut state = State::builder().with_bundle_update().build();
571
572 let (slot1, slot2, slot3) = (
573 StorageKey::from(1),
574 StorageKey::from(2),
575 StorageKey::from(3),
576 );
577
578 let new_account_address = Address::from_slice(&[0x1; 20]);
581 let new_account_created_info = AccountInfo {
582 nonce: 1,
583 balance: U256::from(1),
584 ..Default::default()
585 };
586 let new_account_changed_info = AccountInfo {
587 nonce: 2,
588 ..new_account_created_info.clone()
589 };
590 let new_account_changed_info2 = AccountInfo {
591 nonce: 3,
592 ..new_account_changed_info.clone()
593 };
594
595 let existing_account_address = Address::from_slice(&[0x2; 20]);
597 let existing_account_initial_info = AccountInfo {
598 nonce: 1,
599 ..Default::default()
600 };
601 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
602 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
605 let existing_account_changed_info = AccountInfo {
606 nonce: 2,
607 ..existing_account_initial_info.clone()
608 };
609
610 state.apply_transition(Vec::from([
612 (
613 new_account_address,
614 TransitionAccount {
615 status: AccountStatus::InMemoryChange,
616 info: Some(new_account_created_info.clone()),
617 previous_status: AccountStatus::LoadedNotExisting,
618 previous_info: None,
619 ..Default::default()
620 },
621 ),
622 (
623 existing_account_address,
624 TransitionAccount {
625 status: AccountStatus::InMemoryChange,
626 info: Some(existing_account_changed_info.clone()),
627 previous_status: AccountStatus::Loaded,
628 previous_info: Some(existing_account_initial_info.clone()),
629 storage: HashMap::from_iter([(
630 slot1,
631 StorageSlot::new_changed(
632 *existing_account_initial_storage.get(&slot1).unwrap(),
633 StorageValue::from(1000),
634 ),
635 )]),
636 storage_was_destroyed: false,
637 },
638 ),
639 ]));
640
641 state.apply_transition(Vec::from([(
643 new_account_address,
644 TransitionAccount {
645 status: AccountStatus::InMemoryChange,
646 info: Some(new_account_changed_info.clone()),
647 previous_status: AccountStatus::InMemoryChange,
648 previous_info: Some(new_account_created_info.clone()),
649 ..Default::default()
650 },
651 )]));
652
653 state.apply_transition(Vec::from([
655 (
656 new_account_address,
657 TransitionAccount {
658 status: AccountStatus::InMemoryChange,
659 info: Some(new_account_changed_info2.clone()),
660 previous_status: AccountStatus::InMemoryChange,
661 previous_info: Some(new_account_changed_info),
662 storage: HashMap::from_iter([(
663 slot1,
664 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
665 )]),
666 storage_was_destroyed: false,
667 },
668 ),
669 (
670 existing_account_address,
671 TransitionAccount {
672 status: AccountStatus::InMemoryChange,
673 info: Some(existing_account_changed_info.clone()),
674 previous_status: AccountStatus::InMemoryChange,
675 previous_info: Some(existing_account_changed_info.clone()),
676 storage: HashMap::from_iter([
677 (
678 slot1,
679 StorageSlot::new_changed(
680 StorageValue::from(100),
681 StorageValue::from(1_000),
682 ),
683 ),
684 (
685 slot2,
686 StorageSlot::new_changed(
687 *existing_account_initial_storage.get(&slot2).unwrap(),
688 StorageValue::from(2_000),
689 ),
690 ),
691 (
693 slot3,
694 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)),
695 ),
696 ]),
697 storage_was_destroyed: false,
698 },
699 ),
700 ]));
701
702 state.merge_transitions(BundleRetention::Reverts);
703 let mut bundle_state = state.take_bundle();
704
705 bundle_state.reverts.sort();
708 assert_eq!(
709 bundle_state.reverts.as_ref(),
710 Vec::from([Vec::from([
711 (
712 new_account_address,
713 AccountRevert {
714 account: AccountInfoRevert::DeleteIt,
715 previous_status: AccountStatus::LoadedNotExisting,
716 storage: HashMap::from_iter([(
717 slot1,
718 RevertToSlot::Some(StorageValue::ZERO)
719 )]),
720 wipe_storage: false,
721 }
722 ),
723 (
724 existing_account_address,
725 AccountRevert {
726 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
727 previous_status: AccountStatus::Loaded,
728 storage: HashMap::from_iter([
729 (
730 slot1,
731 RevertToSlot::Some(
732 *existing_account_initial_storage.get(&slot1).unwrap()
733 )
734 ),
735 (
736 slot2,
737 RevertToSlot::Some(
738 *existing_account_initial_storage.get(&slot2).unwrap()
739 )
740 ),
741 (slot3, RevertToSlot::Some(StorageValue::ZERO))
742 ]),
743 wipe_storage: false,
744 }
745 ),
746 ])]),
747 "The account or storage reverts are incorrect"
748 );
749
750 assert_eq!(
753 bundle_state.account(&new_account_address),
754 Some(&BundleAccount {
755 info: Some(new_account_changed_info2),
756 original_info: None,
757 status: AccountStatus::InMemoryChange,
758 storage: HashMap::from_iter([(
759 slot1,
760 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
761 )]),
762 }),
763 "The latest state of the new account is incorrect"
764 );
765
766 assert_eq!(
769 bundle_state.account(&existing_account_address),
770 Some(&BundleAccount {
771 info: Some(existing_account_changed_info),
772 original_info: Some(existing_account_initial_info),
773 status: AccountStatus::InMemoryChange,
774 storage: HashMap::from_iter([
775 (
776 slot1,
777 StorageSlot::new_changed(
778 *existing_account_initial_storage.get(&slot1).unwrap(),
779 StorageValue::from(1_000)
780 )
781 ),
782 (
783 slot2,
784 StorageSlot::new_changed(
785 *existing_account_initial_storage.get(&slot2).unwrap(),
786 StorageValue::from(2_000)
787 )
788 ),
789 (
791 slot3,
792 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
793 ),
794 ]),
795 }),
796 "The latest state of the existing account is incorrect"
797 );
798 }
799
800 #[test]
803 fn bundle_scoped_reverts_collapse() {
804 let mut state = State::builder().with_bundle_update().build();
805
806 let new_account_address = Address::from_slice(&[0x1; 20]);
808 let new_account_created_info = AccountInfo {
809 nonce: 1,
810 balance: U256::from(1),
811 ..Default::default()
812 };
813
814 let existing_account_address = Address::from_slice(&[0x2; 20]);
816 let existing_account_initial_info = AccountInfo {
817 nonce: 1,
818 ..Default::default()
819 };
820 let existing_account_updated_info = AccountInfo {
821 nonce: 1,
822 balance: U256::from(1),
823 ..Default::default()
824 };
825
826 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
828 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
829 let existing_account_with_storage_info = AccountInfo {
830 nonce: 1,
831 ..Default::default()
832 };
833 state.apply_transition(Vec::from([
835 (
836 new_account_address,
837 TransitionAccount {
838 status: AccountStatus::InMemoryChange,
839 info: Some(new_account_created_info.clone()),
840 previous_status: AccountStatus::LoadedNotExisting,
841 previous_info: None,
842 ..Default::default()
843 },
844 ),
845 (
846 existing_account_address,
847 TransitionAccount {
848 status: AccountStatus::Changed,
849 info: Some(existing_account_updated_info.clone()),
850 previous_status: AccountStatus::Loaded,
851 previous_info: Some(existing_account_initial_info.clone()),
852 ..Default::default()
853 },
854 ),
855 (
856 existing_account_with_storage_address,
857 TransitionAccount {
858 status: AccountStatus::Changed,
859 info: Some(existing_account_with_storage_info.clone()),
860 previous_status: AccountStatus::Loaded,
861 previous_info: Some(existing_account_with_storage_info.clone()),
862 storage: HashMap::from_iter([
863 (
864 slot1,
865 StorageSlot::new_changed(StorageValue::from(1), StorageValue::from(10)),
866 ),
867 (
868 slot2,
869 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(20)),
870 ),
871 ]),
872 storage_was_destroyed: false,
873 },
874 ),
875 ]));
876
877 state.apply_transition(Vec::from([
879 (
880 new_account_address,
881 TransitionAccount {
882 status: AccountStatus::Destroyed,
883 info: None,
884 previous_status: AccountStatus::InMemoryChange,
885 previous_info: Some(new_account_created_info),
886 ..Default::default()
887 },
888 ),
889 (
890 existing_account_address,
891 TransitionAccount {
892 status: AccountStatus::Changed,
893 info: Some(existing_account_initial_info),
894 previous_status: AccountStatus::Changed,
895 previous_info: Some(existing_account_updated_info),
896 ..Default::default()
897 },
898 ),
899 (
900 existing_account_with_storage_address,
901 TransitionAccount {
902 status: AccountStatus::Changed,
903 info: Some(existing_account_with_storage_info.clone()),
904 previous_status: AccountStatus::Changed,
905 previous_info: Some(existing_account_with_storage_info.clone()),
906 storage: HashMap::from_iter([
907 (
908 slot1,
909 StorageSlot::new_changed(StorageValue::from(10), StorageValue::from(1)),
910 ),
911 (
912 slot2,
913 StorageSlot::new_changed(StorageValue::from(20), StorageValue::ZERO),
914 ),
915 ]),
916 storage_was_destroyed: false,
917 },
918 ),
919 ]));
920
921 state.merge_transitions(BundleRetention::Reverts);
922
923 let mut bundle_state = state.take_bundle();
924 bundle_state.reverts.sort();
925
926 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
929 }
930
931 #[test]
933 fn selfdestruct_state_and_reverts() {
934 let mut state = State::builder().with_bundle_update().build();
935
936 let existing_account_address = Address::from_slice(&[0x1; 20]);
938 let existing_account_info = AccountInfo {
939 nonce: 1,
940 ..Default::default()
941 };
942
943 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
944
945 state.apply_transition(Vec::from([(
947 existing_account_address,
948 TransitionAccount {
949 status: AccountStatus::Destroyed,
950 info: None,
951 previous_status: AccountStatus::Loaded,
952 previous_info: Some(existing_account_info.clone()),
953 storage: HashMap::default(),
954 storage_was_destroyed: true,
955 },
956 )]));
957
958 state.apply_transition(Vec::from([(
960 existing_account_address,
961 TransitionAccount {
962 status: AccountStatus::DestroyedChanged,
963 info: Some(existing_account_info.clone()),
964 previous_status: AccountStatus::Destroyed,
965 previous_info: None,
966 storage: HashMap::from_iter([(
967 slot1,
968 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
969 )]),
970 storage_was_destroyed: false,
971 },
972 )]));
973
974 state.apply_transition(Vec::from([(
976 existing_account_address,
977 TransitionAccount {
978 status: AccountStatus::DestroyedAgain,
979 info: None,
980 previous_status: AccountStatus::DestroyedChanged,
981 previous_info: Some(existing_account_info.clone()),
982 storage: HashMap::default(),
984 storage_was_destroyed: true,
985 },
986 )]));
987
988 state.apply_transition(Vec::from([(
990 existing_account_address,
991 TransitionAccount {
992 status: AccountStatus::DestroyedChanged,
993 info: Some(existing_account_info.clone()),
994 previous_status: AccountStatus::DestroyedAgain,
995 previous_info: None,
996 storage: HashMap::from_iter([(
997 slot2,
998 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)),
999 )]),
1000 storage_was_destroyed: false,
1001 },
1002 )]));
1003
1004 state.merge_transitions(BundleRetention::Reverts);
1005
1006 let bundle_state = state.take_bundle();
1007
1008 assert_eq!(
1009 bundle_state.state,
1010 HashMap::from_iter([(
1011 existing_account_address,
1012 BundleAccount {
1013 info: Some(existing_account_info.clone()),
1014 original_info: Some(existing_account_info.clone()),
1015 storage: HashMap::from_iter([(
1016 slot2,
1017 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1018 )]),
1019 status: AccountStatus::DestroyedChanged,
1020 }
1021 )])
1022 );
1023
1024 assert_eq!(
1025 bundle_state.reverts.as_ref(),
1026 Vec::from([Vec::from([(
1027 existing_account_address,
1028 AccountRevert {
1029 account: AccountInfoRevert::DoNothing,
1030 previous_status: AccountStatus::Loaded,
1031 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1032 wipe_storage: true,
1033 }
1034 )])])
1035 )
1036 }
1037}