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::from(1), 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.insert(
862 U256::from(1),
863 StorageSlot { present_value: U256::from(4), ..Default::default() },
864 );
865
866 let account = BundleAccount {
868 status: AccountStatus::Changed,
869 info: Some(account_info.clone()),
870 storage,
871 original_info: None,
872 };
873
874 let state = vec![(&address, &account)];
876
877 let hashed_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(state);
879
880 assert_eq!(hashed_state.accounts.len(), 1);
882 assert_eq!(hashed_state.storages.len(), 1);
883
884 assert_eq!(
886 *hashed_state.accounts.get(&keccak256(address)).unwrap(),
887 Some(account_info.into())
888 );
889 }
890
891 #[test]
892 fn destroyed_prefunded_account_without_storage_emits_no_storage() {
893 let original_info = AccountInfo { balance: U256::from(1), ..Default::default() };
894 let account = BundleAccount::new(
895 Some(original_info),
896 None,
897 StorageWithOriginalValues::default(),
898 AccountStatus::Destroyed,
899 );
900
901 assert!(bundle_hashed_storage(&account).is_none());
902 }
903
904 #[test]
905 fn destroyed_accounts_emit_zero_storage_changes() {
906 let existing_contract =
907 AccountInfo { code_hash: B256::repeat_byte(0x01), ..Default::default() };
908 let legacy_empty_account = AccountInfo::default();
909 let prefunded_account = AccountInfo { balance: U256::from(1), ..Default::default() };
910
911 for original_info in
912 [Some(existing_contract), Some(legacy_empty_account), Some(prefunded_account), None]
913 {
914 let account = BundleAccount::new(
915 original_info,
916 None,
917 changed_storage(U256::from(2), U256::ZERO),
918 AccountStatus::Destroyed,
919 );
920
921 let storage = bundle_hashed_storage(&account).unwrap();
922 let hashed_slot = keccak256(B256::from(U256::from(1)));
923 assert_eq!(storage.storage[&hashed_slot], U256::ZERO);
924 }
925 }
926
927 #[test]
928 fn destroyed_recreated_accounts_preserve_storage() {
929 let value = U256::from(2);
930 let new_account = BundleAccount::new(
931 None,
932 Some(AccountInfo::default()),
933 changed_storage(U256::ZERO, value),
934 AccountStatus::DestroyedChanged,
935 );
936 let original_info =
937 AccountInfo { code_hash: B256::repeat_byte(0x01), ..Default::default() };
938 let existing_account = BundleAccount::new(
939 Some(original_info),
940 Some(AccountInfo::default()),
941 changed_storage(U256::ZERO, value),
942 AccountStatus::DestroyedChanged,
943 );
944
945 let new_storage = bundle_hashed_storage(&new_account).unwrap();
946 let existing_storage = bundle_hashed_storage(&existing_account).unwrap();
947 let hashed_slot = keccak256(B256::from(U256::from(1)));
948 assert_eq!(new_storage.storage[&hashed_slot], value);
949 assert_eq!(existing_storage.storage[&hashed_slot], value);
950 }
951
952 #[test]
953 fn test_hashed_post_state_with_accounts() {
954 let address_1 = Address::random();
956 let address_2 = Address::random();
957
958 let account_info_1 = AccountInfo {
959 balance: U256::from(1000),
960 nonce: 1,
961 code_hash: B256::random(),
962 code: None,
963 ..Default::default()
964 };
965
966 let account_1 = (keccak256(address_1), Some(account_info_1.into()));
968 let account_2 = (keccak256(address_2), None);
969
970 let hashed_state = HashedPostState::default().with_accounts(vec![account_1, account_2]);
972
973 assert_eq!(hashed_state.accounts.len(), 2);
975 assert!(hashed_state.accounts.contains_key(&keccak256(address_1)));
976 assert!(hashed_state.accounts.contains_key(&keccak256(address_2)));
977 }
978
979 #[test]
980 fn test_hashed_post_state_with_storages() {
981 let address_1 = Address::random();
983 let address_2 = Address::random();
984
985 let storage_1 = (keccak256(address_1), HashedStorage::default());
986 let storage_2 = (keccak256(address_2), HashedStorage::default());
987
988 let hashed_state = HashedPostState::default().with_storages(vec![storage_1, storage_2]);
990
991 assert_eq!(hashed_state.storages.len(), 2);
993 assert!(hashed_state.storages.contains_key(&keccak256(address_1)));
994 assert!(hashed_state.storages.contains_key(&keccak256(address_2)));
995 }
996
997 #[test]
998 fn test_hashed_post_state_is_empty() {
999 let empty_state = HashedPostState::default();
1001 assert!(empty_state.is_empty());
1002
1003 let non_empty_state = HashedPostState::default()
1005 .with_accounts(vec![(keccak256(Address::random()), Some(Account::default()))]);
1006 assert!(!non_empty_state.is_empty());
1007 }
1008
1009 fn create_state_for_multi_proof_targets() -> HashedPostState {
1010 let mut state = HashedPostState::default();
1011
1012 let addr1 = B256::random();
1013 let addr2 = B256::random();
1014 state.accounts.insert(addr1, Some(Default::default()));
1015 state.accounts.insert(addr2, Some(Default::default()));
1016
1017 let mut storage = HashedStorage::default();
1018 let slot1 = B256::random();
1019 let slot2 = B256::random();
1020 storage.storage.insert(slot1, U256::ZERO);
1021 storage.storage.insert(slot2, U256::from(1));
1022 state.storages.insert(addr1, storage);
1023
1024 state
1025 }
1026
1027 #[test]
1028 fn test_multi_proof_targets_difference_empty_state() {
1029 let state = HashedPostState::default();
1030 let excluded = MultiProofTargets::default();
1031
1032 let targets = state.multi_proof_targets_difference(&excluded);
1033 assert!(targets.is_empty());
1034 }
1035
1036 #[test]
1037 fn test_multi_proof_targets_difference_new_account_targets() {
1038 let state = create_state_for_multi_proof_targets();
1039 let excluded = MultiProofTargets::default();
1040
1041 let targets = state.multi_proof_targets_difference(&excluded);
1043 assert_eq!(targets.len(), state.accounts.len());
1044 for addr in state.accounts.keys() {
1045 assert!(targets.contains_key(addr));
1046 }
1047 }
1048
1049 #[test]
1050 fn test_multi_proof_targets_difference_new_storage_targets() {
1051 let state = create_state_for_multi_proof_targets();
1052 let excluded = MultiProofTargets::default();
1053
1054 let targets = state.multi_proof_targets_difference(&excluded);
1055
1056 for (addr, storage) in &state.storages {
1058 assert!(targets.contains_key(addr));
1059 let target_slots = &targets[addr];
1060 assert_eq!(target_slots.len(), storage.storage.len());
1061 for slot in storage.storage.keys() {
1062 assert!(target_slots.contains(slot));
1063 }
1064 }
1065 }
1066
1067 #[test]
1068 fn test_multi_proof_targets_difference_filter_excluded_accounts() {
1069 let state = create_state_for_multi_proof_targets();
1070 let mut excluded = MultiProofTargets::default();
1071
1072 let excluded_addr = state
1074 .accounts
1075 .keys()
1076 .find(|&&addr| !state.storages.contains_key(&addr))
1077 .expect("Should have an account without storage");
1078
1079 excluded.insert(*excluded_addr, HashSet::default());
1081
1082 let targets = state.multi_proof_targets_difference(&excluded);
1083
1084 assert!(!targets.contains_key(excluded_addr));
1086 assert_eq!(targets.len(), state.accounts.len() - 1);
1088 }
1089
1090 #[test]
1091 fn test_multi_proof_targets_difference_filter_excluded_storage() {
1092 let state = create_state_for_multi_proof_targets();
1093 let mut excluded = MultiProofTargets::default();
1094
1095 let (addr, storage) = state.storages.iter().next().unwrap();
1097 let mut excluded_slots = HashSet::default();
1098 let excluded_slot = *storage.storage.keys().next().unwrap();
1099 excluded_slots.insert(excluded_slot);
1100 excluded.insert(*addr, excluded_slots);
1101
1102 let targets = state.multi_proof_targets_difference(&excluded);
1103
1104 let target_slots = &targets[addr];
1106 assert!(!target_slots.contains(&excluded_slot));
1107 assert_eq!(target_slots.len(), storage.storage.len() - 1);
1108 }
1109
1110 #[test]
1111 fn test_multi_proof_targets_difference_mixed_excluded_state() {
1112 let mut state = HashedPostState::default();
1113 let mut excluded = MultiProofTargets::default();
1114
1115 let addr1 = B256::random();
1116 let addr2 = B256::random();
1117 let slot1 = B256::random();
1118 let slot2 = B256::random();
1119
1120 state.accounts.insert(addr1, Some(Default::default()));
1121 state.accounts.insert(addr2, Some(Default::default()));
1122
1123 let mut storage = HashedStorage::default();
1124 storage.storage.insert(slot1, U256::ZERO);
1125 storage.storage.insert(slot2, U256::from(1));
1126 state.storages.insert(addr1, storage);
1127
1128 let mut excluded_slots = HashSet::default();
1129 excluded_slots.insert(slot1);
1130 excluded.insert(addr1, excluded_slots);
1131
1132 let targets = state.multi_proof_targets_difference(&excluded);
1133
1134 assert!(targets.contains_key(&addr2));
1135 assert!(!targets[&addr1].contains(&slot1));
1136 assert!(targets[&addr1].contains(&slot2));
1137 }
1138
1139 #[test]
1140 fn test_multi_proof_targets_difference_unmodified_account_with_storage() {
1141 let mut state = HashedPostState::default();
1142 let excluded = MultiProofTargets::default();
1143
1144 let addr = B256::random();
1145 let slot1 = B256::random();
1146 let slot2 = B256::random();
1147
1148 let mut storage = HashedStorage::default();
1151 storage.storage.insert(slot1, U256::from(1));
1152 storage.storage.insert(slot2, U256::from(2));
1153 state.storages.insert(addr, storage);
1154
1155 assert!(!state.accounts.contains_key(&addr));
1156 assert!(!excluded.contains_key(&addr));
1157
1158 let targets = state.multi_proof_targets_difference(&excluded);
1159
1160 assert!(targets.contains_key(&addr));
1162
1163 let target_slots = &targets[&addr];
1164 assert_eq!(target_slots.len(), 2);
1165 assert!(target_slots.contains(&slot1));
1166 assert!(target_slots.contains(&slot2));
1167 }
1168
1169 #[test]
1170 fn test_hashed_post_state_sorted_extend_ref() {
1171 let mut state1 = HashedPostStateSorted {
1173 accounts: vec![
1174 (B256::from([1; 32]), Some(Account::default())),
1175 (B256::from([3; 32]), Some(Account::default())),
1176 (B256::from([5; 32]), None),
1177 ],
1178 storages: B256Map::default(),
1179 };
1180
1181 let state2 = HashedPostStateSorted {
1182 accounts: vec![
1183 (B256::from([2; 32]), Some(Account::default())),
1184 (B256::from([3; 32]), Some(Account { nonce: 1, ..Default::default() })), (B256::from([4; 32]), Some(Account::default())),
1186 (B256::from([6; 32]), None),
1187 ],
1188 storages: B256Map::default(),
1189 };
1190
1191 state1.extend_ref_and_sort(&state2);
1192
1193 assert_eq!(state1.accounts.len(), 6);
1195 assert_eq!(state1.accounts[0].0, B256::from([1; 32]));
1196 assert_eq!(state1.accounts[1].0, B256::from([2; 32]));
1197 assert_eq!(state1.accounts[2].0, B256::from([3; 32]));
1198 assert_eq!(state1.accounts[2].1.as_ref().unwrap().nonce, 1); assert_eq!(state1.accounts[3].0, B256::from([4; 32]));
1200 assert_eq!(state1.accounts[4].0, B256::from([5; 32]));
1201 assert_eq!(state1.accounts[4].1, None);
1202 assert_eq!(state1.accounts[5].0, B256::from([6; 32]));
1203 assert_eq!(state1.accounts[5].1, None);
1204 }
1205
1206 #[test]
1207 fn test_hashed_storage_sorted_extend_ref() {
1208 let mut storage1 = HashedStorageSorted {
1210 storage_slots: vec![
1211 (B256::from([1; 32]), U256::from(10)),
1212 (B256::from([3; 32]), U256::from(30)),
1213 (B256::from([5; 32]), U256::ZERO),
1214 ],
1215 };
1216
1217 let storage2 = HashedStorageSorted {
1218 storage_slots: vec![
1219 (B256::from([2; 32]), U256::from(20)),
1220 (B256::from([3; 32]), U256::from(300)), (B256::from([4; 32]), U256::from(40)),
1222 (B256::from([6; 32]), U256::ZERO),
1223 ],
1224 };
1225
1226 storage1.extend_ref(&storage2);
1227
1228 assert_eq!(storage1.storage_slots.len(), 6);
1229 assert_eq!(storage1.storage_slots[0].0, B256::from([1; 32]));
1230 assert_eq!(storage1.storage_slots[0].1, U256::from(10));
1231 assert_eq!(storage1.storage_slots[1].0, B256::from([2; 32]));
1232 assert_eq!(storage1.storage_slots[1].1, U256::from(20));
1233 assert_eq!(storage1.storage_slots[2].0, B256::from([3; 32]));
1234 assert_eq!(storage1.storage_slots[2].1, U256::from(300)); assert_eq!(storage1.storage_slots[3].0, B256::from([4; 32]));
1236 assert_eq!(storage1.storage_slots[3].1, U256::from(40));
1237 assert_eq!(storage1.storage_slots[4].0, B256::from([5; 32]));
1238 assert_eq!(storage1.storage_slots[4].1, U256::ZERO);
1239 assert_eq!(storage1.storage_slots[5].0, B256::from([6; 32]));
1240 assert_eq!(storage1.storage_slots[5].1, U256::ZERO);
1241 }
1242
1243 #[test]
1245 fn test_hashed_post_state_extend_from_sorted_with_accounts() {
1246 let addr1 = B256::random();
1247 let addr2 = B256::random();
1248
1249 let mut state = HashedPostState::default();
1250 state.accounts.insert(addr1, Some(Default::default()));
1251
1252 let mut sorted_state = HashedPostStateSorted::default();
1253 sorted_state.accounts.push((addr2, Some(Default::default())));
1254
1255 state.extend_from_sorted(&sorted_state);
1256
1257 assert_eq!(state.accounts.len(), 2);
1258 assert!(state.accounts.contains_key(&addr1));
1259 assert!(state.accounts.contains_key(&addr2));
1260 }
1261
1262 #[test]
1264 fn test_hashed_post_state_extend_from_sorted_with_destroyed_accounts() {
1265 let addr1 = B256::random();
1266
1267 let mut state = HashedPostState::default();
1268
1269 let mut sorted_state = HashedPostStateSorted::default();
1270 sorted_state.accounts.push((addr1, None));
1271
1272 state.extend_from_sorted(&sorted_state);
1273
1274 assert!(state.accounts.contains_key(&addr1));
1275 assert_eq!(state.accounts.get(&addr1), Some(&None));
1276 }
1277
1278 #[test]
1279 fn test_hashed_post_state_sorted_disjointed_merge_batch() {
1280 fn account(nonce: u64) -> Account {
1281 Account { nonce, ..Default::default() }
1282 }
1283
1284 let kept_account = B256::with_last_byte(1);
1285 let removed_account = B256::with_last_byte(2);
1286 let kept_storage = B256::with_last_byte(3);
1287 let slot1 = B256::with_last_byte(11);
1288 let slot2 = B256::with_last_byte(12);
1289
1290 let older = HashedPostStateSorted::new(
1291 vec![(kept_account, Some(account(1))), (removed_account, Some(account(10)))],
1292 B256Map::from_iter([(
1293 kept_storage,
1294 HashedStorageSorted { storage_slots: vec![(slot1, U256::from(1))] },
1295 )]),
1296 );
1297
1298 let newer = HashedPostStateSorted::new(
1299 vec![(kept_account, Some(account(2)))],
1300 B256Map::from_iter([(
1301 kept_storage,
1302 HashedStorageSorted {
1303 storage_slots: vec![(slot1, U256::from(3)), (slot2, U256::from(4))],
1304 },
1305 )]),
1306 );
1307
1308 let remove_a = HashedPostStateSorted::new(
1309 vec![(removed_account, None)],
1310 B256Map::from_iter([(
1311 kept_storage,
1312 HashedStorageSorted { storage_slots: vec![(slot2, U256::ZERO)] },
1313 )]),
1314 );
1315
1316 let remove_b = HashedPostStateSorted::new(
1317 vec![(B256::with_last_byte(255), Some(account(99)))],
1318 B256Map::default(),
1319 );
1320
1321 let result = HashedPostStateSorted::disjointed_merge_batch(
1322 &[&older, &newer],
1323 &[&remove_b, &remove_a],
1324 );
1325
1326 assert_eq!(result.accounts, vec![(kept_account, Some(account(2)))]);
1327 assert_eq!(result.storages.len(), 1);
1328 assert_eq!(
1329 result.storages.get(&kept_storage),
1330 Some(&HashedStorageSorted { storage_slots: vec![(slot1, U256::from(3))] })
1331 );
1332 }
1333
1334 #[test]
1335 fn test_hashed_post_state_sorted_disjointed_merge_batch_empty_mask_merges_batch() {
1336 let address = B256::with_last_byte(1);
1337 let storage = B256::with_last_byte(2);
1338 let slot = B256::with_last_byte(3);
1339 let empty_storage = B256::with_last_byte(4);
1340 let older = HashedPostStateSorted::new(
1341 vec![(address, Some(Account { nonce: 1, ..Default::default() }))],
1342 B256Map::from_iter([
1343 (storage, HashedStorageSorted { storage_slots: vec![(slot, U256::from(1))] }),
1344 (empty_storage, HashedStorageSorted::default()),
1345 ]),
1346 );
1347 let newer = HashedPostStateSorted::new(
1348 vec![(address, Some(Account { nonce: 2, ..Default::default() }))],
1349 B256Map::from_iter([(
1350 storage,
1351 HashedStorageSorted { storage_slots: vec![(slot, U256::from(2))] },
1352 )]),
1353 );
1354 let expected = HashedPostStateSorted::merge_batch(vec![newer.clone(), older.clone()]);
1355
1356 let result = HashedPostStateSorted::disjointed_merge_batch(&[&older, &newer], &[]);
1357
1358 assert_eq!(result, expected);
1359 }
1360
1361 #[test]
1362 fn test_hashed_post_state_sorted_disjointed_merge_batch_removes_overlapping_batch_key() {
1363 fn account(nonce: u64) -> Account {
1364 Account { nonce, ..Default::default() }
1365 }
1366
1367 let overlapping_account = B256::with_last_byte(21);
1368
1369 let older = HashedPostStateSorted::new(
1370 vec![(overlapping_account, Some(account(1)))],
1371 B256Map::default(),
1372 );
1373
1374 let newer = HashedPostStateSorted::new(
1375 vec![(overlapping_account, Some(account(2)))],
1376 B256Map::default(),
1377 );
1378
1379 let remove =
1380 HashedPostStateSorted::new(vec![(overlapping_account, None)], B256Map::default());
1381
1382 let result = HashedPostStateSorted::disjointed_merge_batch(&[&older, &newer], &[&remove]);
1383
1384 assert!(result.accounts.is_empty());
1385 }
1386
1387 #[test]
1388 fn test_hashed_post_state_sorted_disjointed_merge_batch_keeps_equal_overlaps() {
1389 fn account(nonce: u64) -> Account {
1390 Account { nonce, ..Default::default() }
1391 }
1392
1393 let address = B256::with_last_byte(21);
1394 let deleted_address = B256::with_last_byte(24);
1395 let storage = B256::with_last_byte(22);
1396 let deleted_storage = B256::with_last_byte(25);
1397 let slot = B256::with_last_byte(23);
1398 let deleted_slot = B256::with_last_byte(26);
1399 let batch = HashedPostStateSorted::new(
1400 vec![(address, Some(account(1))), (deleted_address, None)],
1401 B256Map::from_iter([
1402 (storage, HashedStorageSorted { storage_slots: vec![(slot, U256::from(1))] }),
1403 (
1404 deleted_storage,
1405 HashedStorageSorted { storage_slots: vec![(deleted_slot, U256::ZERO)] },
1406 ),
1407 ]),
1408 );
1409 let different_mask = HashedPostStateSorted::new(
1410 vec![(address, Some(account(2))), (deleted_address, Some(account(3)))],
1411 B256Map::from_iter([
1412 (storage, HashedStorageSorted { storage_slots: vec![(slot, U256::from(2))] }),
1413 (
1414 deleted_storage,
1415 HashedStorageSorted { storage_slots: vec![(deleted_slot, U256::from(3))] },
1416 ),
1417 ]),
1418 );
1419 let equal_mask = batch.clone();
1420
1421 let result = HashedPostStateSorted::disjointed_merge_batch(
1422 &[&batch],
1423 &[&different_mask, &equal_mask],
1424 );
1425 let reversed = HashedPostStateSorted::disjointed_merge_batch(
1426 &[&batch],
1427 &[&equal_mask, &different_mask],
1428 );
1429
1430 assert_eq!(result, batch);
1431 assert_eq!(reversed, result);
1432 }
1433
1434 #[test]
1435 fn test_hashed_post_state_sorted_disjointed_merge_batch_ignores_empty_storage_mask() {
1436 let storage = B256::with_last_byte(31);
1437 let slot = B256::with_last_byte(32);
1438
1439 let batch = HashedPostStateSorted::new(
1440 vec![],
1441 B256Map::from_iter([(
1442 storage,
1443 HashedStorageSorted { storage_slots: vec![(slot, U256::from(1))] },
1444 )]),
1445 );
1446 let mask = HashedPostStateSorted::new(
1447 vec![],
1448 B256Map::from_iter([(storage, HashedStorageSorted { storage_slots: vec![] })]),
1449 );
1450
1451 let result = HashedPostStateSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1452
1453 assert_eq!(
1454 result.storages.get(&storage),
1455 Some(&HashedStorageSorted { storage_slots: vec![(slot, U256::from(1))] })
1456 );
1457 }
1458
1459 #[test]
1461 fn test_hashed_storage_extend_from_sorted() {
1462 let slot1 = B256::random();
1463 let slot2 = B256::random();
1464 let slot3 = B256::random();
1465
1466 let mut storage = HashedStorage::from_iter([(slot1, U256::from(100))]);
1467
1468 let sorted = HashedStorageSorted {
1469 storage_slots: vec![(slot2, U256::from(200)), (slot3, U256::ZERO)],
1470 };
1471
1472 storage.extend_from_sorted(&sorted);
1473 assert_eq!(storage.storage.len(), 3);
1474 assert_eq!(storage.storage.get(&slot1), Some(&U256::from(100)));
1475 assert_eq!(storage.storage.get(&slot2), Some(&U256::from(200)));
1476 assert_eq!(storage.storage.get(&slot3), Some(&U256::ZERO));
1477 }
1478
1479 #[test]
1480 fn test_hashed_post_state_chunking_length() {
1481 let addr1 = B256::from([1; 32]);
1482 let addr2 = B256::from([2; 32]);
1483 let addr3 = B256::from([3; 32]);
1484 let addr4 = B256::from([4; 32]);
1485 let slot1 = B256::from([1; 32]);
1486 let slot2 = B256::from([2; 32]);
1487 let slot3 = B256::from([3; 32]);
1488
1489 let state = HashedPostState {
1490 accounts: B256Map::from_iter([(addr1, None), (addr2, None), (addr4, None)]),
1491 storages: B256Map::from_iter([
1492 (
1493 addr1,
1494 HashedStorage {
1495 storage: B256Map::from_iter([
1496 (slot1, U256::ZERO),
1497 (slot2, U256::ZERO),
1498 (slot3, U256::ZERO),
1499 ]),
1500 },
1501 ),
1502 (
1503 addr2,
1504 HashedStorage {
1505 storage: B256Map::from_iter([
1506 (slot1, U256::ZERO),
1507 (slot2, U256::ZERO),
1508 (slot3, U256::ZERO),
1509 ]),
1510 },
1511 ),
1512 (
1513 addr3,
1514 HashedStorage {
1515 storage: B256Map::from_iter([
1516 (slot1, U256::ZERO),
1517 (slot2, U256::ZERO),
1518 (slot3, U256::ZERO),
1519 ]),
1520 },
1521 ),
1522 ]),
1523 };
1524
1525 let chunking_length = state.chunking_length();
1526 for size in 1..=state.clone().chunks(1).count() {
1527 let chunk_count = state.clone().chunks(size).count();
1528 let expected_count = chunking_length.div_ceil(size);
1529 assert_eq!(
1530 chunk_count, expected_count,
1531 "chunking_length: {}, size: {}",
1532 chunking_length, size
1533 );
1534 }
1535 }
1536
1537 #[test]
1538 fn test_clone_into_sorted_equivalence() {
1539 let addr1 = B256::from([1; 32]);
1540 let addr2 = B256::from([2; 32]);
1541 let addr3 = B256::from([3; 32]);
1542 let slot1 = B256::from([1; 32]);
1543 let slot2 = B256::from([2; 32]);
1544 let slot3 = B256::from([3; 32]);
1545
1546 let state = HashedPostState {
1547 accounts: B256Map::from_iter([
1548 (addr1, Some(Account { nonce: 1, balance: U256::from(100), ..Default::default() })),
1549 (addr2, None),
1550 (addr3, Some(Account::default())),
1551 ]),
1552 storages: B256Map::from_iter([
1553 (
1554 addr1,
1555 HashedStorage {
1556 storage: B256Map::from_iter([
1557 (slot1, U256::from(10)),
1558 (slot2, U256::from(20)),
1559 ]),
1560 },
1561 ),
1562 (addr2, HashedStorage { storage: B256Map::from_iter([(slot3, U256::ZERO)]) }),
1563 ]),
1564 };
1565
1566 let sorted_via_clone = state.clone().into_sorted();
1568 let sorted_via_clone_into = state.clone_into_sorted();
1569
1570 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1571
1572 assert_eq!(state.accounts.len(), 3);
1574 assert_eq!(state.storages.len(), 2);
1575 }
1576
1577 #[test]
1578 fn test_hashed_storage_clone_into_sorted_equivalence() {
1579 let slot1 = B256::from([1; 32]);
1580 let slot2 = B256::from([2; 32]);
1581 let slot3 = B256::from([3; 32]);
1582
1583 let storage = HashedStorage {
1584 storage: B256Map::from_iter([
1585 (slot1, U256::from(100)),
1586 (slot2, U256::ZERO),
1587 (slot3, U256::from(300)),
1588 ]),
1589 };
1590
1591 let sorted_via_clone = storage.clone().into_sorted();
1593 let sorted_via_clone_into = storage.clone_into_sorted();
1594
1595 assert_eq!(sorted_via_clone, sorted_via_clone_into);
1596
1597 assert_eq!(storage.storage.len(), 3);
1599 }
1600}
1601
1602#[cfg(feature = "serde-bincode-compat")]
1604pub mod serde_bincode_compat {
1605 use super::Account;
1606 use alloc::{borrow::Cow, vec::Vec};
1607 use alloy_primitives::{map::B256Map, B256, U256};
1608 use core::fmt;
1609 use serde::{
1610 de::{Error as _, SeqAccess, Visitor},
1611 Deserialize, Deserializer, Serialize, Serializer,
1612 };
1613 use serde_with::{DeserializeAs, SerializeAs};
1614
1615 #[derive(Debug, Serialize, Deserialize)]
1631 pub struct HashedPostState<'a> {
1632 accounts: Cow<'a, B256Map<Option<Account>>>,
1633 storages: B256Map<HashedStorage<'a>>,
1634 }
1635
1636 impl<'a> From<&'a super::HashedPostState> for HashedPostState<'a> {
1637 fn from(value: &'a super::HashedPostState) -> Self {
1638 Self {
1639 accounts: Cow::Borrowed(&value.accounts),
1640 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
1641 }
1642 }
1643 }
1644
1645 impl<'a> From<HashedPostState<'a>> for super::HashedPostState {
1646 fn from(value: HashedPostState<'a>) -> Self {
1647 Self {
1648 accounts: value.accounts.into_owned(),
1649 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
1650 }
1651 }
1652 }
1653
1654 impl SerializeAs<super::HashedPostState> for HashedPostState<'_> {
1655 fn serialize_as<S>(
1656 source: &super::HashedPostState,
1657 serializer: S,
1658 ) -> Result<S::Ok, S::Error>
1659 where
1660 S: Serializer,
1661 {
1662 HashedPostState::from(source).serialize(serializer)
1663 }
1664 }
1665
1666 impl<'de> DeserializeAs<'de, super::HashedPostState> for HashedPostState<'de> {
1667 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostState, D::Error>
1668 where
1669 D: Deserializer<'de>,
1670 {
1671 HashedPostState::deserialize(deserializer).map(Into::into)
1672 }
1673 }
1674
1675 #[derive(Debug, Serialize, Deserialize)]
1691 pub struct HashedStorage<'a> {
1692 storage: Cow<'a, B256Map<U256>>,
1693 }
1694
1695 impl<'a> From<&'a super::HashedStorage> for HashedStorage<'a> {
1696 fn from(value: &'a super::HashedStorage) -> Self {
1697 Self { storage: Cow::Borrowed(&value.storage) }
1698 }
1699 }
1700
1701 impl<'a> From<HashedStorage<'a>> for super::HashedStorage {
1702 fn from(value: HashedStorage<'a>) -> Self {
1703 Self { storage: value.storage.into_owned() }
1704 }
1705 }
1706
1707 impl SerializeAs<super::HashedStorage> for HashedStorage<'_> {
1708 fn serialize_as<S>(source: &super::HashedStorage, serializer: S) -> Result<S::Ok, S::Error>
1709 where
1710 S: Serializer,
1711 {
1712 HashedStorage::from(source).serialize(serializer)
1713 }
1714 }
1715
1716 impl<'de> DeserializeAs<'de, super::HashedStorage> for HashedStorage<'de> {
1717 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorage, D::Error>
1718 where
1719 D: Deserializer<'de>,
1720 {
1721 HashedStorage::deserialize(deserializer).map(Into::into)
1722 }
1723 }
1724
1725 #[derive(Debug, Serialize, Deserialize)]
1741 pub struct HashedPostStateSorted<'a> {
1742 accounts: Cow<'a, [(B256, Option<Account>)]>,
1743 storages: B256Map<HashedStorageSorted<'a>>,
1744 }
1745
1746 impl<'a> From<&'a super::HashedPostStateSorted> for HashedPostStateSorted<'a> {
1747 fn from(value: &'a super::HashedPostStateSorted) -> Self {
1748 Self {
1749 accounts: Cow::Borrowed(&value.accounts),
1750 storages: value.storages.iter().map(|(k, v)| (*k, v.into())).collect(),
1751 }
1752 }
1753 }
1754
1755 impl<'a> From<HashedPostStateSorted<'a>> for super::HashedPostStateSorted {
1756 fn from(value: HashedPostStateSorted<'a>) -> Self {
1757 Self {
1758 accounts: value.accounts.into_owned(),
1759 storages: value.storages.into_iter().map(|(k, v)| (k, v.into())).collect(),
1760 }
1761 }
1762 }
1763
1764 impl SerializeAs<super::HashedPostStateSorted> for HashedPostStateSorted<'_> {
1765 fn serialize_as<S>(
1766 source: &super::HashedPostStateSorted,
1767 serializer: S,
1768 ) -> Result<S::Ok, S::Error>
1769 where
1770 S: Serializer,
1771 {
1772 HashedPostStateSorted::from(source).serialize(serializer)
1773 }
1774 }
1775
1776 impl<'de> DeserializeAs<'de, super::HashedPostStateSorted> for HashedPostStateSorted<'de> {
1777 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedPostStateSorted, D::Error>
1778 where
1779 D: Deserializer<'de>,
1780 {
1781 HashedPostStateSorted::deserialize(deserializer).map(Into::into)
1782 }
1783 }
1784
1785 #[derive(Debug, Serialize)]
1801 pub struct HashedStorageSorted<'a> {
1802 storage_slots: Cow<'a, [(B256, U256)]>,
1803 }
1804
1805 impl<'de, 'a> Deserialize<'de> for HashedStorageSorted<'a> {
1806 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1807 where
1808 D: Deserializer<'de>,
1809 {
1810 struct HashedStorageSortedVisitor;
1811
1812 impl<'de> Visitor<'de> for HashedStorageSortedVisitor {
1813 type Value = Vec<(B256, U256)>;
1814
1815 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1816 formatter.write_str("hashed storage with an optional legacy wipe marker")
1817 }
1818
1819 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1820 where
1821 A: SeqAccess<'de>,
1822 {
1823 let len = seq.size_hint().unwrap_or_default();
1824 if !matches!(len, 1 | 2) {
1825 return Err(A::Error::invalid_length(len, &self))
1826 }
1827
1828 let storage_slots =
1829 seq.next_element()?.ok_or_else(|| A::Error::invalid_length(0, &self))?;
1830 if len == 2 {
1831 let _: bool = seq
1832 .next_element()?
1833 .ok_or_else(|| A::Error::invalid_length(1, &self))?;
1834 }
1835
1836 Ok(storage_slots)
1837 }
1838 }
1839
1840 deserializer
1843 .deserialize_tuple(1, HashedStorageSortedVisitor)
1844 .map(|storage_slots| Self { storage_slots: Cow::Owned(storage_slots) })
1845 }
1846 }
1847
1848 impl<'a> From<&'a super::HashedStorageSorted> for HashedStorageSorted<'a> {
1849 fn from(value: &'a super::HashedStorageSorted) -> Self {
1850 Self { storage_slots: Cow::Borrowed(&value.storage_slots) }
1851 }
1852 }
1853
1854 impl<'a> From<HashedStorageSorted<'a>> for super::HashedStorageSorted {
1855 fn from(value: HashedStorageSorted<'a>) -> Self {
1856 Self { storage_slots: value.storage_slots.into_owned() }
1857 }
1858 }
1859
1860 impl SerializeAs<super::HashedStorageSorted> for HashedStorageSorted<'_> {
1861 fn serialize_as<S>(
1862 source: &super::HashedStorageSorted,
1863 serializer: S,
1864 ) -> Result<S::Ok, S::Error>
1865 where
1866 S: Serializer,
1867 {
1868 HashedStorageSorted::from(source).serialize(serializer)
1869 }
1870 }
1871
1872 impl<'de> DeserializeAs<'de, super::HashedStorageSorted> for HashedStorageSorted<'de> {
1873 fn deserialize_as<D>(deserializer: D) -> Result<super::HashedStorageSorted, D::Error>
1874 where
1875 D: Deserializer<'de>,
1876 {
1877 HashedStorageSorted::deserialize(deserializer).map(Into::into)
1878 }
1879 }
1880
1881 #[cfg(test)]
1882 mod tests {
1883 use crate::{
1884 hashed_state::{
1885 HashedPostState, HashedPostStateSorted, HashedStorage, HashedStorageSorted,
1886 },
1887 serde_bincode_compat,
1888 };
1889 use alloy_primitives::{B256, U256};
1890 use reth_primitives_traits::Account;
1891 use serde::{Deserialize, Serialize};
1892 use serde_with::serde_as;
1893
1894 #[test]
1895 fn test_hashed_post_state_bincode_roundtrip() {
1896 if Account::EXTENSIONS_ENABLED {
1898 return;
1899 }
1900
1901 #[serde_as]
1902 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1903 struct Data {
1904 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostState")]
1905 hashed_state: HashedPostState,
1906 }
1907
1908 let mut data = Data { hashed_state: HashedPostState::default() };
1909 let encoded = bincode::serialize(&data).unwrap();
1910 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1911 assert_eq!(decoded, data);
1912
1913 data.hashed_state.accounts.insert(B256::random(), Some(Account::default()));
1914 let encoded = bincode::serialize(&data).unwrap();
1915 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1916 assert_eq!(decoded, data);
1917
1918 data.hashed_state.storages.insert(B256::random(), HashedStorage::default());
1919 let encoded = bincode::serialize(&data).unwrap();
1920 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1921 assert_eq!(decoded, data);
1922 }
1923
1924 #[test]
1925 fn test_hashed_storage_bincode_roundtrip() {
1926 #[serde_as]
1927 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1928 struct Data {
1929 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorage")]
1930 hashed_storage: HashedStorage,
1931 }
1932
1933 let mut data = Data { hashed_storage: HashedStorage::default() };
1934 let encoded = bincode::serialize(&data).unwrap();
1935 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1936 assert_eq!(decoded, data);
1937
1938 data.hashed_storage.storage.insert(B256::random(), U256::from(1));
1939 let encoded = bincode::serialize(&data).unwrap();
1940 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1941 assert_eq!(decoded, data);
1942 }
1943
1944 #[test]
1945 fn test_hashed_post_state_sorted_bincode_roundtrip() {
1946 if Account::EXTENSIONS_ENABLED {
1948 return;
1949 }
1950
1951 #[serde_as]
1952 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1953 struct Data {
1954 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedPostStateSorted")]
1955 hashed_state: HashedPostStateSorted,
1956 }
1957
1958 let mut data = Data { hashed_state: HashedPostStateSorted::default() };
1959 let encoded = bincode::serialize(&data).unwrap();
1960 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1961 assert_eq!(decoded, data);
1962
1963 data.hashed_state.accounts.push((B256::random(), Some(Account::default())));
1964 data.hashed_state
1965 .accounts
1966 .push((B256::random(), Some(Account { nonce: 1, ..Default::default() })));
1967 let encoded = bincode::serialize(&data).unwrap();
1968 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1969 assert_eq!(decoded, data);
1970
1971 data.hashed_state.storages.insert(
1972 B256::random(),
1973 HashedStorageSorted { storage_slots: vec![(B256::from([1; 32]), U256::from(10))] },
1974 );
1975 let encoded = bincode::serialize(&data).unwrap();
1976 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1977 assert_eq!(decoded, data);
1978 }
1979
1980 #[test]
1981 fn test_hashed_storage_sorted_bincode_roundtrip() {
1982 #[serde_as]
1983 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1984 struct Data {
1985 #[serde_as(as = "serde_bincode_compat::hashed_state::HashedStorageSorted")]
1986 hashed_storage: HashedStorageSorted,
1987 }
1988
1989 let mut data =
1990 Data { hashed_storage: HashedStorageSorted { storage_slots: Vec::new() } };
1991 let encoded = bincode::serialize(&data).unwrap();
1992 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1993 assert_eq!(decoded, data);
1994
1995 data.hashed_storage.storage_slots.push((B256::random(), U256::from(1)));
1996 let encoded = bincode::serialize(&data).unwrap();
1997 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1998 assert_eq!(decoded, data);
1999 }
2000 }
2001}