1use core::ops::Not;
2
3use crate::{
4 added_removed_keys::MultiAddedRemovedKeys,
5 prefix_set::{PrefixSetMut, TriePrefixSetsMut},
6 utils::{extend_sorted_vec, 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::{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 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_plain_storage(
58 account.status,
59 account.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
60 );
61
62 (
63 hashed_address,
64 hashed_account,
65 (!hashed_storage.is_empty()).then_some(hashed_storage),
66 )
67 })
68 .collect()
69 }
70
71 pub fn from_hashed_storage(hashed_address: B256, storage: HashedStorage) -> Self {
73 Self {
74 accounts: HashMap::default(),
75 storages: HashMap::from_iter([(hashed_address, storage)]),
76 }
77 }
78
79 pub fn with_accounts(
81 mut self,
82 accounts: impl IntoIterator<Item = (B256, Option<Account>)>,
83 ) -> Self {
84 self.accounts = HashMap::from_iter(accounts);
85 self
86 }
87
88 pub fn with_storages(
90 mut self,
91 storages: impl IntoIterator<Item = (B256, HashedStorage)>,
92 ) -> Self {
93 self.storages = HashMap::from_iter(storages);
94 self
95 }
96
97 pub fn is_empty(&self) -> bool {
99 self.accounts.is_empty() && self.storages.is_empty()
100 }
101
102 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
106 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
108 let mut destroyed_accounts = HashSet::default();
109 for (hashed_address, account) in &self.accounts {
110 account_prefix_set.insert(Nibbles::unpack(hashed_address));
111
112 if account.is_none() {
113 destroyed_accounts.insert(*hashed_address);
114 }
115 }
116
117 let mut storage_prefix_sets =
119 HashMap::with_capacity_and_hasher(self.storages.len(), Default::default());
120 for (hashed_address, hashed_storage) in &self.storages {
121 account_prefix_set.insert(Nibbles::unpack(hashed_address));
122 storage_prefix_sets.insert(*hashed_address, hashed_storage.construct_prefix_set());
123 }
124
125 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
126 }
127
128 pub fn multi_proof_targets(&self) -> MultiProofTargets {
130 let mut targets = MultiProofTargets::with_capacity(self.accounts.len());
132 for hashed_address in self.accounts.keys() {
133 targets.insert(*hashed_address, Default::default());
134 }
135 for (hashed_address, storage) in &self.storages {
136 targets.entry(*hashed_address).or_default().extend(storage.storage.keys().copied());
137 }
138 targets
139 }
140
141 pub fn multi_proof_targets_difference(
147 &self,
148 excluded: &MultiProofTargets,
149 ) -> MultiProofTargets {
150 let mut targets = MultiProofTargets::default();
151 for hashed_address in self.accounts.keys() {
152 if !excluded.contains_key(hashed_address) {
153 targets.insert(*hashed_address, Default::default());
154 }
155 }
156 for (hashed_address, storage) in &self.storages {
157 let maybe_excluded_storage = excluded.get(hashed_address);
158 let mut hashed_slots_targets = storage
159 .storage
160 .keys()
161 .filter(|slot| !maybe_excluded_storage.is_some_and(|f| f.contains(*slot)))
162 .peekable();
163 if hashed_slots_targets.peek().is_some() {
164 targets.entry(*hashed_address).or_default().extend(hashed_slots_targets);
165 }
166 }
167 targets
168 }
169
170 pub fn partition_by_targets(
177 mut self,
178 targets: &MultiProofTargets,
179 added_removed_keys: &MultiAddedRemovedKeys,
180 ) -> (Self, Self) {
181 let mut state_updates_not_in_targets = Self::default();
182
183 self.storages.retain(|&address, storage| {
184 let storage_added_removed_keys = added_removed_keys.get_storage(&address);
185
186 let (retain, storage_not_in_targets) = match targets.get(&address) {
187 Some(storage_in_targets) => {
188 let mut storage_not_in_targets = HashedStorage::default();
189 storage.storage.retain(|&slot, value| {
190 if storage_in_targets.contains(&slot) &&
191 !storage_added_removed_keys.is_some_and(|k| k.is_removed(&slot))
192 {
193 return true
194 }
195
196 storage_not_in_targets.storage.insert(slot, *value);
197 false
198 });
199
200 let retain = !storage.storage.is_empty();
204
205 if !retain {
209 storage_not_in_targets.wiped = storage.wiped;
210 }
211
212 (
213 retain,
214 storage_not_in_targets.is_empty().not().then_some(storage_not_in_targets),
215 )
216 }
217 None => (false, Some(core::mem::take(storage))),
218 };
219
220 if let Some(storage_not_in_targets) = storage_not_in_targets {
221 state_updates_not_in_targets.storages.insert(address, storage_not_in_targets);
222 }
223
224 retain
225 });
226 self.accounts.retain(|&address, account| {
227 if targets.contains_key(&address) {
228 return true
229 }
230
231 state_updates_not_in_targets.accounts.insert(address, *account);
232 false
233 });
234
235 (self, state_updates_not_in_targets)
236 }
237
238 pub fn chunks(self, size: usize) -> ChunkedHashedPostState {
242 ChunkedHashedPostState::new(self, size)
243 }
244
245 pub fn chunking_length(&self) -> usize {
247 self.accounts.len() +
248 self.storages
249 .values()
250 .map(|storage| if storage.wiped { 1 } else { 0 } + storage.storage.len())
251 .sum::<usize>()
252 }
253
254 pub fn extend(&mut self, other: Self) {
257 self.extend_inner(Cow::Owned(other));
258 }
259
260 pub fn extend_ref(&mut self, other: &Self) {
265 self.extend_inner(Cow::Borrowed(other));
266 }
267
268 fn extend_inner(&mut self, other: Cow<'_, Self>) {
269 self.accounts.extend(other.accounts.iter().map(|(&k, &v)| (k, v)));
270
271 self.storages.reserve(other.storages.len());
272 match other {
273 Cow::Borrowed(other) => {
274 self.extend_storages(other.storages.iter().map(|(k, v)| (*k, Cow::Borrowed(v))))
275 }
276 Cow::Owned(other) => {
277 self.extend_storages(other.storages.into_iter().map(|(k, v)| (k, Cow::Owned(v))))
278 }
279 }
280 }
281
282 fn extend_storages<'a>(
283 &mut self,
284 storages: impl IntoIterator<Item = (B256, Cow<'a, HashedStorage>)>,
285 ) {
286 for (hashed_address, storage) in storages {
287 match self.storages.entry(hashed_address) {
288 hash_map::Entry::Vacant(entry) => {
289 entry.insert(storage.into_owned());
290 }
291 hash_map::Entry::Occupied(mut entry) => {
292 entry.get_mut().extend(&storage);
293 }
294 }
295 }
296 }
297
298 pub fn extend_from_sorted(&mut self, sorted: &HashedPostStateSorted) {
302 self.accounts.reserve(sorted.accounts.len());
304
305 for (address, account) in &sorted.accounts {
307 self.accounts.insert(*address, *account);
308 }
309
310 self.storages.reserve(sorted.storages.len());
312
313 for (hashed_address, sorted_storage) in &sorted.storages {
315 match self.storages.entry(*hashed_address) {
316 hash_map::Entry::Vacant(entry) => {
317 let mut new_storage = HashedStorage::new(false);
318 new_storage.extend_from_sorted(sorted_storage);
319 entry.insert(new_storage);
320 }
321 hash_map::Entry::Occupied(mut entry) => {
322 entry.get_mut().extend_from_sorted(sorted_storage);
323 }
324 }
325 }
326 }
327
328 pub fn into_sorted(self) -> HashedPostStateSorted {
330 let mut accounts: Vec<_> = self.accounts.into_iter().collect();
331 accounts.sort_unstable_by_key(|(address, _)| *address);
332
333 let storages = self
334 .storages
335 .into_iter()
336 .map(|(hashed_address, storage)| (hashed_address, storage.into_sorted()))
337 .collect();
338
339 HashedPostStateSorted { accounts, storages }
340 }
341
342 pub fn clone_into_sorted(&self) -> HashedPostStateSorted {
345 let mut accounts: Vec<_> = self.accounts.iter().map(|(&k, &v)| (k, v)).collect();
346 accounts.sort_unstable_by_key(|(address, _)| *address);
347
348 let storages = self
349 .storages
350 .iter()
351 .map(|(&hashed_address, storage)| (hashed_address, storage.clone_into_sorted()))
352 .collect();
353
354 HashedPostStateSorted { accounts, storages }
355 }
356
357 pub fn clear(&mut self) {
359 self.accounts.clear();
360 self.storages.clear();
361 }
362}
363
364impl FromIterator<(B256, Option<Account>, Option<HashedStorage>)> for HashedPostState {
365 fn from_iter<T: IntoIterator<Item = (B256, Option<Account>, Option<HashedStorage>)>>(
381 iter: T,
382 ) -> Self {
383 let iter = iter.into_iter();
384 let (lower, _) = iter.size_hint();
385 let mut hashed_state = Self::with_capacity(lower);
386
387 for (hashed_address, info, hashed_storage) in iter {
388 hashed_state.accounts.insert(hashed_address, info);
389 if let Some(storage) = hashed_storage {
390 hashed_state.storages.insert(hashed_address, storage);
391 }
392 }
393
394 hashed_state
395 }
396}
397
398#[cfg(feature = "rayon")]
399impl FromParallelIterator<(B256, Option<Account>, Option<HashedStorage>)> for HashedPostState {
400 fn from_par_iter<I>(par_iter: I) -> Self
412 where
413 I: IntoParallelIterator<Item = (B256, Option<Account>, Option<HashedStorage>)>,
414 {
415 let vec: Vec<_> = par_iter.into_par_iter().collect();
416 vec.into_iter().collect()
417 }
418}
419
420#[derive(PartialEq, Eq, Clone, Debug, Default)]
422#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
423pub struct HashedStorage {
424 pub wiped: bool,
426 pub storage: B256Map<U256>,
428}
429
430impl HashedStorage {
431 pub fn new(wiped: bool) -> Self {
433 Self { wiped, storage: HashMap::default() }
434 }
435
436 pub fn is_empty(&self) -> bool {
438 !self.wiped && self.storage.is_empty()
439 }
440
441 pub fn from_iter(wiped: bool, iter: impl IntoIterator<Item = (B256, U256)>) -> Self {
443 Self { wiped, storage: HashMap::from_iter(iter) }
444 }
445
446 pub fn from_plain_storage<'a>(
448 status: AccountStatus,
449 storage: impl IntoIterator<Item = (&'a U256, &'a U256)>,
450 ) -> Self {
451 Self::from_iter(
452 status.was_destroyed(),
453 storage.into_iter().map(|(key, value)| (keccak256(B256::from(*key)), *value)),
454 )
455 }
456
457 pub fn construct_prefix_set(&self) -> PrefixSetMut {
459 if self.wiped {
460 PrefixSetMut::all()
461 } else {
462 let mut prefix_set = PrefixSetMut::with_capacity(self.storage.len());
463 for hashed_slot in self.storage.keys() {
464 prefix_set.insert(Nibbles::unpack(hashed_slot));
465 }
466 prefix_set
467 }
468 }
469
470 pub fn extend(&mut self, other: &Self) {
473 if other.wiped {
474 self.wiped = true;
475 self.storage.clear();
476 }
477 self.storage.extend(other.storage.iter().map(|(&k, &v)| (k, v)));
478 }
479
480 pub fn extend_from_sorted(&mut self, sorted: &HashedStorageSorted) {
484 if sorted.wiped {
485 self.wiped = true;
486 self.storage.clear();
487 }
488
489 self.storage.reserve(sorted.storage_slots.len());
491
492 for (slot, value) in &sorted.storage_slots {
494 self.storage.insert(*slot, *value);
495 }
496 }
497
498 pub fn into_sorted(self) -> HashedStorageSorted {
500 let mut storage_slots: Vec<_> = self.storage.into_iter().collect();
501 storage_slots.sort_unstable_by_key(|(key, _)| *key);
502
503 HashedStorageSorted { storage_slots, wiped: self.wiped }
504 }
505
506 pub fn clone_into_sorted(&self) -> HashedStorageSorted {
509 let mut storage_slots: Vec<_> = self.storage.iter().map(|(&k, &v)| (k, v)).collect();
510 storage_slots.sort_unstable_by_key(|(key, _)| *key);
511
512 HashedStorageSorted { storage_slots, wiped: self.wiped }
513 }
514}
515
516#[derive(PartialEq, Eq, Clone, Default, Debug)]
518#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
519pub struct HashedPostStateSorted {
520 pub accounts: Vec<(B256, Option<Account>)>,
522 pub storages: B256Map<HashedStorageSorted>,
524}
525
526impl HashedPostStateSorted {
527 pub const fn new(
529 accounts: Vec<(B256, Option<Account>)>,
530 storages: B256Map<HashedStorageSorted>,
531 ) -> Self {
532 Self { accounts, storages }
533 }
534
535 pub const fn accounts(&self) -> &Vec<(B256, Option<Account>)> {
537 &self.accounts
538 }
539
540 pub const fn account_storages(&self) -> &B256Map<HashedStorageSorted> {
542 &self.storages
543 }
544
545 pub fn is_empty(&self) -> bool {
547 self.accounts.is_empty() && self.storages.is_empty()
548 }
549
550 pub fn total_len(&self) -> usize {
552 self.accounts.len() + self.storages.values().map(|s| s.len()).sum::<usize>()
553 }
554
555 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
560 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
561 let mut destroyed_accounts = HashSet::default();
562 for (hashed_address, account) in &self.accounts {
563 account_prefix_set.insert(Nibbles::unpack(hashed_address));
564 if account.is_none() {
565 destroyed_accounts.insert(*hashed_address);
566 }
567 }
568
569 let mut storage_prefix_sets =
570 B256Map::with_capacity_and_hasher(self.storages.len(), Default::default());
571 for (hashed_address, hashed_storage) in &self.storages {
572 account_prefix_set.insert(Nibbles::unpack(hashed_address));
574
575 let prefix_set = if hashed_storage.wiped {
576 PrefixSetMut::all()
577 } else {
578 let mut prefix_set =
579 PrefixSetMut::with_capacity(hashed_storage.storage_slots.len());
580 prefix_set.extend_keys(
581 hashed_storage
582 .storage_slots
583 .iter()
584 .map(|(hashed_slot, _)| Nibbles::unpack(hashed_slot)),
585 );
586 prefix_set
587 };
588
589 storage_prefix_sets.insert(*hashed_address, prefix_set);
590 }
591
592 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
593 }
594
595 pub fn extend_ref_and_sort(&mut self, other: &Self) {
600 extend_sorted_vec(&mut self.accounts, &other.accounts);
602
603 for (hashed_address, other_storage) in &other.storages {
605 self.storages
606 .entry(*hashed_address)
607 .and_modify(|existing| existing.extend_ref(other_storage))
608 .or_insert_with(|| other_storage.clone());
609 }
610 }
611
612 pub fn merge_batch<T: AsRef<Self> + From<Self>>(iter: impl IntoIterator<Item = T>) -> T {
617 let items: alloc::vec::Vec<_> = iter.into_iter().collect();
618 match items.len() {
619 0 => Self::default().into(),
620 1 => items.into_iter().next().expect("len == 1"),
621 _ => Self::merge_slice(&items).into(),
622 }
623 }
624
625 pub fn merge_slice<T: AsRef<Self>>(items: &[T]) -> Self {
631 const THRESHOLD: usize = 30;
632
633 let k = items.len();
634
635 if k == 0 {
636 return Self::default();
637 }
638 if k == 1 {
639 return items[0].as_ref().clone();
640 }
641
642 if k < THRESHOLD {
643 let mut iter = items.iter().rev();
645 let mut acc = iter.next().expect("k > 0").as_ref().clone();
646 for next in iter {
647 acc.extend_ref_and_sort(next.as_ref());
648 }
649 return acc;
650 }
651
652 let accounts = kway_merge_sorted(items.iter().map(|i| i.as_ref().accounts.as_slice()));
654
655 struct StorageAcc<'a> {
656 wiped: bool,
657 sealed: bool,
658 slices: Vec<&'a [(B256, U256)]>,
659 }
660
661 let mut acc: B256Map<StorageAcc<'_>> = B256Map::default();
662
663 for item in items {
664 for (addr, storage) in &item.as_ref().storages {
665 let entry = acc.entry(*addr).or_insert_with(|| StorageAcc {
666 wiped: false,
667 sealed: false,
668 slices: Vec::new(),
669 });
670
671 if entry.sealed {
672 continue;
673 }
674
675 entry.slices.push(storage.storage_slots.as_slice());
676 if storage.wiped {
677 entry.wiped = true;
678 entry.sealed = true;
679 }
680 }
681 }
682
683 let storages = acc
684 .into_iter()
685 .map(|(addr, entry)| {
686 let storage_slots = kway_merge_sorted(entry.slices);
687 (addr, HashedStorageSorted { wiped: entry.wiped, storage_slots })
688 })
689 .collect();
690
691 Self { accounts, storages }
692 }
693
694 pub fn clear(&mut self) {
696 self.accounts.clear();
697 self.storages.clear();
698 }
699}
700
701impl AsRef<Self> for HashedPostStateSorted {
702 fn as_ref(&self) -> &Self {
703 self
704 }
705}
706
707#[derive(Clone, Eq, PartialEq, Debug, Default)]
709#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
710pub struct HashedStorageSorted {
711 pub storage_slots: Vec<(B256, U256)>,
713 pub wiped: bool,
715}
716
717impl HashedStorageSorted {
718 pub const fn is_wiped(&self) -> bool {
720 self.wiped
721 }
722
723 pub fn storage_slots_ref(&self) -> &[(B256, U256)] {
725 &self.storage_slots
726 }
727
728 pub const fn len(&self) -> usize {
730 self.storage_slots.len()
731 }
732
733 pub const fn is_empty(&self) -> bool {
735 self.storage_slots.is_empty()
736 }
737
738 pub fn extend_ref(&mut self, other: &Self) {
743 if other.wiped {
744 self.wiped = true;
746 self.storage_slots.clear();
747 self.storage_slots.extend(other.storage_slots.iter().copied());
748 return;
749 }
750
751 extend_sorted_vec(&mut self.storage_slots, &other.storage_slots);
753 }
754
755 pub fn merge_batch<'a>(updates: impl IntoIterator<Item = &'a Self>) -> Self {
758 let updates: Vec<_> = updates.into_iter().collect();
759 if updates.is_empty() {
760 return Self::default();
761 }
762
763 let wipe_idx = updates.iter().position(|u| u.wiped);
764 let relevant = wipe_idx.map_or(&updates[..], |idx| &updates[..=idx]);
765 let storage_slots = kway_merge_sorted(relevant.iter().map(|u| u.storage_slots.as_slice()));
766
767 Self { wiped: wipe_idx.is_some(), storage_slots }
768 }
769}
770
771impl From<HashedStorageSorted> for HashedStorage {
772 fn from(sorted: HashedStorageSorted) -> Self {
773 let mut storage = B256Map::default();
774
775 for (slot, value) in sorted.storage_slots {
777 storage.insert(slot, value);
778 }
779
780 Self { wiped: sorted.wiped, storage }
781 }
782}
783
784impl From<HashedPostStateSorted> for HashedPostState {
785 fn from(sorted: HashedPostStateSorted) -> Self {
786 let mut accounts =
787 B256Map::with_capacity_and_hasher(sorted.accounts.len(), Default::default());
788
789 for (address, account) in sorted.accounts {
791 accounts.insert(address, account);
792 }
793
794 let storages = sorted
796 .storages
797 .into_iter()
798 .map(|(address, storage)| (address, storage.into()))
799 .collect();
800
801 Self { accounts, storages }
802 }
803}
804
805#[derive(Debug)]
813pub struct ChunkedHashedPostState {
814 flattened: alloc::vec::IntoIter<(B256, FlattenedHashedPostStateItem)>,
815 size: usize,
816}
817
818#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
821enum FlattenedStateOrder {
822 StorageWipe,
823 StorageUpdate(B256),
824 Account,
825}
826
827#[derive(Debug)]
828enum FlattenedHashedPostStateItem {
829 Account(Option<Account>),
830 StorageWipe,
831 StorageUpdate { slot: B256, value: U256 },
832}
833
834impl FlattenedHashedPostStateItem {
835 const fn order(&self) -> FlattenedStateOrder {
836 match self {
837 Self::StorageWipe => FlattenedStateOrder::StorageWipe,
838 Self::StorageUpdate { slot, .. } => FlattenedStateOrder::StorageUpdate(*slot),
839 Self::Account(_) => FlattenedStateOrder::Account,
840 }
841 }
842}
843
844impl ChunkedHashedPostState {
845 fn new(hashed_post_state: HashedPostState, size: usize) -> Self {
846 let flattened = hashed_post_state
847 .storages
848 .into_iter()
849 .flat_map(|(address, storage)| {
850 storage
851 .wiped
852 .then_some((address, FlattenedHashedPostStateItem::StorageWipe))
853 .into_iter()
854 .chain(storage.storage.into_iter().map(move |(slot, value)| {
855 (address, FlattenedHashedPostStateItem::StorageUpdate { slot, value })
856 }))
857 })
858 .chain(hashed_post_state.accounts.into_iter().map(|(address, account)| {
859 (address, FlattenedHashedPostStateItem::Account(account))
860 }))
861 .sorted_unstable_by_key(|(address, item)| (*address, item.order()));
866
867 Self { flattened, size }
868 }
869}
870
871impl Iterator for ChunkedHashedPostState {
872 type Item = HashedPostState;
873
874 fn next(&mut self) -> Option<Self::Item> {
875 let mut chunk = HashedPostState::default();
876
877 let mut current_size = 0;
878 while current_size < self.size {
879 let Some((address, item)) = self.flattened.next() else { break };
880
881 match item {
882 FlattenedHashedPostStateItem::Account(account) => {
883 chunk.accounts.insert(address, account);
884 }
885 FlattenedHashedPostStateItem::StorageWipe => {
886 chunk.storages.entry(address).or_default().wiped = true;
887 }
888 FlattenedHashedPostStateItem::StorageUpdate { slot, value } => {
889 chunk.storages.entry(address).or_default().storage.insert(slot, value);
890 }
891 }
892
893 current_size += 1;
894 }
895
896 if chunk.is_empty() {
897 None
898 } else {
899 Some(chunk)
900 }
901 }
902}
903
904#[cfg(test)]
905mod tests {
906 use super::*;
907 use crate::KeccakKeyHasher;
908 use alloy_primitives::Bytes;
909 use revm::{
910 database::{states::StorageSlot, StorageWithOriginalValues},
911 state::{AccountInfo, Bytecode},
912 };
913
914 #[test]
915 fn hashed_state_wiped_extension() {
916 let hashed_address = B256::default();
917 let hashed_slot = B256::with_last_byte(64);
918 let hashed_slot2 = B256::with_last_byte(65);
919
920 let original_slot_value = U256::from(123);
922 let mut hashed_state = HashedPostState::default().with_storages([(
923 hashed_address,
924 HashedStorage::from_iter(
925 false,
926 [(hashed_slot, original_slot_value), (hashed_slot2, original_slot_value)],
927 ),
928 )]);
929
930 let updated_slot_value = U256::from(321);
932 let extension = HashedPostState::default().with_storages([(
933 hashed_address,
934 HashedStorage::from_iter(false, [(hashed_slot, updated_slot_value)]),
935 )]);
936 hashed_state.extend(extension);
937
938 let account_storage = hashed_state.storages.get(&hashed_address);
939 assert_eq!(
940 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
941 Some(&updated_slot_value)
942 );
943 assert_eq!(
944 account_storage.and_then(|st| st.storage.get(&hashed_slot2)),
945 Some(&original_slot_value)
946 );
947 assert_eq!(account_storage.map(|st| st.wiped), Some(false));
948
949 let wiped_extension =
951 HashedPostState::default().with_storages([(hashed_address, HashedStorage::new(true))]);
952 hashed_state.extend(wiped_extension);
953
954 let account_storage = hashed_state.storages.get(&hashed_address);
955 assert_eq!(account_storage.map(|st| st.storage.is_empty()), Some(true));
956 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
957
958 hashed_state.extend(HashedPostState::default().with_storages([(
960 hashed_address,
961 HashedStorage::from_iter(false, [(hashed_slot, original_slot_value)]),
962 )]));
963 let account_storage = hashed_state.storages.get(&hashed_address);
964 assert_eq!(
965 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
966 Some(&original_slot_value)
967 );
968 assert_eq!(account_storage.and_then(|st| st.storage.get(&hashed_slot2)), None);
969 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
970
971 hashed_state.extend(HashedPostState::default().with_storages([(
973 hashed_address,
974 HashedStorage::from_iter(false, [(hashed_slot2, updated_slot_value)]),
975 )]));
976 let account_storage = hashed_state.storages.get(&hashed_address);
977 assert_eq!(
978 account_storage.and_then(|st| st.storage.get(&hashed_slot)),
979 Some(&original_slot_value)
980 );
981 assert_eq!(
982 account_storage.and_then(|st| st.storage.get(&hashed_slot2)),
983 Some(&updated_slot_value)
984 );
985 assert_eq!(account_storage.map(|st| st.wiped), Some(true));
986 }
987
988 #[test]
989 fn test_hashed_post_state_from_bundle_state() {
990 let address = Address::random();
992
993 let account_info = AccountInfo {
995 balance: U256::from(123),
996 nonce: 42,
997 code_hash: B256::random(),
998 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2]))),
999 account_id: None,
1000 };
1001
1002 let mut storage = StorageWithOriginalValues::default();
1003 storage.insert(
1004 U256::from(1),
1005 StorageSlot { present_value: U256::from(4), ..Default::default() },
1006 );
1007
1008 let account = BundleAccount {
1010 status: AccountStatus::Changed,
1011 info: Some(account_info.clone()),
1012 storage,
1013 original_info: None,
1014 };
1015
1016 let state = vec![(&address, &account)];
1018
1019 let hashed_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(state);
1021
1022 assert_eq!(hashed_state.accounts.len(), 1);
1024 assert_eq!(hashed_state.storages.len(), 1);
1025
1026 assert_eq!(
1028 *hashed_state.accounts.get(&keccak256(address)).unwrap(),
1029 Some(account_info.into())
1030 );
1031 }
1032
1033 #[test]
1034 fn test_hashed_post_state_with_accounts() {
1035 let address_1 = Address::random();
1037 let address_2 = Address::random();
1038
1039 let account_info_1 = AccountInfo {
1040 balance: U256::from(1000),
1041 nonce: 1,
1042 code_hash: B256::random(),
1043 code: None,
1044 account_id: None,
1045 };
1046
1047 let account_1 = (keccak256(address_1), Some(account_info_1.into()));
1049 let account_2 = (keccak256(address_2), None);
1050
1051 let hashed_state = HashedPostState::default().with_accounts(vec![account_1, account_2]);
1053
1054 assert_eq!(hashed_state.accounts.len(), 2);
1056 assert!(hashed_state.accounts.contains_key(&keccak256(address_1)));
1057 assert!(hashed_state.accounts.contains_key(&keccak256(address_2)));
1058 }
1059
1060 #[test]
1061 fn test_hashed_post_state_with_storages() {
1062 let address_1 = Address::random();
1064 let address_2 = Address::random();
1065
1066 let storage_1 = (keccak256(address_1), HashedStorage::new(false));
1067 let storage_2 = (keccak256(address_2), HashedStorage::new(true));
1068
1069 let hashed_state = HashedPostState::default().with_storages(vec![storage_1, storage_2]);
1071
1072 assert_eq!(hashed_state.storages.len(), 2);
1074 assert!(hashed_state.storages.contains_key(&keccak256(address_1)));
1075 assert!(hashed_state.storages.contains_key(&keccak256(address_2)));
1076 }
1077
1078 #[test]
1079 fn test_hashed_post_state_is_empty() {
1080 let empty_state = HashedPostState::default();
1082 assert!(empty_state.is_empty());
1083
1084 let non_empty_state = HashedPostState::default()
1086 .with_accounts(vec![(keccak256(Address::random()), Some(Account::default()))]);
1087 assert!(!non_empty_state.is_empty());
1088 }
1089
1090 fn create_state_for_multi_proof_targets() -> HashedPostState {
1091 let mut state = HashedPostState::default();
1092
1093 let addr1 = B256::random();
1094 let addr2 = B256::random();
1095 state.accounts.insert(addr1, Some(Default::default()));
1096 state.accounts.insert(addr2, Some(Default::default()));
1097
1098 let mut storage = HashedStorage::default();
1099 let slot1 = B256::random();
1100 let slot2 = B256::random();
1101 storage.storage.insert(slot1, U256::ZERO);
1102 storage.storage.insert(slot2, U256::from(1));
1103 state.storages.insert(addr1, storage);
1104
1105 state
1106 }
1107
1108 #[test]
1109 fn test_multi_proof_targets_difference_empty_state() {
1110 let state = HashedPostState::default();
1111 let excluded = MultiProofTargets::default();
1112
1113 let targets = state.multi_proof_targets_difference(&excluded);
1114 assert!(targets.is_empty());
1115 }
1116
1117 #[test]
1118 fn test_multi_proof_targets_difference_new_account_targets() {
1119 let state = create_state_for_multi_proof_targets();
1120 let excluded = MultiProofTargets::default();
1121
1122 let targets = state.multi_proof_targets_difference(&excluded);
1124 assert_eq!(targets.len(), state.accounts.len());
1125 for addr in state.accounts.keys() {
1126 assert!(targets.contains_key(addr));
1127 }
1128 }
1129
1130 #[test]
1131 fn test_multi_proof_targets_difference_new_storage_targets() {
1132 let state = create_state_for_multi_proof_targets();
1133 let excluded = MultiProofTargets::default();
1134
1135 let targets = state.multi_proof_targets_difference(&excluded);
1136
1137 for (addr, storage) in &state.storages {
1139 assert!(targets.contains_key(addr));
1140 let target_slots = &targets[addr];
1141 assert_eq!(target_slots.len(), storage.storage.len());
1142 for slot in storage.storage.keys() {
1143 assert!(target_slots.contains(slot));
1144 }
1145 }
1146 }
1147
1148 #[test]
1149 fn test_multi_proof_targets_difference_filter_excluded_accounts() {
1150 let state = create_state_for_multi_proof_targets();
1151 let mut excluded = MultiProofTargets::default();
1152
1153 let excluded_addr = state
1155 .accounts
1156 .keys()
1157 .find(|&&addr| !state.storages.contains_key(&addr))
1158 .expect("Should have an account without storage");
1159
1160 excluded.insert(*excluded_addr, HashSet::default());
1162
1163 let targets = state.multi_proof_targets_difference(&excluded);
1164
1165 assert!(!targets.contains_key(excluded_addr));
1167 assert_eq!(targets.len(), state.accounts.len() - 1);
1169 }
1170
1171 #[test]
1172 fn test_multi_proof_targets_difference_filter_excluded_storage() {
1173 let state = create_state_for_multi_proof_targets();
1174 let mut excluded = MultiProofTargets::default();
1175
1176 let (addr, storage) = state.storages.iter().next().unwrap();
1178 let mut excluded_slots = HashSet::default();
1179 let excluded_slot = *storage.storage.keys().next().unwrap();
1180 excluded_slots.insert(excluded_slot);
1181 excluded.insert(*addr, excluded_slots);
1182
1183 let targets = state.multi_proof_targets_difference(&excluded);
1184
1185 let target_slots = &targets[addr];
1187 assert!(!target_slots.contains(&excluded_slot));
1188 assert_eq!(target_slots.len(), storage.storage.len() - 1);
1189 }
1190
1191 #[test]
1192 fn test_multi_proof_targets_difference_mixed_excluded_state() {
1193 let mut state = HashedPostState::default();
1194 let mut excluded = MultiProofTargets::default();
1195
1196 let addr1 = B256::random();
1197 let addr2 = B256::random();
1198 let slot1 = B256::random();
1199 let slot2 = B256::random();
1200
1201 state.accounts.insert(addr1, Some(Default::default()));
1202 state.accounts.insert(addr2, Some(Default::default()));
1203
1204 let mut storage = HashedStorage::default();
1205 storage.storage.insert(slot1, U256::ZERO);
1206 storage.storage.insert(slot2, U256::from(1));
1207 state.storages.insert(addr1, storage);
1208
1209 let mut excluded_slots = HashSet::default();
1210 excluded_slots.insert(slot1);
1211 excluded.insert(addr1, excluded_slots);
1212
1213 let targets = state.multi_proof_targets_difference(&excluded);
1214
1215 assert!(targets.contains_key(&addr2));
1216 assert!(!targets[&addr1].contains(&slot1));
1217 assert!(targets[&addr1].contains(&slot2));
1218 }
1219
1220 #[test]
1221 fn test_multi_proof_targets_difference_unmodified_account_with_storage() {
1222 let mut state = HashedPostState::default();
1223 let excluded = MultiProofTargets::default();
1224
1225 let addr = B256::random();
1226 let slot1 = B256::random();
1227 let slot2 = B256::random();
1228
1229 let mut storage = HashedStorage::default();
1232 storage.storage.insert(slot1, U256::from(1));
1233 storage.storage.insert(slot2, U256::from(2));
1234 state.storages.insert(addr, storage);
1235
1236 assert!(!state.accounts.contains_key(&addr));
1237 assert!(!excluded.contains_key(&addr));
1238
1239 let targets = state.multi_proof_targets_difference(&excluded);
1240
1241 assert!(targets.contains_key(&addr));
1243
1244 let target_slots = &targets[&addr];
1245 assert_eq!(target_slots.len(), 2);
1246 assert!(target_slots.contains(&slot1));
1247 assert!(target_slots.contains(&slot2));
1248 }
1249
1250 #[test]
1251 fn test_partition_by_targets() {
1252 let addr1 = B256::random();
1253 let addr2 = B256::random();
1254 let slot1 = B256::random();
1255 let slot2 = B256::random();
1256
1257 let state = HashedPostState {
1258 accounts: B256Map::from_iter([
1259 (addr1, Some(Default::default())),
1260 (addr2, Some(Default::default())),
1261 ]),
1262 storages: B256Map::from_iter([(
1263 addr1,
1264 HashedStorage {
1265 wiped: true,
1266 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1267 },
1268 )]),
1269 };
1270 let targets = MultiProofTargets::from_iter([(addr1, HashSet::from_iter([slot1]))]);
1271
1272 let (with_targets, without_targets) =
1273 state.partition_by_targets(&targets, &MultiAddedRemovedKeys::new());
1274
1275 assert_eq!(
1276 with_targets,
1277 HashedPostState {
1278 accounts: B256Map::from_iter([(addr1, Some(Default::default()))]),
1279 storages: B256Map::from_iter([(
1280 addr1,
1281 HashedStorage {
1282 wiped: true,
1283 storage: B256Map::from_iter([(slot1, U256::ZERO)])
1284 }
1285 )]),
1286 }
1287 );
1288 assert_eq!(
1289 without_targets,
1290 HashedPostState {
1291 accounts: B256Map::from_iter([(addr2, Some(Default::default()))]),
1292 storages: B256Map::from_iter([(
1293 addr1,
1294 HashedStorage {
1295 wiped: false,
1296 storage: B256Map::from_iter([(slot2, U256::from(1))])
1297 }
1298 )]),
1299 }
1300 );
1301 }
1302
1303 #[test]
1304 fn test_chunks() {
1305 let addr1 = B256::from([1; 32]);
1306 let addr2 = B256::from([2; 32]);
1307 let slot1 = B256::from([1; 32]);
1308 let slot2 = B256::from([2; 32]);
1309
1310 let state = HashedPostState {
1311 accounts: B256Map::from_iter([
1312 (addr1, Some(Default::default())),
1313 (addr2, Some(Default::default())),
1314 ]),
1315 storages: B256Map::from_iter([(
1316 addr2,
1317 HashedStorage {
1318 wiped: true,
1319 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1320 },
1321 )]),
1322 };
1323
1324 let mut chunks = state.chunks(2);
1325 assert_eq!(
1326 chunks.next(),
1327 Some(HashedPostState {
1328 accounts: B256Map::from_iter([(addr1, Some(Default::default()))]),
1329 storages: B256Map::from_iter([(addr2, HashedStorage::new(true)),])
1330 })
1331 );
1332 assert_eq!(
1333 chunks.next(),
1334 Some(HashedPostState {
1335 accounts: B256Map::default(),
1336 storages: B256Map::from_iter([(
1337 addr2,
1338 HashedStorage {
1339 wiped: false,
1340 storage: B256Map::from_iter([(slot1, U256::ZERO), (slot2, U256::from(1))]),
1341 },
1342 )])
1343 })
1344 );
1345 assert_eq!(
1346 chunks.next(),
1347 Some(HashedPostState {
1348 accounts: B256Map::from_iter([(addr2, Some(Default::default()))]),
1349 storages: B256Map::default()
1350 })
1351 );
1352 assert_eq!(chunks.next(), None);
1353 }
1354
1355 #[test]
1356 fn test_chunks_ordering_guarantee() {
1357 let addr = B256::from([1; 32]);
1360 let slot1 = B256::from([1; 32]);
1361 let slot2 = B256::from([2; 32]);
1362
1363 let state = HashedPostState {
1364 accounts: B256Map::from_iter([(addr, Some(Default::default()))]),
1365 storages: B256Map::from_iter([(
1366 addr,
1367 HashedStorage {
1368 wiped: true,
1369 storage: B256Map::from_iter([(slot1, U256::from(1)), (slot2, U256::from(2))]),
1370 },
1371 )]),
1372 };
1373
1374 let chunks: Vec<_> = state.chunks(1).collect();
1375
1376 assert_eq!(chunks.len(), 4);
1378
1379 assert!(chunks[0].accounts.is_empty());
1381 assert_eq!(chunks[0].storages.len(), 1);
1382 assert!(chunks[0].storages.get(&addr).unwrap().wiped);
1383 assert!(chunks[0].storages.get(&addr).unwrap().storage.is_empty());
1384
1385 assert!(chunks[1].accounts.is_empty());
1387 assert!(!chunks[1].storages.get(&addr).unwrap().wiped);
1388 assert_eq!(chunks[1].storages.get(&addr).unwrap().storage.len(), 1);
1389
1390 assert!(chunks[2].accounts.is_empty());
1391 assert!(!chunks[2].storages.get(&addr).unwrap().wiped);
1392 assert_eq!(chunks[2].storages.get(&addr).unwrap().storage.len(), 1);
1393
1394 assert_eq!(chunks[3].accounts.len(), 1);
1396 assert!(chunks[3].accounts.contains_key(&addr));
1397 assert!(chunks[3].storages.is_empty());
1398 }
1399
1400 #[test]
1401 fn test_hashed_post_state_sorted_extend_ref() {
1402 let mut state1 = HashedPostStateSorted {
1404 accounts: vec![
1405 (B256::from([1; 32]), Some(Account::default())),
1406 (B256::from([3; 32]), Some(Account::default())),
1407 (B256::from([5; 32]), None),
1408 ],
1409 storages: B256Map::default(),
1410 };
1411
1412 let state2 = HashedPostStateSorted {
1413 accounts: vec![
1414 (B256::from([2; 32]), Some(Account::default())),
1415 (B256::from([3; 32]), Some(Account { nonce: 1, ..Default::default() })), (B256::from([4; 32]), Some(Account::default())),
1417 (B256::from([6; 32]), None),
1418 ],
1419 storages: B256Map::default(),
1420 };
1421
1422 state1.extend_ref_and_sort(&state2);
1423
1424 assert_eq!(state1.accounts.len(), 6);
1426 assert_eq!(state1.accounts[0].0, B256::from([1; 32]));
1427 assert_eq!(state1.accounts[1].0, B256::from([2; 32]));
1428 assert_eq!(state1.accounts[2].0, B256::from([3; 32]));
1429 assert_eq!(state1.accounts[2].1.unwrap().nonce, 1); assert_eq!(state1.accounts[3].0, B256::from([4; 32]));
1431 assert_eq!(state1.accounts[4].0, B256::from([5; 32]));
1432 assert_eq!(state1.accounts[4].1, None);
1433 assert_eq!(state1.accounts[5].0, B256::from([6; 32]));
1434 assert_eq!(state1.accounts[5].1, None);
1435 }
1436
1437 #[test]
1438 fn test_hashed_storage_sorted_extend_ref() {
1439 let mut storage1 = HashedStorageSorted {
1441 storage_slots: vec![
1442 (B256::from([1; 32]), U256::from(10)),
1443 (B256::from([3; 32]), U256::from(30)),
1444 (B256::from([5; 32]), U256::ZERO),
1445 ],
1446 wiped: false,
1447 };
1448
1449 let storage2 = HashedStorageSorted {
1450 storage_slots: vec![
1451 (B256::from([2; 32]), U256::from(20)),
1452 (B256::from([3; 32]), U256::from(300)), (B256::from([4; 32]), U256::from(40)),
1454 (B256::from([6; 32]), U256::ZERO),
1455 ],
1456 wiped: false,
1457 };
1458
1459 storage1.extend_ref(&storage2);
1460
1461 assert_eq!(storage1.storage_slots.len(), 6);
1462 assert_eq!(storage1.storage_slots[0].0, B256::from([1; 32]));
1463 assert_eq!(storage1.storage_slots[0].1, U256::from(10));
1464 assert_eq!(storage1.storage_slots[1].0, B256::from([2; 32]));
1465 assert_eq!(storage1.storage_slots[1].1, U256::from(20));
1466 assert_eq!(storage1.storage_slots[2].0, B256::from([3; 32]));
1467 assert_eq!(storage1.storage_slots[2].1, U256::from(300)); assert_eq!(storage1.storage_slots[3].0, B256::from([4; 32]));
1469 assert_eq!(storage1.storage_slots[3].1, U256::from(40));
1470 assert_eq!(storage1.storage_slots[4].0, B256::from([5; 32]));
1471 assert_eq!(storage1.storage_slots[4].1, U256::ZERO);
1472 assert_eq!(storage1.storage_slots[5].0, B256::from([6; 32]));
1473 assert_eq!(storage1.storage_slots[5].1, U256::ZERO);
1474 assert!(!storage1.wiped);
1475
1476 let mut storage3 = HashedStorageSorted {
1478 storage_slots: vec![
1479 (B256::from([1; 32]), U256::from(10)),
1480 (B256::from([2; 32]), U256::ZERO),
1481 ],
1482 wiped: false,
1483 };
1484
1485 let storage4 = HashedStorageSorted {
1486 storage_slots: vec![
1487 (B256::from([3; 32]), U256::from(30)),
1488 (B256::from([4; 32]), U256::ZERO),
1489 ],
1490 wiped: true,
1491 };
1492
1493 storage3.extend_ref(&storage4);
1494
1495 assert!(storage3.wiped);
1496 assert_eq!(storage3.storage_slots.len(), 2);
1498 assert_eq!(storage3.storage_slots[0].0, B256::from([3; 32]));
1499 assert_eq!(storage3.storage_slots[0].1, U256::from(30));
1500 assert_eq!(storage3.storage_slots[1].0, B256::from([4; 32]));
1501 assert_eq!(storage3.storage_slots[1].1, U256::ZERO);
1502 }
1503
1504 #[test]
1506 fn test_hashed_post_state_extend_from_sorted_with_accounts() {
1507 let addr1 = B256::random();
1508 let addr2 = B256::random();
1509
1510 let mut state = HashedPostState::default();
1511 state.accounts.insert(addr1, Some(Default::default()));
1512
1513 let mut sorted_state = HashedPostStateSorted::default();
1514 sorted_state.accounts.push((addr2, Some(Default::default())));
1515
1516 state.extend_from_sorted(&sorted_state);
1517
1518 assert_eq!(state.accounts.len(), 2);
1519 assert!(state.accounts.contains_key(&addr1));
1520 assert!(state.accounts.contains_key(&addr2));
1521 }
1522
1523 #[test]
1525 fn test_hashed_post_state_extend_from_sorted_with_destroyed_accounts() {
1526 let addr1 = B256::random();
1527
1528 let mut state = HashedPostState::default();
1529
1530 let mut sorted_state = HashedPostStateSorted::default();
1531 sorted_state.accounts.push((addr1, None));
1532
1533 state.extend_from_sorted(&sorted_state);
1534
1535 assert!(state.accounts.contains_key(&addr1));
1536 assert_eq!(state.accounts.get(&addr1), Some(&None));
1537 }
1538
1539 #[test]
1541 fn test_hashed_storage_extend_from_sorted_non_wiped() {
1542 let slot1 = B256::random();
1543 let slot2 = B256::random();
1544 let slot3 = B256::random();
1545
1546 let mut storage = HashedStorage::from_iter(false, [(slot1, U256::from(100))]);
1547
1548 let sorted = HashedStorageSorted {
1549 storage_slots: vec![(slot2, U256::from(200)), (slot3, U256::ZERO)],
1550 wiped: false,
1551 };
1552
1553 storage.extend_from_sorted(&sorted);
1554
1555 assert!(!storage.wiped);
1556 assert_eq!(storage.storage.len(), 3);
1557 assert_eq!(storage.storage.get(&slot1), Some(&U256::from(100)));
1558 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1559 assert_eq!(storage.storage.get(&slot3), Some(&U256::ZERO));
1560 }
1561
1562 #[test]
1564 fn test_hashed_storage_extend_from_sorted_wiped() {
1565 let slot1 = B256::random();
1566 let slot2 = B256::random();
1567
1568 let mut storage = HashedStorage::from_iter(false, [(slot1, U256::from(100))]);
1569
1570 let sorted =
1571 HashedStorageSorted { storage_slots: vec![(slot2, U256::from(200))], wiped: true };
1572
1573 storage.extend_from_sorted(&sorted);
1574
1575 assert!(storage.wiped);
1576 assert_eq!(storage.storage.len(), 1);
1578 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1579 }
1580
1581 #[test]
1582 fn test_hashed_post_state_chunking_length() {
1583 let addr1 = B256::from([1; 32]);
1584 let addr2 = B256::from([2; 32]);
1585 let addr3 = B256::from([3; 32]);
1586 let addr4 = B256::from([4; 32]);
1587 let slot1 = B256::from([1; 32]);
1588 let slot2 = B256::from([2; 32]);
1589 let slot3 = B256::from([3; 32]);
1590
1591 let state = HashedPostState {
1592 accounts: B256Map::from_iter([(addr1, None), (addr2, None), (addr4, None)]),
1593 storages: B256Map::from_iter([
1594 (
1595 addr1,
1596 HashedStorage {
1597 wiped: false,
1598 storage: B256Map::from_iter([
1599 (slot1, U256::ZERO),
1600 (slot2, U256::ZERO),
1601 (slot3, U256::ZERO),
1602 ]),
1603 },
1604 ),
1605 (
1606 addr2,
1607 HashedStorage {
1608 wiped: true,
1609 storage: B256Map::from_iter([
1610 (slot1, U256::ZERO),
1611 (slot2, U256::ZERO),
1612 (slot3, U256::ZERO),
1613 ]),
1614 },
1615 ),
1616 (
1617 addr3,
1618 HashedStorage {
1619 wiped: false,
1620 storage: B256Map::from_iter([
1621 (slot1, U256::ZERO),
1622 (slot2, U256::ZERO),
1623 (slot3, U256::ZERO),
1624 ]),
1625 },
1626 ),
1627 ]),
1628 };
1629
1630 let chunking_length = state.chunking_length();
1631 for size in 1..=state.clone().chunks(1).count() {
1632 let chunk_count = state.clone().chunks(size).count();
1633 let expected_count = chunking_length.div_ceil(size);
1634 assert_eq!(
1635 chunk_count, expected_count,
1636 "chunking_length: {}, size: {}",
1637 chunking_length, size
1638 );
1639 }
1640 }
1641
1642 #[test]
1643 fn test_clone_into_sorted_equivalence() {
1644 let addr1 = B256::from([1; 32]);
1645 let addr2 = B256::from([2; 32]);
1646 let addr3 = B256::from([3; 32]);
1647 let slot1 = B256::from([1; 32]);
1648 let slot2 = B256::from([2; 32]);
1649 let slot3 = B256::from([3; 32]);
1650
1651 let state = HashedPostState {
1652 accounts: B256Map::from_iter([
1653 (addr1, Some(Account { nonce: 1, balance: U256::from(100), bytecode_hash: None })),
1654 (addr2, None),
1655 (addr3, Some(Account::default())),
1656 ]),
1657 storages: B256Map::from_iter([
1658 (
1659 addr1,
1660 HashedStorage {
1661 wiped: false,
1662 storage: B256Map::from_iter([
1663 (slot1, U256::from(10)),
1664 (slot2, U256::from(20)),
1665 ]),
1666 },
1667 ),
1668 (
1669 addr2,
1670 HashedStorage {
1671 wiped: true,
1672 storage: B256Map::from_iter([(slot3, U256::ZERO)]),
1673 },
1674 ),
1675 ]),
1676 };
1677
1678 let sorted_via_clone = state.clone().into_sorted();
1680 let sorted_via_clone_into = state.clone_into_sorted();
1681
1682 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1683
1684 assert_eq!(state.accounts.len(), 3);
1686 assert_eq!(state.storages.len(), 2);
1687 }
1688
1689 #[test]
1690 fn test_hashed_storage_clone_into_sorted_equivalence() {
1691 let slot1 = B256::from([1; 32]);
1692 let slot2 = B256::from([2; 32]);
1693 let slot3 = B256::from([3; 32]);
1694
1695 let storage = HashedStorage {
1696 wiped: true,
1697 storage: B256Map::from_iter([
1698 (slot1, U256::from(100)),
1699 (slot2, U256::ZERO),
1700 (slot3, U256::from(300)),
1701 ]),
1702 };
1703
1704 let sorted_via_clone = storage.clone().into_sorted();
1706 let sorted_via_clone_into = storage.clone_into_sorted();
1707
1708 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1709
1710 assert_eq!(storage.storage.len(), 3);
1712 assert!(storage.wiped);
1713 }
1714}
1715
1716#[cfg(feature = "serde-bincode-compat")]
1718pub mod serde_bincode_compat {
1719 use super::Account;
1720 use alloc::borrow::Cow;
1721 use alloy_primitives::{map::B256Map, B256, U256};
1722 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1723 use serde_with::{DeserializeAs, SerializeAs};
1724
1725 #[derive(Debug, Serialize, Deserialize)]
1741 pub struct HashedPostState<'a> {
1742 accounts: Cow<'a, B256Map<Option<Account>>>,
1743 storages: B256Map<HashedStorage<'a>>,
1744 }
1745
1746 impl<'a> From<&'a super::HashedPostState> for HashedPostState<'a> {
1747 fn from(value: &'a super::HashedPostState) -> Self {
1748 Self {
1749 accounts: Cow::Borrowed(&value.accounts),
1750 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
1751 }
1752 }
1753 }
1754
1755 impl<'a> From<HashedPostState<'a>> for super::HashedPostState {
1756 fn from(value: HashedPostState<'a>) -> Self {
1757 Self {
1758 accounts: value.accounts.into_owned(),
1759 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
1760 }
1761 }
1762 }
1763
1764 impl SerializeAs<super::HashedPostState> for HashedPostState<'_> {
1765 fn serialize_as<S>(
1766 source: &super::HashedPostState,
1767 serializer: S,
1768 ) -> Result<S::Ok, S::Error>
1769 where
1770 S: Serializer,
1771 {
1772 HashedPostState::from(source).serialize(serializer)
1773 }
1774 }
1775
1776 impl<'de> DeserializeAs<'de, super::HashedPostState> for HashedPostState<'de> {
1777 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostState, D::Error>
1778 where
1779 D: Deserializer<'de>,
1780 {
1781 HashedPostState::deserialize(deserializer).map(Into::into)
1782 }
1783 }
1784
1785 #[derive(Debug, Serialize, Deserialize)]
1801 pub struct HashedStorage<'a> {
1802 wiped: bool,
1803 storage: Cow<'a, B256Map<U256>>,
1804 }
1805
1806 impl<'a> From<&'a super::HashedStorage> for HashedStorage<'a> {
1807 fn from(value: &'a super::HashedStorage) -> Self {
1808 Self { wiped: value.wiped, storage: Cow::Borrowed(&value.storage) }
1809 }
1810 }
1811
1812 impl<'a> From<HashedStorage<'a>> for super::HashedStorage {
1813 fn from(value: HashedStorage<'a>) -> Self {
1814 Self { wiped: value.wiped, storage: value.storage.into_owned() }
1815 }
1816 }
1817
1818 impl SerializeAs<super::HashedStorage> for HashedStorage<'_> {
1819 fn serialize_as<S>(source: &super::HashedStorage, serializer: S) -> Result<S::Ok, S::Error>
1820 where
1821 S: Serializer,
1822 {
1823 HashedStorage::from(source).serialize(serializer)
1824 }
1825 }
1826
1827 impl<'de> DeserializeAs<'de, super::HashedStorage> for HashedStorage<'de> {
1828 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorage, D::Error>
1829 where
1830 D: Deserializer<'de>,
1831 {
1832 HashedStorage::deserialize(deserializer).map(Into::into)
1833 }
1834 }
1835
1836 #[derive(Debug, Serialize, Deserialize)]
1852 pub struct HashedPostStateSorted<'a> {
1853 accounts: Cow<'a, [(B256, Option<Account>)]>,
1854 storages: B256Map<HashedStorageSorted<'a>>,
1855 }
1856
1857 impl<'a> From<&'a super::HashedPostStateSorted> for HashedPostStateSorted<'a> {
1858 fn from(value: &'a super::HashedPostStateSorted) -> Self {
1859 Self {
1860 accounts: Cow::Borrowed(&value.accounts),
1861 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
1862 }
1863 }
1864 }
1865
1866 impl<'a> From<HashedPostStateSorted<'a>> for super::HashedPostStateSorted {
1867 fn from(value: HashedPostStateSorted<'a>) -> Self {
1868 Self {
1869 accounts: value.accounts.into_owned(),
1870 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
1871 }
1872 }
1873 }
1874
1875 impl SerializeAs<super::HashedPostStateSorted> for HashedPostStateSorted<'_> {
1876 fn serialize_as<S>(
1877 source: &super::HashedPostStateSorted,
1878 serializer: S,
1879 ) -> Result<S::Ok, S::Error>
1880 where
1881 S: Serializer,
1882 {
1883 HashedPostStateSorted::from(source).serialize(serializer)
1884 }
1885 }
1886
1887 impl<'de> DeserializeAs<'de, super::HashedPostStateSorted> for HashedPostStateSorted<'de> {
1888 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostStateSorted, D::Error>
1889 where
1890 D: Deserializer<'de>,
1891 {
1892 HashedPostStateSorted::deserialize(deserializer).map(Into::into)
1893 }
1894 }
1895
1896 #[derive(Debug, Serialize, Deserialize)]
1912 pub struct HashedStorageSorted<'a> {
1913 storage_slots: Cow<'a, [(B256, U256)]>,
1914 wiped: bool,
1915 }
1916
1917 impl<'a> From<&'a super::HashedStorageSorted> for HashedStorageSorted<'a> {
1918 fn from(value: &'a super::HashedStorageSorted) -> Self {
1919 Self { storage_slots: Cow::Borrowed(&value.storage_slots), wiped: value.wiped }
1920 }
1921 }
1922
1923 impl<'a> From<HashedStorageSorted<'a>> for super::HashedStorageSorted {
1924 fn from(value: HashedStorageSorted<'a>) -> Self {
1925 Self { storage_slots: value.storage_slots.into_owned(), wiped: value.wiped }
1926 }
1927 }
1928
1929 impl SerializeAs<super::HashedStorageSorted> for HashedStorageSorted<'_> {
1930 fn serialize_as<S>(
1931 source: &super::HashedStorageSorted,
1932 serializer: S,
1933 ) -> Result<S::Ok, S::Error>
1934 where
1935 S: Serializer,
1936 {
1937 HashedStorageSorted::from(source).serialize(serializer)
1938 }
1939 }
1940
1941 impl<'de> DeserializeAs<'de, super::HashedStorageSorted> for HashedStorageSorted<'de> {
1942 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorageSorted, D::Error>
1943 where
1944 D: Deserializer<'de>,
1945 {
1946 HashedStorageSorted::deserialize(deserializer).map(Into::into)
1947 }
1948 }
1949
1950 #[cfg(test)]
1951 mod tests {
1952 use crate::{
1953 hashed_state::{
1954 HashedPostState, HashedPostStateSorted, HashedStorage, HashedStorageSorted,
1955 },
1956 serde_bincode_compat,
1957 };
1958 use alloy_primitives::{B256, U256};
1959 use reth_primitives_traits::Account;
1960 use serde::{Deserialize, Serialize};
1961 use serde_with::serde_as;
1962
1963 #[test]
1964 fn test_hashed_post_state_bincode_roundtrip() {
1965 #[serde_as]
1966 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1967 struct Data {
1968 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostState")]
1969 hashed_state: HashedPostState,
1970 }
1971
1972 let mut data = Data { hashed_state: HashedPostState::default() };
1973 let encoded = bincode::serialize(&data).unwrap();
1974 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1975 assert_eq!(decoded, data);
1976
1977 data.hashed_state.accounts.insert(B256::random(), Some(Account::default()));
1978 let encoded = bincode::serialize(&data).unwrap();
1979 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1980 assert_eq!(decoded, data);
1981
1982 data.hashed_state.storages.insert(B256::random(), HashedStorage::default());
1983 let encoded = bincode::serialize(&data).unwrap();
1984 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1985 assert_eq!(decoded, data);
1986 }
1987
1988 #[test]
1989 fn test_hashed_storage_bincode_roundtrip() {
1990 #[serde_as]
1991 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1992 struct Data {
1993 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorage")]
1994 hashed_storage: HashedStorage,
1995 }
1996
1997 let mut data = Data { hashed_storage: HashedStorage::default() };
1998 let encoded = bincode::serialize(&data).unwrap();
1999 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2000 assert_eq!(decoded, data);
2001
2002 data.hashed_storage.wiped = true;
2003 let encoded = bincode::serialize(&data).unwrap();
2004 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2005 assert_eq!(decoded, data);
2006
2007 data.hashed_storage.storage.insert(B256::random(), U256::from(1));
2008 let encoded = bincode::serialize(&data).unwrap();
2009 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2010 assert_eq!(decoded, data);
2011 }
2012
2013 #[test]
2014 fn test_hashed_post_state_sorted_bincode_roundtrip() {
2015 #[serde_as]
2016 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2017 struct Data {
2018 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostStateSorted")]
2019 hashed_state: HashedPostStateSorted,
2020 }
2021
2022 let mut data = Data { hashed_state: HashedPostStateSorted::default() };
2023 let encoded = bincode::serialize(&data).unwrap();
2024 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2025 assert_eq!(decoded, data);
2026
2027 data.hashed_state.accounts.push((B256::random(), Some(Account::default())));
2028 data.hashed_state
2029 .accounts
2030 .push((B256::random(), Some(Account { nonce: 1, ..Default::default() })));
2031 let encoded = bincode::serialize(&data).unwrap();
2032 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2033 assert_eq!(decoded, data);
2034
2035 data.hashed_state.storages.insert(
2036 B256::random(),
2037 HashedStorageSorted {
2038 storage_slots: vec![(B256::from([1; 32]), U256::from(10))],
2039 wiped: false,
2040 },
2041 );
2042 let encoded = bincode::serialize(&data).unwrap();
2043 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2044 assert_eq!(decoded, data);
2045 }
2046
2047 #[test]
2048 fn test_hashed_storage_sorted_bincode_roundtrip() {
2049 #[serde_as]
2050 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2051 struct Data {
2052 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorageSorted")]
2053 hashed_storage: HashedStorageSorted,
2054 }
2055
2056 let mut data = Data {
2057 hashed_storage: HashedStorageSorted { storage_slots: Vec::new(), wiped: false },
2058 };
2059 let encoded = bincode::serialize(&data).unwrap();
2060 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2061 assert_eq!(decoded, data);
2062
2063 data.hashed_storage.wiped = true;
2064 let encoded = bincode::serialize(&data).unwrap();
2065 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2066 assert_eq!(decoded, data);
2067
2068 data.hashed_storage.storage_slots.push((B256::random(), U256::from(1)));
2069 let encoded = bincode::serialize(&data).unwrap();
2070 let decoded: Data = bincode::deserialize(&encoded).unwrap();
2071 assert_eq!(decoded, data);
2072 }
2073 }
2074}