1use core::ops::Not;
2
3use crate::{
4 added_removed_keys::MultiAddedRemovedKeys,
5 prefix_set::{PrefixSetMut, TriePrefixSetsMut},
6 utils::{extend_sorted_vec, kway_merge_disjoint_sorted, kway_merge_sorted},
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::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
22
23use revm::database::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 pub fn from_bundle_state<'a, KH: KeyHasher>(
50 state: impl IntoIterator<Item = (&'a Address, &'a BundleAccount)>,
51 ) -> Self {
52 state
53 .into_iter()
54 .map(|(address, account)| {
55 let hashed_address = KH::hash_key(address);
56 let hashed_account = account.info.as_ref().map(Into::into);
57 let hashed_storage = HashedStorage::from_iter(
58 account
59 .storage
60 .iter()
61 .map(|(slot, value)| (keccak256(B256::from(*slot)), value.present_value)),
62 );
63
64 (
65 hashed_address,
66 hashed_account,
67 (!hashed_storage.is_empty()).then_some(hashed_storage),
68 )
69 })
70 .collect()
71 }
72
73 pub fn from_hashed_storage(hashed_address: B256, storage: HashedStorage) -> Self {
75 Self {
76 accounts: HashMap::default(),
77 storages: HashMap::from_iter([(hashed_address, storage)]),
78 }
79 }
80
81 pub fn with_accounts(
83 mut self,
84 accounts: impl IntoIterator<Item = (B256, Option<Account>)>,
85 ) -> Self {
86 self.accounts = HashMap::from_iter(accounts);
87 self
88 }
89
90 pub fn with_storages(
92 mut self,
93 storages: impl IntoIterator<Item = (B256, HashedStorage)>,
94 ) -> Self {
95 self.storages = HashMap::from_iter(storages);
96 self
97 }
98
99 pub fn is_empty(&self) -> bool {
101 self.accounts.is_empty() && self.storages.is_empty()
102 }
103
104 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
108 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
110 let mut destroyed_accounts = HashSet::default();
111 for (hashed_address, account) in &self.accounts {
112 account_prefix_set.insert(Nibbles::unpack(hashed_address));
113
114 if account.is_none() {
115 destroyed_accounts.insert(*hashed_address);
116 }
117 }
118
119 let mut storage_prefix_sets =
121 HashMap::with_capacity_and_hasher(self.storages.len(), Default::default());
122 for (hashed_address, hashed_storage) in &self.storages {
123 account_prefix_set.insert(Nibbles::unpack(hashed_address));
124 storage_prefix_sets.insert(*hashed_address, hashed_storage.construct_prefix_set());
125 }
126
127 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
128 }
129
130 pub fn multi_proof_targets(&self) -> MultiProofTargets {
132 let mut targets = MultiProofTargets::with_capacity(self.accounts.len());
134 for hashed_address in self.accounts.keys() {
135 targets.insert(*hashed_address, Default::default());
136 }
137 for (hashed_address, storage) in &self.storages {
138 targets.entry(*hashed_address).or_default().extend(storage.storage.keys().copied());
139 }
140 targets
141 }
142
143 pub fn multi_proof_targets_difference(
149 &self,
150 excluded: &MultiProofTargets,
151 ) -> MultiProofTargets {
152 let mut targets = MultiProofTargets::default();
153 for hashed_address in self.accounts.keys() {
154 if !excluded.contains_key(hashed_address) {
155 targets.insert(*hashed_address, Default::default());
156 }
157 }
158 for (hashed_address, storage) in &self.storages {
159 let maybe_excluded_storage = excluded.get(hashed_address);
160 let mut hashed_slots_targets = storage
161 .storage
162 .keys()
163 .filter(|slot| !maybe_excluded_storage.is_some_and(|f| f.contains(*slot)))
164 .peekable();
165 if hashed_slots_targets.peek().is_some() {
166 targets.entry(*hashed_address).or_default().extend(hashed_slots_targets);
167 }
168 }
169 targets
170 }
171
172 pub fn partition_by_targets(
179 mut self,
180 targets: &MultiProofTargets,
181 added_removed_keys: &MultiAddedRemovedKeys,
182 ) -> (Self, Self) {
183 let mut state_updates_not_in_targets = Self::default();
184
185 self.storages.retain(|&address, storage| {
186 let storage_added_removed_keys = added_removed_keys.get_storage(&address);
187
188 let (retain, storage_not_in_targets) = match targets.get(&address) {
189 Some(storage_in_targets) => {
190 let mut storage_not_in_targets = HashedStorage::default();
191 storage.storage.retain(|&slot, value| {
192 if storage_in_targets.contains(&slot) &&
193 !storage_added_removed_keys.is_some_and(|k| k.is_removed(&slot))
194 {
195 return true
196 }
197
198 storage_not_in_targets.storage.insert(slot, *value);
199 false
200 });
201
202 let retain = !storage.storage.is_empty();
206
207 if !retain {
211 storage_not_in_targets.wiped = storage.wiped;
212 }
213
214 (
215 retain,
216 storage_not_in_targets.is_empty().not().then_some(storage_not_in_targets),
217 )
218 }
219 None => (false, Some(core::mem::take(storage))),
220 };
221
222 if let Some(storage_not_in_targets) = storage_not_in_targets {
223 state_updates_not_in_targets.storages.insert(address, storage_not_in_targets);
224 }
225
226 retain
227 });
228 self.accounts.retain(|&address, account| {
229 if targets.contains_key(&address) {
230 return true
231 }
232
233 state_updates_not_in_targets.accounts.insert(address, *account);
234 false
235 });
236
237 (self, state_updates_not_in_targets)
238 }
239
240 pub fn chunks(self, size: usize) -> ChunkedHashedPostState {
244 ChunkedHashedPostState::new(self, size)
245 }
246
247 pub fn chunking_length(&self) -> usize {
249 self.accounts.len() +
250 self.storages
251 .values()
252 .map(|storage| if storage.wiped { 1 } else { 0 } + storage.storage.len())
253 .sum::<usize>()
254 }
255
256 pub fn extend(&mut self, other: Self) {
259 self.extend_inner(Cow::Owned(other));
260 }
261
262 pub fn extend_ref(&mut self, other: &Self) {
267 self.extend_inner(Cow::Borrowed(other));
268 }
269
270 fn extend_inner(&mut self, other: Cow<'_, Self>) {
271 self.accounts.extend(other.accounts.iter().map(|(&k, &v)| (k, v)));
272
273 self.storages.reserve(other.storages.len());
274 match other {
275 Cow::Borrowed(other) => {
276 self.extend_storages(other.storages.iter().map(|(k, v)| (*k, Cow::Borrowed(v))))
277 }
278 Cow::Owned(other) => {
279 self.extend_storages(other.storages.into_iter().map(|(k, v)| (k, Cow::Owned(v))))
280 }
281 }
282 }
283
284 fn extend_storages<'a>(
285 &mut self,
286 storages: impl IntoIterator<Item = (B256, Cow<'a, HashedStorage>)>,
287 ) {
288 for (hashed_address, storage) in storages {
289 match self.storages.entry(hashed_address) {
290 hash_map::Entry::Vacant(entry) => {
291 entry.insert(storage.into_owned());
292 }
293 hash_map::Entry::Occupied(mut entry) => {
294 entry.get_mut().extend(&storage);
295 }
296 }
297 }
298 }
299
300 pub fn extend_from_sorted(&mut self, sorted: &HashedPostStateSorted) {
304 self.accounts.reserve(sorted.accounts.len());
306
307 for (address, account) in &sorted.accounts {
309 self.accounts.insert(*address, *account);
310 }
311
312 self.storages.reserve(sorted.storages.len());
314
315 for (hashed_address, sorted_storage) in &sorted.storages {
317 match self.storages.entry(*hashed_address) {
318 hash_map::Entry::Vacant(entry) => {
319 let mut new_storage = HashedStorage::new(false);
320 new_storage.extend_from_sorted(sorted_storage);
321 entry.insert(new_storage);
322 }
323 hash_map::Entry::Occupied(mut entry) => {
324 entry.get_mut().extend_from_sorted(sorted_storage);
325 }
326 }
327 }
328 }
329
330 pub fn into_sorted(self) -> HashedPostStateSorted {
332 let mut accounts: Vec<_> = self.accounts.into_iter().collect();
333 accounts.sort_unstable_by_key(|(address, _)| *address);
334
335 let storages = self
336 .storages
337 .into_iter()
338 .map(|(hashed_address, storage)| (hashed_address, storage.into_sorted()))
339 .collect();
340
341 HashedPostStateSorted { accounts, storages }
342 }
343
344 pub fn clone_into_sorted(&self) -> HashedPostStateSorted {
347 let mut accounts: Vec<_> = self.accounts.iter().map(|(&k, &v)| (k, v)).collect();
348 accounts.sort_unstable_by_key(|(address, _)| *address);
349
350 let storages = self
351 .storages
352 .iter()
353 .map(|(&hashed_address, storage)| (hashed_address, storage.clone_into_sorted()))
354 .collect();
355
356 HashedPostStateSorted { accounts, storages }
357 }
358
359 pub fn clear(&mut self) {
361 self.accounts.clear();
362 self.storages.clear();
363 }
364}
365
366impl FromIterator<(B256, Option<Account>, Option<HashedStorage>)> for HashedPostState {
367 fn from_iter<T: IntoIterator<Item = (B256, Option<Account>, Option<HashedStorage>)>>(
383 iter: T,
384 ) -> Self {
385 let iter = iter.into_iter();
386 let (lower, _) = iter.size_hint();
387 let mut hashed_state = Self::with_capacity(lower);
388
389 for (hashed_address, info, hashed_storage) in iter {
390 hashed_state.accounts.insert(hashed_address, info);
391 if let Some(storage) = hashed_storage {
392 hashed_state.storages.insert(hashed_address, storage);
393 }
394 }
395
396 hashed_state
397 }
398}
399
400#[cfg(feature = "rayon")]
401impl FromParallelIterator<(B256, Option<Account>, Option<HashedStorage>)> for HashedPostState {
402 fn from_par_iter<I>(par_iter: I) -> Self
414 where
415 I: IntoParallelIterator<Item = (B256, Option<Account>, Option<HashedStorage>)>,
416 {
417 let vec: Vec<_> = par_iter.into_par_iter().collect();
418 vec.into_iter().collect()
419 }
420}
421
422#[derive(PartialEq, Eq, Clone, Debug, Default)]
424#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
425pub struct HashedStorage {
426 pub wiped: bool,
428 pub storage: B256Map<U256>,
430}
431
432impl HashedStorage {
433 pub fn new(wiped: bool) -> Self {
435 Self { wiped, storage: HashMap::default() }
436 }
437
438 pub fn is_empty(&self) -> bool {
440 !self.wiped && self.storage.is_empty()
441 }
442
443 #[expect(clippy::should_implement_trait)]
445 pub fn from_iter(iter: impl IntoIterator<Item = (B256, U256)>) -> Self {
446 Self { wiped: false, storage: HashMap::from_iter(iter) }
447 }
448
449 pub fn from_plain_storage<'a>(storage: impl IntoIterator<Item = (&'a U256, &'a U256)>) -> Self {
451 Self::from_iter(
452 storage.into_iter().map(|(key, value)| (keccak256(B256::from(*key)), *value)),
453 )
454 }
455
456 pub fn construct_prefix_set(&self) -> PrefixSetMut {
458 if self.wiped {
459 PrefixSetMut::all()
460 } else {
461 let mut prefix_set = PrefixSetMut::with_capacity(self.storage.len());
462 for hashed_slot in self.storage.keys() {
463 prefix_set.insert(Nibbles::unpack(hashed_slot));
464 }
465 prefix_set
466 }
467 }
468
469 pub fn extend(&mut self, other: &Self) {
472 if other.wiped {
473 self.wiped = true;
474 self.storage.clear();
475 }
476 self.storage.extend(other.storage.iter().map(|(&k, &v)| (k, v)));
477 }
478
479 pub fn extend_from_sorted(&mut self, sorted: &HashedStorageSorted) {
483 if sorted.wiped {
484 self.wiped = true;
485 self.storage.clear();
486 }
487
488 self.storage.reserve(sorted.storage_slots.len());
490
491 for (slot, value) in &sorted.storage_slots {
493 self.storage.insert(*slot, *value);
494 }
495 }
496
497 pub fn into_sorted(self) -> HashedStorageSorted {
499 let mut storage_slots: Vec<_> = self.storage.into_iter().collect();
500 storage_slots.sort_unstable_by_key(|(key, _)| *key);
501
502 HashedStorageSorted { storage_slots, wiped: self.wiped }
503 }
504
505 pub fn clone_into_sorted(&self) -> HashedStorageSorted {
508 let mut storage_slots: Vec<_> = self.storage.iter().map(|(&k, &v)| (k, v)).collect();
509 storage_slots.sort_unstable_by_key(|(key, _)| *key);
510
511 HashedStorageSorted { storage_slots, wiped: self.wiped }
512 }
513}
514
515#[derive(PartialEq, Eq, Clone, Default, Debug)]
517#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
518pub struct HashedPostStateSorted {
519 pub accounts: Vec<(B256, Option<Account>)>,
521 pub storages: B256Map<HashedStorageSorted>,
523}
524
525impl HashedPostStateSorted {
526 pub const fn new(
528 accounts: Vec<(B256, Option<Account>)>,
529 storages: B256Map<HashedStorageSorted>,
530 ) -> Self {
531 Self { accounts, storages }
532 }
533
534 pub const fn accounts(&self) -> &Vec<(B256, Option<Account>)> {
536 &self.accounts
537 }
538
539 pub const fn account_storages(&self) -> &B256Map<HashedStorageSorted> {
541 &self.storages
542 }
543
544 pub fn is_empty(&self) -> bool {
546 self.accounts.is_empty() && self.storages.is_empty()
547 }
548
549 pub fn total_len(&self) -> usize {
551 self.accounts.len() + self.storages.values().map(|s| s.len()).sum::<usize>()
552 }
553
554 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
559 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
560 let mut destroyed_accounts = HashSet::default();
561 for (hashed_address, account) in &self.accounts {
562 account_prefix_set.insert(Nibbles::unpack(hashed_address));
563 if account.is_none() {
564 destroyed_accounts.insert(*hashed_address);
565 }
566 }
567
568 let mut storage_prefix_sets =
569 B256Map::with_capacity_and_hasher(self.storages.len(), Default::default());
570 for (hashed_address, hashed_storage) in &self.storages {
571 account_prefix_set.insert(Nibbles::unpack(hashed_address));
573
574 let prefix_set = if hashed_storage.wiped {
575 PrefixSetMut::all()
576 } else {
577 let mut prefix_set =
578 PrefixSetMut::with_capacity(hashed_storage.storage_slots.len());
579 prefix_set.extend_keys(
580 hashed_storage
581 .storage_slots
582 .iter()
583 .map(|(hashed_slot, _)| Nibbles::unpack(hashed_slot)),
584 );
585 prefix_set
586 };
587
588 storage_prefix_sets.insert(*hashed_address, prefix_set);
589 }
590
591 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
592 }
593
594 pub fn extend_ref_and_sort(&mut self, other: &Self) {
599 extend_sorted_vec(&mut self.accounts, &other.accounts);
601
602 for (hashed_address, other_storage) in &other.storages {
604 self.storages
605 .entry(*hashed_address)
606 .and_modify(|existing| existing.extend_ref(other_storage))
607 .or_insert_with(|| other_storage.clone());
608 }
609 }
610
611 pub fn merge_batch<T: AsRef<Self> + From<Self>>(iter: impl IntoIterator<Item = T>) -> T {
616 let items: alloc::vec::Vec<_> = iter.into_iter().collect();
617 match items.len() {
618 0 => Self::default().into(),
619 1 => items.into_iter().next().expect("len == 1"),
620 _ => Self::merge_slice(&items).into(),
621 }
622 }
623
624 pub fn merge_slice<T: AsRef<Self>>(items: &[T]) -> Self {
630 const THRESHOLD: usize = 30;
631
632 let k = items.len();
633
634 if k == 0 {
635 return Self::default();
636 }
637 if k == 1 {
638 return items[0].as_ref().clone();
639 }
640
641 if k < THRESHOLD {
642 let mut iter = items.iter().rev();
644 let mut acc = iter.next().expect("k > 0").as_ref().clone();
645 for next in iter {
646 acc.extend_ref_and_sort(next.as_ref());
647 }
648 return acc;
649 }
650
651 let accounts = kway_merge_sorted(items.iter().map(|i| i.as_ref().accounts.as_slice()));
653
654 struct StorageAcc<'a> {
655 wiped: bool,
656 sealed: bool,
657 slices: Vec<&'a [(B256, U256)]>,
658 }
659
660 let mut acc: B256Map<StorageAcc<'_>> = B256Map::default();
661
662 for item in items {
663 for (addr, storage) in &item.as_ref().storages {
664 let entry = acc.entry(*addr).or_insert_with(|| StorageAcc {
665 wiped: false,
666 sealed: false,
667 slices: Vec::new(),
668 });
669
670 if entry.sealed {
671 continue;
672 }
673
674 entry.slices.push(storage.storage_slots.as_slice());
675 if storage.wiped {
676 entry.wiped = true;
677 entry.sealed = true;
678 }
679 }
680 }
681
682 let storages = acc
683 .into_iter()
684 .map(|(addr, entry)| {
685 let storage_slots = kway_merge_sorted(entry.slices);
686 (addr, HashedStorageSorted { wiped: entry.wiped, storage_slots })
687 })
688 .collect();
689
690 Self { accounts, storages }
691 }
692
693 pub fn disjointed_merge_batch<'a>(batch: &[&'a Self], mask: &[&'a Self]) -> Self {
705 let account_count = batch.iter().map(|item| item.accounts.len()).sum();
706 let mut accounts = Vec::with_capacity(account_count);
707 accounts.extend(kway_merge_disjoint_sorted(
708 batch.iter().rev().map(|item| item.accounts.as_slice()),
709 mask.iter().map(|item| item.accounts.as_slice()),
710 ));
711
712 struct StorageAcc<'a> {
713 slot_count: usize,
714 slices: Vec<&'a [(B256, U256)]>,
715 }
716
717 #[derive(Default)]
718 struct StorageMaskAcc<'a> {
719 slices: Vec<&'a [(B256, U256)]>,
720 }
721
722 let mut storages = B256Map::with_capacity_and_hasher(
723 batch.iter().map(|item| item.storages.len()).sum(),
724 Default::default(),
725 );
726
727 for item in batch.iter().rev() {
728 for (hashed_address, storage) in &item.storages {
729 assert!(
730 !storage.wiped,
731 "storage wipes are not supported by disjointed_merge_batch"
732 );
733 let entry = storages
734 .entry(*hashed_address)
735 .or_insert_with(|| StorageAcc { slot_count: 0, slices: Vec::new() });
736 entry.slices.push(storage.storage_slots.as_slice());
737 entry.slot_count += storage.storage_slots.len();
738 }
739 }
740
741 let mut storage_masks: B256Map<StorageMaskAcc<'a>> = B256Map::with_capacity_and_hasher(
742 mask.iter().map(|item| item.storages.len()).sum(),
743 Default::default(),
744 );
745 for item in mask {
746 for (hashed_address, storage) in &item.storages {
747 assert!(
748 !storage.wiped,
749 "storage wipes are not supported by disjointed_merge_batch"
750 );
751 let entry = storage_masks.entry(*hashed_address).or_default();
752 entry.slices.push(storage.storage_slots.as_slice());
753 }
754 }
755
756 let storages = storages
757 .into_iter()
758 .filter_map(|(hashed_address, entry)| {
759 let slot_count = entry.slot_count;
760 let storage_slots = match storage_masks.get(&hashed_address) {
761 Some(mask_entry) => {
762 let mut storage_slots = Vec::with_capacity(slot_count);
763 storage_slots.extend(kway_merge_disjoint_sorted(
764 entry.slices,
765 mask_entry.slices.iter().copied(),
766 ));
767 storage_slots
768 }
769 None => kway_merge_sorted(entry.slices),
770 };
771
772 (!storage_slots.is_empty() || mask.is_empty()).then_some((
773 hashed_address,
774 HashedStorageSorted { wiped: false, storage_slots },
775 ))
776 })
777 .collect();
778
779 Self { accounts, storages }
780 }
781
782 pub fn clear(&mut self) {
784 self.accounts.clear();
785 self.storages.clear();
786 }
787}
788
789impl AsRef<Self> for HashedPostStateSorted {
790 fn as_ref(&self) -> &Self {
791 self
792 }
793}
794
795#[derive(Clone, Eq, PartialEq, Debug, Default)]
797#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
798pub struct HashedStorageSorted {
799 pub storage_slots: Vec<(B256, U256)>,
801 pub wiped: bool,
803}
804
805impl HashedStorageSorted {
806 pub const fn is_wiped(&self) -> bool {
808 self.wiped
809 }
810
811 pub fn storage_slots_ref(&self) -> &[(B256, U256)] {
813 &self.storage_slots
814 }
815
816 pub const fn len(&self) -> usize {
818 self.storage_slots.len()
819 }
820
821 pub const fn is_empty(&self) -> bool {
823 self.storage_slots.is_empty()
824 }
825
826 pub fn extend_ref(&mut self, other: &Self) {
831 if other.wiped {
832 self.wiped = true;
834 self.storage_slots.clear();
835 self.storage_slots.extend(other.storage_slots.iter().copied());
836 return;
837 }
838
839 extend_sorted_vec(&mut self.storage_slots, &other.storage_slots);
841 }
842
843 pub fn merge_batch<'a>(updates: impl IntoIterator<Item = &'a Self>) -> Self {
846 let updates: Vec<_> = updates.into_iter().collect();
847 if updates.is_empty() {
848 return Self::default();
849 }
850
851 let wipe_idx = updates.iter().position(|u| u.wiped);
852 let relevant = wipe_idx.map_or(&updates[..], |idx| &updates[..=idx]);
853 let storage_slots = kway_merge_sorted(relevant.iter().map(|u| u.storage_slots.as_slice()));
854
855 Self { wiped: wipe_idx.is_some(), storage_slots }
856 }
857}
858
859impl From<HashedStorageSorted> for HashedStorage {
860 fn from(sorted: HashedStorageSorted) -> Self {
861 let mut storage = B256Map::default();
862
863 for (slot, value) in sorted.storage_slots {
865 storage.insert(slot, value);
866 }
867
868 Self { wiped: sorted.wiped, storage }
869 }
870}
871
872impl From<HashedPostStateSorted> for HashedPostState {
873 fn from(sorted: HashedPostStateSorted) -> Self {
874 let mut accounts =
875 B256Map::with_capacity_and_hasher(sorted.accounts.len(), Default::default());
876
877 for (address, account) in sorted.accounts {
879 accounts.insert(address, account);
880 }
881
882 let storages = sorted
884 .storages
885 .into_iter()
886 .map(|(address, storage)| (address, storage.into()))
887 .collect();
888
889 Self { accounts, storages }
890 }
891}
892
893#[derive(Debug)]
901pub struct ChunkedHashedPostState {
902 flattened: alloc::vec::IntoIter<(B256, FlattenedHashedPostStateItem)>,
903 size: usize,
904}
905
906#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
909enum FlattenedStateOrder {
910 StorageWipe,
911 StorageUpdate(B256),
912 Account,
913}
914
915#[derive(Debug)]
916enum FlattenedHashedPostStateItem {
917 Account(Option<Account>),
918 StorageWipe,
919 StorageUpdate { slot: B256, value: U256 },
920}
921
922impl FlattenedHashedPostStateItem {
923 const fn order(&self) -> FlattenedStateOrder {
924 match self {
925 Self::StorageWipe => FlattenedStateOrder::StorageWipe,
926 Self::StorageUpdate { slot, .. } => FlattenedStateOrder::StorageUpdate(*slot),
927 Self::Account(_) => FlattenedStateOrder::Account,
928 }
929 }
930}
931
932impl ChunkedHashedPostState {
933 fn new(hashed_post_state: HashedPostState, size: usize) -> Self {
934 let flattened = hashed_post_state
935 .storages
936 .into_iter()
937 .flat_map(|(address, storage)| {
938 storage
939 .wiped
940 .then_some((address, FlattenedHashedPostStateItem::StorageWipe))
941 .into_iter()
942 .chain(storage.storage.into_iter().map(move |(slot, value)| {
943 (address, FlattenedHashedPostStateItem::StorageUpdate { slot, value })
944 }))
945 })
946 .chain(hashed_post_state.accounts.into_iter().map(|(address, account)| {
947 (address, FlattenedHashedPostStateItem::Account(account))
948 }))
949 .sorted_unstable_by_key(|(address, item)| (*address, item.order()));
954
955 Self { flattened, size }
956 }
957}
958
959impl Iterator for ChunkedHashedPostState {
960 type Item = HashedPostState;
961
962 fn next(&mut self) -> Option<Self::Item> {
963 let mut chunk = HashedPostState::default();
964
965 let mut current_size = 0;
966 while current_size < self.size {
967 let Some((address, item)) = self.flattened.next() else { break };
968
969 match item {
970 FlattenedHashedPostStateItem::Account(account) => {
971 chunk.accounts.insert(address, account);
972 }
973 FlattenedHashedPostStateItem::StorageWipe => {
974 chunk.storages.entry(address).or_default().wiped = true;
975 }
976 FlattenedHashedPostStateItem::StorageUpdate { slot, value } => {
977 chunk.storages.entry(address).or_default().storage.insert(slot, value);
978 }
979 }
980
981 current_size += 1;
982 }
983
984 if chunk.is_empty() {
985 None
986 } else {
987 Some(chunk)
988 }
989 }
990}
991
992#[cfg(test)]
993mod tests {
994 use super::*;
995 use crate::KeccakKeyHasher;
996 use alloy_primitives::Bytes;
997 use revm::{
998 database::{states::StorageSlot, AccountStatus, StorageWithOriginalValues},
999 state::{AccountInfo, Bytecode},
1000 };
1001
1002 fn bundle_hashed_storage(account: &BundleAccount) -> Option<HashedStorage> {
1003 let address = Address::ZERO;
1004 let mut state =
1005 HashedPostState::from_bundle_state::<KeccakKeyHasher>([(&address, account)]);
1006 state.storages.remove(&keccak256(address))
1007 }
1008
1009 fn changed_storage(original: U256, present: U256) -> StorageWithOriginalValues {
1010 core::iter::once((U256::from(1), StorageSlot::new_changed(original, present))).collect()
1011 }
1012
1013 #[test]
1014 fn hashed_state_wiped_extension() {
1015 let hashed_address = B256::default();
1016 let hashed_slot = B256::with_last_byte(64);
1017 let hashed_slot2 = B256::with_last_byte(65);
1018
1019 let original_slot_value = U256::from(123);
1021 let mut hashed_state = HashedPostState::default().with_storages([(
1022 hashed_address,
1023 HashedStorage::from_iter([
1024 (hashed_slot, original_slot_value),
1025 (hashed_slot2, original_slot_value),
1026 ]),
1027 )]);
1028
1029 let updated_slot_value = U256::from(321);
1031 let extension = HashedPostState::default().with_storages([(
1032 hashed_address,
1033 HashedStorage::from_iter([(hashed_slot, updated_slot_value)]),
1034 )]);
1035 hashed_state.extend(extension);
1036
1037 let account_storage = hashed_state.storages.get(&hashed_address);
1038 assert_eq!(
1039 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
1040 Some(&updated_slot_value)
1041 );
1042 assert_eq!(
1043 account_storage.and_then(|st| st.storage.get(&hashed_slot2)),
1044 Some(&original_slot_value)
1045 );
1046 assert_eq!(account_storage.map(|st| st.wiped), Some(false));
1047
1048 let wiped_extension =
1050 HashedPostState::default().with_storages([(hashed_address, HashedStorage::new(true))]);
1051 hashed_state.extend(wiped_extension);
1052
1053 let account_storage = hashed_state.storages.get(&hashed_address);
1054 assert_eq!(account_storage.map(|st| st.storage.is_empty()), Some(true));
1055 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
1056
1057 hashed_state.extend(HashedPostState::default().with_storages([(
1059 hashed_address,
1060 HashedStorage::from_iter([(hashed_slot, original_slot_value)]),
1061 )]));
1062 let account_storage = hashed_state.storages.get(&hashed_address);
1063 assert_eq!(
1064 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
1065 Some(&original_slot_value)
1066 );
1067 assert_eq!(account_storage.and_then(|st| st.storage.get(&hashed_slot2)), None);
1068 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
1069
1070 hashed_state.extend(HashedPostState::default().with_storages([(
1072 hashed_address,
1073 HashedStorage::from_iter([(hashed_slot2, updated_slot_value)]),
1074 )]));
1075 let account_storage = hashed_state.storages.get(&hashed_address);
1076 assert_eq!(
1077 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
1078 Some(&original_slot_value)
1079 );
1080 assert_eq!(
1081 account_storage.and_then(|st| st.storage.get(&hashed_slot2)),
1082 Some(&updated_slot_value)
1083 );
1084 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
1085 }
1086
1087 #[test]
1088 fn test_hashed_post_state_from_bundle_state() {
1089 let address = Address::random();
1091
1092 let account_info = AccountInfo {
1094 balance: U256::from(123),
1095 nonce: 42,
1096 code_hash: B256::random(),
1097 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2]))),
1098 account_id: None,
1099 };
1100
1101 let mut storage = StorageWithOriginalValues::default();
1102 storage.insert(
1103 U256::from(1),
1104 StorageSlot { present_value: U256::from(4), ..Default::default() },
1105 );
1106
1107 let account = BundleAccount {
1109 status: AccountStatus::Changed,
1110 info: Some(account_info.clone()),
1111 storage,
1112 original_info: None,
1113 };
1114
1115 let state = vec![(&address, &account)];
1117
1118 let hashed_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(state);
1120
1121 assert_eq!(hashed_state.accounts.len(), 1);
1123 assert_eq!(hashed_state.storages.len(), 1);
1124
1125 assert_eq!(
1127 *hashed_state.accounts.get(&keccak256(address)).unwrap(),
1128 Some(account_info.into())
1129 );
1130 }
1131
1132 #[test]
1133 fn destroyed_prefunded_account_without_storage_emits_no_storage() {
1134 let original_info = AccountInfo { balance: U256::from(1), ..Default::default() };
1135 let account = BundleAccount::new(
1136 Some(original_info),
1137 None,
1138 StorageWithOriginalValues::default(),
1139 AccountStatus::Destroyed,
1140 );
1141
1142 assert!(bundle_hashed_storage(&account).is_none());
1143 }
1144
1145 #[test]
1146 fn destroyed_accounts_emit_zero_storage_changes_without_wipe() {
1147 let existing_contract =
1148 AccountInfo { code_hash: B256::repeat_byte(0x01), ..Default::default() };
1149 let legacy_empty_account = AccountInfo::default();
1150 let prefunded_account = AccountInfo { balance: U256::from(1), ..Default::default() };
1151
1152 for original_info in
1153 [Some(existing_contract), Some(legacy_empty_account), Some(prefunded_account), None]
1154 {
1155 let account = BundleAccount::new(
1156 original_info,
1157 None,
1158 changed_storage(U256::from(2), U256::ZERO),
1159 AccountStatus::Destroyed,
1160 );
1161
1162 let storage = bundle_hashed_storage(&account).unwrap();
1163 let hashed_slot = keccak256(B256::from(U256::from(1)));
1164 assert!(!storage.wiped);
1165 assert_eq!(storage.storage[&hashed_slot], U256::ZERO);
1166 }
1167 }
1168
1169 #[test]
1170 fn destroyed_recreated_accounts_preserve_storage_without_wipe() {
1171 let value = U256::from(2);
1172 let new_account = BundleAccount::new(
1173 None,
1174 Some(AccountInfo::default()),
1175 changed_storage(U256::ZERO, value),
1176 AccountStatus::DestroyedChanged,
1177 );
1178 let original_info =
1179 AccountInfo { code_hash: B256::repeat_byte(0x01), ..Default::default() };
1180 let existing_account = BundleAccount::new(
1181 Some(original_info),
1182 Some(AccountInfo::default()),
1183 changed_storage(U256::ZERO, value),
1184 AccountStatus::DestroyedChanged,
1185 );
1186
1187 let new_storage = bundle_hashed_storage(&new_account).unwrap();
1188 let existing_storage = bundle_hashed_storage(&existing_account).unwrap();
1189 let hashed_slot = keccak256(B256::from(U256::from(1)));
1190
1191 assert!(!new_storage.wiped);
1192 assert!(!existing_storage.wiped);
1193 assert_eq!(new_storage.storage[&hashed_slot], value);
1194 assert_eq!(existing_storage.storage[&hashed_slot], value);
1195 }
1196
1197 #[test]
1198 fn test_hashed_post_state_with_accounts() {
1199 let address_1 = Address::random();
1201 let address_2 = Address::random();
1202
1203 let account_info_1 = AccountInfo {
1204 balance: U256::from(1000),
1205 nonce: 1,
1206 code_hash: B256::random(),
1207 code: None,
1208 account_id: None,
1209 };
1210
1211 let account_1 = (keccak256(address_1), Some(account_info_1.into()));
1213 let account_2 = (keccak256(address_2), None);
1214
1215 let hashed_state = HashedPostState::default().with_accounts(vec![account_1, account_2]);
1217
1218 assert_eq!(hashed_state.accounts.len(), 2);
1220 assert!(hashed_state.accounts.contains_key(&keccak256(address_1)));
1221 assert!(hashed_state.accounts.contains_key(&keccak256(address_2)));
1222 }
1223
1224 #[test]
1225 fn test_hashed_post_state_with_storages() {
1226 let address_1 = Address::random();
1228 let address_2 = Address::random();
1229
1230 let storage_1 = (keccak256(address_1), HashedStorage::new(false));
1231 let storage_2 = (keccak256(address_2), HashedStorage::new(true));
1232
1233 let hashed_state = HashedPostState::default().with_storages(vec![storage_1, storage_2]);
1235
1236 assert_eq!(hashed_state.storages.len(), 2);
1238 assert!(hashed_state.storages.contains_key(&keccak256(address_1)));
1239 assert!(hashed_state.storages.contains_key(&keccak256(address_2)));
1240 }
1241
1242 #[test]
1243 fn test_hashed_post_state_is_empty() {
1244 let empty_state = HashedPostState::default();
1246 assert!(empty_state.is_empty());
1247
1248 let non_empty_state = HashedPostState::default()
1250 .with_accounts(vec![(keccak256(Address::random()), Some(Account::default()))]);
1251 assert!(!non_empty_state.is_empty());
1252 }
1253
1254 fn create_state_for_multi_proof_targets() -> HashedPostState {
1255 let mut state = HashedPostState::default();
1256
1257 let addr1 = B256::random();
1258 let addr2 = B256::random();
1259 state.accounts.insert(addr1, Some(Default::default()));
1260 state.accounts.insert(addr2, Some(Default::default()));
1261
1262 let mut storage = HashedStorage::default();
1263 let slot1 = B256::random();
1264 let slot2 = B256::random();
1265 storage.storage.insert(slot1, U256::ZERO);
1266 storage.storage.insert(slot2, U256::from(1));
1267 state.storages.insert(addr1, storage);
1268
1269 state
1270 }
1271
1272 #[test]
1273 fn test_multi_proof_targets_difference_empty_state() {
1274 let state = HashedPostState::default();
1275 let excluded = MultiProofTargets::default();
1276
1277 let targets = state.multi_proof_targets_difference(&excluded);
1278 assert!(targets.is_empty());
1279 }
1280
1281 #[test]
1282 fn test_multi_proof_targets_difference_new_account_targets() {
1283 let state = create_state_for_multi_proof_targets();
1284 let excluded = MultiProofTargets::default();
1285
1286 let targets = state.multi_proof_targets_difference(&excluded);
1288 assert_eq!(targets.len(), state.accounts.len());
1289 for addr in state.accounts.keys() {
1290 assert!(targets.contains_key(addr));
1291 }
1292 }
1293
1294 #[test]
1295 fn test_multi_proof_targets_difference_new_storage_targets() {
1296 let state = create_state_for_multi_proof_targets();
1297 let excluded = MultiProofTargets::default();
1298
1299 let targets = state.multi_proof_targets_difference(&excluded);
1300
1301 for (addr, storage) in &state.storages {
1303 assert!(targets.contains_key(addr));
1304 let target_slots = &targets[addr];
1305 assert_eq!(target_slots.len(), storage.storage.len());
1306 for slot in storage.storage.keys() {
1307 assert!(target_slots.contains(slot));
1308 }
1309 }
1310 }
1311
1312 #[test]
1313 fn test_multi_proof_targets_difference_filter_excluded_accounts() {
1314 let state = create_state_for_multi_proof_targets();
1315 let mut excluded = MultiProofTargets::default();
1316
1317 let excluded_addr = state
1319 .accounts
1320 .keys()
1321 .find(|&&addr| !state.storages.contains_key(&addr))
1322 .expect("Should have an account without storage");
1323
1324 excluded.insert(*excluded_addr, HashSet::default());
1326
1327 let targets = state.multi_proof_targets_difference(&excluded);
1328
1329 assert!(!targets.contains_key(excluded_addr));
1331 assert_eq!(targets.len(), state.accounts.len() - 1);
1333 }
1334
1335 #[test]
1336 fn test_multi_proof_targets_difference_filter_excluded_storage() {
1337 let state = create_state_for_multi_proof_targets();
1338 let mut excluded = MultiProofTargets::default();
1339
1340 let (addr, storage) = state.storages.iter().next().unwrap();
1342 let mut excluded_slots = HashSet::default();
1343 let excluded_slot = *storage.storage.keys().next().unwrap();
1344 excluded_slots.insert(excluded_slot);
1345 excluded.insert(*addr, excluded_slots);
1346
1347 let targets = state.multi_proof_targets_difference(&excluded);
1348
1349 let target_slots = &targets[addr];
1351 assert!(!target_slots.contains(&excluded_slot));
1352 assert_eq!(target_slots.len(), storage.storage.len() - 1);
1353 }
1354
1355 #[test]
1356 fn test_multi_proof_targets_difference_mixed_excluded_state() {
1357 let mut state = HashedPostState::default();
1358 let mut excluded = MultiProofTargets::default();
1359
1360 let addr1 = B256::random();
1361 let addr2 = B256::random();
1362 let slot1 = B256::random();
1363 let slot2 = B256::random();
1364
1365 state.accounts.insert(addr1, Some(Default::default()));
1366 state.accounts.insert(addr2, Some(Default::default()));
1367
1368 let mut storage = HashedStorage::default();
1369 storage.storage.insert(slot1, U256::ZERO);
1370 storage.storage.insert(slot2, U256::from(1));
1371 state.storages.insert(addr1, storage);
1372
1373 let mut excluded_slots = HashSet::default();
1374 excluded_slots.insert(slot1);
1375 excluded.insert(addr1, excluded_slots);
1376
1377 let targets = state.multi_proof_targets_difference(&excluded);
1378
1379 assert!(targets.contains_key(&addr2));
1380 assert!(!targets[&addr1].contains(&slot1));
1381 assert!(targets[&addr1].contains(&slot2));
1382 }
1383
1384 #[test]
1385 fn test_multi_proof_targets_difference_unmodified_account_with_storage() {
1386 let mut state = HashedPostState::default();
1387 let excluded = MultiProofTargets::default();
1388
1389 let addr = B256::random();
1390 let slot1 = B256::random();
1391 let slot2 = B256::random();
1392
1393 let mut storage = HashedStorage::default();
1396 storage.storage.insert(slot1, U256::from(1));
1397 storage.storage.insert(slot2, U256::from(2));
1398 state.storages.insert(addr, storage);
1399
1400 assert!(!state.accounts.contains_key(&addr));
1401 assert!(!excluded.contains_key(&addr));
1402
1403 let targets = state.multi_proof_targets_difference(&excluded);
1404
1405 assert!(targets.contains_key(&addr));
1407
1408 let target_slots = &targets[&addr];
1409 assert_eq!(target_slots.len(), 2);
1410 assert!(target_slots.contains(&slot1));
1411 assert!(target_slots.contains(&slot2));
1412 }
1413
1414 #[test]
1415 fn test_partition_by_targets() {
1416 let addr1 = B256::random();
1417 let addr2 = B256::random();
1418 let slot1 = B256::random();
1419 let slot2 = B256::random();
1420
1421 let state = HashedPostState {
1422 accounts: B256Map::from_iter([
1423 (addr1, Some(Default::default())),
1424 (addr2, Some(Default::default())),
1425 ]),
1426 storages: B256Map::from_iter([(
1427 addr1,
1428 HashedStorage {
1429 wiped: true,
1430 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1431 },
1432 )]),
1433 };
1434 let targets = MultiProofTargets::from_iter([(addr1, HashSet::from_iter([slot1]))]);
1435
1436 let (with_targets, without_targets) =
1437 state.partition_by_targets(&targets, &MultiAddedRemovedKeys::new());
1438
1439 assert_eq!(
1440 with_targets,
1441 HashedPostState {
1442 accounts: B256Map::from_iter([(addr1, Some(Default::default()))]),
1443 storages: B256Map::from_iter([(
1444 addr1,
1445 HashedStorage {
1446 wiped: true,
1447 storage: B256Map::from_iter([(slot1, U256::ZERO)])
1448 }
1449 )]),
1450 }
1451 );
1452 assert_eq!(
1453 without_targets,
1454 HashedPostState {
1455 accounts: B256Map::from_iter([(addr2, Some(Default::default()))]),
1456 storages: B256Map::from_iter([(
1457 addr1,
1458 HashedStorage {
1459 wiped: false,
1460 storage: B256Map::from_iter([(slot2, U256::from(1))])
1461 }
1462 )]),
1463 }
1464 );
1465 }
1466
1467 #[test]
1468 fn test_chunks() {
1469 let addr1 = B256::from([1; 32]);
1470 let addr2 = B256::from([2; 32]);
1471 let slot1 = B256::from([1; 32]);
1472 let slot2 = B256::from([2; 32]);
1473
1474 let state = HashedPostState {
1475 accounts: B256Map::from_iter([
1476 (addr1, Some(Default::default())),
1477 (addr2, Some(Default::default())),
1478 ]),
1479 storages: B256Map::from_iter([(
1480 addr2,
1481 HashedStorage {
1482 wiped: true,
1483 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1484 },
1485 )]),
1486 };
1487
1488 let mut chunks = state.chunks(2);
1489 assert_eq!(
1490 chunks.next(),
1491 Some(HashedPostState {
1492 accounts: B256Map::from_iter([(addr1, Some(Default::default()))]),
1493 storages: B256Map::from_iter([(addr2, HashedStorage::new(true)),])
1494 })
1495 );
1496 assert_eq!(
1497 chunks.next(),
1498 Some(HashedPostState {
1499 accounts: B256Map::default(),
1500 storages: B256Map::from_iter([(
1501 addr2,
1502 HashedStorage {
1503 wiped: false,
1504 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1505 },
1506 )])
1507 })
1508 );
1509 assert_eq!(
1510 chunks.next(),
1511 Some(HashedPostState {
1512 accounts: B256Map::from_iter([(addr2, Some(Default::default()))]),
1513 storages: B256Map::default()
1514 })
1515 );
1516 assert_eq!(chunks.next(), None);
1517 }
1518
1519 #[test]
1520 fn test_chunks_ordering_guarantee() {
1521 let addr = B256::from([1; 32]);
1524 let slot1 = B256::from([1; 32]);
1525 let slot2 = B256::from([2; 32]);
1526
1527 let state = HashedPostState {
1528 accounts: B256Map::from_iter([(addr, Some(Default::default()))]),
1529 storages: B256Map::from_iter([(
1530 addr,
1531 HashedStorage {
1532 wiped: true,
1533 storage: B256Map::from_iter([(slot1, U256::from(1)), (slot2, U256::from(2))]),
1534 },
1535 )]),
1536 };
1537
1538 let chunks: Vec<_> = state.chunks(1).collect();
1539
1540 assert_eq!(chunks.len(), 4);
1542
1543 assert!(chunks[0].accounts.is_empty());
1545 assert_eq!(chunks[0].storages.len(), 1);
1546 assert!(chunks[0].storages.get(&addr).unwrap().wiped);
1547 assert!(chunks[0].storages.get(&addr).unwrap().storage.is_empty());
1548
1549 assert!(chunks[1].accounts.is_empty());
1551 assert!(!chunks[1].storages.get(&addr).unwrap().wiped);
1552 assert_eq!(chunks[1].storages.get(&addr).unwrap().storage.len(), 1);
1553
1554 assert!(chunks[2].accounts.is_empty());
1555 assert!(!chunks[2].storages.get(&addr).unwrap().wiped);
1556 assert_eq!(chunks[2].storages.get(&addr).unwrap().storage.len(), 1);
1557
1558 assert_eq!(chunks[3].accounts.len(), 1);
1560 assert!(chunks[3].accounts.contains_key(&addr));
1561 assert!(chunks[3].storages.is_empty());
1562 }
1563
1564 #[test]
1565 fn test_hashed_post_state_sorted_extend_ref() {
1566 let mut state1 = HashedPostStateSorted {
1568 accounts: vec![
1569 (B256::from([1; 32]), Some(Account::default())),
1570 (B256::from([3; 32]), Some(Account::default())),
1571 (B256::from([5; 32]), None),
1572 ],
1573 storages: B256Map::default(),
1574 };
1575
1576 let state2 = HashedPostStateSorted {
1577 accounts: vec![
1578 (B256::from([2; 32]), Some(Account::default())),
1579 (B256::from([3; 32]), Some(Account { nonce: 1, ..Default::default() })), (B256::from([4; 32]), Some(Account::default())),
1581 (B256::from([6; 32]), None),
1582 ],
1583 storages: B256Map::default(),
1584 };
1585
1586 state1.extend_ref_and_sort(&state2);
1587
1588 assert_eq!(state1.accounts.len(), 6);
1590 assert_eq!(state1.accounts[0].0, B256::from([1; 32]));
1591 assert_eq!(state1.accounts[1].0, B256::from([2; 32]));
1592 assert_eq!(state1.accounts[2].0, B256::from([3; 32]));
1593 assert_eq!(state1.accounts[2].1.unwrap().nonce, 1); assert_eq!(state1.accounts[3].0, B256::from([4; 32]));
1595 assert_eq!(state1.accounts[4].0, B256::from([5; 32]));
1596 assert_eq!(state1.accounts[4].1, None);
1597 assert_eq!(state1.accounts[5].0, B256::from([6; 32]));
1598 assert_eq!(state1.accounts[5].1, None);
1599 }
1600
1601 #[test]
1602 fn test_hashed_storage_sorted_extend_ref() {
1603 let mut storage1 = HashedStorageSorted {
1605 storage_slots: vec![
1606 (B256::from([1; 32]), U256::from(10)),
1607 (B256::from([3; 32]), U256::from(30)),
1608 (B256::from([5; 32]), U256::ZERO),
1609 ],
1610 wiped: false,
1611 };
1612
1613 let storage2 = HashedStorageSorted {
1614 storage_slots: vec![
1615 (B256::from([2; 32]), U256::from(20)),
1616 (B256::from([3; 32]), U256::from(300)), (B256::from([4; 32]), U256::from(40)),
1618 (B256::from([6; 32]), U256::ZERO),
1619 ],
1620 wiped: false,
1621 };
1622
1623 storage1.extend_ref(&storage2);
1624
1625 assert_eq!(storage1.storage_slots.len(), 6);
1626 assert_eq!(storage1.storage_slots[0].0, B256::from([1; 32]));
1627 assert_eq!(storage1.storage_slots[0].1, U256::from(10));
1628 assert_eq!(storage1.storage_slots[1].0, B256::from([2; 32]));
1629 assert_eq!(storage1.storage_slots[1].1, U256::from(20));
1630 assert_eq!(storage1.storage_slots[2].0, B256::from([3; 32]));
1631 assert_eq!(storage1.storage_slots[2].1, U256::from(300)); assert_eq!(storage1.storage_slots[3].0, B256::from([4; 32]));
1633 assert_eq!(storage1.storage_slots[3].1, U256::from(40));
1634 assert_eq!(storage1.storage_slots[4].0, B256::from([5; 32]));
1635 assert_eq!(storage1.storage_slots[4].1, U256::ZERO);
1636 assert_eq!(storage1.storage_slots[5].0, B256::from([6; 32]));
1637 assert_eq!(storage1.storage_slots[5].1, U256::ZERO);
1638 assert!(!storage1.wiped);
1639
1640 let mut storage3 = HashedStorageSorted {
1642 storage_slots: vec![
1643 (B256::from([1; 32]), U256::from(10)),
1644 (B256::from([2; 32]), U256::ZERO),
1645 ],
1646 wiped: false,
1647 };
1648
1649 let storage4 = HashedStorageSorted {
1650 storage_slots: vec![
1651 (B256::from([3; 32]), U256::from(30)),
1652 (B256::from([4; 32]), U256::ZERO),
1653 ],
1654 wiped: true,
1655 };
1656
1657 storage3.extend_ref(&storage4);
1658
1659 assert!(storage3.wiped);
1660 assert_eq!(storage3.storage_slots.len(), 2);
1662 assert_eq!(storage3.storage_slots[0].0, B256::from([3; 32]));
1663 assert_eq!(storage3.storage_slots[0].1, U256::from(30));
1664 assert_eq!(storage3.storage_slots[1].0, B256::from([4; 32]));
1665 assert_eq!(storage3.storage_slots[1].1, U256::ZERO);
1666 }
1667
1668 #[test]
1670 fn test_hashed_post_state_extend_from_sorted_with_accounts() {
1671 let addr1 = B256::random();
1672 let addr2 = B256::random();
1673
1674 let mut state = HashedPostState::default();
1675 state.accounts.insert(addr1, Some(Default::default()));
1676
1677 let mut sorted_state = HashedPostStateSorted::default();
1678 sorted_state.accounts.push((addr2, Some(Default::default())));
1679
1680 state.extend_from_sorted(&sorted_state);
1681
1682 assert_eq!(state.accounts.len(), 2);
1683 assert!(state.accounts.contains_key(&addr1));
1684 assert!(state.accounts.contains_key(&addr2));
1685 }
1686
1687 #[test]
1689 fn test_hashed_post_state_extend_from_sorted_with_destroyed_accounts() {
1690 let addr1 = B256::random();
1691
1692 let mut state = HashedPostState::default();
1693
1694 let mut sorted_state = HashedPostStateSorted::default();
1695 sorted_state.accounts.push((addr1, None));
1696
1697 state.extend_from_sorted(&sorted_state);
1698
1699 assert!(state.accounts.contains_key(&addr1));
1700 assert_eq!(state.accounts.get(&addr1), Some(&None));
1701 }
1702
1703 #[test]
1704 fn test_hashed_post_state_sorted_disjointed_merge_batch() {
1705 fn account(nonce: u64) -> Account {
1706 Account { nonce, balance: U256::ZERO, bytecode_hash: None }
1707 }
1708
1709 let kept_account = B256::with_last_byte(1);
1710 let removed_account = B256::with_last_byte(2);
1711 let kept_storage = B256::with_last_byte(3);
1712 let slot1 = B256::with_last_byte(11);
1713 let slot2 = B256::with_last_byte(12);
1714
1715 let older = HashedPostStateSorted::new(
1716 vec![(kept_account, Some(account(1))), (removed_account, Some(account(10)))],
1717 B256Map::from_iter([(
1718 kept_storage,
1719 HashedStorageSorted { wiped: false, storage_slots: vec![(slot1, U256::from(1))] },
1720 )]),
1721 );
1722
1723 let newer = HashedPostStateSorted::new(
1724 vec![(kept_account, Some(account(2)))],
1725 B256Map::from_iter([(
1726 kept_storage,
1727 HashedStorageSorted {
1728 wiped: false,
1729 storage_slots: vec![(slot1, U256::from(3)), (slot2, U256::from(4))],
1730 },
1731 )]),
1732 );
1733
1734 let remove_a = HashedPostStateSorted::new(
1735 vec![(removed_account, None)],
1736 B256Map::from_iter([(
1737 kept_storage,
1738 HashedStorageSorted { wiped: false, storage_slots: vec![(slot2, U256::ZERO)] },
1739 )]),
1740 );
1741
1742 let remove_b = HashedPostStateSorted::new(
1743 vec![(B256::with_last_byte(255), Some(account(99)))],
1744 B256Map::default(),
1745 );
1746
1747 let result = HashedPostStateSorted::disjointed_merge_batch(
1748 &[&older, &newer],
1749 &[&remove_b, &remove_a],
1750 );
1751
1752 assert_eq!(result.accounts, vec![(kept_account, Some(account(2)))]);
1753 assert_eq!(result.storages.len(), 1);
1754 assert_eq!(
1755 result.storages.get(&kept_storage),
1756 Some(&HashedStorageSorted {
1757 wiped: false,
1758 storage_slots: vec![(slot1, U256::from(3))],
1759 })
1760 );
1761 }
1762
1763 #[test]
1764 fn test_hashed_post_state_sorted_disjointed_merge_batch_empty_mask_merges_batch() {
1765 let address = B256::with_last_byte(1);
1766 let storage = B256::with_last_byte(2);
1767 let slot = B256::with_last_byte(3);
1768 let empty_storage = B256::with_last_byte(4);
1769 let older = HashedPostStateSorted::new(
1770 vec![(address, Some(Account { nonce: 1, ..Default::default() }))],
1771 B256Map::from_iter([
1772 (
1773 storage,
1774 HashedStorageSorted {
1775 wiped: false,
1776 storage_slots: vec![(slot, U256::from(1))],
1777 },
1778 ),
1779 (empty_storage, HashedStorageSorted::default()),
1780 ]),
1781 );
1782 let newer = HashedPostStateSorted::new(
1783 vec![(address, Some(Account { nonce: 2, ..Default::default() }))],
1784 B256Map::from_iter([(
1785 storage,
1786 HashedStorageSorted { wiped: false, storage_slots: vec![(slot, U256::from(2))] },
1787 )]),
1788 );
1789 let expected = HashedPostStateSorted::merge_batch(vec![newer.clone(), older.clone()]);
1790
1791 let result = HashedPostStateSorted::disjointed_merge_batch(&[&older, &newer], &[]);
1792
1793 assert_eq!(result, expected);
1794 }
1795
1796 #[test]
1797 fn test_hashed_post_state_sorted_disjointed_merge_batch_removes_overlapping_batch_key() {
1798 fn account(nonce: u64) -> Account {
1799 Account { nonce, balance: U256::ZERO, bytecode_hash: None }
1800 }
1801
1802 let overlapping_account = B256::with_last_byte(21);
1803
1804 let older = HashedPostStateSorted::new(
1805 vec![(overlapping_account, Some(account(1)))],
1806 B256Map::default(),
1807 );
1808
1809 let newer = HashedPostStateSorted::new(
1810 vec![(overlapping_account, Some(account(2)))],
1811 B256Map::default(),
1812 );
1813
1814 let remove =
1815 HashedPostStateSorted::new(vec![(overlapping_account, None)], B256Map::default());
1816
1817 let result = HashedPostStateSorted::disjointed_merge_batch(&[&older, &newer], &[&remove]);
1818
1819 assert!(result.accounts.is_empty());
1820 }
1821
1822 #[test]
1823 fn test_hashed_post_state_sorted_disjointed_merge_batch_keeps_equal_overlaps() {
1824 fn account(nonce: u64) -> Account {
1825 Account { nonce, balance: U256::ZERO, bytecode_hash: None }
1826 }
1827
1828 let address = B256::with_last_byte(21);
1829 let deleted_address = B256::with_last_byte(24);
1830 let storage = B256::with_last_byte(22);
1831 let deleted_storage = B256::with_last_byte(25);
1832 let slot = B256::with_last_byte(23);
1833 let deleted_slot = B256::with_last_byte(26);
1834 let batch = HashedPostStateSorted::new(
1835 vec![(address, Some(account(1))), (deleted_address, None)],
1836 B256Map::from_iter([
1837 (
1838 storage,
1839 HashedStorageSorted {
1840 wiped: false,
1841 storage_slots: vec![(slot, U256::from(1))],
1842 },
1843 ),
1844 (
1845 deleted_storage,
1846 HashedStorageSorted {
1847 wiped: false,
1848 storage_slots: vec![(deleted_slot, U256::ZERO)],
1849 },
1850 ),
1851 ]),
1852 );
1853 let different_mask = HashedPostStateSorted::new(
1854 vec![(address, Some(account(2))), (deleted_address, Some(account(3)))],
1855 B256Map::from_iter([
1856 (
1857 storage,
1858 HashedStorageSorted {
1859 wiped: false,
1860 storage_slots: vec![(slot, U256::from(2))],
1861 },
1862 ),
1863 (
1864 deleted_storage,
1865 HashedStorageSorted {
1866 wiped: false,
1867 storage_slots: vec![(deleted_slot, U256::from(3))],
1868 },
1869 ),
1870 ]),
1871 );
1872 let equal_mask = batch.clone();
1873
1874 let result = HashedPostStateSorted::disjointed_merge_batch(
1875 &[&batch],
1876 &[&different_mask, &equal_mask],
1877 );
1878 let reversed = HashedPostStateSorted::disjointed_merge_batch(
1879 &[&batch],
1880 &[&equal_mask, &different_mask],
1881 );
1882
1883 assert_eq!(result, batch);
1884 assert_eq!(reversed, result);
1885 }
1886
1887 #[test]
1888 fn test_hashed_post_state_sorted_disjointed_merge_batch_ignores_empty_storage_mask() {
1889 let storage = B256::with_last_byte(31);
1890 let slot = B256::with_last_byte(32);
1891
1892 let batch = HashedPostStateSorted::new(
1893 vec![],
1894 B256Map::from_iter([(
1895 storage,
1896 HashedStorageSorted { wiped: false, storage_slots: vec![(slot, U256::from(1))] },
1897 )]),
1898 );
1899 let mask = HashedPostStateSorted::new(
1900 vec![],
1901 B256Map::from_iter([(
1902 storage,
1903 HashedStorageSorted { wiped: false, storage_slots: vec![] },
1904 )]),
1905 );
1906
1907 let result = HashedPostStateSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1908
1909 assert_eq!(
1910 result.storages.get(&storage),
1911 Some(&HashedStorageSorted { wiped: false, storage_slots: vec![(slot, U256::from(1))] })
1912 );
1913 }
1914
1915 #[test]
1917 fn test_hashed_storage_extend_from_sorted_non_wiped() {
1918 let slot1 = B256::random();
1919 let slot2 = B256::random();
1920 let slot3 = B256::random();
1921
1922 let mut storage = HashedStorage::from_iter([(slot1, U256::from(100))]);
1923
1924 let sorted = HashedStorageSorted {
1925 storage_slots: vec![(slot2, U256::from(200)), (slot3, U256::ZERO)],
1926 wiped: false,
1927 };
1928
1929 storage.extend_from_sorted(&sorted);
1930
1931 assert!(!storage.wiped);
1932 assert_eq!(storage.storage.len(), 3);
1933 assert_eq!(storage.storage.get(&slot1), Some(&U256::from(100)));
1934 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1935 assert_eq!(storage.storage.get(&slot3), Some(&U256::ZERO));
1936 }
1937
1938 #[test]
1940 fn test_hashed_storage_extend_from_sorted_wiped() {
1941 let slot1 = B256::random();
1942 let slot2 = B256::random();
1943
1944 let mut storage = HashedStorage::from_iter([(slot1, U256::from(100))]);
1945
1946 let sorted =
1947 HashedStorageSorted { storage_slots: vec![(slot2, U256::from(200))], wiped: true };
1948
1949 storage.extend_from_sorted(&sorted);
1950
1951 assert!(storage.wiped);
1952 assert_eq!(storage.storage.len(), 1);
1954 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1955 }
1956
1957 #[test]
1958 fn test_hashed_post_state_chunking_length() {
1959 let addr1 = B256::from([1; 32]);
1960 let addr2 = B256::from([2; 32]);
1961 let addr3 = B256::from([3; 32]);
1962 let addr4 = B256::from([4; 32]);
1963 let slot1 = B256::from([1; 32]);
1964 let slot2 = B256::from([2; 32]);
1965 let slot3 = B256::from([3; 32]);
1966
1967 let state = HashedPostState {
1968 accounts: B256Map::from_iter([(addr1, None), (addr2, None), (addr4, None)]),
1969 storages: B256Map::from_iter([
1970 (
1971 addr1,
1972 HashedStorage {
1973 wiped: false,
1974 storage: B256Map::from_iter([
1975 (slot1, U256::ZERO),
1976 (slot2, U256::ZERO),
1977 (slot3, U256::ZERO),
1978 ]),
1979 },
1980 ),
1981 (
1982 addr2,
1983 HashedStorage {
1984 wiped: true,
1985 storage: B256Map::from_iter([
1986 (slot1, U256::ZERO),
1987 (slot2, U256::ZERO),
1988 (slot3, U256::ZERO),
1989 ]),
1990 },
1991 ),
1992 (
1993 addr3,
1994 HashedStorage {
1995 wiped: false,
1996 storage: B256Map::from_iter([
1997 (slot1, U256::ZERO),
1998 (slot2, U256::ZERO),
1999 (slot3, U256::ZERO),
2000 ]),
2001 },
2002 ),
2003 ]),
2004 };
2005
2006 let chunking_length = state.chunking_length();
2007 for size in 1..=state.clone().chunks(1).count() {
2008 let chunk_count = state.clone().chunks(size).count();
2009 let expected_count = chunking_length.div_ceil(size);
2010 assert_eq!(
2011 chunk_count, expected_count,
2012 "chunking_length: {}, size: {}",
2013 chunking_length, size
2014 );
2015 }
2016 }
2017
2018 #[test]
2019 fn test_clone_into_sorted_equivalence() {
2020 let addr1 = B256::from([1; 32]);
2021 let addr2 = B256::from([2; 32]);
2022 let addr3 = B256::from([3; 32]);
2023 let slot1 = B256::from([1; 32]);
2024 let slot2 = B256::from([2; 32]);
2025 let slot3 = B256::from([3; 32]);
2026
2027 let state = HashedPostState {
2028 accounts: B256Map::from_iter([
2029 (addr1, Some(Account { nonce: 1, balance: U256::from(100), bytecode_hash: None })),
2030 (addr2, None),
2031 (addr3, Some(Account::default())),
2032 ]),
2033 storages: B256Map::from_iter([
2034 (
2035 addr1,
2036 HashedStorage {
2037 wiped: false,
2038 storage: B256Map::from_iter([
2039 (slot1, U256::from(10)),
2040 (slot2, U256::from(20)),
2041 ]),
2042 },
2043 ),
2044 (
2045 addr2,
2046 HashedStorage {
2047 wiped: true,
2048 storage: B256Map::from_iter([(slot3, U256::ZERO)]),
2049 },
2050 ),
2051 ]),
2052 };
2053
2054 let sorted_via_clone = state.clone().into_sorted();
2056 let sorted_via_clone_into = state.clone_into_sorted();
2057
2058 assert_eq!(sorted_via_clone, sorted_via_clone_into);
2059
2060 assert_eq!(state.accounts.len(), 3);
2062 assert_eq!(state.storages.len(), 2);
2063 }
2064
2065 #[test]
2066 fn test_hashed_storage_clone_into_sorted_equivalence() {
2067 let slot1 = B256::from([1; 32]);
2068 let slot2 = B256::from([2; 32]);
2069 let slot3 = B256::from([3; 32]);
2070
2071 let storage = HashedStorage {
2072 wiped: true,
2073 storage: B256Map::from_iter([
2074 (slot1, U256::from(100)),
2075 (slot2, U256::ZERO),
2076 (slot3, U256::from(300)),
2077 ]),
2078 };
2079
2080 let sorted_via_clone = storage.clone().into_sorted();
2082 let sorted_via_clone_into = storage.clone_into_sorted();
2083
2084 assert_eq!(sorted_via_clone, sorted_via_clone_into);
2085
2086 assert_eq!(storage.storage.len(), 3);
2088 assert!(storage.wiped);
2089 }
2090}
2091
2092#[cfg(feature = "serde-bincode-compat")]
2094pub mod serde_bincode_compat {
2095 use super::Account;
2096 use alloc::borrow::Cow;
2097 use alloy_primitives::{map::B256Map, B256, U256};
2098 use serde::{Deserialize, Deserializer, Serialize, Serializer};
2099 use serde_with::{DeserializeAs, SerializeAs};
2100
2101 #[derive(Debug, Serialize, Deserialize)]
2117 pub struct HashedPostState<'a> {
2118 accounts: Cow<'a, B256Map<Option<Account>>>,
2119 storages: B256Map<HashedStorage<'a>>,
2120 }
2121
2122 impl<'a> From<&'a super::HashedPostState> for HashedPostState<'a> {
2123 fn from(value: &'a super::HashedPostState) -> Self {
2124 Self {
2125 accounts: Cow::Borrowed(&value.accounts),
2126 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
2127 }
2128 }
2129 }
2130
2131 impl<'a> From<HashedPostState<'a>> for super::HashedPostState {
2132 fn from(value: HashedPostState<'a>) -> Self {
2133 Self {
2134 accounts: value.accounts.into_owned(),
2135 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
2136 }
2137 }
2138 }
2139
2140 impl SerializeAs<super::HashedPostState> for HashedPostState<'_> {
2141 fn serialize_as<S>(
2142 source: &super::HashedPostState,
2143 serializer: S,
2144 ) -> Result<S::Ok, S::Error>
2145 where
2146 S: Serializer,
2147 {
2148 HashedPostState::from(source).serialize(serializer)
2149 }
2150 }
2151
2152 impl<'de> DeserializeAs<'de, super::HashedPostState> for HashedPostState<'de> {
2153 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostState, D::Error>
2154 where
2155 D: Deserializer<'de>,
2156 {
2157 HashedPostState::deserialize(deserializer).map(Into::into)
2158 }
2159 }
2160
2161 #[derive(Debug, Serialize, Deserialize)]
2177 pub struct HashedStorage<'a> {
2178 wiped: bool,
2179 storage: Cow<'a, B256Map<U256>>,
2180 }
2181
2182 impl<'a> From<&'a super::HashedStorage> for HashedStorage<'a> {
2183 fn from(value: &'a super::HashedStorage) -> Self {
2184 Self { wiped: value.wiped, storage: Cow::Borrowed(&value.storage) }
2185 }
2186 }
2187
2188 impl<'a> From<HashedStorage<'a>> for super::HashedStorage {
2189 fn from(value: HashedStorage<'a>) -> Self {
2190 Self { wiped: value.wiped, storage: value.storage.into_owned() }
2191 }
2192 }
2193
2194 impl SerializeAs<super::HashedStorage> for HashedStorage<'_> {
2195 fn serialize_as<S>(source: &super::HashedStorage, serializer: S) -> Result<S::Ok, S::Error>
2196 where
2197 S: Serializer,
2198 {
2199 HashedStorage::from(source).serialize(serializer)
2200 }
2201 }
2202
2203 impl<'de> DeserializeAs<'de, super::HashedStorage> for HashedStorage<'de> {
2204 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorage, D::Error>
2205 where
2206 D: Deserializer<'de>,
2207 {
2208 HashedStorage::deserialize(deserializer).map(Into::into)
2209 }
2210 }
2211
2212 #[derive(Debug, Serialize, Deserialize)]
2228 pub struct HashedPostStateSorted<'a> {
2229 accounts: Cow<'a, [(B256, Option<Account>)]>,
2230 storages: B256Map<HashedStorageSorted<'a>>,
2231 }
2232
2233 impl<'a> From<&'a super::HashedPostStateSorted> for HashedPostStateSorted<'a> {
2234 fn from(value: &'a super::HashedPostStateSorted) -> Self {
2235 Self {
2236 accounts: Cow::Borrowed(&value.accounts),
2237 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
2238 }
2239 }
2240 }
2241
2242 impl<'a> From<HashedPostStateSorted<'a>> for super::HashedPostStateSorted {
2243 fn from(value: HashedPostStateSorted<'a>) -> Self {
2244 Self {
2245 accounts: value.accounts.into_owned(),
2246 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
2247 }
2248 }
2249 }
2250
2251 impl SerializeAs<super::HashedPostStateSorted> for HashedPostStateSorted<'_> {
2252 fn serialize_as<S>(
2253 source: &super::HashedPostStateSorted,
2254 serializer: S,
2255 ) -> Result<S::Ok, S::Error>
2256 where
2257 S: Serializer,
2258 {
2259 HashedPostStateSorted::from(source).serialize(serializer)
2260 }
2261 }
2262
2263 impl<'de> DeserializeAs<'de, super::HashedPostStateSorted> for HashedPostStateSorted<'de> {
2264 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostStateSorted, D::Error>
2265 where
2266 D: Deserializer<'de>,
2267 {
2268 HashedPostStateSorted::deserialize(deserializer).map(Into::into)
2269 }
2270 }
2271
2272 #[derive(Debug, Serialize, Deserialize)]
2288 pub struct HashedStorageSorted<'a> {
2289 storage_slots: Cow<'a, [(B256, U256)]>,
2290 wiped: bool,
2291 }
2292
2293 impl<'a> From<&'a super::HashedStorageSorted> for HashedStorageSorted<'a> {
2294 fn from(value: &'a super::HashedStorageSorted) -> Self {
2295 Self { storage_slots: Cow::Borrowed(&value.storage_slots), wiped: value.wiped }
2296 }
2297 }
2298
2299 impl<'a> From<HashedStorageSorted<'a>> for super::HashedStorageSorted {
2300 fn from(value: HashedStorageSorted<'a>) -> Self {
2301 Self { storage_slots: value.storage_slots.into_owned(), wiped: value.wiped }
2302 }
2303 }
2304
2305 impl SerializeAs<super::HashedStorageSorted> for HashedStorageSorted<'_> {
2306 fn serialize_as<S>(
2307 source: &super::HashedStorageSorted,
2308 serializer: S,
2309 ) -> Result<S::Ok, S::Error>
2310 where
2311 S: Serializer,
2312 {
2313 HashedStorageSorted::from(source).serialize(serializer)
2314 }
2315 }
2316
2317 impl<'de> DeserializeAs<'de, super::HashedStorageSorted> for HashedStorageSorted<'de> {
2318 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorageSorted, D::Error>
2319 where
2320 D: Deserializer<'de>,
2321 {
2322 HashedStorageSorted::deserialize(deserializer).map(Into::into)
2323 }
2324 }
2325
2326 #[cfg(test)]
2327 mod tests {
2328 use crate::{
2329 hashed_state::{
2330 HashedPostState, HashedPostStateSorted, HashedStorage, HashedStorageSorted,
2331 },
2332 serde_bincode_compat,
2333 };
2334 use alloy_primitives::{B256, U256};
2335 use reth_primitives_traits::Account;
2336 use serde::{Deserialize, Serialize};
2337 use serde_with::serde_as;
2338
2339 #[test]
2340 fn test_hashed_post_state_bincode_roundtrip() {
2341 #[serde_as]
2342 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2343 struct Data {
2344 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostState")]
2345 hashed_state: HashedPostState,
2346 }
2347
2348 let mut data = Data { hashed_state: HashedPostState::default() };
2349 let encoded = bincode::serialize(&data).unwrap();
2350 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2351 assert_eq!(decoded, data);
2352
2353 data.hashed_state.accounts.insert(B256::random(), Some(Account::default()));
2354 let encoded = bincode::serialize(&data).unwrap();
2355 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2356 assert_eq!(decoded, data);
2357
2358 data.hashed_state.storages.insert(B256::random(), HashedStorage::default());
2359 let encoded = bincode::serialize(&data).unwrap();
2360 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2361 assert_eq!(decoded, data);
2362 }
2363
2364 #[test]
2365 fn test_hashed_storage_bincode_roundtrip() {
2366 #[serde_as]
2367 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2368 struct Data {
2369 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorage")]
2370 hashed_storage: HashedStorage,
2371 }
2372
2373 let mut data = Data { hashed_storage: HashedStorage::default() };
2374 let encoded = bincode::serialize(&data).unwrap();
2375 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2376 assert_eq!(decoded, data);
2377
2378 data.hashed_storage.wiped = true;
2379 let encoded = bincode::serialize(&data).unwrap();
2380 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2381 assert_eq!(decoded, data);
2382
2383 data.hashed_storage.storage.insert(B256::random(), U256::from(1));
2384 let encoded = bincode::serialize(&data).unwrap();
2385 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2386 assert_eq!(decoded, data);
2387 }
2388
2389 #[test]
2390 fn test_hashed_post_state_sorted_bincode_roundtrip() {
2391 #[serde_as]
2392 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2393 struct Data {
2394 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostStateSorted")]
2395 hashed_state: HashedPostStateSorted,
2396 }
2397
2398 let mut data = Data { hashed_state: HashedPostStateSorted::default() };
2399 let encoded = bincode::serialize(&data).unwrap();
2400 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2401 assert_eq!(decoded, data);
2402
2403 data.hashed_state.accounts.push((B256::random(), Some(Account::default())));
2404 data.hashed_state
2405 .accounts
2406 .push((B256::random(), Some(Account { nonce: 1, ..Default::default() })));
2407 let encoded = bincode::serialize(&data).unwrap();
2408 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2409 assert_eq!(decoded, data);
2410
2411 data.hashed_state.storages.insert(
2412 B256::random(),
2413 HashedStorageSorted {
2414 storage_slots: vec![(B256::from([1; 32]), U256::from(10))],
2415 wiped: false,
2416 },
2417 );
2418 let encoded = bincode::serialize(&data).unwrap();
2419 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2420 assert_eq!(decoded, data);
2421 }
2422
2423 #[test]
2424 fn test_hashed_storage_sorted_bincode_roundtrip() {
2425 #[serde_as]
2426 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2427 struct Data {
2428 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorageSorted")]
2429 hashed_storage: HashedStorageSorted,
2430 }
2431
2432 let mut data = Data {
2433 hashed_storage: HashedStorageSorted { storage_slots: Vec::new(), wiped: false },
2434 };
2435 let encoded = bincode::serialize(&data).unwrap();
2436 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2437 assert_eq!(decoded, data);
2438
2439 data.hashed_storage.wiped = true;
2440 let encoded = bincode::serialize(&data).unwrap();
2441 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2442 assert_eq!(decoded, data);
2443
2444 data.hashed_storage.storage_slots.push((B256::random(), U256::from(1)));
2445 let encoded = bincode::serialize(&data).unwrap();
2446 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2447 assert_eq!(decoded, data);
2448 }
2449 }
2450}