1use crate::{
2 prefix_set::{PrefixSetMut, TriePrefixSetsMut},
3 utils::{extend_sorted_vec, kway_merge_disjoint_sorted, kway_merge_sorted},
4 KeyHasher, MultiProofTargets, Nibbles,
5};
6use alloc::{borrow::Cow, vec::Vec};
7use alloy_primitives::{
8 keccak256,
9 map::{hash_map, B256Map, HashMap, HashSet},
10 Address, B256, U256,
11};
12use itertools::Itertools;
13use reth_primitives_traits::Account;
14
15#[cfg(feature = "rayon")]
16use rayon::prelude::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
17
18use revm::database::BundleAccount;
19
20#[derive(PartialEq, Eq, Clone, Default, Debug)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct HashedPostState {
25 pub accounts: B256Map<Option<Account>>,
27 pub storages: B256Map<HashedStorage>,
29}
30
31impl HashedPostState {
32 pub fn with_capacity(capacity: usize) -> Self {
34 Self {
35 accounts: B256Map::with_capacity_and_hasher(capacity, Default::default()),
36 storages: B256Map::with_capacity_and_hasher(capacity, Default::default()),
37 }
38 }
39
40 #[inline]
44 pub fn from_bundle_state<'a, KH: KeyHasher>(
45 state: impl IntoIterator<Item = (&'a Address, &'a BundleAccount)>,
46 ) -> Self {
47 state
48 .into_iter()
49 .map(|(address, account)| {
50 let hashed_address = KH::hash_key(address);
51 let hashed_account = account.info.as_ref().map(Into::into);
52 let hashed_storage = HashedStorage::from_iter(
53 account
54 .storage
55 .iter()
56 .map(|(slot, value)| (keccak256(B256::from(*slot)), value.present_value)),
57 );
58
59 (
60 hashed_address,
61 hashed_account,
62 (!hashed_storage.is_empty()).then_some(hashed_storage),
63 )
64 })
65 .collect()
66 }
67
68 pub fn from_hashed_storage(hashed_address: B256, storage: HashedStorage) -> Self {
70 Self {
71 accounts: HashMap::default(),
72 storages: HashMap::from_iter([(hashed_address, storage)]),
73 }
74 }
75
76 pub fn with_accounts(
78 mut self,
79 accounts: impl IntoIterator<Item = (B256, Option<Account>)>,
80 ) -> Self {
81 self.accounts = HashMap::from_iter(accounts);
82 self
83 }
84
85 pub fn with_storages(
87 mut self,
88 storages: impl IntoIterator<Item = (B256, HashedStorage)>,
89 ) -> Self {
90 self.storages = HashMap::from_iter(storages);
91 self
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.accounts.is_empty() && self.storages.is_empty()
97 }
98
99 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
103 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
105 let mut destroyed_accounts = HashSet::default();
106 for (hashed_address, account) in &self.accounts {
107 account_prefix_set.insert(Nibbles::unpack(hashed_address));
108
109 if account.is_none() {
110 destroyed_accounts.insert(*hashed_address);
111 }
112 }
113
114 let mut storage_prefix_sets =
116 HashMap::with_capacity_and_hasher(self.storages.len(), Default::default());
117 for (hashed_address, hashed_storage) in &self.storages {
118 account_prefix_set.insert(Nibbles::unpack(hashed_address));
119 storage_prefix_sets.insert(*hashed_address, hashed_storage.construct_prefix_set());
120 }
121
122 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
123 }
124
125 pub fn multi_proof_targets(&self) -> MultiProofTargets {
127 let mut targets = MultiProofTargets::with_capacity(self.accounts.len());
129 for hashed_address in self.accounts.keys() {
130 targets.insert(*hashed_address, Default::default());
131 }
132 for (hashed_address, storage) in &self.storages {
133 targets.entry(*hashed_address).or_default().extend(storage.storage.keys().copied());
134 }
135 targets
136 }
137
138 pub fn multi_proof_targets_difference(
144 &self,
145 excluded: &MultiProofTargets,
146 ) -> MultiProofTargets {
147 let mut targets = MultiProofTargets::default();
148 for hashed_address in self.accounts.keys() {
149 if !excluded.contains_key(hashed_address) {
150 targets.insert(*hashed_address, Default::default());
151 }
152 }
153 for (hashed_address, storage) in &self.storages {
154 let maybe_excluded_storage = excluded.get(hashed_address);
155 let mut hashed_slots_targets = storage
156 .storage
157 .keys()
158 .filter(|slot| !maybe_excluded_storage.is_some_and(|f| f.contains(*slot)))
159 .peekable();
160 if hashed_slots_targets.peek().is_some() {
161 targets.entry(*hashed_address).or_default().extend(hashed_slots_targets);
162 }
163 }
164 targets
165 }
166
167 pub fn chunks(self, size: usize) -> ChunkedHashedPostState {
175 ChunkedHashedPostState::new(self, size)
176 }
177
178 pub fn chunking_length(&self) -> usize {
180 self.accounts.len() +
181 self.storages.values().map(|storage| storage.storage.len()).sum::<usize>()
182 }
183
184 pub fn extend(&mut self, other: Self) {
187 self.extend_inner(Cow::Owned(other));
188 }
189
190 pub fn extend_ref(&mut self, other: &Self) {
195 self.extend_inner(Cow::Borrowed(other));
196 }
197
198 #[allow(clippy::clone_on_copy)]
199 fn extend_inner(&mut self, other: Cow<'_, Self>) {
200 self.accounts.extend(other.accounts.iter().map(|(&k, v)| (k, v.clone())));
201
202 self.storages.reserve(other.storages.len());
203 match other {
204 Cow::Borrowed(other) => {
205 self.extend_storages(other.storages.iter().map(|(k, v)| (*k, Cow::Borrowed(v))))
206 }
207 Cow::Owned(other) => {
208 self.extend_storages(other.storages.into_iter().map(|(k, v)| (k, Cow::Owned(v))))
209 }
210 }
211 }
212
213 fn extend_storages<'a>(
214 &mut self,
215 storages: impl IntoIterator<Item = (B256, Cow<'a, HashedStorage>)>,
216 ) {
217 for (hashed_address, storage) in storages {
218 match self.storages.entry(hashed_address) {
219 hash_map::Entry::Vacant(entry) => {
220 entry.insert(storage.into_owned());
221 }
222 hash_map::Entry::Occupied(mut entry) => {
223 entry.get_mut().extend(&storage);
224 }
225 }
226 }
227 }
228
229 #[allow(clippy::clone_on_copy)]
233 pub fn extend_from_sorted(&mut self, sorted: &HashedPostStateSorted) {
234 self.accounts.reserve(sorted.accounts.len());
236
237 for (address, account) in &sorted.accounts {
239 self.accounts.insert(*address, account.clone());
240 }
241
242 self.storages.reserve(sorted.storages.len());
244
245 for (hashed_address, sorted_storage) in &sorted.storages {
247 match self.storages.entry(*hashed_address) {
248 hash_map::Entry::Vacant(entry) => {
249 let mut new_storage = HashedStorage::default();
250 new_storage.extend_from_sorted(sorted_storage);
251 entry.insert(new_storage);
252 }
253 hash_map::Entry::Occupied(mut entry) => {
254 entry.get_mut().extend_from_sorted(sorted_storage);
255 }
256 }
257 }
258 }
259
260 pub fn into_sorted(self) -> HashedPostStateSorted {
262 let mut accounts: Vec<_> = self.accounts.into_iter().collect();
263 accounts.sort_unstable_by_key(|(address, _)| *address);
264
265 let storages = self
266 .storages
267 .into_iter()
268 .map(|(hashed_address, storage)| (hashed_address, storage.into_sorted()))
269 .collect();
270
271 HashedPostStateSorted { accounts, storages }
272 }
273
274 #[allow(clippy::clone_on_copy)]
277 pub fn clone_into_sorted(&self) -> HashedPostStateSorted {
278 let mut accounts: Vec<_> = self.accounts.iter().map(|(&k, v)| (k, v.clone())).collect();
279 accounts.sort_unstable_by_key(|(address, _)| *address);
280
281 let storages = self
282 .storages
283 .iter()
284 .map(|(&hashed_address, storage)| (hashed_address, storage.clone_into_sorted()))
285 .collect();
286
287 HashedPostStateSorted { accounts, storages }
288 }
289
290 pub fn clear(&mut self) {
292 self.accounts.clear();
293 self.storages.clear();
294 }
295}
296
297impl FromIterator<(B256, Option<Account>, Option<HashedStorage>)> for HashedPostState {
298 fn from_iter<T: IntoIterator<Item = (B256, Option<Account>, Option<HashedStorage>)>>(
314 iter: T,
315 ) -> Self {
316 let iter = iter.into_iter();
317 let (lower, _) = iter.size_hint();
318 let mut hashed_state = Self::with_capacity(lower);
319
320 for (hashed_address, info, hashed_storage) in iter {
321 hashed_state.accounts.insert(hashed_address, info);
322 if let Some(storage) = hashed_storage {
323 hashed_state.storages.insert(hashed_address, storage);
324 }
325 }
326
327 hashed_state
328 }
329}
330
331#[cfg(feature = "rayon")]
332impl FromParallelIterator<(B256, Option<Account>, Option<HashedStorage>)> for HashedPostState {
333 fn from_par_iter<I>(par_iter: I) -> Self
345 where
346 I: IntoParallelIterator<Item = (B256, Option<Account>, Option<HashedStorage>)>,
347 {
348 let vec: Vec<_> = par_iter.into_par_iter().collect();
349 vec.into_iter().collect()
350 }
351}
352
353#[derive(PartialEq, Eq, Clone, Debug, Default)]
355#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
356pub struct HashedStorage {
357 pub storage: B256Map<U256>,
359}
360
361impl HashedStorage {
362 pub fn is_empty(&self) -> bool {
364 self.storage.is_empty()
365 }
366
367 #[expect(clippy::should_implement_trait)]
369 pub fn from_iter(iter: impl IntoIterator<Item = (B256, U256)>) -> Self {
370 Self { storage: HashMap::from_iter(iter) }
371 }
372
373 pub fn from_plain_storage<'a>(storage: impl IntoIterator<Item = (&'a U256, &'a U256)>) -> Self {
375 Self::from_iter(
376 storage.into_iter().map(|(key, value)| (keccak256(B256::from(*key)), *value)),
377 )
378 }
379
380 pub fn construct_prefix_set(&self) -> PrefixSetMut {
382 let mut prefix_set = PrefixSetMut::with_capacity(self.storage.len());
383 for hashed_slot in self.storage.keys() {
384 prefix_set.insert(Nibbles::unpack(hashed_slot));
385 }
386 prefix_set
387 }
388
389 pub fn extend(&mut self, other: &Self) {
392 self.storage.extend(other.storage.iter().map(|(&k, &v)| (k, v)));
393 }
394
395 pub fn extend_from_sorted(&mut self, sorted: &HashedStorageSorted) {
399 self.storage.reserve(sorted.storage_slots.len());
401
402 for (slot, value) in &sorted.storage_slots {
404 self.storage.insert(*slot, *value);
405 }
406 }
407
408 pub fn into_sorted(self) -> HashedStorageSorted {
410 let mut storage_slots: Vec<_> = self.storage.into_iter().collect();
411 storage_slots.sort_unstable_by_key(|(key, _)| *key);
412
413 HashedStorageSorted { storage_slots }
414 }
415
416 pub fn clone_into_sorted(&self) -> HashedStorageSorted {
419 let mut storage_slots: Vec<_> = self.storage.iter().map(|(&k, &v)| (k, v)).collect();
420 storage_slots.sort_unstable_by_key(|(key, _)| *key);
421
422 HashedStorageSorted { storage_slots }
423 }
424}
425
426#[derive(PartialEq, Eq, Clone, Default, Debug)]
428#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
429pub struct HashedPostStateSorted {
430 pub accounts: Vec<(B256, Option<Account>)>,
432 pub storages: B256Map<HashedStorageSorted>,
434}
435
436impl HashedPostStateSorted {
437 pub const fn new(
439 accounts: Vec<(B256, Option<Account>)>,
440 storages: B256Map<HashedStorageSorted>,
441 ) -> Self {
442 Self { accounts, storages }
443 }
444
445 pub const fn accounts(&self) -> &Vec<(B256, Option<Account>)> {
447 &self.accounts
448 }
449
450 pub const fn account_storages(&self) -> &B256Map<HashedStorageSorted> {
452 &self.storages
453 }
454
455 pub fn is_empty(&self) -> bool {
457 self.accounts.is_empty() && self.storages.is_empty()
458 }
459
460 pub fn total_len(&self) -> usize {
462 self.accounts.len() + self.storages.values().map(|s| s.len()).sum::<usize>()
463 }
464
465 pub fn construct_prefix_sets(&self) -> TriePrefixSetsMut {
470 let mut account_prefix_set = PrefixSetMut::with_capacity(self.accounts.len());
471 let mut destroyed_accounts = HashSet::default();
472 for (hashed_address, account) in &self.accounts {
473 account_prefix_set.insert(Nibbles::unpack(hashed_address));
474 if account.is_none() {
475 destroyed_accounts.insert(*hashed_address);
476 }
477 }
478
479 let mut storage_prefix_sets =
480 B256Map::with_capacity_and_hasher(self.storages.len(), Default::default());
481 for (hashed_address, hashed_storage) in &self.storages {
482 account_prefix_set.insert(Nibbles::unpack(hashed_address));
484 let mut prefix_set = PrefixSetMut::with_capacity(hashed_storage.storage_slots.len());
485 prefix_set.extend_keys(
486 hashed_storage
487 .storage_slots
488 .iter()
489 .map(|(hashed_slot, _)| Nibbles::unpack(hashed_slot)),
490 );
491
492 storage_prefix_sets.insert(*hashed_address, prefix_set);
493 }
494
495 TriePrefixSetsMut { account_prefix_set, storage_prefix_sets, destroyed_accounts }
496 }
497
498 pub fn extend_ref_and_sort(&mut self, other: &Self) {
503 extend_sorted_vec(&mut self.accounts, &other.accounts);
505
506 for (hashed_address, other_storage) in &other.storages {
508 self.storages
509 .entry(*hashed_address)
510 .and_modify(|existing| existing.extend_ref(other_storage))
511 .or_insert_with(|| other_storage.clone());
512 }
513 }
514
515 pub fn merge_batch<T: AsRef<Self> + From<Self>>(iter: impl IntoIterator<Item = T>) -> T {
520 let items: alloc::vec::Vec<_> = iter.into_iter().collect();
521 match items.len() {
522 0 => Self::default().into(),
523 1 => items.into_iter().next().expect("len == 1"),
524 _ => Self::merge_slice(&items).into(),
525 }
526 }
527
528 pub fn merge_slice<T: AsRef<Self>>(items: &[T]) -> Self {
534 const THRESHOLD: usize = 30;
535
536 let k = items.len();
537
538 if k == 0 {
539 return Self::default();
540 }
541 if k == 1 {
542 return items[0].as_ref().clone();
543 }
544
545 if k < THRESHOLD {
546 let mut iter = items.iter().rev();
548 let mut acc = iter.next().expect("k > 0").as_ref().clone();
549 for next in iter {
550 acc.extend_ref_and_sort(next.as_ref());
551 }
552 return acc;
553 }
554
555 let accounts = kway_merge_sorted(items.iter().map(|i| i.as_ref().accounts.as_slice()));
557
558 struct StorageAcc<'a> {
559 slices: Vec<&'a [(B256, U256)]>,
560 }
561
562 let mut acc: B256Map<StorageAcc<'_>> = B256Map::default();
563
564 for item in items {
565 for (addr, storage) in &item.as_ref().storages {
566 let entry = acc.entry(*addr).or_insert_with(|| StorageAcc { slices: Vec::new() });
567 entry.slices.push(storage.storage_slots.as_slice());
568 }
569 }
570
571 let storages = acc
572 .into_iter()
573 .map(|(addr, entry)| {
574 let storage_slots = kway_merge_sorted(entry.slices);
575 (addr, HashedStorageSorted { storage_slots })
576 })
577 .collect();
578
579 Self { accounts, storages }
580 }
581
582 pub fn disjointed_merge_batch<'a>(batch: &[&'a Self], mask: &[&'a Self]) -> Self {
590 let account_count = batch.iter().map(|item| item.accounts.len()).sum();
591 let mut accounts = Vec::with_capacity(account_count);
592 accounts.extend(kway_merge_disjoint_sorted(
593 batch.iter().rev().map(|item| item.accounts.as_slice()),
594 mask.iter().map(|item| item.accounts.as_slice()),
595 ));
596
597 struct StorageAcc<'a> {
598 slot_count: usize,
599 slices: Vec<&'a [(B256, U256)]>,
600 }
601
602 #[derive(Default)]
603 struct StorageMaskAcc<'a> {
604 slices: Vec<&'a [(B256, U256)]>,
605 }
606
607 let mut storages = B256Map::with_capacity_and_hasher(
608 batch.iter().map(|item| item.storages.len()).sum(),
609 Default::default(),
610 );
611
612 for item in batch.iter().rev() {
613 for (hashed_address, storage) in &item.storages {
614 let entry = storages
615 .entry(*hashed_address)
616 .or_insert_with(|| StorageAcc { slot_count: 0, slices: Vec::new() });
617 entry.slices.push(storage.storage_slots.as_slice());
618 entry.slot_count += storage.storage_slots.len();
619 }
620 }
621
622 let mut storage_masks: B256Map<StorageMaskAcc<'a>> = B256Map::with_capacity_and_hasher(
623 mask.iter().map(|item| item.storages.len()).sum(),
624 Default::default(),
625 );
626 for item in mask {
627 for (hashed_address, storage) in &item.storages {
628 let entry = storage_masks.entry(*hashed_address).or_default();
629 entry.slices.push(storage.storage_slots.as_slice());
630 }
631 }
632
633 let storages = storages
634 .into_iter()
635 .filter_map(|(hashed_address, entry)| {
636 let slot_count = entry.slot_count;
637 let storage_slots = match storage_masks.get(&hashed_address) {
638 Some(mask_entry) => {
639 let mut storage_slots = Vec::with_capacity(slot_count);
640 storage_slots.extend(kway_merge_disjoint_sorted(
641 entry.slices,
642 mask_entry.slices.iter().copied(),
643 ));
644 storage_slots
645 }
646 None => kway_merge_sorted(entry.slices),
647 };
648
649 (!storage_slots.is_empty() || mask.is_empty())
650 .then_some((hashed_address, HashedStorageSorted { storage_slots }))
651 })
652 .collect();
653
654 Self { accounts, storages }
655 }
656
657 pub fn clear(&mut self) {
659 self.accounts.clear();
660 self.storages.clear();
661 }
662}
663
664impl AsRef<Self> for HashedPostStateSorted {
665 fn as_ref(&self) -> &Self {
666 self
667 }
668}
669
670#[derive(Clone, Eq, PartialEq, Debug, Default)]
672#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
673pub struct HashedStorageSorted {
674 pub storage_slots: Vec<(B256, U256)>,
676}
677
678impl HashedStorageSorted {
679 pub fn storage_slots_ref(&self) -> &[(B256, U256)] {
681 &self.storage_slots
682 }
683
684 pub const fn len(&self) -> usize {
686 self.storage_slots.len()
687 }
688
689 pub const fn is_empty(&self) -> bool {
691 self.storage_slots.is_empty()
692 }
693
694 pub fn extend_ref(&mut self, other: &Self) {
696 extend_sorted_vec(&mut self.storage_slots, &other.storage_slots);
697 }
698
699 pub fn merge_batch<'a>(updates: impl IntoIterator<Item = &'a Self>) -> Self {
701 let updates: Vec<_> = updates.into_iter().collect();
702 Self {
703 storage_slots: kway_merge_sorted(updates.iter().map(|u| u.storage_slots.as_slice())),
704 }
705 }
706}
707
708impl From<HashedStorageSorted> for HashedStorage {
709 fn from(sorted: HashedStorageSorted) -> Self {
710 let mut storage = B256Map::default();
711
712 for (slot, value) in sorted.storage_slots {
714 storage.insert(slot, value);
715 }
716
717 Self { storage }
718 }
719}
720
721impl From<HashedPostStateSorted> for HashedPostState {
722 fn from(sorted: HashedPostStateSorted) -> Self {
723 let mut accounts =
724 B256Map::with_capacity_and_hasher(sorted.accounts.len(), Default::default());
725
726 for (address, account) in sorted.accounts {
728 accounts.insert(address, account);
729 }
730
731 let storages = sorted
733 .storages
734 .into_iter()
735 .map(|(address, storage)| (address, storage.into()))
736 .collect();
737
738 Self { accounts, storages }
739 }
740}
741
742#[derive(Debug)]
747pub struct ChunkedHashedPostState {
748 flattened: alloc::vec::IntoIter<(B256, FlattenedHashedPostStateItem)>,
749 size: usize,
750}
751
752#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
755enum FlattenedStateOrder {
756 StorageUpdate(B256),
757 Account,
758}
759
760#[derive(Debug)]
761enum FlattenedHashedPostStateItem {
762 Account(Option<Account>),
763 StorageUpdate { slot: B256, value: U256 },
764}
765
766impl FlattenedHashedPostStateItem {
767 const fn order(&self) -> FlattenedStateOrder {
768 match self {
769 Self::StorageUpdate { slot, .. } => FlattenedStateOrder::StorageUpdate(*slot),
770 Self::Account(_) => FlattenedStateOrder::Account,
771 }
772 }
773}
774
775impl ChunkedHashedPostState {
776 fn new(hashed_post_state: HashedPostState, size: usize) -> Self {
777 assert!(size > 0, "chunk size must be non-zero");
778 let flattened = hashed_post_state
779 .storages
780 .into_iter()
781 .flat_map(|(address, storage)| {
782 storage.storage.into_iter().map(move |(slot, value)| {
783 (address, FlattenedHashedPostStateItem::StorageUpdate { slot, value })
784 })
785 })
786 .chain(hashed_post_state.accounts.into_iter().map(|(address, account)| {
787 (address, FlattenedHashedPostStateItem::Account(account))
788 }))
789 .sorted_unstable_by_key(|(address, item)| (*address, item.order()));
793
794 Self { flattened, size }
795 }
796}
797
798impl Iterator for ChunkedHashedPostState {
799 type Item = HashedPostState;
800
801 fn next(&mut self) -> Option<Self::Item> {
802 let mut chunk = HashedPostState::default();
803
804 let mut current_size = 0;
805 while current_size < self.size {
806 let Some((address, item)) = self.flattened.next() else { break };
807
808 match item {
809 FlattenedHashedPostStateItem::Account(account) => {
810 chunk.accounts.insert(address, account);
811 }
812 FlattenedHashedPostStateItem::StorageUpdate { slot, value } => {
813 chunk.storages.entry(address).or_default().storage.insert(slot, value);
814 }
815 }
816
817 current_size += 1;
818 }
819
820 if chunk.is_empty() {
821 None
822 } else {
823 Some(chunk)
824 }
825 }
826}
827
828#[cfg(test)]
829mod tests {
830 use super::*;
831 use crate::KeccakKeyHasher;
832 use alloy_primitives::Bytes;
833 use revm::{
834 database::{states::StorageSlot, AccountStatus, StorageWithOriginalValues},
835 state::{AccountInfo, Bytecode},
836 };
837
838 fn bundle_hashed_storage(account: &BundleAccount) -> Option<HashedStorage> {
839 let address = Address::ZERO;
840 let mut state =
841 HashedPostState::from_bundle_state::<KeccakKeyHasher>([(&address, account)]);
842 state.storages.remove(&keccak256(address))
843 }
844
845 fn changed_storage(original: U256, present: U256) -> StorageWithOriginalValues {
846 core::iter::once((U256::ONE, StorageSlot::new_changed(original, present))).collect()
847 }
848
849 #[test]
850 fn test_hashed_post_state_from_bundle_state() {
851 let address = Address::random();
853
854 let account_info = AccountInfo {
856 balance: U256::from(123),
857 nonce: 42,
858 code_hash: B256::random(),
859 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2]))),
860 ..Default::default()
861 };
862
863 let mut storage = StorageWithOriginalValues::default();
864 storage
865 .insert(U256::ONE, StorageSlot { present_value: U256::from(4), ..Default::default() });
866
867 let account = BundleAccount {
869 status: AccountStatus::Changed,
870 info: Some(account_info.clone()),
871 storage,
872 original_info: None,
873 };
874
875 let state = vec![(&address, &account)];
877
878 let hashed_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(state);
880
881 assert_eq!(hashed_state.accounts.len(), 1);
883 assert_eq!(hashed_state.storages.len(), 1);
884
885 assert_eq!(
887 *hashed_state.accounts.get(&keccak256(address)).unwrap(),
888 Some(account_info.into())
889 );
890 }
891
892 #[test]
893 fn destroyed_prefunded_account_without_storage_emits_no_storage() {
894 let original_info = AccountInfo { balance: U256::ONE, ..Default::default() };
895 let account = BundleAccount::new(
896 Some(original_info),
897 None,
898 StorageWithOriginalValues::default(),
899 AccountStatus::Destroyed,
900 );
901
902 assert!(bundle_hashed_storage(&account).is_none());
903 }
904
905 #[test]
906 fn destroyed_accounts_emit_zero_storage_changes() {
907 let existing_contract =
908 AccountInfo { code_hash: B256::repeat_byte(0x01), ..Default::default() };
909 let legacy_empty_account = AccountInfo::default();
910 let prefunded_account = AccountInfo { balance: U256::ONE, ..Default::default() };
911
912 for original_info in
913 [Some(existing_contract), Some(legacy_empty_account), Some(prefunded_account), None]
914 {
915 let account = BundleAccount::new(
916 original_info,
917 None,
918 changed_storage(U256::from(2), U256::ZERO),
919 AccountStatus::Destroyed,
920 );
921
922 let storage = bundle_hashed_storage(&account).unwrap();
923 let hashed_slot = keccak256(B256::with_last_byte(1));
924 assert_eq!(storage.storage[&hashed_slot], U256::ZERO);
925 }
926 }
927
928 #[test]
929 fn destroyed_recreated_accounts_preserve_storage() {
930 let value = U256::from(2);
931 let new_account = BundleAccount::new(
932 None,
933 Some(AccountInfo::default()),
934 changed_storage(U256::ZERO, value),
935 AccountStatus::DestroyedChanged,
936 );
937 let original_info =
938 AccountInfo { code_hash: B256::repeat_byte(0x01), ..Default::default() };
939 let existing_account = BundleAccount::new(
940 Some(original_info),
941 Some(AccountInfo::default()),
942 changed_storage(U256::ZERO, value),
943 AccountStatus::DestroyedChanged,
944 );
945
946 let new_storage = bundle_hashed_storage(&new_account).unwrap();
947 let existing_storage = bundle_hashed_storage(&existing_account).unwrap();
948 let hashed_slot = keccak256(B256::with_last_byte(1));
949 assert_eq!(new_storage.storage[&hashed_slot], value);
950 assert_eq!(existing_storage.storage[&hashed_slot], value);
951 }
952
953 #[test]
954 fn test_hashed_post_state_with_accounts() {
955 let address_1 = Address::random();
957 let address_2 = Address::random();
958
959 let account_info_1 = AccountInfo {
960 balance: U256::from(1000),
961 nonce: 1,
962 code_hash: B256::random(),
963 code: None,
964 ..Default::default()
965 };
966
967 let account_1 = (keccak256(address_1), Some(account_info_1.into()));
969 let account_2 = (keccak256(address_2), None);
970
971 let hashed_state = HashedPostState::default().with_accounts(vec![account_1, account_2]);
973
974 assert_eq!(hashed_state.accounts.len(), 2);
976 assert!(hashed_state.accounts.contains_key(&keccak256(address_1)));
977 assert!(hashed_state.accounts.contains_key(&keccak256(address_2)));
978 }
979
980 #[test]
981 fn test_hashed_post_state_with_storages() {
982 let address_1 = Address::random();
984 let address_2 = Address::random();
985
986 let storage_1 = (keccak256(address_1), HashedStorage::default());
987 let storage_2 = (keccak256(address_2), HashedStorage::default());
988
989 let hashed_state = HashedPostState::default().with_storages(vec![storage_1, storage_2]);
991
992 assert_eq!(hashed_state.storages.len(), 2);
994 assert!(hashed_state.storages.contains_key(&keccak256(address_1)));
995 assert!(hashed_state.storages.contains_key(&keccak256(address_2)));
996 }
997
998 #[test]
999 fn test_hashed_post_state_is_empty() {
1000 let empty_state = HashedPostState::default();
1002 assert!(empty_state.is_empty());
1003
1004 let non_empty_state = HashedPostState::default()
1006 .with_accounts(vec![(keccak256(Address::random()), Some(Account::default()))]);
1007 assert!(!non_empty_state.is_empty());
1008 }
1009
1010 fn create_state_for_multi_proof_targets() -> HashedPostState {
1011 let mut state = HashedPostState::default();
1012
1013 let addr1 = B256::random();
1014 let addr2 = B256::random();
1015 state.accounts.insert(addr1, Some(Default::default()));
1016 state.accounts.insert(addr2, Some(Default::default()));
1017
1018 let mut storage = HashedStorage::default();
1019 let slot1 = B256::random();
1020 let slot2 = B256::random();
1021 storage.storage.insert(slot1, U256::ZERO);
1022 storage.storage.insert(slot2, U256::ONE);
1023 state.storages.insert(addr1, storage);
1024
1025 state
1026 }
1027
1028 #[test]
1029 fn test_multi_proof_targets_difference_empty_state() {
1030 let state = HashedPostState::default();
1031 let excluded = MultiProofTargets::default();
1032
1033 let targets = state.multi_proof_targets_difference(&excluded);
1034 assert!(targets.is_empty());
1035 }
1036
1037 #[test]
1038 fn test_multi_proof_targets_difference_new_account_targets() {
1039 let state = create_state_for_multi_proof_targets();
1040 let excluded = MultiProofTargets::default();
1041
1042 let targets = state.multi_proof_targets_difference(&excluded);
1044 assert_eq!(targets.len(), state.accounts.len());
1045 for addr in state.accounts.keys() {
1046 assert!(targets.contains_key(addr));
1047 }
1048 }
1049
1050 #[test]
1051 fn test_multi_proof_targets_difference_new_storage_targets() {
1052 let state = create_state_for_multi_proof_targets();
1053 let excluded = MultiProofTargets::default();
1054
1055 let targets = state.multi_proof_targets_difference(&excluded);
1056
1057 for (addr, storage) in &state.storages {
1059 assert!(targets.contains_key(addr));
1060 let target_slots = &targets[addr];
1061 assert_eq!(target_slots.len(), storage.storage.len());
1062 for slot in storage.storage.keys() {
1063 assert!(target_slots.contains(slot));
1064 }
1065 }
1066 }
1067
1068 #[test]
1069 fn test_multi_proof_targets_difference_filter_excluded_accounts() {
1070 let state = create_state_for_multi_proof_targets();
1071 let mut excluded = MultiProofTargets::default();
1072
1073 let excluded_addr = state
1075 .accounts
1076 .keys()
1077 .find(|&&addr| !state.storages.contains_key(&addr))
1078 .expect("Should have an account without storage");
1079
1080 excluded.insert(*excluded_addr, HashSet::default());
1082
1083 let targets = state.multi_proof_targets_difference(&excluded);
1084
1085 assert!(!targets.contains_key(excluded_addr));
1087 assert_eq!(targets.len(), state.accounts.len() - 1);
1089 }
1090
1091 #[test]
1092 fn test_multi_proof_targets_difference_filter_excluded_storage() {
1093 let state = create_state_for_multi_proof_targets();
1094 let mut excluded = MultiProofTargets::default();
1095
1096 let (addr, storage) = state.storages.iter().next().unwrap();
1098 let mut excluded_slots = HashSet::default();
1099 let excluded_slot = *storage.storage.keys().next().unwrap();
1100 excluded_slots.insert(excluded_slot);
1101 excluded.insert(*addr, excluded_slots);
1102
1103 let targets = state.multi_proof_targets_difference(&excluded);
1104
1105 let target_slots = &targets[addr];
1107 assert!(!target_slots.contains(&excluded_slot));
1108 assert_eq!(target_slots.len(), storage.storage.len() - 1);
1109 }
1110
1111 #[test]
1112 fn test_multi_proof_targets_difference_mixed_excluded_state() {
1113 let mut state = HashedPostState::default();
1114 let mut excluded = MultiProofTargets::default();
1115
1116 let addr1 = B256::random();
1117 let addr2 = B256::random();
1118 let slot1 = B256::random();
1119 let slot2 = B256::random();
1120
1121 state.accounts.insert(addr1, Some(Default::default()));
1122 state.accounts.insert(addr2, Some(Default::default()));
1123
1124 let mut storage = HashedStorage::default();
1125 storage.storage.insert(slot1, U256::ZERO);
1126 storage.storage.insert(slot2, U256::ONE);
1127 state.storages.insert(addr1, storage);
1128
1129 let mut excluded_slots = HashSet::default();
1130 excluded_slots.insert(slot1);
1131 excluded.insert(addr1, excluded_slots);
1132
1133 let targets = state.multi_proof_targets_difference(&excluded);
1134
1135 assert!(targets.contains_key(&addr2));
1136 assert!(!targets[&addr1].contains(&slot1));
1137 assert!(targets[&addr1].contains(&slot2));
1138 }
1139
1140 #[test]
1141 fn test_multi_proof_targets_difference_unmodified_account_with_storage() {
1142 let mut state = HashedPostState::default();
1143 let excluded = MultiProofTargets::default();
1144
1145 let addr = B256::random();
1146 let slot1 = B256::random();
1147 let slot2 = B256::random();
1148
1149 let mut storage = HashedStorage::default();
1152 storage.storage.insert(slot1, U256::ONE);
1153 storage.storage.insert(slot2, U256::from(2));
1154 state.storages.insert(addr, storage);
1155
1156 assert!(!state.accounts.contains_key(&addr));
1157 assert!(!excluded.contains_key(&addr));
1158
1159 let targets = state.multi_proof_targets_difference(&excluded);
1160
1161 assert!(targets.contains_key(&addr));
1163
1164 let target_slots = &targets[&addr];
1165 assert_eq!(target_slots.len(), 2);
1166 assert!(target_slots.contains(&slot1));
1167 assert!(target_slots.contains(&slot2));
1168 }
1169
1170 #[test]
1171 fn test_hashed_post_state_sorted_extend_ref() {
1172 let mut state1 = HashedPostStateSorted {
1174 accounts: vec![
1175 (B256::repeat_byte(1), Some(Account::default())),
1176 (B256::repeat_byte(3), Some(Account::default())),
1177 (B256::repeat_byte(5), None),
1178 ],
1179 storages: B256Map::default(),
1180 };
1181
1182 let state2 = HashedPostStateSorted {
1183 accounts: vec![
1184 (B256::repeat_byte(2), Some(Account::default())),
1185 (B256::repeat_byte(3), Some(Account { nonce: 1, ..Default::default() })), (B256::repeat_byte(4), Some(Account::default())),
1187 (B256::repeat_byte(6), None),
1188 ],
1189 storages: B256Map::default(),
1190 };
1191
1192 state1.extend_ref_and_sort(&state2);
1193
1194 assert_eq!(state1.accounts.len(), 6);
1196 assert_eq!(state1.accounts[0].0, B256::repeat_byte(1));
1197 assert_eq!(state1.accounts[1].0, B256::repeat_byte(2));
1198 assert_eq!(state1.accounts[2].0, B256::repeat_byte(3));
1199 assert_eq!(state1.accounts[2].1.as_ref().unwrap().nonce, 1); assert_eq!(state1.accounts[3].0, B256::repeat_byte(4));
1201 assert_eq!(state1.accounts[4].0, B256::repeat_byte(5));
1202 assert_eq!(state1.accounts[4].1, None);
1203 assert_eq!(state1.accounts[5].0, B256::repeat_byte(6));
1204 assert_eq!(state1.accounts[5].1, None);
1205 }
1206
1207 #[test]
1208 fn test_hashed_storage_sorted_extend_ref() {
1209 let mut storage1 = HashedStorageSorted {
1211 storage_slots: vec![
1212 (B256::repeat_byte(1), U256::from(10)),
1213 (B256::repeat_byte(3), U256::from(30)),
1214 (B256::repeat_byte(5), U256::ZERO),
1215 ],
1216 };
1217
1218 let storage2 = HashedStorageSorted {
1219 storage_slots: vec![
1220 (B256::repeat_byte(2), U256::from(20)),
1221 (B256::repeat_byte(3), U256::from(300)), (B256::repeat_byte(4), U256::from(40)),
1223 (B256::repeat_byte(6), U256::ZERO),
1224 ],
1225 };
1226
1227 storage1.extend_ref(&storage2);
1228
1229 assert_eq!(storage1.storage_slots.len(), 6);
1230 assert_eq!(storage1.storage_slots[0].0, B256::repeat_byte(1));
1231 assert_eq!(storage1.storage_slots[0].1, U256::from(10));
1232 assert_eq!(storage1.storage_slots[1].0, B256::repeat_byte(2));
1233 assert_eq!(storage1.storage_slots[1].1, U256::from(20));
1234 assert_eq!(storage1.storage_slots[2].0, B256::repeat_byte(3));
1235 assert_eq!(storage1.storage_slots[2].1, U256::from(300)); assert_eq!(storage1.storage_slots[3].0, B256::repeat_byte(4));
1237 assert_eq!(storage1.storage_slots[3].1, U256::from(40));
1238 assert_eq!(storage1.storage_slots[4].0, B256::repeat_byte(5));
1239 assert_eq!(storage1.storage_slots[4].1, U256::ZERO);
1240 assert_eq!(storage1.storage_slots[5].0, B256::repeat_byte(6));
1241 assert_eq!(storage1.storage_slots[5].1, U256::ZERO);
1242 }
1243
1244 #[test]
1246 fn test_hashed_post_state_extend_from_sorted_with_accounts() {
1247 let addr1 = B256::random();
1248 let addr2 = B256::random();
1249
1250 let mut state = HashedPostState::default();
1251 state.accounts.insert(addr1, Some(Default::default()));
1252
1253 let mut sorted_state = HashedPostStateSorted::default();
1254 sorted_state.accounts.push((addr2, Some(Default::default())));
1255
1256 state.extend_from_sorted(&sorted_state);
1257
1258 assert_eq!(state.accounts.len(), 2);
1259 assert!(state.accounts.contains_key(&addr1));
1260 assert!(state.accounts.contains_key(&addr2));
1261 }
1262
1263 #[test]
1265 fn test_hashed_post_state_extend_from_sorted_with_destroyed_accounts() {
1266 let addr1 = B256::random();
1267
1268 let mut state = HashedPostState::default();
1269
1270 let mut sorted_state = HashedPostStateSorted::default();
1271 sorted_state.accounts.push((addr1, None));
1272
1273 state.extend_from_sorted(&sorted_state);
1274
1275 assert!(state.accounts.contains_key(&addr1));
1276 assert_eq!(state.accounts.get(&addr1), Some(&None));
1277 }
1278
1279 #[test]
1280 fn test_hashed_post_state_sorted_disjointed_merge_batch() {
1281 fn account(nonce: u64) -> Account {
1282 Account { nonce, ..Default::default() }
1283 }
1284
1285 let kept_account = B256::with_last_byte(1);
1286 let removed_account = B256::with_last_byte(2);
1287 let kept_storage = B256::with_last_byte(3);
1288 let slot1 = B256::with_last_byte(11);
1289 let slot2 = B256::with_last_byte(12);
1290
1291 let older = HashedPostStateSorted::new(
1292 vec![(kept_account, Some(account(1))), (removed_account, Some(account(10)))],
1293 B256Map::from_iter([(
1294 kept_storage,
1295 HashedStorageSorted { storage_slots: vec![(slot1, U256::ONE)] },
1296 )]),
1297 );
1298
1299 let newer = HashedPostStateSorted::new(
1300 vec![(kept_account, Some(account(2)))],
1301 B256Map::from_iter([(
1302 kept_storage,
1303 HashedStorageSorted {
1304 storage_slots: vec![(slot1, U256::from(3)), (slot2, U256::from(4))],
1305 },
1306 )]),
1307 );
1308
1309 let remove_a = HashedPostStateSorted::new(
1310 vec![(removed_account, None)],
1311 B256Map::from_iter([(
1312 kept_storage,
1313 HashedStorageSorted { storage_slots: vec![(slot2, U256::ZERO)] },
1314 )]),
1315 );
1316
1317 let remove_b = HashedPostStateSorted::new(
1318 vec![(B256::with_last_byte(255), Some(account(99)))],
1319 B256Map::default(),
1320 );
1321
1322 let result = HashedPostStateSorted::disjointed_merge_batch(
1323 &[&older, &newer],
1324 &[&remove_b, &remove_a],
1325 );
1326
1327 assert_eq!(result.accounts, vec![(kept_account, Some(account(2)))]);
1328 assert_eq!(result.storages.len(), 1);
1329 assert_eq!(
1330 result.storages.get(&kept_storage),
1331 Some(&HashedStorageSorted { storage_slots: vec![(slot1, U256::from(3))] })
1332 );
1333 }
1334
1335 #[test]
1336 fn test_hashed_post_state_sorted_disjointed_merge_batch_empty_mask_merges_batch() {
1337 let address = B256::with_last_byte(1);
1338 let storage = B256::with_last_byte(2);
1339 let slot = B256::with_last_byte(3);
1340 let empty_storage = B256::with_last_byte(4);
1341 let older = HashedPostStateSorted::new(
1342 vec![(address, Some(Account { nonce: 1, ..Default::default() }))],
1343 B256Map::from_iter([
1344 (storage, HashedStorageSorted { storage_slots: vec![(slot, U256::ONE)] }),
1345 (empty_storage, HashedStorageSorted::default()),
1346 ]),
1347 );
1348 let newer = HashedPostStateSorted::new(
1349 vec![(address, Some(Account { nonce: 2, ..Default::default() }))],
1350 B256Map::from_iter([(
1351 storage,
1352 HashedStorageSorted { storage_slots: vec![(slot, U256::from(2))] },
1353 )]),
1354 );
1355 let expected = HashedPostStateSorted::merge_batch(vec![newer.clone(), older.clone()]);
1356
1357 let result = HashedPostStateSorted::disjointed_merge_batch(&[&older, &newer], &[]);
1358
1359 assert_eq!(result, expected);
1360 }
1361
1362 #[test]
1363 fn test_hashed_post_state_sorted_disjointed_merge_batch_removes_overlapping_batch_key() {
1364 fn account(nonce: u64) -> Account {
1365 Account { nonce, ..Default::default() }
1366 }
1367
1368 let overlapping_account = B256::with_last_byte(21);
1369
1370 let older = HashedPostStateSorted::new(
1371 vec![(overlapping_account, Some(account(1)))],
1372 B256Map::default(),
1373 );
1374
1375 let newer = HashedPostStateSorted::new(
1376 vec![(overlapping_account, Some(account(2)))],
1377 B256Map::default(),
1378 );
1379
1380 let remove =
1381 HashedPostStateSorted::new(vec![(overlapping_account, None)], B256Map::default());
1382
1383 let result = HashedPostStateSorted::disjointed_merge_batch(&[&older, &newer], &[&remove]);
1384
1385 assert!(result.accounts.is_empty());
1386 }
1387
1388 #[test]
1389 fn test_hashed_post_state_sorted_disjointed_merge_batch_keeps_equal_overlaps() {
1390 fn account(nonce: u64) -> Account {
1391 Account { nonce, ..Default::default() }
1392 }
1393
1394 let address = B256::with_last_byte(21);
1395 let deleted_address = B256::with_last_byte(24);
1396 let storage = B256::with_last_byte(22);
1397 let deleted_storage = B256::with_last_byte(25);
1398 let slot = B256::with_last_byte(23);
1399 let deleted_slot = B256::with_last_byte(26);
1400 let batch = HashedPostStateSorted::new(
1401 vec![(address, Some(account(1))), (deleted_address, None)],
1402 B256Map::from_iter([
1403 (storage, HashedStorageSorted { storage_slots: vec![(slot, U256::ONE)] }),
1404 (
1405 deleted_storage,
1406 HashedStorageSorted { storage_slots: vec![(deleted_slot, U256::ZERO)] },
1407 ),
1408 ]),
1409 );
1410 let different_mask = HashedPostStateSorted::new(
1411 vec![(address, Some(account(2))), (deleted_address, Some(account(3)))],
1412 B256Map::from_iter([
1413 (storage, HashedStorageSorted { storage_slots: vec![(slot, U256::from(2))] }),
1414 (
1415 deleted_storage,
1416 HashedStorageSorted { storage_slots: vec![(deleted_slot, U256::from(3))] },
1417 ),
1418 ]),
1419 );
1420 let equal_mask = batch.clone();
1421
1422 let result = HashedPostStateSorted::disjointed_merge_batch(
1423 &[&batch],
1424 &[&different_mask, &equal_mask],
1425 );
1426 let reversed = HashedPostStateSorted::disjointed_merge_batch(
1427 &[&batch],
1428 &[&equal_mask, &different_mask],
1429 );
1430
1431 assert_eq!(result, batch);
1432 assert_eq!(reversed, result);
1433 }
1434
1435 #[test]
1436 fn test_hashed_post_state_sorted_disjointed_merge_batch_ignores_empty_storage_mask() {
1437 let storage = B256::with_last_byte(31);
1438 let slot = B256::with_last_byte(32);
1439
1440 let batch = HashedPostStateSorted::new(
1441 vec![],
1442 B256Map::from_iter([(
1443 storage,
1444 HashedStorageSorted { storage_slots: vec![(slot, U256::ONE)] },
1445 )]),
1446 );
1447 let mask = HashedPostStateSorted::new(
1448 vec![],
1449 B256Map::from_iter([(storage, HashedStorageSorted { storage_slots: vec![] })]),
1450 );
1451
1452 let result = HashedPostStateSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1453
1454 assert_eq!(
1455 result.storages.get(&storage),
1456 Some(&HashedStorageSorted { storage_slots: vec![(slot, U256::ONE)] })
1457 );
1458 }
1459
1460 #[test]
1462 fn test_hashed_storage_extend_from_sorted() {
1463 let slot1 = B256::random();
1464 let slot2 = B256::random();
1465 let slot3 = B256::random();
1466
1467 let mut storage = HashedStorage::from_iter([(slot1, U256::from(100))]);
1468
1469 let sorted = HashedStorageSorted {
1470 storage_slots: vec![(slot2, U256::from(200)), (slot3, U256::ZERO)],
1471 };
1472
1473 storage.extend_from_sorted(&sorted);
1474 assert_eq!(storage.storage.len(), 3);
1475 assert_eq!(storage.storage.get(&slot1), Some(&U256::from(100)));
1476 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1477 assert_eq!(storage.storage.get(&slot3), Some(&U256::ZERO));
1478 }
1479
1480 #[test]
1481 fn test_hashed_post_state_chunking_length() {
1482 let addr1 = B256::repeat_byte(1);
1483 let addr2 = B256::repeat_byte(2);
1484 let addr3 = B256::repeat_byte(3);
1485 let addr4 = B256::repeat_byte(4);
1486 let slot1 = B256::repeat_byte(1);
1487 let slot2 = B256::repeat_byte(2);
1488 let slot3 = B256::repeat_byte(3);
1489
1490 let state = HashedPostState {
1491 accounts: B256Map::from_iter([(addr1, None), (addr2, None), (addr4, None)]),
1492 storages: B256Map::from_iter([
1493 (
1494 addr1,
1495 HashedStorage {
1496 storage: B256Map::from_iter([
1497 (slot1, U256::ZERO),
1498 (slot2, U256::ZERO),
1499 (slot3, U256::ZERO),
1500 ]),
1501 },
1502 ),
1503 (
1504 addr2,
1505 HashedStorage {
1506 storage: B256Map::from_iter([
1507 (slot1, U256::ZERO),
1508 (slot2, U256::ZERO),
1509 (slot3, U256::ZERO),
1510 ]),
1511 },
1512 ),
1513 (
1514 addr3,
1515 HashedStorage {
1516 storage: B256Map::from_iter([
1517 (slot1, U256::ZERO),
1518 (slot2, U256::ZERO),
1519 (slot3, U256::ZERO),
1520 ]),
1521 },
1522 ),
1523 ]),
1524 };
1525
1526 let chunking_length = state.chunking_length();
1527 for size in 1..=state.clone().chunks(1).count() {
1528 let chunk_count = state.clone().chunks(size).count();
1529 let expected_count = chunking_length.div_ceil(size);
1530 assert_eq!(
1531 chunk_count, expected_count,
1532 "chunking_length: {}, size: {}",
1533 chunking_length, size
1534 );
1535 }
1536 }
1537
1538 #[test]
1539 fn test_clone_into_sorted_equivalence() {
1540 let addr1 = B256::repeat_byte(1);
1541 let addr2 = B256::repeat_byte(2);
1542 let addr3 = B256::repeat_byte(3);
1543 let slot1 = B256::repeat_byte(1);
1544 let slot2 = B256::repeat_byte(2);
1545 let slot3 = B256::repeat_byte(3);
1546
1547 let state = HashedPostState {
1548 accounts: B256Map::from_iter([
1549 (addr1, Some(Account { nonce: 1, balance: U256::from(100), ..Default::default() })),
1550 (addr2, None),
1551 (addr3, Some(Account::default())),
1552 ]),
1553 storages: B256Map::from_iter([
1554 (
1555 addr1,
1556 HashedStorage {
1557 storage: B256Map::from_iter([
1558 (slot1, U256::from(10)),
1559 (slot2, U256::from(20)),
1560 ]),
1561 },
1562 ),
1563 (addr2, HashedStorage { storage: B256Map::from_iter([(slot3, U256::ZERO)]) }),
1564 ]),
1565 };
1566
1567 let sorted_via_clone = state.clone().into_sorted();
1569 let sorted_via_clone_into = state.clone_into_sorted();
1570
1571 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1572
1573 assert_eq!(state.accounts.len(), 3);
1575 assert_eq!(state.storages.len(), 2);
1576 }
1577
1578 #[test]
1579 fn test_hashed_storage_clone_into_sorted_equivalence() {
1580 let slot1 = B256::repeat_byte(1);
1581 let slot2 = B256::repeat_byte(2);
1582 let slot3 = B256::repeat_byte(3);
1583
1584 let storage = HashedStorage {
1585 storage: B256Map::from_iter([
1586 (slot1, U256::from(100)),
1587 (slot2, U256::ZERO),
1588 (slot3, U256::from(300)),
1589 ]),
1590 };
1591
1592 let sorted_via_clone = storage.clone().into_sorted();
1594 let sorted_via_clone_into = storage.clone_into_sorted();
1595
1596 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1597
1598 assert_eq!(storage.storage.len(), 3);
1600 }
1601}
1602
1603#[cfg(feature = "serde-bincode-compat")]
1605pub mod serde_bincode_compat {
1606 use super::Account;
1607 use alloc::{borrow::Cow, vec::Vec};
1608 use alloy_primitives::{map::B256Map, B256, U256};
1609 use core::fmt;
1610 use serde::{
1611 de::{Error as _, SeqAccess, Visitor},
1612 Deserialize, Deserializer, Serialize, Serializer,
1613 };
1614 use serde_with::{DeserializeAs, SerializeAs};
1615
1616 #[derive(Debug, Serialize, Deserialize)]
1632 pub struct HashedPostState<'a> {
1633 accounts: Cow<'a, B256Map<Option<Account>>>,
1634 storages: B256Map<HashedStorage<'a>>,
1635 }
1636
1637 impl<'a> From<&'a super::HashedPostState> for HashedPostState<'a> {
1638 fn from(value: &'a super::HashedPostState) -> Self {
1639 Self {
1640 accounts: Cow::Borrowed(&value.accounts),
1641 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
1642 }
1643 }
1644 }
1645
1646 impl<'a> From<HashedPostState<'a>> for super::HashedPostState {
1647 fn from(value: HashedPostState<'a>) -> Self {
1648 Self {
1649 accounts: value.accounts.into_owned(),
1650 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
1651 }
1652 }
1653 }
1654
1655 impl SerializeAs<super::HashedPostState> for HashedPostState<'_> {
1656 fn serialize_as<S>(
1657 source: &super::HashedPostState,
1658 serializer: S,
1659 ) -> Result<S::Ok, S::Error>
1660 where
1661 S: Serializer,
1662 {
1663 HashedPostState::from(source).serialize(serializer)
1664 }
1665 }
1666
1667 impl<'de> DeserializeAs<'de, super::HashedPostState> for HashedPostState<'de> {
1668 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostState, D::Error>
1669 where
1670 D: Deserializer<'de>,
1671 {
1672 HashedPostState::deserialize(deserializer).map(Into::into)
1673 }
1674 }
1675
1676 #[derive(Debug, Serialize, Deserialize)]
1692 pub struct HashedStorage<'a> {
1693 storage: Cow<'a, B256Map<U256>>,
1694 }
1695
1696 impl<'a> From<&'a super::HashedStorage> for HashedStorage<'a> {
1697 fn from(value: &'a super::HashedStorage) -> Self {
1698 Self { storage: Cow::Borrowed(&value.storage) }
1699 }
1700 }
1701
1702 impl<'a> From<HashedStorage<'a>> for super::HashedStorage {
1703 fn from(value: HashedStorage<'a>) -> Self {
1704 Self { storage: value.storage.into_owned() }
1705 }
1706 }
1707
1708 impl SerializeAs<super::HashedStorage> for HashedStorage<'_> {
1709 fn serialize_as<S>(source: &super::HashedStorage, serializer: S) -> Result<S::Ok, S::Error>
1710 where
1711 S: Serializer,
1712 {
1713 HashedStorage::from(source).serialize(serializer)
1714 }
1715 }
1716
1717 impl<'de> DeserializeAs<'de, super::HashedStorage> for HashedStorage<'de> {
1718 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorage, D::Error>
1719 where
1720 D: Deserializer<'de>,
1721 {
1722 HashedStorage::deserialize(deserializer).map(Into::into)
1723 }
1724 }
1725
1726 #[derive(Debug, Serialize, Deserialize)]
1742 pub struct HashedPostStateSorted<'a> {
1743 accounts: Cow<'a, [(B256, Option<Account>)]>,
1744 storages: B256Map<HashedStorageSorted<'a>>,
1745 }
1746
1747 impl<'a> From<&'a super::HashedPostStateSorted> for HashedPostStateSorted<'a> {
1748 fn from(value: &'a super::HashedPostStateSorted) -> Self {
1749 Self {
1750 accounts: Cow::Borrowed(&value.accounts),
1751 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
1752 }
1753 }
1754 }
1755
1756 impl<'a> From<HashedPostStateSorted<'a>> for super::HashedPostStateSorted {
1757 fn from(value: HashedPostStateSorted<'a>) -> Self {
1758 Self {
1759 accounts: value.accounts.into_owned(),
1760 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
1761 }
1762 }
1763 }
1764
1765 impl SerializeAs<super::HashedPostStateSorted> for HashedPostStateSorted<'_> {
1766 fn serialize_as<S>(
1767 source: &super::HashedPostStateSorted,
1768 serializer: S,
1769 ) -> Result<S::Ok, S::Error>
1770 where
1771 S: Serializer,
1772 {
1773 HashedPostStateSorted::from(source).serialize(serializer)
1774 }
1775 }
1776
1777 impl<'de> DeserializeAs<'de, super::HashedPostStateSorted> for HashedPostStateSorted<'de> {
1778 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostStateSorted, D::Error>
1779 where
1780 D: Deserializer<'de>,
1781 {
1782 HashedPostStateSorted::deserialize(deserializer).map(Into::into)
1783 }
1784 }
1785
1786 #[derive(Debug, Serialize)]
1802 pub struct HashedStorageSorted<'a> {
1803 storage_slots: Cow<'a, [(B256, U256)]>,
1804 }
1805
1806 impl<'de, 'a> Deserialize<'de> for HashedStorageSorted<'a> {
1807 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1808 where
1809 D: Deserializer<'de>,
1810 {
1811 struct HashedStorageSortedVisitor;
1812
1813 impl<'de> Visitor<'de> for HashedStorageSortedVisitor {
1814 type Value = Vec<(B256, U256)>;
1815
1816 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1817 formatter.write_str("hashed storage with an optional legacy wipe marker")
1818 }
1819
1820 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1821 where
1822 A: SeqAccess<'de>,
1823 {
1824 let len = seq.size_hint().unwrap_or_default();
1825 if !matches!(len, 1 | 2) {
1826 return Err(A::Error::invalid_length(len, &self))
1827 }
1828
1829 let storage_slots =
1830 seq.next_element()?.ok_or_else(|| A::Error::invalid_length(0, &self))?;
1831 if len == 2 {
1832 let _: bool = seq
1833 .next_element()?
1834 .ok_or_else(|| A::Error::invalid_length(1, &self))?;
1835 }
1836
1837 Ok(storage_slots)
1838 }
1839 }
1840
1841 deserializer
1844 .deserialize_tuple(1, HashedStorageSortedVisitor)
1845 .map(|storage_slots| Self { storage_slots: Cow::Owned(storage_slots) })
1846 }
1847 }
1848
1849 impl<'a> From<&'a super::HashedStorageSorted> for HashedStorageSorted<'a> {
1850 fn from(value: &'a super::HashedStorageSorted) -> Self {
1851 Self { storage_slots: Cow::Borrowed(&value.storage_slots) }
1852 }
1853 }
1854
1855 impl<'a> From<HashedStorageSorted<'a>> for super::HashedStorageSorted {
1856 fn from(value: HashedStorageSorted<'a>) -> Self {
1857 Self { storage_slots: value.storage_slots.into_owned() }
1858 }
1859 }
1860
1861 impl SerializeAs<super::HashedStorageSorted> for HashedStorageSorted<'_> {
1862 fn serialize_as<S>(
1863 source: &super::HashedStorageSorted,
1864 serializer: S,
1865 ) -> Result<S::Ok, S::Error>
1866 where
1867 S: Serializer,
1868 {
1869 HashedStorageSorted::from(source).serialize(serializer)
1870 }
1871 }
1872
1873 impl<'de> DeserializeAs<'de, super::HashedStorageSorted> for HashedStorageSorted<'de> {
1874 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorageSorted, D::Error>
1875 where
1876 D: Deserializer<'de>,
1877 {
1878 HashedStorageSorted::deserialize(deserializer).map(Into::into)
1879 }
1880 }
1881
1882 #[cfg(test)]
1883 mod tests {
1884 use crate::{
1885 hashed_state::{
1886 HashedPostState, HashedPostStateSorted, HashedStorage, HashedStorageSorted,
1887 },
1888 serde_bincode_compat,
1889 };
1890 use alloy_primitives::{B256, U256};
1891 use reth_primitives_traits::Account;
1892 use serde::{Deserialize, Serialize};
1893 use serde_with::serde_as;
1894
1895 #[test]
1896 fn test_hashed_post_state_bincode_roundtrip() {
1897 if Account::EXTENSIONS_ENABLED {
1899 return;
1900 }
1901
1902 #[serde_as]
1903 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1904 struct Data {
1905 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostState")]
1906 hashed_state: HashedPostState,
1907 }
1908
1909 let mut data = Data { hashed_state: HashedPostState::default() };
1910 let encoded = bincode::serialize(&data).unwrap();
1911 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1912 assert_eq!(decoded, data);
1913
1914 data.hashed_state.accounts.insert(B256::random(), Some(Account::default()));
1915 let encoded = bincode::serialize(&data).unwrap();
1916 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1917 assert_eq!(decoded, data);
1918
1919 data.hashed_state.storages.insert(B256::random(), HashedStorage::default());
1920 let encoded = bincode::serialize(&data).unwrap();
1921 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1922 assert_eq!(decoded, data);
1923 }
1924
1925 #[test]
1926 fn test_hashed_storage_bincode_roundtrip() {
1927 #[serde_as]
1928 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1929 struct Data {
1930 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorage")]
1931 hashed_storage: HashedStorage,
1932 }
1933
1934 let mut data = Data { hashed_storage: HashedStorage::default() };
1935 let encoded = bincode::serialize(&data).unwrap();
1936 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1937 assert_eq!(decoded, data);
1938
1939 data.hashed_storage.storage.insert(B256::random(), U256::ONE);
1940 let encoded = bincode::serialize(&data).unwrap();
1941 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1942 assert_eq!(decoded, data);
1943 }
1944
1945 #[test]
1946 fn test_hashed_post_state_sorted_bincode_roundtrip() {
1947 if Account::EXTENSIONS_ENABLED {
1949 return;
1950 }
1951
1952 #[serde_as]
1953 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1954 struct Data {
1955 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostStateSorted")]
1956 hashed_state: HashedPostStateSorted,
1957 }
1958
1959 let mut data = Data { hashed_state: HashedPostStateSorted::default() };
1960 let encoded = bincode::serialize(&data).unwrap();
1961 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1962 assert_eq!(decoded, data);
1963
1964 data.hashed_state.accounts.push((B256::random(), Some(Account::default())));
1965 data.hashed_state
1966 .accounts
1967 .push((B256::random(), Some(Account { nonce: 1, ..Default::default() })));
1968 let encoded = bincode::serialize(&data).unwrap();
1969 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1970 assert_eq!(decoded, data);
1971
1972 data.hashed_state.storages.insert(
1973 B256::random(),
1974 HashedStorageSorted { storage_slots: vec![(B256::repeat_byte(1), U256::from(10))] },
1975 );
1976 let encoded = bincode::serialize(&data).unwrap();
1977 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1978 assert_eq!(decoded, data);
1979 }
1980
1981 #[test]
1982 fn test_hashed_storage_sorted_bincode_roundtrip() {
1983 #[serde_as]
1984 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1985 struct Data {
1986 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorageSorted")]
1987 hashed_storage: HashedStorageSorted,
1988 }
1989
1990 let mut data =
1991 Data { hashed_storage: HashedStorageSorted { storage_slots: Vec::new() } };
1992 let encoded = bincode::serialize(&data).unwrap();
1993 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1994 assert_eq!(decoded, data);
1995
1996 data.hashed_storage.storage_slots.push((B256::random(), U256::ONE));
1997 let encoded = bincode::serialize(&data).unwrap();
1998 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1999 assert_eq!(decoded, data);
2000 }
2001 }
2002}