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