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