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, BlockAccessIndex},
15 Account, AccountId, 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: BlockAccessIndex) {
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
297 .basic_by_account_id(account_id, &mut basic)
298 .map_err(EvmDatabaseError::Bal)?;
299 }
300 Ok(basic)
301 }
302
303 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
304 let res = match self.cache.contracts.entry(code_hash) {
305 hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
306 hash_map::Entry::Vacant(entry) => {
307 if self.use_preloaded_bundle {
308 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
309 entry.insert(code.clone());
310 return Ok(code.clone());
311 }
312 }
313 let code = self
315 .database
316 .code_by_hash(code_hash)
317 .map_err(EvmDatabaseError::Database)?;
318 entry.insert(code.clone());
319 Ok(code)
320 }
321 };
322 res
323 }
324
325 fn storage(
326 &mut self,
327 address: Address,
328 index: StorageKey,
329 ) -> Result<StorageValue, Self::Error> {
330 if let Some(storage) = self
331 .bal_state
332 .storage(&address, index)
333 .map_err(EvmDatabaseError::Bal)?
334 {
335 return Ok(storage);
337 }
338 self.storage(address, index)
339 .map_err(EvmDatabaseError::Database)
340 }
341
342 fn storage_by_account_id(
343 &mut self,
344 address: Address,
345 account_id: AccountId,
346 key: StorageKey,
347 ) -> Result<StorageValue, Self::Error> {
348 if let Some(storage) = self.bal_state.storage_by_account_id(account_id, key)? {
349 return Ok(storage);
350 }
351
352 self.storage(address, key)
353 .map_err(EvmDatabaseError::Database)
354 }
355
356 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
357 if let Some(hash) = self.block_hashes.get(number) {
359 return Ok(hash);
360 }
361
362 let hash = self
364 .database
365 .block_hash(number)
366 .map_err(EvmDatabaseError::Database)?;
367
368 self.block_hashes.insert(number, hash);
370
371 Ok(hash)
372 }
373}
374
375impl<DB: Database> DatabaseCommit for State<DB> {
376 fn commit(&mut self, changes: AddressMap<Account>) {
377 self.bal_state.commit(&changes);
378 let transitions = self.cache.apply_evm_state_iter(changes, |_, _| {});
379 if let Some(s) = self.transition_state.as_mut() {
380 s.add_transitions(transitions)
381 } else {
382 transitions.for_each(|_| {});
384 }
385 }
386
387 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
388 let transitions = self
389 .cache
390 .apply_evm_state_iter(changes, |address, account| {
391 self.bal_state.commit_one(*address, account);
392 });
393 if let Some(s) = self.transition_state.as_mut() {
394 s.add_transitions(transitions)
395 } else {
396 transitions.for_each(|_| {});
398 }
399 }
400}
401
402impl<DB: DatabaseRef> DatabaseRef for State<DB> {
403 type Error = EvmDatabaseError<DB::Error>;
404
405 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
406 let account_id = self.bal_state.get_account_id(&address)?;
408
409 let mut loaded_account = None;
411 if let Some(account) = self.cache.accounts.get(&address) {
412 loaded_account = Some(account.account_info());
413 };
414
415 if self.use_preloaded_bundle && loaded_account.is_none() {
417 if let Some(account) = self.bundle_state.account(&address) {
418 loaded_account = Some(account.account_info());
419 }
420 }
421
422 if loaded_account.is_none() {
424 loaded_account = Some(
425 self.database
426 .basic_ref(address)
427 .map_err(EvmDatabaseError::Database)?,
428 );
429 }
430
431 let mut account = loaded_account.unwrap();
433
434 if let Some(account_id) = account_id {
436 self.bal_state
437 .basic_by_account_id(account_id, &mut account)
438 .map_err(EvmDatabaseError::Bal)?;
439 }
440 Ok(account)
441 }
442
443 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
444 if let Some(code) = self.cache.contracts.get(&code_hash) {
446 return Ok(code.clone());
447 }
448 if self.use_preloaded_bundle {
450 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
451 return Ok(code.clone());
452 }
453 }
454 self.database
456 .code_by_hash_ref(code_hash)
457 .map_err(EvmDatabaseError::Database)
458 }
459
460 fn storage_ref(
461 &self,
462 address: Address,
463 index: StorageKey,
464 ) -> Result<StorageValue, Self::Error> {
465 if let Some(storage) = self.bal_state.storage(&address, index)? {
467 return Ok(storage);
468 }
469
470 if let Some(account) = self.cache.accounts.get(&address) {
472 if let Some(plain_account) = &account.account {
473 if let Some(storage_value) = plain_account.storage.get(&index) {
475 return Ok(*storage_value);
476 }
477 if account.status.is_storage_known() {
480 return Ok(StorageValue::ZERO);
481 }
482 }
483 }
484
485 self.database
487 .storage_ref(address, index)
488 .map_err(EvmDatabaseError::Database)
489 }
490
491 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
492 if let Some(hash) = self.block_hashes.get(number) {
493 return Ok(hash);
494 }
495 self.database
497 .block_hash_ref(number)
498 .map_err(EvmDatabaseError::Database)
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505 use crate::{
506 states::{reverts::AccountInfoRevert, StorageSlot},
507 AccountRevert, AccountStatus, BundleAccount, RevertToSlot,
508 };
509 use primitives::{keccak256, BLOCK_HASH_HISTORY, U256};
510 #[test]
511 fn has_bal_helper() {
512 let state = State::builder().build();
513 assert!(!state.has_bal());
514
515 let state = State::builder().with_bal(Arc::new(Bal::new())).build();
516 assert!(state.has_bal());
517 }
518
519 #[test]
520 fn block_hash_cache() {
521 let mut state = State::builder().build();
522 state.block_hash(1u64).unwrap();
523 state.block_hash(2u64).unwrap();
524
525 let test_number = BLOCK_HASH_HISTORY + 2;
526
527 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
528 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
529 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
530
531 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
533 assert_eq!(state.block_hashes.get(2), Some(block2_hash));
534
535 state.block_hash(test_number).unwrap();
538
539 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
541 assert_eq!(state.block_hashes.get(2), None);
542 assert_eq!(state.block_hashes.get(test_number), Some(block_test_hash));
543 }
544
545 #[test]
550 fn block_hash_cache_block_zero() {
551 let mut state = State::builder().build();
552
553 assert_eq!(state.block_hashes.get(0), None);
555
556 let block0_hash = state.block_hash(0u64).unwrap();
558
559 let expected_hash = keccak256(U256::from(0).to_string().as_bytes());
561 assert_eq!(block0_hash, expected_hash);
562
563 assert_eq!(state.block_hashes.get(0), Some(expected_hash));
565 }
566 #[test]
573 fn reverts_preserve_old_values() {
574 let mut state = State::builder().with_bundle_update().build();
575
576 let (slot1, slot2, slot3) = (
577 StorageKey::from(1),
578 StorageKey::from(2),
579 StorageKey::from(3),
580 );
581
582 let new_account_address = Address::from_slice(&[0x1; 20]);
585 let new_account_created_info = AccountInfo {
586 nonce: 1,
587 balance: U256::from(1),
588 ..Default::default()
589 };
590 let new_account_changed_info = AccountInfo {
591 nonce: 2,
592 ..new_account_created_info.clone()
593 };
594 let new_account_changed_info2 = AccountInfo {
595 nonce: 3,
596 ..new_account_changed_info.clone()
597 };
598
599 let existing_account_address = Address::from_slice(&[0x2; 20]);
601 let existing_account_initial_info = AccountInfo {
602 nonce: 1,
603 ..Default::default()
604 };
605 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
606 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
609 let existing_account_changed_info = AccountInfo {
610 nonce: 2,
611 ..existing_account_initial_info.clone()
612 };
613
614 state.apply_transition(Vec::from([
616 (
617 new_account_address,
618 TransitionAccount {
619 status: AccountStatus::InMemoryChange,
620 info: Some(new_account_created_info.clone()),
621 previous_status: AccountStatus::LoadedNotExisting,
622 previous_info: None,
623 ..Default::default()
624 },
625 ),
626 (
627 existing_account_address,
628 TransitionAccount {
629 status: AccountStatus::InMemoryChange,
630 info: Some(existing_account_changed_info.clone()),
631 previous_status: AccountStatus::Loaded,
632 previous_info: Some(existing_account_initial_info.clone()),
633 storage: HashMap::from_iter([(
634 slot1,
635 StorageSlot::new_changed(
636 *existing_account_initial_storage.get(&slot1).unwrap(),
637 StorageValue::from(1000),
638 ),
639 )]),
640 storage_was_destroyed: false,
641 },
642 ),
643 ]));
644
645 state.apply_transition(Vec::from([(
647 new_account_address,
648 TransitionAccount {
649 status: AccountStatus::InMemoryChange,
650 info: Some(new_account_changed_info.clone()),
651 previous_status: AccountStatus::InMemoryChange,
652 previous_info: Some(new_account_created_info.clone()),
653 ..Default::default()
654 },
655 )]));
656
657 state.apply_transition(Vec::from([
659 (
660 new_account_address,
661 TransitionAccount {
662 status: AccountStatus::InMemoryChange,
663 info: Some(new_account_changed_info2.clone()),
664 previous_status: AccountStatus::InMemoryChange,
665 previous_info: Some(new_account_changed_info),
666 storage: HashMap::from_iter([(
667 slot1,
668 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
669 )]),
670 storage_was_destroyed: false,
671 },
672 ),
673 (
674 existing_account_address,
675 TransitionAccount {
676 status: AccountStatus::InMemoryChange,
677 info: Some(existing_account_changed_info.clone()),
678 previous_status: AccountStatus::InMemoryChange,
679 previous_info: Some(existing_account_changed_info.clone()),
680 storage: HashMap::from_iter([
681 (
682 slot1,
683 StorageSlot::new_changed(
684 StorageValue::from(100),
685 StorageValue::from(1_000),
686 ),
687 ),
688 (
689 slot2,
690 StorageSlot::new_changed(
691 *existing_account_initial_storage.get(&slot2).unwrap(),
692 StorageValue::from(2_000),
693 ),
694 ),
695 (
697 slot3,
698 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)),
699 ),
700 ]),
701 storage_was_destroyed: false,
702 },
703 ),
704 ]));
705
706 state.merge_transitions(BundleRetention::Reverts);
707 let mut bundle_state = state.take_bundle();
708
709 bundle_state.reverts.sort();
712 assert_eq!(
713 bundle_state.reverts.as_ref(),
714 Vec::from([Vec::from([
715 (
716 new_account_address,
717 AccountRevert {
718 account: AccountInfoRevert::DeleteIt,
719 previous_status: AccountStatus::LoadedNotExisting,
720 storage: HashMap::from_iter([(
721 slot1,
722 RevertToSlot::Some(StorageValue::ZERO)
723 )]),
724 wipe_storage: false,
725 }
726 ),
727 (
728 existing_account_address,
729 AccountRevert {
730 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
731 previous_status: AccountStatus::Loaded,
732 storage: HashMap::from_iter([
733 (
734 slot1,
735 RevertToSlot::Some(
736 *existing_account_initial_storage.get(&slot1).unwrap()
737 )
738 ),
739 (
740 slot2,
741 RevertToSlot::Some(
742 *existing_account_initial_storage.get(&slot2).unwrap()
743 )
744 ),
745 (slot3, RevertToSlot::Some(StorageValue::ZERO))
746 ]),
747 wipe_storage: false,
748 }
749 ),
750 ])]),
751 "The account or storage reverts are incorrect"
752 );
753
754 assert_eq!(
757 bundle_state.account(&new_account_address),
758 Some(&BundleAccount {
759 info: Some(new_account_changed_info2),
760 original_info: None,
761 status: AccountStatus::InMemoryChange,
762 storage: HashMap::from_iter([(
763 slot1,
764 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
765 )]),
766 }),
767 "The latest state of the new account is incorrect"
768 );
769
770 assert_eq!(
773 bundle_state.account(&existing_account_address),
774 Some(&BundleAccount {
775 info: Some(existing_account_changed_info),
776 original_info: Some(existing_account_initial_info),
777 status: AccountStatus::InMemoryChange,
778 storage: HashMap::from_iter([
779 (
780 slot1,
781 StorageSlot::new_changed(
782 *existing_account_initial_storage.get(&slot1).unwrap(),
783 StorageValue::from(1_000)
784 )
785 ),
786 (
787 slot2,
788 StorageSlot::new_changed(
789 *existing_account_initial_storage.get(&slot2).unwrap(),
790 StorageValue::from(2_000)
791 )
792 ),
793 (
795 slot3,
796 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
797 ),
798 ]),
799 }),
800 "The latest state of the existing account is incorrect"
801 );
802 }
803
804 #[test]
807 fn bundle_scoped_reverts_collapse() {
808 let mut state = State::builder().with_bundle_update().build();
809
810 let new_account_address = Address::from_slice(&[0x1; 20]);
812 let new_account_created_info = AccountInfo {
813 nonce: 1,
814 balance: U256::from(1),
815 ..Default::default()
816 };
817
818 let existing_account_address = Address::from_slice(&[0x2; 20]);
820 let existing_account_initial_info = AccountInfo {
821 nonce: 1,
822 ..Default::default()
823 };
824 let existing_account_updated_info = AccountInfo {
825 nonce: 1,
826 balance: U256::from(1),
827 ..Default::default()
828 };
829
830 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
832 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
833 let existing_account_with_storage_info = AccountInfo {
834 nonce: 1,
835 ..Default::default()
836 };
837 state.apply_transition(Vec::from([
839 (
840 new_account_address,
841 TransitionAccount {
842 status: AccountStatus::InMemoryChange,
843 info: Some(new_account_created_info.clone()),
844 previous_status: AccountStatus::LoadedNotExisting,
845 previous_info: None,
846 ..Default::default()
847 },
848 ),
849 (
850 existing_account_address,
851 TransitionAccount {
852 status: AccountStatus::Changed,
853 info: Some(existing_account_updated_info.clone()),
854 previous_status: AccountStatus::Loaded,
855 previous_info: Some(existing_account_initial_info.clone()),
856 ..Default::default()
857 },
858 ),
859 (
860 existing_account_with_storage_address,
861 TransitionAccount {
862 status: AccountStatus::Changed,
863 info: Some(existing_account_with_storage_info.clone()),
864 previous_status: AccountStatus::Loaded,
865 previous_info: Some(existing_account_with_storage_info.clone()),
866 storage: HashMap::from_iter([
867 (
868 slot1,
869 StorageSlot::new_changed(StorageValue::from(1), StorageValue::from(10)),
870 ),
871 (
872 slot2,
873 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(20)),
874 ),
875 ]),
876 storage_was_destroyed: false,
877 },
878 ),
879 ]));
880
881 state.apply_transition(Vec::from([
883 (
884 new_account_address,
885 TransitionAccount {
886 status: AccountStatus::Destroyed,
887 info: None,
888 previous_status: AccountStatus::InMemoryChange,
889 previous_info: Some(new_account_created_info),
890 ..Default::default()
891 },
892 ),
893 (
894 existing_account_address,
895 TransitionAccount {
896 status: AccountStatus::Changed,
897 info: Some(existing_account_initial_info),
898 previous_status: AccountStatus::Changed,
899 previous_info: Some(existing_account_updated_info),
900 ..Default::default()
901 },
902 ),
903 (
904 existing_account_with_storage_address,
905 TransitionAccount {
906 status: AccountStatus::Changed,
907 info: Some(existing_account_with_storage_info.clone()),
908 previous_status: AccountStatus::Changed,
909 previous_info: Some(existing_account_with_storage_info.clone()),
910 storage: HashMap::from_iter([
911 (
912 slot1,
913 StorageSlot::new_changed(StorageValue::from(10), StorageValue::from(1)),
914 ),
915 (
916 slot2,
917 StorageSlot::new_changed(StorageValue::from(20), StorageValue::ZERO),
918 ),
919 ]),
920 storage_was_destroyed: false,
921 },
922 ),
923 ]));
924
925 state.merge_transitions(BundleRetention::Reverts);
926
927 let mut bundle_state = state.take_bundle();
928 bundle_state.reverts.sort();
929
930 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
933 }
934
935 #[test]
937 fn selfdestruct_state_and_reverts() {
938 let mut state = State::builder().with_bundle_update().build();
939
940 let existing_account_address = Address::from_slice(&[0x1; 20]);
942 let existing_account_info = AccountInfo {
943 nonce: 1,
944 ..Default::default()
945 };
946
947 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
948
949 state.apply_transition(Vec::from([(
951 existing_account_address,
952 TransitionAccount {
953 status: AccountStatus::Destroyed,
954 info: None,
955 previous_status: AccountStatus::Loaded,
956 previous_info: Some(existing_account_info.clone()),
957 storage: HashMap::default(),
958 storage_was_destroyed: true,
959 },
960 )]));
961
962 state.apply_transition(Vec::from([(
964 existing_account_address,
965 TransitionAccount {
966 status: AccountStatus::DestroyedChanged,
967 info: Some(existing_account_info.clone()),
968 previous_status: AccountStatus::Destroyed,
969 previous_info: None,
970 storage: HashMap::from_iter([(
971 slot1,
972 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)),
973 )]),
974 storage_was_destroyed: false,
975 },
976 )]));
977
978 state.apply_transition(Vec::from([(
980 existing_account_address,
981 TransitionAccount {
982 status: AccountStatus::DestroyedAgain,
983 info: None,
984 previous_status: AccountStatus::DestroyedChanged,
985 previous_info: Some(existing_account_info.clone()),
986 storage: HashMap::default(),
988 storage_was_destroyed: true,
989 },
990 )]));
991
992 state.apply_transition(Vec::from([(
994 existing_account_address,
995 TransitionAccount {
996 status: AccountStatus::DestroyedChanged,
997 info: Some(existing_account_info.clone()),
998 previous_status: AccountStatus::DestroyedAgain,
999 previous_info: None,
1000 storage: HashMap::from_iter([(
1001 slot2,
1002 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)),
1003 )]),
1004 storage_was_destroyed: false,
1005 },
1006 )]));
1007
1008 state.merge_transitions(BundleRetention::Reverts);
1009
1010 let bundle_state = state.take_bundle();
1011
1012 assert_eq!(
1013 bundle_state.state,
1014 HashMap::from_iter([(
1015 existing_account_address,
1016 BundleAccount {
1017 info: Some(existing_account_info.clone()),
1018 original_info: Some(existing_account_info.clone()),
1019 storage: HashMap::from_iter([(
1020 slot2,
1021 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1022 )]),
1023 status: AccountStatus::DestroyedChanged,
1024 }
1025 )])
1026 );
1027
1028 assert_eq!(
1029 bundle_state.reverts.as_ref(),
1030 Vec::from([Vec::from([(
1031 existing_account_address,
1032 AccountRevert {
1033 account: AccountInfoRevert::DoNothing,
1034 previous_status: AccountStatus::Loaded,
1035 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1036 wipe_storage: true,
1037 }
1038 )])])
1039 )
1040 }
1041}