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