1use core::ops::Not;
2
3use crate::{
4 added_removed_keys::MultiAddedRemovedKeys,
5 prefix_set::{PrefixSetMut, TriePrefixSetsMut},
6 utils::extend_sorted_vec,
7 KeyHasher, MultiProofTargets, Nibbles,
8};
9use alloc::{borrow::Cow, vec::Vec};
10use alloy_primitives::{
11 keccak256,
12 map::{hash_map, B256Map, HashMap, HashSet},
13 Address, B256, U256,
14};
15use itertools::Itertools;
16#[cfg(feature = "rayon")]
17pub use rayon::*;
18use reth_primitives_traits::Account;
19
20#[cfg(feature = "rayon")]
21use rayon::prelude::{IntoParallelIterator, ParallelIterator};
22
23use revm_database::{AccountStatus, BundleAccount};
24
25#[derive(PartialEq, Eq, Clone, Default, Debug)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct HashedPostState {
30 pub accounts: B256Map<Option<Account>>,
32 pub storages: B256Map<HashedStorage>,
34}
35
36impl HashedPostState {
37 pub fn with_capacity(capacity: usize) -> Self {
39 Self {
40 accounts: B256Map::with_capacity_and_hasher(capacity, Default::default()),
41 storages: B256Map::with_capacity_and_hasher(capacity, Default::default()),
42 }
43 }
44
45 #[inline]
49 #[cfg(feature = "rayon")]
50 pub fn from_bundle_state<'a, KH: KeyHasher>(
51 state: impl IntoParallelIterator<Item = (&'a Address, &'a BundleAccount)>,
52 ) -> Self {
53 let hashed = state
54 .into_par_iter()
55 .map(|(address, account)| {
56 let hashed_address = KH::hash_key(address);
57 let hashed_account = account.info.as_ref().map(Into::into);
58 let hashed_storage = HashedStorage::from_plain_storage(
59 account.status,
60 account.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
61 );
62 (hashed_address, (hashed_account, hashed_storage))
63 })
64 .collect::<Vec<(B256, (Option<Account>, HashedStorage))>>();
65
66 let mut accounts = HashMap::with_capacity_and_hasher(hashed.len(), Default::default());
67 let mut storages = HashMap::with_capacity_and_hasher(hashed.len(), Default::default());
68 for (address, (account, storage)) in hashed {
69 accounts.insert(address, account);
70 if !storage.is_empty() {
71 storages.insert(address, storage);
72 }
73 }
74 Self { accounts, storages }
75 }
76
77 #[cfg(not(feature = "rayon"))]
81 pub fn from_bundle_state<'a, KH: KeyHasher>(
82 state: impl IntoIterator<Item = (&'a Address, &'a BundleAccount)>,
83 ) -> Self {
84 let hashed = state
85 .into_iter()
86 .map(|(address, account)| {
87 let hashed_address = KH::hash_key(address);
88 let hashed_account = account.info.as_ref().map(Into::into);
89 let hashed_storage = HashedStorage::from_plain_storage(
90 account.status,
91 account.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
92 );
93 (hashed_address, (hashed_account, hashed_storage))
94 })
95 .collect::<Vec<(B256, (Option<Account>, HashedStorage))>>();
96
97 let mut accounts = HashMap::with_capacity_and_hasher(hashed.len(), Default::default());
98 let mut storages = HashMap::with_capacity_and_hasher(hashed.len(), Default::default());
99 for (address, (account, storage)) in hashed {
100 accounts.insert(address, account);
101 if !storage.is_empty() {
102 storages.insert(address, storage);
103 }
104 }
105 Self { accounts, storages }
106 }
107
108 pub fn from_hashed_storage(hashed_address: B256, storage: HashedStorage) -> Self {
110 Self {
111 accounts: HashMap::default(),
112 storages: HashMap::from_iter([(hashed_address, storage)]),
113 }
114 }
115
116 pub fn with_accounts(
118 mut self,
119 accounts: impl IntoIterator<Item = (B256, Option<Account>)>,
120 ) -> Self {
121 self.accounts = HashMap::from_iter(accounts);
122 self
123 }
124
125 pub fn with_storages(
127 mut self,
128 storages: impl IntoIterator<Item = (B256, HashedStorage)>,
129 ) -> Self {
130 self.storages = HashMap::from_iter(storages);
131 self
132 }
133
134 pub fn is_empty(&self) -> bool {
136 self.accounts.is_empty() && self.storages.is_empty()
137 }
138
139 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
143 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
145 let mut destroyed_accounts = HashSet::default();
146 for (hashed_address, account) in &self.accounts {
147 account_prefix_set.insert(Nibbles::unpack(hashed_address));
148
149 if account.is_none() {
150 destroyed_accounts.insert(*hashed_address);
151 }
152 }
153
154 let mut storage_prefix_sets =
156 HashMap::with_capacity_and_hasher(self.storages.len(), Default::default());
157 for (hashed_address, hashed_storage) in &self.storages {
158 account_prefix_set.insert(Nibbles::unpack(hashed_address));
159 storage_prefix_sets.insert(*hashed_address, hashed_storage.construct_prefix_set());
160 }
161
162 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
163 }
164
165 pub fn multi_proof_targets(&self) -> MultiProofTargets {
167 let mut targets = MultiProofTargets::with_capacity(self.accounts.len());
169 for hashed_address in self.accounts.keys() {
170 targets.insert(*hashed_address, Default::default());
171 }
172 for (hashed_address, storage) in &self.storages {
173 targets.entry(*hashed_address).or_default().extend(storage.storage.keys().copied());
174 }
175 targets
176 }
177
178 pub fn multi_proof_targets_difference(
184 &self,
185 excluded: &MultiProofTargets,
186 ) -> MultiProofTargets {
187 let mut targets = MultiProofTargets::default();
188 for hashed_address in self.accounts.keys() {
189 if !excluded.contains_key(hashed_address) {
190 targets.insert(*hashed_address, Default::default());
191 }
192 }
193 for (hashed_address, storage) in &self.storages {
194 let maybe_excluded_storage = excluded.get(hashed_address);
195 let mut hashed_slots_targets = storage
196 .storage
197 .keys()
198 .filter(|slot| !maybe_excluded_storage.is_some_and(|f| f.contains(*slot)))
199 .peekable();
200 if hashed_slots_targets.peek().is_some() {
201 targets.entry(*hashed_address).or_default().extend(hashed_slots_targets);
202 }
203 }
204 targets
205 }
206
207 pub fn partition_by_targets(
214 mut self,
215 targets: &MultiProofTargets,
216 added_removed_keys: &MultiAddedRemovedKeys,
217 ) -> (Self, Self) {
218 let mut state_updates_not_in_targets = Self::default();
219
220 self.storages.retain(|&address, storage| {
221 let storage_added_removed_keys = added_removed_keys.get_storage(&address);
222
223 let (retain, storage_not_in_targets) = match targets.get(&address) {
224 Some(storage_in_targets) => {
225 let mut storage_not_in_targets = HashedStorage::default();
226 storage.storage.retain(|&slot, value| {
227 if storage_in_targets.contains(&slot) &&
228 !storage_added_removed_keys.is_some_and(|k| k.is_removed(&slot))
229 {
230 return true
231 }
232
233 storage_not_in_targets.storage.insert(slot, *value);
234 false
235 });
236
237 let retain = !storage.storage.is_empty();
241
242 if !retain {
246 storage_not_in_targets.wiped = storage.wiped;
247 }
248
249 (
250 retain,
251 storage_not_in_targets.is_empty().not().then_some(storage_not_in_targets),
252 )
253 }
254 None => (false, Some(core::mem::take(storage))),
255 };
256
257 if let Some(storage_not_in_targets) = storage_not_in_targets {
258 state_updates_not_in_targets.storages.insert(address, storage_not_in_targets);
259 }
260
261 retain
262 });
263 self.accounts.retain(|&address, account| {
264 if targets.contains_key(&address) {
265 return true
266 }
267
268 state_updates_not_in_targets.accounts.insert(address, *account);
269 false
270 });
271
272 (self, state_updates_not_in_targets)
273 }
274
275 pub fn chunks(self, size: usize) -> ChunkedHashedPostState {
279 ChunkedHashedPostState::new(self, size)
280 }
281
282 pub fn chunking_length(&self) -> usize {
284 self.accounts.len() +
285 self.storages
286 .values()
287 .map(|storage| if storage.wiped { 1 } else { 0 } + storage.storage.len())
288 .sum::<usize>()
289 }
290
291 pub fn extend(&mut self, other: Self) {
294 self.extend_inner(Cow::Owned(other));
295 }
296
297 pub fn extend_ref(&mut self, other: &Self) {
302 self.extend_inner(Cow::Borrowed(other));
303 }
304
305 fn extend_inner(&mut self, other: Cow<'_, Self>) {
306 self.accounts.extend(other.accounts.iter().map(|(&k, &v)| (k, v)));
307
308 self.storages.reserve(other.storages.len());
309 match other {
310 Cow::Borrowed(other) => {
311 self.extend_storages(other.storages.iter().map(|(k, v)| (*k, Cow::Borrowed(v))))
312 }
313 Cow::Owned(other) => {
314 self.extend_storages(other.storages.into_iter().map(|(k, v)| (k, Cow::Owned(v))))
315 }
316 }
317 }
318
319 fn extend_storages<'a>(
320 &mut self,
321 storages: impl IntoIterator<Item = (B256, Cow<'a, HashedStorage>)>,
322 ) {
323 for (hashed_address, storage) in storages {
324 match self.storages.entry(hashed_address) {
325 hash_map::Entry::Vacant(entry) => {
326 entry.insert(storage.into_owned());
327 }
328 hash_map::Entry::Occupied(mut entry) => {
329 entry.get_mut().extend(&storage);
330 }
331 }
332 }
333 }
334
335 pub fn extend_from_sorted(&mut self, sorted: &HashedPostStateSorted) {
339 self.accounts.reserve(sorted.accounts.len());
341
342 for (address, account) in &sorted.accounts {
344 self.accounts.insert(*address, *account);
345 }
346
347 self.storages.reserve(sorted.storages.len());
349
350 for (hashed_address, sorted_storage) in &sorted.storages {
352 match self.storages.entry(*hashed_address) {
353 hash_map::Entry::Vacant(entry) => {
354 let mut new_storage = HashedStorage::new(false);
355 new_storage.extend_from_sorted(sorted_storage);
356 entry.insert(new_storage);
357 }
358 hash_map::Entry::Occupied(mut entry) => {
359 entry.get_mut().extend_from_sorted(sorted_storage);
360 }
361 }
362 }
363 }
364
365 pub fn into_sorted(self) -> HashedPostStateSorted {
367 let mut accounts: Vec<_> = self.accounts.into_iter().collect();
368 accounts.sort_unstable_by_key(|(address, _)| *address);
369
370 let storages = self
371 .storages
372 .into_iter()
373 .map(|(hashed_address, storage)| (hashed_address, storage.into_sorted()))
374 .collect();
375
376 HashedPostStateSorted { accounts, storages }
377 }
378
379 pub fn clone_into_sorted(&self) -> HashedPostStateSorted {
382 let mut accounts: Vec<_> = self.accounts.iter().map(|(&k, &v)| (k, v)).collect();
383 accounts.sort_unstable_by_key(|(address, _)| *address);
384
385 let storages = self
386 .storages
387 .iter()
388 .map(|(&hashed_address, storage)| (hashed_address, storage.clone_into_sorted()))
389 .collect();
390
391 HashedPostStateSorted { accounts, storages }
392 }
393
394 pub fn clear(&mut self) {
396 self.accounts.clear();
397 self.storages.clear();
398 }
399}
400
401#[derive(PartialEq, Eq, Clone, Debug, Default)]
403#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
404pub struct HashedStorage {
405 pub wiped: bool,
407 pub storage: B256Map<U256>,
409}
410
411impl HashedStorage {
412 pub fn new(wiped: bool) -> Self {
414 Self { wiped, storage: HashMap::default() }
415 }
416
417 pub fn is_empty(&self) -> bool {
419 !self.wiped && self.storage.is_empty()
420 }
421
422 pub fn from_iter(wiped: bool, iter: impl IntoIterator<Item = (B256, U256)>) -> Self {
424 Self { wiped, storage: HashMap::from_iter(iter) }
425 }
426
427 pub fn from_plain_storage<'a>(
429 status: AccountStatus,
430 storage: impl IntoIterator<Item = (&'a U256, &'a U256)>,
431 ) -> Self {
432 Self::from_iter(
433 status.was_destroyed(),
434 storage.into_iter().map(|(key, value)| (keccak256(B256::from(*key)), *value)),
435 )
436 }
437
438 pub fn construct_prefix_set(&self) -> PrefixSetMut {
440 if self.wiped {
441 PrefixSetMut::all()
442 } else {
443 let mut prefix_set = PrefixSetMut::with_capacity(self.storage.len());
444 for hashed_slot in self.storage.keys() {
445 prefix_set.insert(Nibbles::unpack(hashed_slot));
446 }
447 prefix_set
448 }
449 }
450
451 pub fn extend(&mut self, other: &Self) {
454 if other.wiped {
455 self.wiped = true;
456 self.storage.clear();
457 }
458 self.storage.extend(other.storage.iter().map(|(&k, &v)| (k, v)));
459 }
460
461 pub fn extend_from_sorted(&mut self, sorted: &HashedStorageSorted) {
465 if sorted.wiped {
466 self.wiped = true;
467 self.storage.clear();
468 }
469
470 self.storage.reserve(sorted.storage_slots.len());
472
473 for (slot, value) in &sorted.storage_slots {
475 self.storage.insert(*slot, *value);
476 }
477 }
478
479 pub fn into_sorted(self) -> HashedStorageSorted {
481 let mut storage_slots: Vec<_> = self.storage.into_iter().collect();
482 storage_slots.sort_unstable_by_key(|(key, _)| *key);
483
484 HashedStorageSorted { storage_slots, wiped: self.wiped }
485 }
486
487 pub fn clone_into_sorted(&self) -> HashedStorageSorted {
490 let mut storage_slots: Vec<_> = self.storage.iter().map(|(&k, &v)| (k, v)).collect();
491 storage_slots.sort_unstable_by_key(|(key, _)| *key);
492
493 HashedStorageSorted { storage_slots, wiped: self.wiped }
494 }
495}
496
497#[derive(PartialEq, Eq, Clone, Default, Debug)]
499pub struct HashedPostStateSorted {
500 pub accounts: Vec<(B256, Option<Account>)>,
502 pub storages: B256Map<HashedStorageSorted>,
504}
505
506impl HashedPostStateSorted {
507 pub const fn new(
509 accounts: Vec<(B256, Option<Account>)>,
510 storages: B256Map<HashedStorageSorted>,
511 ) -> Self {
512 Self { accounts, storages }
513 }
514
515 pub const fn accounts(&self) -> &Vec<(B256, Option<Account>)> {
517 &self.accounts
518 }
519
520 pub const fn account_storages(&self) -> &B256Map<HashedStorageSorted> {
522 &self.storages
523 }
524
525 pub fn is_empty(&self) -> bool {
527 self.accounts.is_empty() && self.storages.is_empty()
528 }
529
530 pub fn total_len(&self) -> usize {
532 self.accounts.len() + self.storages.values().map(|s| s.len()).sum::<usize>()
533 }
534
535 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
540 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
541 let mut destroyed_accounts = HashSet::default();
542 for (hashed_address, account) in &self.accounts {
543 account_prefix_set.insert(Nibbles::unpack(hashed_address));
544 if account.is_none() {
545 destroyed_accounts.insert(*hashed_address);
546 }
547 }
548
549 let mut storage_prefix_sets =
550 B256Map::with_capacity_and_hasher(self.storages.len(), Default::default());
551 for (hashed_address, hashed_storage) in &self.storages {
552 account_prefix_set.insert(Nibbles::unpack(hashed_address));
554
555 let prefix_set = if hashed_storage.wiped {
556 PrefixSetMut::all()
557 } else {
558 let mut prefix_set =
559 PrefixSetMut::with_capacity(hashed_storage.storage_slots.len());
560 prefix_set.extend_keys(
561 hashed_storage
562 .storage_slots
563 .iter()
564 .map(|(hashed_slot, _)| Nibbles::unpack(hashed_slot)),
565 );
566 prefix_set
567 };
568
569 storage_prefix_sets.insert(*hashed_address, prefix_set);
570 }
571
572 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
573 }
574
575 pub fn extend_ref(&mut self, other: &Self) {
578 extend_sorted_vec(&mut self.accounts, &other.accounts);
580
581 for (hashed_address, other_storage) in &other.storages {
583 self.storages
584 .entry(*hashed_address)
585 .and_modify(|existing| existing.extend_ref(other_storage))
586 .or_insert_with(|| other_storage.clone());
587 }
588 }
589
590 pub fn clear(&mut self) {
592 self.accounts.clear();
593 self.storages.clear();
594 }
595}
596
597impl AsRef<Self> for HashedPostStateSorted {
598 fn as_ref(&self) -> &Self {
599 self
600 }
601}
602
603#[derive(Clone, Eq, PartialEq, Debug)]
605pub struct HashedStorageSorted {
606 pub storage_slots: Vec<(B256, U256)>,
608 pub wiped: bool,
610}
611
612impl HashedStorageSorted {
613 pub const fn is_wiped(&self) -> bool {
615 self.wiped
616 }
617
618 pub fn storage_slots_ref(&self) -> &[(B256, U256)] {
620 &self.storage_slots
621 }
622
623 pub const fn len(&self) -> usize {
625 self.storage_slots.len()
626 }
627
628 pub const fn is_empty(&self) -> bool {
630 self.storage_slots.is_empty()
631 }
632
633 pub fn extend_ref(&mut self, other: &Self) {
638 if other.wiped {
639 self.wiped = true;
641 self.storage_slots.clear();
642 self.storage_slots.extend(other.storage_slots.iter().copied());
643 return;
644 }
645
646 extend_sorted_vec(&mut self.storage_slots, &other.storage_slots);
648 }
649}
650
651impl From<HashedStorageSorted> for HashedStorage {
652 fn from(sorted: HashedStorageSorted) -> Self {
653 let mut storage = B256Map::default();
654
655 for (slot, value) in sorted.storage_slots {
657 storage.insert(slot, value);
658 }
659
660 Self { wiped: sorted.wiped, storage }
661 }
662}
663
664impl From<HashedPostStateSorted> for HashedPostState {
665 fn from(sorted: HashedPostStateSorted) -> Self {
666 let mut accounts = B256Map::default();
667
668 for (address, account) in sorted.accounts {
670 accounts.insert(address, account);
671 }
672
673 let storages = sorted
675 .storages
676 .into_iter()
677 .map(|(address, storage)| (address, storage.into()))
678 .collect();
679
680 Self { accounts, storages }
681 }
682}
683
684#[derive(Debug)]
692pub struct ChunkedHashedPostState {
693 flattened: alloc::vec::IntoIter<(B256, FlattenedHashedPostStateItem)>,
694 size: usize,
695}
696
697#[derive(Debug)]
698enum FlattenedHashedPostStateItem {
699 Account(Option<Account>),
700 StorageWipe,
701 StorageUpdate { slot: B256, value: U256 },
702}
703
704impl ChunkedHashedPostState {
705 fn new(hashed_post_state: HashedPostState, size: usize) -> Self {
706 let flattened = hashed_post_state
707 .storages
708 .into_iter()
709 .flat_map(|(address, storage)| {
710 Some((address, FlattenedHashedPostStateItem::StorageWipe))
712 .filter(|_| storage.wiped)
713 .into_iter()
714 .chain(
715 storage.storage.into_iter().sorted_unstable_by_key(|(slot, _)| *slot).map(
716 move |(slot, value)| {
717 (
718 address,
719 FlattenedHashedPostStateItem::StorageUpdate { slot, value },
720 )
721 },
722 ),
723 )
724 })
725 .chain(hashed_post_state.accounts.into_iter().map(|(address, account)| {
726 (address, FlattenedHashedPostStateItem::Account(account))
727 }))
728 .sorted_by_key(|(address, _)| *address);
733
734 Self { flattened, size }
735 }
736}
737
738impl Iterator for ChunkedHashedPostState {
739 type Item = HashedPostState;
740
741 fn next(&mut self) -> Option<Self::Item> {
742 let mut chunk = HashedPostState::default();
743
744 let mut current_size = 0;
745 while current_size < self.size {
746 let Some((address, item)) = self.flattened.next() else { break };
747
748 match item {
749 FlattenedHashedPostStateItem::Account(account) => {
750 chunk.accounts.insert(address, account);
751 }
752 FlattenedHashedPostStateItem::StorageWipe => {
753 chunk.storages.entry(address).or_default().wiped = true;
754 }
755 FlattenedHashedPostStateItem::StorageUpdate { slot, value } => {
756 chunk.storages.entry(address).or_default().storage.insert(slot, value);
757 }
758 }
759
760 current_size += 1;
761 }
762
763 if chunk.is_empty() {
764 None
765 } else {
766 Some(chunk)
767 }
768 }
769}
770
771#[cfg(test)]
772mod tests {
773 use super::*;
774 use crate::KeccakKeyHasher;
775 use alloy_primitives::Bytes;
776 use revm_database::{states::StorageSlot, StorageWithOriginalValues};
777 use revm_state::{AccountInfo, Bytecode};
778
779 #[test]
780 fn hashed_state_wiped_extension() {
781 let hashed_address = B256::default();
782 let hashed_slot = B256::with_last_byte(64);
783 let hashed_slot2 = B256::with_last_byte(65);
784
785 let original_slot_value = U256::from(123);
787 let mut hashed_state = HashedPostState::default().with_storages([(
788 hashed_address,
789 HashedStorage::from_iter(
790 false,
791 [(hashed_slot, original_slot_value), (hashed_slot2, original_slot_value)],
792 ),
793 )]);
794
795 let updated_slot_value = U256::from(321);
797 let extension = HashedPostState::default().with_storages([(
798 hashed_address,
799 HashedStorage::from_iter(false, [(hashed_slot, updated_slot_value)]),
800 )]);
801 hashed_state.extend(extension);
802
803 let account_storage = hashed_state.storages.get(&hashed_address);
804 assert_eq!(
805 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
806 Some(&updated_slot_value)
807 );
808 assert_eq!(
809 account_storage.and_then(|st| st.storage.get(&hashed_slot2)),
810 Some(&original_slot_value)
811 );
812 assert_eq!(account_storage.map(|st| st.wiped), Some(false));
813
814 let wiped_extension =
816 HashedPostState::default().with_storages([(hashed_address, HashedStorage::new(true))]);
817 hashed_state.extend(wiped_extension);
818
819 let account_storage = hashed_state.storages.get(&hashed_address);
820 assert_eq!(account_storage.map(|st| st.storage.is_empty()), Some(true));
821 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
822
823 hashed_state.extend(HashedPostState::default().with_storages([(
825 hashed_address,
826 HashedStorage::from_iter(false, [(hashed_slot, original_slot_value)]),
827 )]));
828 let account_storage = hashed_state.storages.get(&hashed_address);
829 assert_eq!(
830 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
831 Some(&original_slot_value)
832 );
833 assert_eq!(account_storage.and_then(|st| st.storage.get(&hashed_slot2)), None);
834 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
835
836 hashed_state.extend(HashedPostState::default().with_storages([(
838 hashed_address,
839 HashedStorage::from_iter(false, [(hashed_slot2, updated_slot_value)]),
840 )]));
841 let account_storage = hashed_state.storages.get(&hashed_address);
842 assert_eq!(
843 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
844 Some(&original_slot_value)
845 );
846 assert_eq!(
847 account_storage.and_then(|st| st.storage.get(&hashed_slot2)),
848 Some(&updated_slot_value)
849 );
850 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
851 }
852
853 #[test]
854 fn test_hashed_post_state_from_bundle_state() {
855 let address = Address::random();
857
858 let account_info = AccountInfo {
860 balance: U256::from(123),
861 nonce: 42,
862 code_hash: B256::random(),
863 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2]))),
864 };
865
866 let mut storage = StorageWithOriginalValues::default();
867 storage.insert(
868 U256::from(1),
869 StorageSlot { present_value: U256::from(4), ..Default::default() },
870 );
871
872 let account = BundleAccount {
874 status: AccountStatus::Changed,
875 info: Some(account_info.clone()),
876 storage,
877 original_info: None,
878 };
879
880 let state = vec![(&address, &account)];
882
883 let hashed_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(state);
885
886 assert_eq!(hashed_state.accounts.len(), 1);
888 assert_eq!(hashed_state.storages.len(), 1);
889
890 assert_eq!(
892 *hashed_state.accounts.get(&keccak256(address)).unwrap(),
893 Some(account_info.into())
894 );
895 }
896
897 #[test]
898 fn test_hashed_post_state_with_accounts() {
899 let address_1 = Address::random();
901 let address_2 = Address::random();
902
903 let account_info_1 = AccountInfo {
904 balance: U256::from(1000),
905 nonce: 1,
906 code_hash: B256::random(),
907 code: None,
908 };
909
910 let account_1 = (keccak256(address_1), Some(account_info_1.into()));
912 let account_2 = (keccak256(address_2), None);
913
914 let hashed_state = HashedPostState::default().with_accounts(vec![account_1, account_2]);
916
917 assert_eq!(hashed_state.accounts.len(), 2);
919 assert!(hashed_state.accounts.contains_key(&keccak256(address_1)));
920 assert!(hashed_state.accounts.contains_key(&keccak256(address_2)));
921 }
922
923 #[test]
924 fn test_hashed_post_state_with_storages() {
925 let address_1 = Address::random();
927 let address_2 = Address::random();
928
929 let storage_1 = (keccak256(address_1), HashedStorage::new(false));
930 let storage_2 = (keccak256(address_2), HashedStorage::new(true));
931
932 let hashed_state = HashedPostState::default().with_storages(vec![storage_1, storage_2]);
934
935 assert_eq!(hashed_state.storages.len(), 2);
937 assert!(hashed_state.storages.contains_key(&keccak256(address_1)));
938 assert!(hashed_state.storages.contains_key(&keccak256(address_2)));
939 }
940
941 #[test]
942 fn test_hashed_post_state_is_empty() {
943 let empty_state = HashedPostState::default();
945 assert!(empty_state.is_empty());
946
947 let non_empty_state = HashedPostState::default()
949 .with_accounts(vec![(keccak256(Address::random()), Some(Account::default()))]);
950 assert!(!non_empty_state.is_empty());
951 }
952
953 fn create_state_for_multi_proof_targets() -> HashedPostState {
954 let mut state = HashedPostState::default();
955
956 let addr1 = B256::random();
957 let addr2 = B256::random();
958 state.accounts.insert(addr1, Some(Default::default()));
959 state.accounts.insert(addr2, Some(Default::default()));
960
961 let mut storage = HashedStorage::default();
962 let slot1 = B256::random();
963 let slot2 = B256::random();
964 storage.storage.insert(slot1, U256::ZERO);
965 storage.storage.insert(slot2, U256::from(1));
966 state.storages.insert(addr1, storage);
967
968 state
969 }
970
971 #[test]
972 fn test_multi_proof_targets_difference_empty_state() {
973 let state = HashedPostState::default();
974 let excluded = MultiProofTargets::default();
975
976 let targets = state.multi_proof_targets_difference(&excluded);
977 assert!(targets.is_empty());
978 }
979
980 #[test]
981 fn test_multi_proof_targets_difference_new_account_targets() {
982 let state = create_state_for_multi_proof_targets();
983 let excluded = MultiProofTargets::default();
984
985 let targets = state.multi_proof_targets_difference(&excluded);
987 assert_eq!(targets.len(), state.accounts.len());
988 for addr in state.accounts.keys() {
989 assert!(targets.contains_key(addr));
990 }
991 }
992
993 #[test]
994 fn test_multi_proof_targets_difference_new_storage_targets() {
995 let state = create_state_for_multi_proof_targets();
996 let excluded = MultiProofTargets::default();
997
998 let targets = state.multi_proof_targets_difference(&excluded);
999
1000 for (addr, storage) in &state.storages {
1002 assert!(targets.contains_key(addr));
1003 let target_slots = &targets[addr];
1004 assert_eq!(target_slots.len(), storage.storage.len());
1005 for slot in storage.storage.keys() {
1006 assert!(target_slots.contains(slot));
1007 }
1008 }
1009 }
1010
1011 #[test]
1012 fn test_multi_proof_targets_difference_filter_excluded_accounts() {
1013 let state = create_state_for_multi_proof_targets();
1014 let mut excluded = MultiProofTargets::default();
1015
1016 let excluded_addr = state
1018 .accounts
1019 .keys()
1020 .find(|&&addr| !state.storages.contains_key(&addr))
1021 .expect("Should have an account without storage");
1022
1023 excluded.insert(*excluded_addr, HashSet::default());
1025
1026 let targets = state.multi_proof_targets_difference(&excluded);
1027
1028 assert!(!targets.contains_key(excluded_addr));
1030 assert_eq!(targets.len(), state.accounts.len() - 1);
1032 }
1033
1034 #[test]
1035 fn test_multi_proof_targets_difference_filter_excluded_storage() {
1036 let state = create_state_for_multi_proof_targets();
1037 let mut excluded = MultiProofTargets::default();
1038
1039 let (addr, storage) = state.storages.iter().next().unwrap();
1041 let mut excluded_slots = HashSet::default();
1042 let excluded_slot = *storage.storage.keys().next().unwrap();
1043 excluded_slots.insert(excluded_slot);
1044 excluded.insert(*addr, excluded_slots);
1045
1046 let targets = state.multi_proof_targets_difference(&excluded);
1047
1048 let target_slots = &targets[addr];
1050 assert!(!target_slots.contains(&excluded_slot));
1051 assert_eq!(target_slots.len(), storage.storage.len() - 1);
1052 }
1053
1054 #[test]
1055 fn test_multi_proof_targets_difference_mixed_excluded_state() {
1056 let mut state = HashedPostState::default();
1057 let mut excluded = MultiProofTargets::default();
1058
1059 let addr1 = B256::random();
1060 let addr2 = B256::random();
1061 let slot1 = B256::random();
1062 let slot2 = B256::random();
1063
1064 state.accounts.insert(addr1, Some(Default::default()));
1065 state.accounts.insert(addr2, Some(Default::default()));
1066
1067 let mut storage = HashedStorage::default();
1068 storage.storage.insert(slot1, U256::ZERO);
1069 storage.storage.insert(slot2, U256::from(1));
1070 state.storages.insert(addr1, storage);
1071
1072 let mut excluded_slots = HashSet::default();
1073 excluded_slots.insert(slot1);
1074 excluded.insert(addr1, excluded_slots);
1075
1076 let targets = state.multi_proof_targets_difference(&excluded);
1077
1078 assert!(targets.contains_key(&addr2));
1079 assert!(!targets[&addr1].contains(&slot1));
1080 assert!(targets[&addr1].contains(&slot2));
1081 }
1082
1083 #[test]
1084 fn test_multi_proof_targets_difference_unmodified_account_with_storage() {
1085 let mut state = HashedPostState::default();
1086 let excluded = MultiProofTargets::default();
1087
1088 let addr = B256::random();
1089 let slot1 = B256::random();
1090 let slot2 = B256::random();
1091
1092 let mut storage = HashedStorage::default();
1095 storage.storage.insert(slot1, U256::from(1));
1096 storage.storage.insert(slot2, U256::from(2));
1097 state.storages.insert(addr, storage);
1098
1099 assert!(!state.accounts.contains_key(&addr));
1100 assert!(!excluded.contains_key(&addr));
1101
1102 let targets = state.multi_proof_targets_difference(&excluded);
1103
1104 assert!(targets.contains_key(&addr));
1106
1107 let target_slots = &targets[&addr];
1108 assert_eq!(target_slots.len(), 2);
1109 assert!(target_slots.contains(&slot1));
1110 assert!(target_slots.contains(&slot2));
1111 }
1112
1113 #[test]
1114 fn test_partition_by_targets() {
1115 let addr1 = B256::random();
1116 let addr2 = B256::random();
1117 let slot1 = B256::random();
1118 let slot2 = B256::random();
1119
1120 let state = HashedPostState {
1121 accounts: B256Map::from_iter([
1122 (addr1, Some(Default::default())),
1123 (addr2, Some(Default::default())),
1124 ]),
1125 storages: B256Map::from_iter([(
1126 addr1,
1127 HashedStorage {
1128 wiped: true,
1129 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1130 },
1131 )]),
1132 };
1133 let targets = MultiProofTargets::from_iter([(addr1, HashSet::from_iter([slot1]))]);
1134
1135 let (with_targets, without_targets) =
1136 state.partition_by_targets(&targets, &MultiAddedRemovedKeys::new());
1137
1138 assert_eq!(
1139 with_targets,
1140 HashedPostState {
1141 accounts: B256Map::from_iter([(addr1, Some(Default::default()))]),
1142 storages: B256Map::from_iter([(
1143 addr1,
1144 HashedStorage {
1145 wiped: true,
1146 storage: B256Map::from_iter([(slot1, U256::ZERO)])
1147 }
1148 )]),
1149 }
1150 );
1151 assert_eq!(
1152 without_targets,
1153 HashedPostState {
1154 accounts: B256Map::from_iter([(addr2, Some(Default::default()))]),
1155 storages: B256Map::from_iter([(
1156 addr1,
1157 HashedStorage {
1158 wiped: false,
1159 storage: B256Map::from_iter([(slot2, U256::from(1))])
1160 }
1161 )]),
1162 }
1163 );
1164 }
1165
1166 #[test]
1167 fn test_chunks() {
1168 let addr1 = B256::from([1; 32]);
1169 let addr2 = B256::from([2; 32]);
1170 let slot1 = B256::from([1; 32]);
1171 let slot2 = B256::from([2; 32]);
1172
1173 let state = HashedPostState {
1174 accounts: B256Map::from_iter([
1175 (addr1, Some(Default::default())),
1176 (addr2, Some(Default::default())),
1177 ]),
1178 storages: B256Map::from_iter([(
1179 addr2,
1180 HashedStorage {
1181 wiped: true,
1182 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1183 },
1184 )]),
1185 };
1186
1187 let mut chunks = state.chunks(2);
1188 assert_eq!(
1189 chunks.next(),
1190 Some(HashedPostState {
1191 accounts: B256Map::from_iter([(addr1, Some(Default::default()))]),
1192 storages: B256Map::from_iter([(addr2, HashedStorage::new(true)),])
1193 })
1194 );
1195 assert_eq!(
1196 chunks.next(),
1197 Some(HashedPostState {
1198 accounts: B256Map::default(),
1199 storages: B256Map::from_iter([(
1200 addr2,
1201 HashedStorage {
1202 wiped: false,
1203 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1204 },
1205 )])
1206 })
1207 );
1208 assert_eq!(
1209 chunks.next(),
1210 Some(HashedPostState {
1211 accounts: B256Map::from_iter([(addr2, Some(Default::default()))]),
1212 storages: B256Map::default()
1213 })
1214 );
1215 assert_eq!(chunks.next(), None);
1216 }
1217
1218 #[test]
1219 fn test_hashed_post_state_sorted_extend_ref() {
1220 let mut state1 = HashedPostStateSorted {
1222 accounts: vec![
1223 (B256::from([1; 32]), Some(Account::default())),
1224 (B256::from([3; 32]), Some(Account::default())),
1225 (B256::from([5; 32]), None),
1226 ],
1227 storages: B256Map::default(),
1228 };
1229
1230 let state2 = HashedPostStateSorted {
1231 accounts: vec![
1232 (B256::from([2; 32]), Some(Account::default())),
1233 (B256::from([3; 32]), Some(Account { nonce: 1, ..Default::default() })), (B256::from([4; 32]), Some(Account::default())),
1235 (B256::from([6; 32]), None),
1236 ],
1237 storages: B256Map::default(),
1238 };
1239
1240 state1.extend_ref(&state2);
1241
1242 assert_eq!(state1.accounts.len(), 6);
1244 assert_eq!(state1.accounts[0].0, B256::from([1; 32]));
1245 assert_eq!(state1.accounts[1].0, B256::from([2; 32]));
1246 assert_eq!(state1.accounts[2].0, B256::from([3; 32]));
1247 assert_eq!(state1.accounts[2].1.unwrap().nonce, 1); assert_eq!(state1.accounts[3].0, B256::from([4; 32]));
1249 assert_eq!(state1.accounts[4].0, B256::from([5; 32]));
1250 assert_eq!(state1.accounts[4].1, None);
1251 assert_eq!(state1.accounts[5].0, B256::from([6; 32]));
1252 assert_eq!(state1.accounts[5].1, None);
1253 }
1254
1255 #[test]
1256 fn test_hashed_storage_sorted_extend_ref() {
1257 let mut storage1 = HashedStorageSorted {
1259 storage_slots: vec![
1260 (B256::from([1; 32]), U256::from(10)),
1261 (B256::from([3; 32]), U256::from(30)),
1262 (B256::from([5; 32]), U256::ZERO),
1263 ],
1264 wiped: false,
1265 };
1266
1267 let storage2 = HashedStorageSorted {
1268 storage_slots: vec![
1269 (B256::from([2; 32]), U256::from(20)),
1270 (B256::from([3; 32]), U256::from(300)), (B256::from([4; 32]), U256::from(40)),
1272 (B256::from([6; 32]), U256::ZERO),
1273 ],
1274 wiped: false,
1275 };
1276
1277 storage1.extend_ref(&storage2);
1278
1279 assert_eq!(storage1.storage_slots.len(), 6);
1280 assert_eq!(storage1.storage_slots[0].0, B256::from([1; 32]));
1281 assert_eq!(storage1.storage_slots[0].1, U256::from(10));
1282 assert_eq!(storage1.storage_slots[1].0, B256::from([2; 32]));
1283 assert_eq!(storage1.storage_slots[1].1, U256::from(20));
1284 assert_eq!(storage1.storage_slots[2].0, B256::from([3; 32]));
1285 assert_eq!(storage1.storage_slots[2].1, U256::from(300)); assert_eq!(storage1.storage_slots[3].0, B256::from([4; 32]));
1287 assert_eq!(storage1.storage_slots[3].1, U256::from(40));
1288 assert_eq!(storage1.storage_slots[4].0, B256::from([5; 32]));
1289 assert_eq!(storage1.storage_slots[4].1, U256::ZERO);
1290 assert_eq!(storage1.storage_slots[5].0, B256::from([6; 32]));
1291 assert_eq!(storage1.storage_slots[5].1, U256::ZERO);
1292 assert!(!storage1.wiped);
1293
1294 let mut storage3 = HashedStorageSorted {
1296 storage_slots: vec![
1297 (B256::from([1; 32]), U256::from(10)),
1298 (B256::from([2; 32]), U256::ZERO),
1299 ],
1300 wiped: false,
1301 };
1302
1303 let storage4 = HashedStorageSorted {
1304 storage_slots: vec![
1305 (B256::from([3; 32]), U256::from(30)),
1306 (B256::from([4; 32]), U256::ZERO),
1307 ],
1308 wiped: true,
1309 };
1310
1311 storage3.extend_ref(&storage4);
1312
1313 assert!(storage3.wiped);
1314 assert_eq!(storage3.storage_slots.len(), 2);
1316 assert_eq!(storage3.storage_slots[0].0, B256::from([3; 32]));
1317 assert_eq!(storage3.storage_slots[0].1, U256::from(30));
1318 assert_eq!(storage3.storage_slots[1].0, B256::from([4; 32]));
1319 assert_eq!(storage3.storage_slots[1].1, U256::ZERO);
1320 }
1321
1322 #[test]
1324 fn test_hashed_post_state_extend_from_sorted_with_accounts() {
1325 let addr1 = B256::random();
1326 let addr2 = B256::random();
1327
1328 let mut state = HashedPostState::default();
1329 state.accounts.insert(addr1, Some(Default::default()));
1330
1331 let mut sorted_state = HashedPostStateSorted::default();
1332 sorted_state.accounts.push((addr2, Some(Default::default())));
1333
1334 state.extend_from_sorted(&sorted_state);
1335
1336 assert_eq!(state.accounts.len(), 2);
1337 assert!(state.accounts.contains_key(&addr1));
1338 assert!(state.accounts.contains_key(&addr2));
1339 }
1340
1341 #[test]
1343 fn test_hashed_post_state_extend_from_sorted_with_destroyed_accounts() {
1344 let addr1 = B256::random();
1345
1346 let mut state = HashedPostState::default();
1347
1348 let mut sorted_state = HashedPostStateSorted::default();
1349 sorted_state.accounts.push((addr1, None));
1350
1351 state.extend_from_sorted(&sorted_state);
1352
1353 assert!(state.accounts.contains_key(&addr1));
1354 assert_eq!(state.accounts.get(&addr1), Some(&None));
1355 }
1356
1357 #[test]
1359 fn test_hashed_storage_extend_from_sorted_non_wiped() {
1360 let slot1 = B256::random();
1361 let slot2 = B256::random();
1362 let slot3 = B256::random();
1363
1364 let mut storage = HashedStorage::from_iter(false, [(slot1, U256::from(100))]);
1365
1366 let sorted = HashedStorageSorted {
1367 storage_slots: vec![(slot2, U256::from(200)), (slot3, U256::ZERO)],
1368 wiped: false,
1369 };
1370
1371 storage.extend_from_sorted(&sorted);
1372
1373 assert!(!storage.wiped);
1374 assert_eq!(storage.storage.len(), 3);
1375 assert_eq!(storage.storage.get(&slot1), Some(&U256::from(100)));
1376 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1377 assert_eq!(storage.storage.get(&slot3), Some(&U256::ZERO));
1378 }
1379
1380 #[test]
1382 fn test_hashed_storage_extend_from_sorted_wiped() {
1383 let slot1 = B256::random();
1384 let slot2 = B256::random();
1385
1386 let mut storage = HashedStorage::from_iter(false, [(slot1, U256::from(100))]);
1387
1388 let sorted =
1389 HashedStorageSorted { storage_slots: vec![(slot2, U256::from(200))], wiped: true };
1390
1391 storage.extend_from_sorted(&sorted);
1392
1393 assert!(storage.wiped);
1394 assert_eq!(storage.storage.len(), 1);
1396 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1397 }
1398
1399 #[test]
1400 fn test_hashed_post_state_chunking_length() {
1401 let addr1 = B256::from([1; 32]);
1402 let addr2 = B256::from([2; 32]);
1403 let addr3 = B256::from([3; 32]);
1404 let addr4 = B256::from([4; 32]);
1405 let slot1 = B256::from([1; 32]);
1406 let slot2 = B256::from([2; 32]);
1407 let slot3 = B256::from([3; 32]);
1408
1409 let state = HashedPostState {
1410 accounts: B256Map::from_iter([(addr1, None), (addr2, None), (addr4, None)]),
1411 storages: B256Map::from_iter([
1412 (
1413 addr1,
1414 HashedStorage {
1415 wiped: false,
1416 storage: B256Map::from_iter([
1417 (slot1, U256::ZERO),
1418 (slot2, U256::ZERO),
1419 (slot3, U256::ZERO),
1420 ]),
1421 },
1422 ),
1423 (
1424 addr2,
1425 HashedStorage {
1426 wiped: true,
1427 storage: B256Map::from_iter([
1428 (slot1, U256::ZERO),
1429 (slot2, U256::ZERO),
1430 (slot3, U256::ZERO),
1431 ]),
1432 },
1433 ),
1434 (
1435 addr3,
1436 HashedStorage {
1437 wiped: false,
1438 storage: B256Map::from_iter([
1439 (slot1, U256::ZERO),
1440 (slot2, U256::ZERO),
1441 (slot3, U256::ZERO),
1442 ]),
1443 },
1444 ),
1445 ]),
1446 };
1447
1448 let chunking_length = state.chunking_length();
1449 for size in 1..=state.clone().chunks(1).count() {
1450 let chunk_count = state.clone().chunks(size).count();
1451 let expected_count = chunking_length.div_ceil(size);
1452 assert_eq!(
1453 chunk_count, expected_count,
1454 "chunking_length: {}, size: {}",
1455 chunking_length, size
1456 );
1457 }
1458 }
1459
1460 #[test]
1461 fn test_clone_into_sorted_equivalence() {
1462 let addr1 = B256::from([1; 32]);
1463 let addr2 = B256::from([2; 32]);
1464 let addr3 = B256::from([3; 32]);
1465 let slot1 = B256::from([1; 32]);
1466 let slot2 = B256::from([2; 32]);
1467 let slot3 = B256::from([3; 32]);
1468
1469 let state = HashedPostState {
1470 accounts: B256Map::from_iter([
1471 (addr1, Some(Account { nonce: 1, balance: U256::from(100), bytecode_hash: None })),
1472 (addr2, None),
1473 (addr3, Some(Account::default())),
1474 ]),
1475 storages: B256Map::from_iter([
1476 (
1477 addr1,
1478 HashedStorage {
1479 wiped: false,
1480 storage: B256Map::from_iter([
1481 (slot1, U256::from(10)),
1482 (slot2, U256::from(20)),
1483 ]),
1484 },
1485 ),
1486 (
1487 addr2,
1488 HashedStorage {
1489 wiped: true,
1490 storage: B256Map::from_iter([(slot3, U256::ZERO)]),
1491 },
1492 ),
1493 ]),
1494 };
1495
1496 let sorted_via_clone = state.clone().into_sorted();
1498 let sorted_via_clone_into = state.clone_into_sorted();
1499
1500 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1501
1502 assert_eq!(state.accounts.len(), 3);
1504 assert_eq!(state.storages.len(), 2);
1505 }
1506
1507 #[test]
1508 fn test_hashed_storage_clone_into_sorted_equivalence() {
1509 let slot1 = B256::from([1; 32]);
1510 let slot2 = B256::from([2; 32]);
1511 let slot3 = B256::from([3; 32]);
1512
1513 let storage = HashedStorage {
1514 wiped: true,
1515 storage: B256Map::from_iter([
1516 (slot1, U256::from(100)),
1517 (slot2, U256::ZERO),
1518 (slot3, U256::from(300)),
1519 ]),
1520 };
1521
1522 let sorted_via_clone = storage.clone().into_sorted();
1524 let sorted_via_clone_into = storage.clone_into_sorted();
1525
1526 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1527
1528 assert_eq!(storage.storage.len(), 3);
1530 assert!(storage.wiped);
1531 }
1532}