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, OnStateHook,
11};
12use primitives::{hash_map, Address, AddressMap, HashMap, StorageKey, StorageValue, B256};
13use state::{
14 bal::{alloy::AlloyBal, Bal, BlockAccessIndex},
15 Account, AccountId, AccountInfo, EvmStorage,
16};
17use std::{borrow::Cow, 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(derive_more::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 #[debug(skip)]
75 pub state_hook: Option<Box<dyn OnStateHook>>,
76}
77
78impl State<EmptyDB> {
80 pub fn builder() -> StateBuilder<EmptyDB> {
82 StateBuilder::default()
83 }
84}
85
86impl<DB: Database> State<DB> {
87 pub fn bundle_size_hint(&self) -> usize {
91 self.bundle_state.size_hint()
92 }
93
94 pub fn insert_not_existing(&mut self, address: Address) {
96 self.cache.insert_not_existing(address)
97 }
98
99 pub fn insert_account(&mut self, address: Address, info: AccountInfo) {
101 self.cache.insert_account(address, info)
102 }
103
104 pub fn insert_account_with_storage(
106 &mut self,
107 address: Address,
108 info: AccountInfo,
109 storage: PlainStorage,
110 ) {
111 self.cache
112 .insert_account_with_storage(address, info, storage)
113 }
114
115 pub fn apply_transition<'a>(
117 &mut self,
118 transitions: impl IntoIterator<Item = (Address, TransitionAccount<Option<Cow<'a, EvmStorage>>>)>,
119 ) {
120 if let Some(s) = self.transition_state.as_mut() {
122 s.add_transitions(transitions)
123 }
124 }
125
126 pub fn merge_transitions(&mut self, retention: BundleRetention) {
132 if let Some(transition_state) = self.transition_state.as_mut().map(TransitionState::take) {
133 self.bundle_state
134 .apply_transitions_and_create_reverts(transition_state, retention);
135 }
136 }
137
138 pub fn load_cache_account(&mut self, address: Address) -> Result<&mut CacheAccount, DB::Error> {
143 Self::load_cache_account_with(
144 &mut self.cache,
145 self.use_preloaded_bundle,
146 &self.bundle_state,
147 &mut self.database,
148 address,
149 )
150 }
151
152 fn load_cache_account_with<'a>(
160 cache: &'a mut CacheState,
161 use_preloaded_bundle: bool,
162 bundle_state: &BundleState,
163 database: &mut DB,
164 address: Address,
165 ) -> Result<&'a mut CacheAccount, DB::Error> {
166 Ok(match cache.accounts.entry(address) {
167 hash_map::Entry::Vacant(entry) => {
168 if use_preloaded_bundle {
169 if let Some(account) = bundle_state.account(&address).map(Into::into) {
171 return Ok(entry.insert(account));
172 }
173 }
174 let info = database.basic(address)?;
176 let account = match info {
177 None => CacheAccount::new_loaded_not_existing(),
178 Some(acc) if acc.is_empty() => {
179 CacheAccount::new_loaded_empty_eip161(HashMap::default())
180 }
181 Some(acc) => CacheAccount::new_loaded(acc, HashMap::default()),
182 };
183 entry.insert(account)
184 }
185 hash_map::Entry::Occupied(entry) => entry.into_mut(),
186 })
187 }
188
189 pub fn take_bundle(&mut self) -> BundleState {
201 core::mem::take(&mut self.bundle_state)
202 }
203
204 #[inline]
206 pub const fn take_built_bal(&mut self) -> Option<Bal> {
207 self.bal_state.take_built_bal()
208 }
209
210 #[inline]
212 pub fn take_built_alloy_bal(&mut self) -> Option<AlloyBal> {
213 self.bal_state.take_built_alloy_bal()
214 }
215
216 #[inline]
218 pub const fn bump_bal_index(&mut self) {
219 self.bal_state.bump_bal_index();
220 }
221
222 #[inline]
224 pub const fn set_bal_index(&mut self, index: BlockAccessIndex) {
225 self.bal_state.bal_index = index;
226 }
227
228 #[inline]
230 pub const fn reset_bal_index(&mut self) {
231 self.bal_state.reset_bal_index();
232 }
233
234 #[inline]
236 pub fn set_bal(&mut self, bal: Option<Arc<Bal>>) {
237 self.bal_state.bal = bal;
238 }
239
240 #[inline]
242 pub fn set_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {
243 self.state_hook = hook;
244 }
245
246 #[inline]
248 #[must_use]
249 pub fn with_state_hook(mut self, hook: Option<Box<dyn OnStateHook>>) -> Self {
250 self.set_state_hook(hook);
251 self
252 }
253
254 #[inline]
256 pub const fn has_bal(&self) -> bool {
257 self.bal_state.bal.is_some()
258 }
259
260 #[inline]
262 fn storage(&mut self, address: Address, index: StorageKey) -> Result<StorageValue, DB::Error> {
263 let account = Self::load_cache_account_with(
265 &mut self.cache,
266 self.use_preloaded_bundle,
267 &self.bundle_state,
268 &mut self.database,
269 address,
270 )?;
271
272 let is_storage_known = account.status.is_storage_known();
274 Ok(account
275 .account
276 .as_mut()
277 .map(|account| match account.storage.entry(index) {
278 hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
279 hash_map::Entry::Vacant(entry) => {
280 let value = if is_storage_known {
283 StorageValue::ZERO
284 } else {
285 self.database.storage(address, index)?
286 };
287 entry.insert(value);
288 Ok(value)
289 }
290 })
291 .transpose()?
292 .unwrap_or_default())
293 }
294}
295
296impl<DB: Database> Database for State<DB> {
297 type Error = EvmDatabaseError<DB::Error>;
298
299 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
300 let account_id = self
302 .bal_state
303 .get_account_id(&address)
304 .map_err(EvmDatabaseError::Bal)?;
305
306 let mut basic = self
307 .load_cache_account(address)
308 .map(|a| a.account_info())
309 .map_err(EvmDatabaseError::Database)?;
310 if let Some(account_id) = account_id {
313 self.bal_state
314 .basic_by_account_id(account_id, &mut basic)
315 .map_err(EvmDatabaseError::Bal)?;
316 }
317 Ok(basic)
318 }
319
320 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
321 let res = match self.cache.contracts.entry(code_hash) {
322 hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
323 hash_map::Entry::Vacant(entry) => {
324 if self.use_preloaded_bundle {
325 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
326 entry.insert(code.clone());
327 return Ok(code.clone());
328 }
329 }
330 let code = self
332 .database
333 .code_by_hash(code_hash)
334 .map_err(EvmDatabaseError::Database)?;
335 entry.insert(code.clone());
336 Ok(code)
337 }
338 };
339 res
340 }
341
342 fn storage(
343 &mut self,
344 address: Address,
345 index: StorageKey,
346 ) -> Result<StorageValue, Self::Error> {
347 if let Some(storage) = self
348 .bal_state
349 .storage(&address, index)
350 .map_err(EvmDatabaseError::Bal)?
351 {
352 return Ok(storage);
354 }
355 self.storage(address, index)
356 .map_err(EvmDatabaseError::Database)
357 }
358
359 fn storage_by_account_id(
360 &mut self,
361 address: Address,
362 account_id: AccountId,
363 key: StorageKey,
364 ) -> Result<StorageValue, Self::Error> {
365 if let Some(storage) = self.bal_state.storage_by_account_id(account_id, key)? {
366 return Ok(storage);
367 }
368
369 self.storage(address, key)
370 .map_err(EvmDatabaseError::Database)
371 }
372
373 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
374 if let Some(hash) = self.block_hashes.get(number) {
376 return Ok(hash);
377 }
378
379 let hash = self
381 .database
382 .block_hash(number)
383 .map_err(EvmDatabaseError::Database)?;
384
385 self.block_hashes.insert(number, hash);
387
388 Ok(hash)
389 }
390}
391
392impl<DB: Database> DatabaseCommit for State<DB> {
393 fn commit(&mut self, changes: AddressMap<Account>) {
394 self.bal_state.commit(&changes);
395
396 if let Some(hook) = self.state_hook.as_mut() {
397 let transitions = self.cache.apply_evm_state_iter(
398 changes
399 .iter()
400 .map(|(address, account)| (*address, Cow::Borrowed(account))),
401 |_, _| {},
402 );
403
404 if let Some(s) = self.transition_state.as_mut() {
405 s.add_transitions(transitions)
406 } else {
407 transitions.for_each(|_| {});
409 }
410
411 hook.on_state(changes);
412 } else {
413 let transitions = self.cache.apply_evm_state_iter(
414 changes
415 .into_iter()
416 .map(|(address, account)| (address, Cow::Owned(account))),
417 |_, _| {},
418 );
419
420 if let Some(s) = self.transition_state.as_mut() {
421 s.add_transitions(transitions)
422 } else {
423 transitions.for_each(|_| {});
425 }
426 }
427 }
428
429 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
430 if self.state_hook.is_some() {
431 let changes = changes.collect::<AddressMap<_>>();
432 self.commit(changes);
433 return;
434 }
435
436 if let Some(s) = self.transition_state.as_mut() {
437 for (address, account) in changes {
438 self.bal_state.commit_one(address, &account);
439 if let Some(transition) =
440 self.cache.apply_account_state(address, Cow::Owned(account))
441 {
442 s.add_transition(address, transition);
443 }
444 }
445 } else {
446 for (address, account) in changes {
447 self.bal_state.commit_one(address, &account);
448 _ = self.cache.apply_account_state(address, Cow::Owned(account));
449 }
450 }
451 }
452}
453
454impl<DB: DatabaseRef> DatabaseRef for State<DB> {
455 type Error = EvmDatabaseError<DB::Error>;
456
457 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
458 let account_id = self.bal_state.get_account_id(&address)?;
460
461 let mut loaded_account = None;
463 if let Some(account) = self.cache.accounts.get(&address) {
464 loaded_account = Some(account.account_info());
465 };
466
467 if self.use_preloaded_bundle && loaded_account.is_none() {
469 if let Some(account) = self.bundle_state.account(&address) {
470 loaded_account = Some(account.account_info());
471 }
472 }
473
474 if loaded_account.is_none() {
476 loaded_account = Some(
477 self.database
478 .basic_ref(address)
479 .map_err(EvmDatabaseError::Database)?,
480 );
481 }
482
483 let mut account = loaded_account.unwrap();
485
486 if let Some(account_id) = account_id {
488 self.bal_state
489 .basic_by_account_id(account_id, &mut account)
490 .map_err(EvmDatabaseError::Bal)?;
491 }
492 Ok(account)
493 }
494
495 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
496 if let Some(code) = self.cache.contracts.get(&code_hash) {
498 return Ok(code.clone());
499 }
500 if self.use_preloaded_bundle {
502 if let Some(code) = self.bundle_state.contracts.get(&code_hash) {
503 return Ok(code.clone());
504 }
505 }
506 self.database
508 .code_by_hash_ref(code_hash)
509 .map_err(EvmDatabaseError::Database)
510 }
511
512 fn storage_ref(
513 &self,
514 address: Address,
515 index: StorageKey,
516 ) -> Result<StorageValue, Self::Error> {
517 if let Some(storage) = self.bal_state.storage(&address, index)? {
519 return Ok(storage);
520 }
521
522 if let Some(account) = self.cache.accounts.get(&address) {
524 if let Some(plain_account) = &account.account {
525 if let Some(storage_value) = plain_account.storage.get(&index) {
527 return Ok(*storage_value);
528 }
529 if account.status.is_storage_known() {
532 return Ok(StorageValue::ZERO);
533 }
534 }
535 }
536
537 self.database
539 .storage_ref(address, index)
540 .map_err(EvmDatabaseError::Database)
541 }
542
543 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
544 if let Some(hash) = self.block_hashes.get(number) {
545 return Ok(hash);
546 }
547 self.database
549 .block_hash_ref(number)
550 .map_err(EvmDatabaseError::Database)
551 }
552}
553
554#[cfg(test)]
555mod tests {
556 use super::*;
557 use crate::{
558 states::{reverts::AccountInfoRevert, StorageSlot},
559 AccountRevert, AccountStatus, BundleAccount, RevertToSlot,
560 };
561 use primitives::{keccak256, BLOCK_HASH_HISTORY, U256};
562 use state::{EvmStorageSlot, TransactionId};
563
564 fn evm_storage<const N: usize>(
565 slots: [(StorageKey, EvmStorageSlot); N],
566 ) -> Option<Cow<'static, EvmStorage>> {
567 Some(Cow::Owned(HashMap::from_iter(slots)))
568 }
569
570 #[test]
571 fn has_bal_helper() {
572 let state = State::builder().build();
573 assert!(!state.has_bal());
574
575 let state = State::builder().with_bal(Arc::new(Bal::new())).build();
576 assert!(state.has_bal());
577 }
578
579 #[test]
580 fn block_hash_cache() {
581 let mut state = State::builder().build();
582 state.block_hash(1u64).unwrap();
583 state.block_hash(2u64).unwrap();
584
585 let test_number = BLOCK_HASH_HISTORY + 2;
586
587 let block1_hash = keccak256(U256::from(1).to_string().as_bytes());
588 let block2_hash = keccak256(U256::from(2).to_string().as_bytes());
589 let block_test_hash = keccak256(U256::from(test_number).to_string().as_bytes());
590
591 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
593 assert_eq!(state.block_hashes.get(2), Some(block2_hash));
594
595 state.block_hash(test_number).unwrap();
598
599 assert_eq!(state.block_hashes.get(1), Some(block1_hash));
601 assert_eq!(state.block_hashes.get(2), None);
602 assert_eq!(state.block_hashes.get(test_number), Some(block_test_hash));
603 }
604
605 #[test]
610 fn block_hash_cache_block_zero() {
611 let mut state = State::builder().build();
612
613 assert_eq!(state.block_hashes.get(0), None);
615
616 let block0_hash = state.block_hash(0u64).unwrap();
618
619 let expected_hash = keccak256(U256::from(0).to_string().as_bytes());
621 assert_eq!(block0_hash, expected_hash);
622
623 assert_eq!(state.block_hashes.get(0), Some(expected_hash));
625 }
626 #[test]
633 fn reverts_preserve_old_values() {
634 let mut state = State::builder().with_bundle_update().build();
635
636 let (slot1, slot2, slot3) = (
637 StorageKey::from(1),
638 StorageKey::from(2),
639 StorageKey::from(3),
640 );
641
642 let new_account_address = Address::from_slice(&[0x1; 20]);
645 let new_account_created_info = AccountInfo {
646 nonce: 1,
647 balance: U256::from(1),
648 ..Default::default()
649 };
650 let new_account_changed_info = AccountInfo {
651 nonce: 2,
652 ..new_account_created_info.clone()
653 };
654 let new_account_changed_info2 = AccountInfo {
655 nonce: 3,
656 ..new_account_changed_info.clone()
657 };
658
659 let existing_account_address = Address::from_slice(&[0x2; 20]);
661 let existing_account_initial_info = AccountInfo {
662 nonce: 1,
663 ..Default::default()
664 };
665 let existing_account_initial_storage = HashMap::<StorageKey, StorageValue>::from_iter([
666 (slot1, StorageValue::from(100)), (slot2, StorageValue::from(200)), ]);
669 let existing_account_changed_info = AccountInfo {
670 nonce: 2,
671 ..existing_account_initial_info.clone()
672 };
673
674 state.apply_transition(Vec::from([
676 (
677 new_account_address,
678 TransitionAccount {
679 status: AccountStatus::InMemoryChange,
680 info: Some(new_account_created_info.clone()),
681 previous_status: AccountStatus::LoadedNotExisting,
682 previous_info: None,
683 storage: None,
684 ..Default::default()
685 },
686 ),
687 (
688 existing_account_address,
689 TransitionAccount {
690 status: AccountStatus::InMemoryChange,
691 info: Some(existing_account_changed_info.clone()),
692 previous_status: AccountStatus::Loaded,
693 previous_info: Some(existing_account_initial_info.clone()),
694 storage: evm_storage([(
695 slot1,
696 EvmStorageSlot::new_changed(
697 *existing_account_initial_storage.get(&slot1).unwrap(),
698 StorageValue::from(1000),
699 TransactionId::ZERO,
700 ),
701 )]),
702 storage_was_destroyed: false,
703 },
704 ),
705 ]));
706
707 state.apply_transition(Vec::from([(
709 new_account_address,
710 TransitionAccount {
711 status: AccountStatus::InMemoryChange,
712 info: Some(new_account_changed_info.clone()),
713 previous_status: AccountStatus::InMemoryChange,
714 previous_info: Some(new_account_created_info.clone()),
715 ..Default::default()
716 },
717 )]));
718
719 state.apply_transition(Vec::from([
721 (
722 new_account_address,
723 TransitionAccount {
724 status: AccountStatus::InMemoryChange,
725 info: Some(new_account_changed_info2.clone()),
726 previous_status: AccountStatus::InMemoryChange,
727 previous_info: Some(new_account_changed_info),
728 storage: evm_storage([(
729 slot1,
730 EvmStorageSlot::new_changed(
731 StorageValue::ZERO,
732 StorageValue::from(1),
733 TransactionId::ZERO,
734 ),
735 )]),
736 storage_was_destroyed: false,
737 },
738 ),
739 (
740 existing_account_address,
741 TransitionAccount {
742 status: AccountStatus::InMemoryChange,
743 info: Some(existing_account_changed_info.clone()),
744 previous_status: AccountStatus::InMemoryChange,
745 previous_info: Some(existing_account_changed_info.clone()),
746 storage: evm_storage([
747 (
748 slot1,
749 EvmStorageSlot::new_changed(
750 StorageValue::from(100),
751 StorageValue::from(1_000),
752 TransactionId::ZERO,
753 ),
754 ),
755 (
756 slot2,
757 EvmStorageSlot::new_changed(
758 *existing_account_initial_storage.get(&slot2).unwrap(),
759 StorageValue::from(2_000),
760 TransactionId::ZERO,
761 ),
762 ),
763 (
765 slot3,
766 EvmStorageSlot::new_changed(
767 StorageValue::ZERO,
768 StorageValue::from(3_000),
769 TransactionId::ZERO,
770 ),
771 ),
772 ]),
773 storage_was_destroyed: false,
774 },
775 ),
776 ]));
777
778 state.merge_transitions(BundleRetention::Reverts);
779 let mut bundle_state = state.take_bundle();
780
781 bundle_state.reverts.sort();
784 assert_eq!(
785 bundle_state.reverts.as_ref(),
786 Vec::from([Vec::from([
787 (
788 new_account_address,
789 AccountRevert {
790 account: AccountInfoRevert::DeleteIt,
791 previous_status: AccountStatus::LoadedNotExisting,
792 storage: HashMap::from_iter([(
793 slot1,
794 RevertToSlot::Some(StorageValue::ZERO)
795 )]),
796 wipe_storage: false,
797 }
798 ),
799 (
800 existing_account_address,
801 AccountRevert {
802 account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()),
803 previous_status: AccountStatus::Loaded,
804 storage: HashMap::from_iter([
805 (
806 slot1,
807 RevertToSlot::Some(
808 *existing_account_initial_storage.get(&slot1).unwrap()
809 )
810 ),
811 (
812 slot2,
813 RevertToSlot::Some(
814 *existing_account_initial_storage.get(&slot2).unwrap()
815 )
816 ),
817 (slot3, RevertToSlot::Some(StorageValue::ZERO))
818 ]),
819 wipe_storage: false,
820 }
821 ),
822 ])]),
823 "The account or storage reverts are incorrect"
824 );
825
826 assert_eq!(
829 bundle_state.account(&new_account_address),
830 Some(&BundleAccount {
831 info: Some(new_account_changed_info2),
832 original_info: None,
833 status: AccountStatus::InMemoryChange,
834 storage: HashMap::from_iter([(
835 slot1,
836 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1))
837 )]),
838 }),
839 "The latest state of the new account is incorrect"
840 );
841
842 assert_eq!(
845 bundle_state.account(&existing_account_address),
846 Some(&BundleAccount {
847 info: Some(existing_account_changed_info),
848 original_info: Some(existing_account_initial_info),
849 status: AccountStatus::InMemoryChange,
850 storage: HashMap::from_iter([
851 (
852 slot1,
853 StorageSlot::new_changed(
854 *existing_account_initial_storage.get(&slot1).unwrap(),
855 StorageValue::from(1_000)
856 )
857 ),
858 (
859 slot2,
860 StorageSlot::new_changed(
861 *existing_account_initial_storage.get(&slot2).unwrap(),
862 StorageValue::from(2_000)
863 )
864 ),
865 (
867 slot3,
868 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000))
869 ),
870 ]),
871 }),
872 "The latest state of the existing account is incorrect"
873 );
874 }
875
876 #[test]
879 fn bundle_scoped_reverts_collapse() {
880 let mut state = State::builder().with_bundle_update().build();
881
882 let new_account_address = Address::from_slice(&[0x1; 20]);
884 let new_account_created_info = AccountInfo {
885 nonce: 1,
886 balance: U256::from(1),
887 ..Default::default()
888 };
889
890 let existing_account_address = Address::from_slice(&[0x2; 20]);
892 let existing_account_initial_info = AccountInfo {
893 nonce: 1,
894 ..Default::default()
895 };
896 let existing_account_updated_info = AccountInfo {
897 nonce: 1,
898 balance: U256::from(1),
899 ..Default::default()
900 };
901
902 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
904 let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]);
905 let existing_account_with_storage_info = AccountInfo {
906 nonce: 1,
907 ..Default::default()
908 };
909 state.apply_transition(Vec::from([
911 (
912 new_account_address,
913 TransitionAccount {
914 status: AccountStatus::InMemoryChange,
915 info: Some(new_account_created_info.clone()),
916 previous_status: AccountStatus::LoadedNotExisting,
917 previous_info: None,
918 ..Default::default()
919 },
920 ),
921 (
922 existing_account_address,
923 TransitionAccount {
924 status: AccountStatus::Changed,
925 info: Some(existing_account_updated_info.clone()),
926 previous_status: AccountStatus::Loaded,
927 previous_info: Some(existing_account_initial_info.clone()),
928 ..Default::default()
929 },
930 ),
931 (
932 existing_account_with_storage_address,
933 TransitionAccount {
934 status: AccountStatus::Changed,
935 info: Some(existing_account_with_storage_info.clone()),
936 previous_status: AccountStatus::Loaded,
937 previous_info: Some(existing_account_with_storage_info.clone()),
938 storage: evm_storage([
939 (
940 slot1,
941 EvmStorageSlot::new_changed(
942 StorageValue::from(1),
943 StorageValue::from(10),
944 TransactionId::ZERO,
945 ),
946 ),
947 (
948 slot2,
949 EvmStorageSlot::new_changed(
950 StorageValue::ZERO,
951 StorageValue::from(20),
952 TransactionId::ZERO,
953 ),
954 ),
955 ]),
956 storage_was_destroyed: false,
957 },
958 ),
959 ]));
960
961 state.apply_transition(Vec::from([
963 (
964 new_account_address,
965 TransitionAccount {
966 status: AccountStatus::Destroyed,
967 info: None,
968 previous_status: AccountStatus::InMemoryChange,
969 previous_info: Some(new_account_created_info),
970 ..Default::default()
971 },
972 ),
973 (
974 existing_account_address,
975 TransitionAccount {
976 status: AccountStatus::Changed,
977 info: Some(existing_account_initial_info),
978 previous_status: AccountStatus::Changed,
979 previous_info: Some(existing_account_updated_info),
980 ..Default::default()
981 },
982 ),
983 (
984 existing_account_with_storage_address,
985 TransitionAccount {
986 status: AccountStatus::Changed,
987 info: Some(existing_account_with_storage_info.clone()),
988 previous_status: AccountStatus::Changed,
989 previous_info: Some(existing_account_with_storage_info.clone()),
990 storage: evm_storage([
991 (
992 slot1,
993 EvmStorageSlot::new_changed(
994 StorageValue::from(10),
995 StorageValue::from(1),
996 TransactionId::ZERO,
997 ),
998 ),
999 (
1000 slot2,
1001 EvmStorageSlot::new_changed(
1002 StorageValue::from(20),
1003 StorageValue::ZERO,
1004 TransactionId::ZERO,
1005 ),
1006 ),
1007 ]),
1008 storage_was_destroyed: false,
1009 },
1010 ),
1011 ]));
1012
1013 state.merge_transitions(BundleRetention::Reverts);
1014
1015 let mut bundle_state = state.take_bundle();
1016 bundle_state.reverts.sort();
1017
1018 assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])]));
1021 }
1022
1023 #[test]
1025 fn selfdestruct_state_and_reverts() {
1026 let mut state = State::builder().with_bundle_update().build();
1027
1028 let existing_account_address = Address::from_slice(&[0x1; 20]);
1030 let existing_account_info = AccountInfo {
1031 nonce: 1,
1032 ..Default::default()
1033 };
1034
1035 let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2));
1036
1037 state.apply_transition(Vec::from([(
1039 existing_account_address,
1040 TransitionAccount {
1041 status: AccountStatus::Destroyed,
1042 info: None,
1043 previous_status: AccountStatus::Loaded,
1044 previous_info: Some(existing_account_info.clone()),
1045 storage: Some(Cow::Owned(HashMap::default())),
1046 storage_was_destroyed: true,
1047 },
1048 )]));
1049
1050 state.apply_transition(Vec::from([(
1052 existing_account_address,
1053 TransitionAccount {
1054 status: AccountStatus::DestroyedChanged,
1055 info: Some(existing_account_info.clone()),
1056 previous_status: AccountStatus::Destroyed,
1057 previous_info: None,
1058 storage: evm_storage([(
1059 slot1,
1060 EvmStorageSlot::new_changed(
1061 StorageValue::ZERO,
1062 StorageValue::from(1),
1063 TransactionId::ZERO,
1064 ),
1065 )]),
1066 storage_was_destroyed: false,
1067 },
1068 )]));
1069
1070 state.apply_transition(Vec::from([(
1072 existing_account_address,
1073 TransitionAccount {
1074 status: AccountStatus::DestroyedAgain,
1075 info: None,
1076 previous_status: AccountStatus::DestroyedChanged,
1077 previous_info: Some(existing_account_info.clone()),
1078 storage: Some(Cow::Owned(HashMap::default())),
1080 storage_was_destroyed: true,
1081 },
1082 )]));
1083
1084 state.apply_transition(Vec::from([(
1086 existing_account_address,
1087 TransitionAccount {
1088 status: AccountStatus::DestroyedChanged,
1089 info: Some(existing_account_info.clone()),
1090 previous_status: AccountStatus::DestroyedAgain,
1091 previous_info: None,
1092 storage: evm_storage([(
1093 slot2,
1094 EvmStorageSlot::new_changed(
1095 StorageValue::ZERO,
1096 StorageValue::from(2),
1097 TransactionId::ZERO,
1098 ),
1099 )]),
1100 storage_was_destroyed: false,
1101 },
1102 )]));
1103
1104 state.merge_transitions(BundleRetention::Reverts);
1105
1106 let bundle_state = state.take_bundle();
1107
1108 assert_eq!(
1109 bundle_state.state,
1110 HashMap::from_iter([(
1111 existing_account_address,
1112 BundleAccount {
1113 info: Some(existing_account_info.clone()),
1114 original_info: Some(existing_account_info.clone()),
1115 storage: HashMap::from_iter([(
1116 slot2,
1117 StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2))
1118 )]),
1119 status: AccountStatus::DestroyedChanged,
1120 }
1121 )])
1122 );
1123
1124 assert_eq!(
1125 bundle_state.reverts.as_ref(),
1126 Vec::from([Vec::from([(
1127 existing_account_address,
1128 AccountRevert {
1129 account: AccountInfoRevert::DoNothing,
1130 previous_status: AccountStatus::Loaded,
1131 storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]),
1132 wipe_storage: true,
1133 }
1134 )])])
1135 )
1136 }
1137}