1use crate::{
2 utils::{extend_sorted_vec, kway_merge_disjoint_sorted, kway_merge_sorted},
3 BranchNodeCompact, HashBuilder, Nibbles,
4};
5use alloc::{
6 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
7 vec::Vec,
8};
9use alloy_primitives::{
10 map::{B256Map, HashMap, HashSet},
11 FixedBytes, B256,
12};
13
14#[derive(PartialEq, Eq, Clone, Default, Debug)]
16#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
17pub struct TrieUpdates {
18 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_map"))]
20 pub account_nodes: HashMap<Nibbles, BranchNodeCompact>,
21 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_set"))]
23 pub removed_nodes: HashSet<Nibbles>,
24 pub storage_tries: B256Map<StorageTrieUpdates>,
26}
27
28impl TrieUpdates {
29 pub fn with_capacity(account_nodes: usize, storage_tries: usize) -> Self {
31 Self {
32 account_nodes: HashMap::with_capacity_and_hasher(account_nodes, Default::default()),
33 removed_nodes: HashSet::with_capacity_and_hasher(account_nodes / 4, Default::default()),
34 storage_tries: B256Map::with_capacity_and_hasher(storage_tries, Default::default()),
35 }
36 }
37
38 pub fn is_empty(&self) -> bool {
40 self.account_nodes.is_empty() &&
41 self.removed_nodes.is_empty() &&
42 self.storage_tries.is_empty()
43 }
44
45 pub const fn account_nodes_ref(&self) -> &HashMap<Nibbles, BranchNodeCompact> {
47 &self.account_nodes
48 }
49
50 pub const fn removed_nodes_ref(&self) -> &HashSet<Nibbles> {
52 &self.removed_nodes
53 }
54
55 pub const fn storage_tries_ref(&self) -> &B256Map<StorageTrieUpdates> {
57 &self.storage_tries
58 }
59
60 pub fn extend(&mut self, other: Self) {
62 self.extend_common(&other);
63 self.account_nodes.extend(exclude_empty_from_pair(other.account_nodes));
64 self.removed_nodes.extend(exclude_empty(other.removed_nodes));
65 for (hashed_address, storage_trie) in other.storage_tries {
66 self.storage_tries.entry(hashed_address).or_default().extend(storage_trie);
67 }
68 }
69
70 pub fn extend_ref(&mut self, other: &Self) {
74 self.extend_common(other);
75 self.account_nodes.extend(exclude_empty_from_pair(
76 other.account_nodes.iter().map(|(k, v)| (*k, v.clone())),
77 ));
78 self.removed_nodes.extend(exclude_empty(other.removed_nodes.iter().copied()));
79 for (hashed_address, storage_trie) in &other.storage_tries {
80 self.storage_tries.entry(*hashed_address).or_default().extend_ref(storage_trie);
81 }
82 }
83
84 fn extend_common(&mut self, other: &Self) {
85 self.account_nodes.retain(|nibbles, _| !other.removed_nodes.contains(nibbles));
86 }
87
88 pub fn extend_from_sorted(&mut self, sorted: &TrieUpdatesSorted) {
95 let new_nodes_count = sorted.account_nodes.len();
97 self.account_nodes.reserve(new_nodes_count);
98
99 for (nibbles, maybe_node) in &sorted.account_nodes {
101 if nibbles.is_empty() {
102 continue;
103 }
104 match maybe_node {
105 Some(node) => {
106 self.removed_nodes.remove(nibbles);
107 self.account_nodes.insert(*nibbles, node.clone());
108 }
109 None => {
110 self.account_nodes.remove(nibbles);
111 self.removed_nodes.insert(*nibbles);
112 }
113 }
114 }
115
116 self.storage_tries.reserve(sorted.storage_tries.len());
118 for (hashed_address, sorted_storage) in &sorted.storage_tries {
119 self.storage_tries
120 .entry(*hashed_address)
121 .or_default()
122 .extend_from_sorted(sorted_storage);
123 }
124 }
125
126 pub fn insert_storage_updates(
128 &mut self,
129 hashed_address: B256,
130 storage_updates: StorageTrieUpdates,
131 ) {
132 if storage_updates.is_empty() {
133 return;
134 }
135 let existing = self.storage_tries.insert(hashed_address, storage_updates);
136 debug_assert!(existing.is_none());
137 }
138
139 pub fn finalize(
141 &mut self,
142 hash_builder: HashBuilder,
143 removed_keys: HashSet<Nibbles>,
144 destroyed_storage_trie_nodes: B256Map<Vec<Nibbles>>,
145 ) {
146 let (_, updated_nodes) = hash_builder.split();
148 self.account_nodes.extend(exclude_empty_from_pair(updated_nodes));
149
150 self.removed_nodes.extend(exclude_empty(removed_keys));
152
153 for (hashed_address, removed_nodes) in destroyed_storage_trie_nodes {
155 let storage_updates = self.storage_tries.entry(hashed_address).or_default();
156 storage_updates.removed_nodes.extend(removed_nodes);
157 }
158 }
159
160 pub fn into_sorted(mut self) -> TrieUpdatesSorted {
162 let mut account_nodes = self
163 .account_nodes
164 .drain()
165 .map(|(path, node)| {
166 self.removed_nodes.remove(&path);
168 (path, Some(node))
169 })
170 .collect::<Vec<_>>();
171
172 account_nodes.extend(self.removed_nodes.drain().map(|path| (path, None)));
173 account_nodes.sort_unstable_by_key(|a| a.0);
174
175 let storage_tries = self
176 .storage_tries
177 .drain()
178 .map(|(hashed_address, updates)| (hashed_address, updates.into_sorted()))
179 .collect();
180 TrieUpdatesSorted { account_nodes, storage_tries }
181 }
182
183 pub fn clone_into_sorted(&self) -> TrieUpdatesSorted {
186 let mut account_nodes = self
187 .account_nodes
188 .iter()
189 .map(|(path, node)| (*path, Some(node.clone())))
190 .collect::<Vec<_>>();
191
192 account_nodes.extend(
194 self.removed_nodes
195 .iter()
196 .filter(|path| !self.account_nodes.contains_key(*path))
197 .map(|path| (*path, None)),
198 );
199 account_nodes.sort_unstable_by_key(|a| a.0);
200
201 let storage_tries = self
202 .storage_tries
203 .iter()
204 .map(|(&hashed_address, updates)| (hashed_address, updates.clone_into_sorted()))
205 .collect();
206 TrieUpdatesSorted { account_nodes, storage_tries }
207 }
208
209 pub fn to_sorted_ref(&self) -> TrieUpdatesSortedRef<'_> {
211 let mut account_nodes = self.account_nodes.iter().collect::<Vec<_>>();
212 account_nodes.sort_unstable_by(|a, b| a.0.cmp(b.0));
213
214 TrieUpdatesSortedRef {
215 removed_nodes: self.removed_nodes.iter().collect::<BTreeSet<_>>(),
216 account_nodes,
217 storage_tries: self.storage_tries.iter().map(|m| (*m.0, m.1.to_sorted_ref())).collect(),
218 }
219 }
220
221 pub fn clear(&mut self) {
223 self.account_nodes.clear();
224 self.removed_nodes.clear();
225 self.storage_tries.clear();
226 }
227}
228
229#[derive(PartialEq, Eq, Clone, Default, Debug)]
231#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
232pub struct StorageTrieUpdates {
233 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_map"))]
235 pub storage_nodes: HashMap<Nibbles, BranchNodeCompact>,
236 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_set"))]
238 pub removed_nodes: HashSet<Nibbles>,
239}
240
241#[cfg(feature = "test-utils")]
242impl StorageTrieUpdates {
243 pub fn new(updates: impl IntoIterator<Item = (Nibbles, BranchNodeCompact)>) -> Self {
245 Self { storage_nodes: exclude_empty_from_pair(updates).collect(), ..Default::default() }
246 }
247}
248
249impl StorageTrieUpdates {
250 pub fn len(&self) -> usize {
252 self.storage_nodes.len() + self.removed_nodes.len()
253 }
254
255 pub const fn storage_nodes_ref(&self) -> &HashMap<Nibbles, BranchNodeCompact> {
257 &self.storage_nodes
258 }
259
260 pub const fn removed_nodes_ref(&self) -> &HashSet<Nibbles> {
262 &self.removed_nodes
263 }
264
265 pub fn is_empty(&self) -> bool {
267 self.storage_nodes.is_empty() && self.removed_nodes.is_empty()
268 }
269
270 pub fn extend(&mut self, other: Self) {
272 self.extend_common(&other);
273 self.storage_nodes.extend(exclude_empty_from_pair(other.storage_nodes));
274 self.removed_nodes.extend(exclude_empty(other.removed_nodes));
275 }
276
277 pub fn extend_ref(&mut self, other: &Self) {
281 self.extend_common(other);
282 self.storage_nodes.extend(exclude_empty_from_pair(
283 other.storage_nodes.iter().map(|(k, v)| (*k, v.clone())),
284 ));
285 self.removed_nodes.extend(exclude_empty(other.removed_nodes.iter().copied()));
286 }
287
288 fn extend_common(&mut self, other: &Self) {
289 self.storage_nodes.retain(|nibbles, _| !other.removed_nodes.contains(nibbles));
290 }
291
292 pub fn extend_from_sorted(&mut self, sorted: &StorageTrieUpdatesSorted) {
299 let new_nodes_count = sorted.storage_nodes.len();
301 self.storage_nodes.reserve(new_nodes_count);
302
303 for (nibbles, maybe_node) in &sorted.storage_nodes {
305 if nibbles.is_empty() {
306 continue;
307 }
308 if let Some(node) = maybe_node {
309 self.removed_nodes.remove(nibbles);
310 self.storage_nodes.insert(*nibbles, node.clone());
311 } else {
312 self.storage_nodes.remove(nibbles);
313 self.removed_nodes.insert(*nibbles);
314 }
315 }
316 }
317
318 pub fn finalize(&mut self, hash_builder: HashBuilder, removed_keys: HashSet<Nibbles>) {
320 let (_, updated_nodes) = hash_builder.split();
322 self.storage_nodes.extend(exclude_empty_from_pair(updated_nodes));
323
324 self.removed_nodes.extend(exclude_empty(removed_keys));
326 }
327
328 pub fn into_sorted(mut self) -> StorageTrieUpdatesSorted {
330 let mut storage_nodes = self
331 .storage_nodes
332 .into_iter()
333 .map(|(path, node)| {
334 self.removed_nodes.remove(&path);
336 (path, Some(node))
337 })
338 .collect::<Vec<_>>();
339
340 storage_nodes.extend(self.removed_nodes.into_iter().map(|path| (path, None)));
341 storage_nodes.sort_unstable_by_key(|a| a.0);
342
343 StorageTrieUpdatesSorted { storage_nodes }
344 }
345
346 pub fn clone_into_sorted(&self) -> StorageTrieUpdatesSorted {
349 let mut storage_nodes = self
350 .storage_nodes
351 .iter()
352 .map(|(path, node)| (*path, Some(node.clone())))
353 .collect::<Vec<_>>();
354
355 storage_nodes.extend(
357 self.removed_nodes
358 .iter()
359 .filter(|path| !self.storage_nodes.contains_key(*path))
360 .map(|path| (*path, None)),
361 );
362 storage_nodes.sort_unstable_by_key(|a| a.0);
363
364 StorageTrieUpdatesSorted { storage_nodes }
365 }
366
367 pub fn to_sorted_ref(&self) -> StorageTrieUpdatesSortedRef<'_> {
370 StorageTrieUpdatesSortedRef {
371 removed_nodes: self.removed_nodes.iter().collect::<BTreeSet<_>>(),
372 storage_nodes: self.storage_nodes.iter().collect::<BTreeMap<_, _>>(),
373 }
374 }
375}
376
377#[cfg(any(test, feature = "serde"))]
382mod serde_nibbles_set {
383 use crate::Nibbles;
384 use alloc::{
385 string::{String, ToString},
386 vec::Vec,
387 };
388 use alloy_primitives::map::HashSet;
389 use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
390
391 pub(super) fn serialize<S>(map: &HashSet<Nibbles>, serializer: S) -> Result<S::Ok, S::Error>
392 where
393 S: Serializer,
394 {
395 let mut storage_nodes =
396 map.iter().map(|elem| alloy_primitives::hex::encode(elem.pack())).collect::<Vec<_>>();
397 storage_nodes.sort_unstable();
398 storage_nodes.serialize(serializer)
399 }
400
401 pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<HashSet<Nibbles>, D::Error>
402 where
403 D: Deserializer<'de>,
404 {
405 Vec::<String>::deserialize(deserializer)?
406 .into_iter()
407 .map(|node| {
408 Ok(Nibbles::unpack(
409 alloy_primitives::hex::decode(node)
410 .map_err(|err| D::Error::custom(err.to_string()))?,
411 ))
412 })
413 .collect::<Result<HashSet<_>, _>>()
414 }
415}
416
417#[cfg(any(test, feature = "serde"))]
422mod serde_nibbles_map {
423 use crate::Nibbles;
424 use alloc::{
425 string::{String, ToString},
426 vec::Vec,
427 };
428 use alloy_primitives::{hex, map::HashMap};
429 use core::marker::PhantomData;
430 use serde::{
431 de::{Error, MapAccess, Visitor},
432 ser::SerializeMap,
433 Deserialize, Deserializer, Serialize, Serializer,
434 };
435
436 pub(super) fn serialize<S, T>(
437 map: &HashMap<Nibbles, T>,
438 serializer: S,
439 ) -> Result<S::Ok, S::Error>
440 where
441 S: Serializer,
442 T: Serialize,
443 {
444 let mut map_serializer = serializer.serialize_map(Some(map.len()))?;
445 let mut storage_nodes = Vec::from_iter(map);
446 storage_nodes.sort_unstable_by_key(|node| node.0);
447 for (k, v) in storage_nodes {
448 let packed = alloy_primitives::hex::encode(k.pack());
450 map_serializer.serialize_entry(&packed, &v)?;
451 }
452 map_serializer.end()
453 }
454
455 pub(super) fn deserialize<'de, D, T>(deserializer: D) -> Result<HashMap<Nibbles, T>, D::Error>
456 where
457 D: Deserializer<'de>,
458 T: Deserialize<'de>,
459 {
460 struct NibblesMapVisitor<T> {
461 marker: PhantomData<T>,
462 }
463
464 impl<'de, T> Visitor<'de> for NibblesMapVisitor<T>
465 where
466 T: Deserialize<'de>,
467 {
468 type Value = HashMap<Nibbles, T>;
469
470 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
471 formatter.write_str("a map with hex-encoded Nibbles keys")
472 }
473
474 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
475 where
476 A: MapAccess<'de>,
477 {
478 let mut result = HashMap::with_capacity_and_hasher(
479 map.size_hint().unwrap_or(0),
480 Default::default(),
481 );
482
483 while let Some((key, value)) = map.next_entry::<String, T>()? {
484 let decoded_key =
485 hex::decode(&key).map_err(|err| Error::custom(err.to_string()))?;
486
487 let nibbles = Nibbles::unpack(&decoded_key);
488
489 result.insert(nibbles, value);
490 }
491
492 Ok(result)
493 }
494 }
495
496 deserializer.deserialize_map(NibblesMapVisitor { marker: PhantomData })
497 }
498}
499
500#[derive(PartialEq, Eq, Clone, Default, Debug)]
502#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
503pub struct TrieUpdatesSortedRef<'a> {
504 pub account_nodes: Vec<(&'a Nibbles, &'a BranchNodeCompact)>,
506 pub removed_nodes: BTreeSet<&'a Nibbles>,
508 pub storage_tries: BTreeMap<FixedBytes<32>, StorageTrieUpdatesSortedRef<'a>>,
510}
511
512#[derive(PartialEq, Eq, Clone, Default, Debug)]
514#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
515pub struct TrieUpdatesSorted {
516 account_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
519 storage_tries: B256Map<StorageTrieUpdatesSorted>,
521}
522
523impl TrieUpdatesSorted {
524 pub fn new(
531 account_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
532 storage_tries: B256Map<StorageTrieUpdatesSorted>,
533 ) -> Self {
534 debug_assert!(
535 account_nodes.is_sorted_by_key(|item| &item.0),
536 "account_nodes must be sorted by Nibbles key"
537 );
538 debug_assert!(
539 storage_tries.values().all(|storage_trie| {
540 storage_trie.storage_nodes.is_sorted_by_key(|item| &item.0)
541 }),
542 "all storage_nodes in storage_tries must be sorted by Nibbles key"
543 );
544 Self { account_nodes, storage_tries }
545 }
546
547 pub fn is_empty(&self) -> bool {
549 self.account_nodes.is_empty() && self.storage_tries.is_empty()
550 }
551
552 pub fn account_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
554 &self.account_nodes
555 }
556
557 pub const fn storage_tries_ref(&self) -> &B256Map<StorageTrieUpdatesSorted> {
559 &self.storage_tries
560 }
561
562 pub fn total_len(&self) -> usize {
564 self.account_nodes.len() +
565 self.storage_tries.values().map(|storage| storage.len()).sum::<usize>()
566 }
567
568 pub fn extend_ref_and_sort(&mut self, other: &Self) {
577 extend_sorted_vec(&mut self.account_nodes, &other.account_nodes);
579
580 for (hashed_address, storage_trie) in &other.storage_tries {
582 self.storage_tries
583 .entry(*hashed_address)
584 .and_modify(|existing| existing.extend_ref(storage_trie))
585 .or_insert_with(|| storage_trie.clone());
586 }
587 }
588
589 pub fn clear(&mut self) {
591 self.account_nodes.clear();
592 self.storage_tries.clear();
593 }
594
595 pub fn merge_batch<T: AsRef<Self> + From<Self>>(iter: impl IntoIterator<Item = T>) -> T {
600 let items: alloc::vec::Vec<_> = iter.into_iter().collect();
601 match items.len() {
602 0 => Self::default().into(),
603 1 => items.into_iter().next().expect("len == 1"),
604 _ => Self::merge_slice(&items).into(),
605 }
606 }
607
608 pub fn merge_slice<T: AsRef<Self>>(items: &[T]) -> Self {
614 const THRESHOLD: usize = 30;
615
616 let k = items.len();
617
618 if k == 0 {
619 return Self::default();
620 }
621 if k == 1 {
622 return items[0].as_ref().clone();
623 }
624
625 if k < THRESHOLD {
626 let mut iter = items.iter().rev();
628 let mut acc = iter.next().expect("k > 0").as_ref().clone();
629 for next in iter {
630 acc.extend_ref_and_sort(next.as_ref());
631 }
632 return acc;
633 }
634
635 Self::merge_iter(items.iter().map(AsRef::as_ref))
636 }
637
638 pub fn merge_iter<'a>(items: impl Iterator<Item = &'a Self> + Clone) -> Self {
643 let account_nodes =
644 kway_merge_sorted(items.clone().map(|item| item.account_nodes.as_slice()));
645
646 struct StorageAcc<'a> {
647 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
648 }
649
650 let mut acc: B256Map<StorageAcc<'_>> = B256Map::default();
651
652 for item in items {
653 for (addr, storage) in &item.storage_tries {
654 let entry = acc.entry(*addr).or_insert_with(|| StorageAcc { slices: Vec::new() });
655 entry.slices.push(storage.storage_nodes.as_slice());
656 }
657 }
658
659 let storage_tries = acc
660 .into_iter()
661 .map(|(addr, entry)| {
662 let storage_nodes = kway_merge_sorted(entry.slices);
663 (addr, StorageTrieUpdatesSorted { storage_nodes })
664 })
665 .collect();
666
667 Self { account_nodes, storage_tries }
668 }
669
670 pub fn disjointed_merge_batch<'a>(batch: &[&'a Self], mask: &[&'a Self]) -> Self {
678 let account_node_count = batch.iter().map(|item| item.account_nodes.len()).sum();
679 let mut account_nodes = Vec::with_capacity(account_node_count);
680 account_nodes.extend(kway_merge_disjoint_sorted(
681 batch.iter().rev().map(|item| item.account_nodes.as_slice()),
682 mask.iter().map(|item| item.account_nodes.as_slice()),
683 ));
684
685 struct StorageAcc<'a> {
686 node_count: usize,
687 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
688 }
689
690 #[derive(Default)]
691 struct StorageMaskAcc<'a> {
692 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
693 }
694
695 let mut storage_tries = B256Map::with_capacity_and_hasher(
696 batch.iter().map(|item| item.storage_tries.len()).sum(),
697 Default::default(),
698 );
699
700 for item in batch.iter().rev() {
701 for (hashed_address, storage_trie) in &item.storage_tries {
702 let entry = storage_tries
703 .entry(*hashed_address)
704 .or_insert_with(|| StorageAcc { node_count: 0, slices: Vec::new() });
705 entry.slices.push(storage_trie.storage_nodes.as_slice());
706 entry.node_count += storage_trie.storage_nodes.len();
707 }
708 }
709
710 let mut storage_masks: B256Map<StorageMaskAcc<'a>> = B256Map::with_capacity_and_hasher(
711 mask.iter().map(|item| item.storage_tries.len()).sum(),
712 Default::default(),
713 );
714 for item in mask {
715 for (hashed_address, storage_trie) in &item.storage_tries {
716 let entry = storage_masks.entry(*hashed_address).or_default();
717 entry.slices.push(storage_trie.storage_nodes.as_slice());
718 }
719 }
720
721 let storage_tries = storage_tries
722 .into_iter()
723 .filter_map(|(hashed_address, entry)| {
724 let node_count = entry.node_count;
725 let storage_nodes = match storage_masks.get(&hashed_address) {
726 Some(mask_entry) => {
727 let mut storage_nodes = Vec::with_capacity(node_count);
728 storage_nodes.extend(kway_merge_disjoint_sorted(
729 entry.slices,
730 mask_entry.slices.iter().copied(),
731 ));
732 storage_nodes
733 }
734 None => kway_merge_sorted(entry.slices),
735 };
736
737 (!storage_nodes.is_empty() || mask.is_empty())
738 .then_some((hashed_address, StorageTrieUpdatesSorted { storage_nodes }))
739 })
740 .collect();
741
742 Self::new(account_nodes, storage_tries)
743 }
744}
745
746impl AsRef<Self> for TrieUpdatesSorted {
747 fn as_ref(&self) -> &Self {
748 self
749 }
750}
751
752impl From<TrieUpdatesSorted> for TrieUpdates {
753 fn from(sorted: TrieUpdatesSorted) -> Self {
754 let mut account_nodes = HashMap::default();
755 let mut removed_nodes = HashSet::default();
756
757 for (nibbles, node) in sorted.account_nodes {
758 if let Some(node) = node {
759 account_nodes.insert(nibbles, node);
760 } else {
761 removed_nodes.insert(nibbles);
762 }
763 }
764
765 let storage_tries = sorted
766 .storage_tries
767 .into_iter()
768 .map(|(address, storage)| (address, storage.into()))
769 .collect();
770
771 Self { account_nodes, removed_nodes, storage_tries }
772 }
773}
774
775#[derive(PartialEq, Eq, Clone, Default, Debug)]
777#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
778pub struct StorageTrieUpdatesSortedRef<'a> {
779 pub storage_nodes: BTreeMap<&'a Nibbles, &'a BranchNodeCompact>,
781 pub removed_nodes: BTreeSet<&'a Nibbles>,
783}
784
785#[derive(PartialEq, Eq, Clone, Default, Debug)]
787#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
788pub struct StorageTrieUpdatesSorted {
789 pub storage_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
792}
793
794impl StorageTrieUpdatesSorted {
795 pub fn storage_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
797 &self.storage_nodes
798 }
799
800 pub const fn len(&self) -> usize {
802 self.storage_nodes.len()
803 }
804
805 pub const fn is_empty(&self) -> bool {
807 self.storage_nodes.is_empty()
808 }
809
810 pub fn extend_ref(&mut self, other: &Self) {
812 extend_sorted_vec(&mut self.storage_nodes, &other.storage_nodes);
813 }
814
815 pub fn merge_batch<'a>(updates: impl IntoIterator<Item = &'a Self>) -> Self {
817 let updates: Vec<_> = updates.into_iter().collect();
818 Self {
819 storage_nodes: kway_merge_sorted(updates.iter().map(|u| u.storage_nodes.as_slice())),
820 }
821 }
822}
823
824fn exclude_empty(iter: impl IntoIterator<Item = Nibbles>) -> impl Iterator<Item = Nibbles> {
826 iter.into_iter().filter(|n| !n.is_empty())
827}
828
829fn exclude_empty_from_pair<V>(
831 iter: impl IntoIterator<Item = (Nibbles, V)>,
832) -> impl Iterator<Item = (Nibbles, V)> {
833 iter.into_iter().filter(|(n, _)| !n.is_empty())
834}
835
836impl From<StorageTrieUpdatesSorted> for StorageTrieUpdates {
837 fn from(sorted: StorageTrieUpdatesSorted) -> Self {
838 let mut storage_nodes = HashMap::default();
839 let mut removed_nodes = HashSet::default();
840
841 for (nibbles, node) in sorted.storage_nodes {
842 if let Some(node) = node {
843 storage_nodes.insert(nibbles, node);
844 } else {
845 removed_nodes.insert(nibbles);
846 }
847 }
848
849 Self { storage_nodes, removed_nodes }
850 }
851}
852
853#[cfg(test)]
854mod tests {
855 use super::*;
856 use alloy_primitives::B256;
857
858 #[test]
859 fn test_finalize_keeps_storage_updates_after_destroyed_node_removal() {
860 let hashed_address = B256::with_last_byte(1);
861 let path = Nibbles::from_nibbles_unchecked([0x01]);
862 let node = BranchNodeCompact::default();
863 let mut updates = TrieUpdates {
864 storage_tries: B256Map::from_iter([(
865 hashed_address,
866 StorageTrieUpdates {
867 storage_nodes: HashMap::from_iter([(path, node.clone())]),
868 ..Default::default()
869 },
870 )]),
871 ..Default::default()
872 };
873
874 updates.finalize(
875 HashBuilder::default(),
876 Default::default(),
877 B256Map::from_iter([(hashed_address, vec![path])]),
878 );
879
880 assert_eq!(
881 updates.into_sorted().storage_tries[&hashed_address].storage_nodes,
882 vec![(path, Some(node))]
883 );
884 }
885
886 #[test]
887 fn test_trie_updates_sorted_extend_ref() {
888 let mut updates1 = TrieUpdatesSorted::default();
890 let updates2 = TrieUpdatesSorted::default();
891 updates1.extend_ref_and_sort(&updates2);
892 assert_eq!(updates1.account_nodes.len(), 0);
893 assert_eq!(updates1.storage_tries.len(), 0);
894
895 let mut updates1 = TrieUpdatesSorted {
897 account_nodes: vec![
898 (Nibbles::from_nibbles_unchecked([0x01]), Some(BranchNodeCompact::default())),
899 (Nibbles::from_nibbles_unchecked([0x03]), None),
900 ],
901 storage_tries: B256Map::default(),
902 };
903 let updates2 = TrieUpdatesSorted {
904 account_nodes: vec![
905 (Nibbles::from_nibbles_unchecked([0x02]), Some(BranchNodeCompact::default())),
906 (Nibbles::from_nibbles_unchecked([0x03]), Some(BranchNodeCompact::default())), ],
908 storage_tries: B256Map::default(),
909 };
910 updates1.extend_ref_and_sort(&updates2);
911 assert_eq!(updates1.account_nodes.len(), 3);
912 assert_eq!(updates1.account_nodes[0].0, Nibbles::from_nibbles_unchecked([0x01]));
914 assert_eq!(updates1.account_nodes[1].0, Nibbles::from_nibbles_unchecked([0x02]));
915 assert_eq!(updates1.account_nodes[2].0, Nibbles::from_nibbles_unchecked([0x03]));
916 assert!(updates1.account_nodes[2].1.is_some());
918
919 let storage_trie1 = StorageTrieUpdatesSorted {
921 storage_nodes: vec![(
922 Nibbles::from_nibbles_unchecked([0x0a]),
923 Some(BranchNodeCompact::default()),
924 )],
925 };
926 let storage_trie2 = StorageTrieUpdatesSorted {
927 storage_nodes: vec![(Nibbles::from_nibbles_unchecked([0x0b]), None)],
928 };
929
930 let hashed_address1 = B256::repeat_byte(1);
931 let hashed_address2 = B256::repeat_byte(2);
932
933 let mut updates1 = TrieUpdatesSorted {
934 account_nodes: vec![],
935 storage_tries: B256Map::from_iter([(hashed_address1, storage_trie1.clone())]),
936 };
937 let updates2 = TrieUpdatesSorted {
938 account_nodes: vec![],
939 storage_tries: B256Map::from_iter([
940 (hashed_address1, storage_trie2),
941 (hashed_address2, storage_trie1),
942 ]),
943 };
944 updates1.extend_ref_and_sort(&updates2);
945 assert_eq!(updates1.storage_tries.len(), 2);
946 assert!(updates1.storage_tries.contains_key(&hashed_address1));
947 assert!(updates1.storage_tries.contains_key(&hashed_address2));
948 let merged_storage = &updates1.storage_tries[&hashed_address1];
950 assert_eq!(merged_storage.storage_nodes.len(), 2);
951 }
952
953 #[test]
954 fn test_trie_updates_sorted_disjointed_merge_batch() {
955 let kept_node = Nibbles::from_nibbles_unchecked([0x01]);
956 let removed_node = Nibbles::from_nibbles_unchecked([0x02]);
957 let kept_storage = B256::repeat_byte(3);
958 let slot1 = Nibbles::from_nibbles_unchecked([0x0a]);
959 let slot2 = Nibbles::from_nibbles_unchecked([0x0b]);
960
961 let older = TrieUpdatesSorted::new(
962 vec![(kept_node, Some(BranchNodeCompact::default())), (removed_node, None)],
963 B256Map::from_iter([(
964 kept_storage,
965 StorageTrieUpdatesSorted { storage_nodes: vec![(slot1, None)] },
966 )]),
967 );
968
969 let newer = TrieUpdatesSorted::new(
970 vec![(kept_node, None)],
971 B256Map::from_iter([(
972 kept_storage,
973 StorageTrieUpdatesSorted {
974 storage_nodes: vec![(slot1, Some(BranchNodeCompact::default())), (slot2, None)],
975 },
976 )]),
977 );
978
979 let remove_a = TrieUpdatesSorted::new(
980 vec![(removed_node, Some(BranchNodeCompact::default()))],
981 B256Map::from_iter([(
982 kept_storage,
983 StorageTrieUpdatesSorted {
984 storage_nodes: vec![(slot2, Some(BranchNodeCompact::default()))],
985 },
986 )]),
987 );
988
989 let remove_b = TrieUpdatesSorted::new(
990 vec![(Nibbles::from_nibbles_unchecked([0x0f]), Some(BranchNodeCompact::default()))],
991 B256Map::default(),
992 );
993
994 let result =
995 TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[&remove_b, &remove_a]);
996
997 assert_eq!(result.account_nodes, vec![(kept_node, None)]);
998 assert_eq!(result.storage_tries.len(), 1);
999 assert_eq!(
1000 result.storage_tries.get(&kept_storage),
1001 Some(&StorageTrieUpdatesSorted {
1002 storage_nodes: vec![(slot1, Some(BranchNodeCompact::default()))],
1003 })
1004 );
1005 }
1006
1007 #[test]
1008 fn test_trie_updates_sorted_disjointed_merge_batch_empty_mask_merges_batch() {
1009 let node = Nibbles::from_nibbles_unchecked([0x01]);
1010 let storage = B256::with_last_byte(2);
1011 let storage_node = Nibbles::from_nibbles_unchecked([0x03]);
1012 let empty_storage = B256::with_last_byte(4);
1013 let older = TrieUpdatesSorted::new(
1014 vec![(node, Some(BranchNodeCompact::default()))],
1015 B256Map::from_iter([
1016 (storage, StorageTrieUpdatesSorted { storage_nodes: vec![(storage_node, None)] }),
1017 (empty_storage, StorageTrieUpdatesSorted::default()),
1018 ]),
1019 );
1020 let newer = TrieUpdatesSorted::new(
1021 vec![(node, None)],
1022 B256Map::from_iter([(
1023 storage,
1024 StorageTrieUpdatesSorted {
1025 storage_nodes: vec![(storage_node, Some(BranchNodeCompact::default()))],
1026 },
1027 )]),
1028 );
1029 let expected = TrieUpdatesSorted::merge_batch(vec![newer.clone(), older.clone()]);
1030
1031 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[]);
1032
1033 assert_eq!(result, expected);
1034 }
1035
1036 #[test]
1037 fn test_trie_updates_sorted_disjointed_merge_batch_removes_overlapping_batch_key() {
1038 let overlapping_node = Nibbles::from_nibbles_unchecked([0x03]);
1039
1040 let older = TrieUpdatesSorted::new(
1041 vec![(overlapping_node, Some(BranchNodeCompact::default()))],
1042 B256Map::default(),
1043 );
1044
1045 let newer = TrieUpdatesSorted::new(vec![(overlapping_node, None)], B256Map::default());
1046
1047 let remove = TrieUpdatesSorted::new(
1048 vec![(overlapping_node, Some(BranchNodeCompact::default()))],
1049 B256Map::default(),
1050 );
1051
1052 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[&remove]);
1053
1054 assert!(result.account_nodes.is_empty());
1055 }
1056
1057 #[test]
1058 fn test_trie_updates_sorted_disjointed_merge_batch_keeps_equal_overlaps() {
1059 fn branch(mask: u16) -> BranchNodeCompact {
1060 BranchNodeCompact::new(mask, 0, 0, vec![], None)
1061 }
1062
1063 let node_path = Nibbles::from_nibbles_unchecked([0x03]);
1064 let deleted_node_path = Nibbles::from_nibbles_unchecked([0x04]);
1065 let storage = B256::repeat_byte(5);
1066 let deleted_storage = B256::repeat_byte(6);
1067 let storage_node_path = Nibbles::from_nibbles_unchecked([0x0c]);
1068 let deleted_storage_node_path = Nibbles::from_nibbles_unchecked([0x0d]);
1069 let batch = TrieUpdatesSorted::new(
1070 vec![(node_path, Some(branch(0b1010_0101))), (deleted_node_path, None)],
1071 B256Map::from_iter([
1072 (
1073 storage,
1074 StorageTrieUpdatesSorted {
1075 storage_nodes: vec![(storage_node_path, Some(branch(0b0011_1100)))],
1076 },
1077 ),
1078 (
1079 deleted_storage,
1080 StorageTrieUpdatesSorted {
1081 storage_nodes: vec![(deleted_storage_node_path, None)],
1082 },
1083 ),
1084 ]),
1085 );
1086 let different_mask = TrieUpdatesSorted::new(
1087 vec![
1088 (node_path, Some(branch(0b0101_1010))),
1089 (deleted_node_path, Some(branch(0b1111_0000))),
1090 ],
1091 B256Map::from_iter([
1092 (
1093 storage,
1094 StorageTrieUpdatesSorted {
1095 storage_nodes: vec![(storage_node_path, Some(branch(0b1100_0011)))],
1096 },
1097 ),
1098 (
1099 deleted_storage,
1100 StorageTrieUpdatesSorted {
1101 storage_nodes: vec![(deleted_storage_node_path, Some(branch(0b0000_1111)))],
1102 },
1103 ),
1104 ]),
1105 );
1106 let equal_mask = batch.clone();
1107
1108 let result =
1109 TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&different_mask, &equal_mask]);
1110 let reversed =
1111 TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&equal_mask, &different_mask]);
1112
1113 assert_eq!(result, batch);
1114 assert_eq!(reversed, result);
1115 }
1116
1117 #[test]
1118 fn test_trie_updates_sorted_disjointed_merge_batch_uses_exact_key_masking() {
1119 let hashed_address = B256::repeat_byte(7);
1120 let grandparent = Nibbles::from_nibbles_unchecked([0x05]);
1121 let parent = Nibbles::from_nibbles_unchecked([0x05, 0x04]);
1122 let child = Nibbles::from_nibbles_unchecked([0x05, 0x04, 0x03]);
1123 let different_node = BranchNodeCompact::new(1, 0, 0, vec![], None);
1124
1125 let batch = TrieUpdatesSorted::new(
1126 vec![
1127 (grandparent, Some(BranchNodeCompact::default())),
1128 (parent, Some(BranchNodeCompact::default())),
1129 (child, Some(BranchNodeCompact::default())),
1130 ],
1131 B256Map::from_iter([(
1132 hashed_address,
1133 StorageTrieUpdatesSorted {
1134 storage_nodes: vec![
1135 (grandparent, Some(BranchNodeCompact::default())),
1136 (parent, Some(BranchNodeCompact::default())),
1137 (child, Some(BranchNodeCompact::default())),
1138 ],
1139 },
1140 )]),
1141 );
1142 let mask = TrieUpdatesSorted::new(
1143 vec![
1144 (grandparent, Some(different_node.clone())),
1145 (parent, Some(different_node.clone())),
1146 ],
1147 B256Map::from_iter([(
1148 hashed_address,
1149 StorageTrieUpdatesSorted {
1150 storage_nodes: vec![
1151 (grandparent, Some(different_node.clone())),
1152 (parent, Some(different_node)),
1153 ],
1154 },
1155 )]),
1156 );
1157
1158 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1159
1160 assert_eq!(result.account_nodes, vec![(child, Some(BranchNodeCompact::default()))]);
1161 assert_eq!(
1162 result.storage_tries.get(&hashed_address),
1163 Some(&StorageTrieUpdatesSorted {
1164 storage_nodes: vec![(child, Some(BranchNodeCompact::default()))],
1165 })
1166 );
1167 }
1168
1169 #[test]
1170 fn test_trie_updates_sorted_disjointed_merge_batch_ignores_empty_storage_mask() {
1171 let storage = B256::repeat_byte(6);
1172 let slot = Nibbles::from_nibbles_unchecked([0x0d]);
1173
1174 let batch = TrieUpdatesSorted::new(
1175 vec![],
1176 B256Map::from_iter([(
1177 storage,
1178 StorageTrieUpdatesSorted {
1179 storage_nodes: vec![(slot, Some(BranchNodeCompact::default()))],
1180 },
1181 )]),
1182 );
1183 let mask = TrieUpdatesSorted::new(
1184 vec![],
1185 B256Map::from_iter([(storage, StorageTrieUpdatesSorted { storage_nodes: vec![] })]),
1186 );
1187
1188 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1189
1190 assert_eq!(
1191 result.storage_tries.get(&storage),
1192 Some(&StorageTrieUpdatesSorted {
1193 storage_nodes: vec![(slot, Some(BranchNodeCompact::default()))],
1194 })
1195 );
1196 }
1197
1198 #[test]
1200 fn test_trie_updates_extend_from_sorted_with_storage_tries() {
1201 let hashed_address = B256::repeat_byte(1);
1202
1203 let mut updates = TrieUpdates::default();
1204
1205 let storage_trie = StorageTrieUpdatesSorted {
1206 storage_nodes: vec![
1207 (Nibbles::from_nibbles_unchecked([0x0a]), Some(BranchNodeCompact::default())),
1208 (Nibbles::from_nibbles_unchecked([0x0b]), None),
1209 ],
1210 };
1211
1212 let sorted = TrieUpdatesSorted {
1213 account_nodes: vec![],
1214 storage_tries: B256Map::from_iter([(hashed_address, storage_trie)]),
1215 };
1216
1217 updates.extend_from_sorted(&sorted);
1218
1219 assert_eq!(updates.storage_tries.len(), 1);
1220 let storage = updates.storage_tries.get(&hashed_address).unwrap();
1221 assert_eq!(storage.storage_nodes.len(), 1);
1222 assert!(storage.removed_nodes.contains(&Nibbles::from_nibbles_unchecked([0x0b])));
1223 }
1224
1225 #[test]
1227 fn test_storage_trie_updates_extend_from_sorted_non_deleted() {
1228 let mut storage = StorageTrieUpdates {
1229 storage_nodes: HashMap::from_iter([(
1230 Nibbles::from_nibbles_unchecked([0x01]),
1231 BranchNodeCompact::default(),
1232 )]),
1233 removed_nodes: Default::default(),
1234 };
1235
1236 let sorted = StorageTrieUpdatesSorted {
1237 storage_nodes: vec![
1238 (Nibbles::from_nibbles_unchecked([0x02]), Some(BranchNodeCompact::default())),
1239 (Nibbles::from_nibbles_unchecked([0x03]), None),
1240 ],
1241 };
1242
1243 storage.extend_from_sorted(&sorted);
1244 assert_eq!(storage.storage_nodes.len(), 2);
1245 assert!(storage.removed_nodes.contains(&Nibbles::from_nibbles_unchecked([0x03])));
1246 }
1247
1248 #[test]
1250 fn test_trie_updates_extend_from_sorted_filters_empty_nibbles() {
1251 let mut updates = TrieUpdates::default();
1252
1253 let sorted = TrieUpdatesSorted {
1254 account_nodes: vec![
1255 (Nibbles::default(), Some(BranchNodeCompact::default())), (Nibbles::from_nibbles_unchecked([0x01]), Some(BranchNodeCompact::default())),
1257 ],
1258 storage_tries: B256Map::default(),
1259 };
1260
1261 updates.extend_from_sorted(&sorted);
1262
1263 assert_eq!(updates.account_nodes.len(), 1);
1265 assert!(updates.account_nodes.contains_key(&Nibbles::from_nibbles_unchecked([0x01])));
1266 assert!(!updates.account_nodes.contains_key(&Nibbles::default()));
1267 }
1268
1269 #[test]
1270 fn test_trie_updates_sorted_merge_iter() {
1271 let path = Nibbles::from_nibbles_unchecked([1]);
1272 let updates = (0..31)
1273 .map(|index| {
1274 let nodes = vec![(path, (index % 2 != 0).then(BranchNodeCompact::default))];
1275 TrieUpdatesSorted::new(
1276 nodes.clone(),
1277 B256Map::from_iter([
1278 (B256::ZERO, StorageTrieUpdatesSorted { storage_nodes: nodes.clone() }),
1279 (
1280 B256::with_last_byte(index + 1),
1281 StorageTrieUpdatesSorted { storage_nodes: nodes },
1282 ),
1283 ]),
1284 )
1285 })
1286 .collect::<Vec<_>>();
1287
1288 for count in [0, 1, 2, 29, 30, 31] {
1289 let mut expected = TrieUpdatesSorted::default();
1290 for update in updates[..count].iter().rev() {
1291 expected.extend_ref_and_sort(update);
1292 }
1293
1294 let iter = (0..).take(count).map(|index| &updates[index]);
1296 assert_eq!(TrieUpdatesSorted::merge_iter(iter), expected);
1297 assert_eq!(TrieUpdatesSorted::merge_slice(&updates[..count]), expected);
1298 }
1299 }
1300}
1301
1302#[cfg(feature = "serde-bincode-compat")]
1304pub mod serde_bincode_compat {
1305 use crate::{BranchNodeCompact, Nibbles};
1306 use alloc::{borrow::Cow, vec::Vec};
1307 use alloy_primitives::map::{B256Map, HashMap, HashSet};
1308 use core::fmt;
1309 use serde::{
1310 de::{Error as _, SeqAccess, Visitor},
1311 Deserialize, Deserializer, Serialize, Serializer,
1312 };
1313 use serde_with::{DeserializeAs, SerializeAs};
1314
1315 #[derive(Debug, Serialize, Deserialize)]
1331 pub struct TrieUpdates<'a> {
1332 account_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
1333 removed_nodes: Cow<'a, HashSet<Nibbles>>,
1334 storage_tries: B256Map<StorageTrieUpdates<'a>>,
1335 }
1336
1337 impl<'a> From<&'a super::TrieUpdates> for TrieUpdates<'a> {
1338 fn from(value: &'a super::TrieUpdates) -> Self {
1339 Self {
1340 account_nodes: Cow::Borrowed(&value.account_nodes),
1341 removed_nodes: Cow::Borrowed(&value.removed_nodes),
1342 storage_tries: value.storage_tries.iter().map(|(k, v)| (*k, v.into())).collect(),
1343 }
1344 }
1345 }
1346
1347 impl<'a> From<TrieUpdates<'a>> for super::TrieUpdates {
1348 fn from(value: TrieUpdates<'a>) -> Self {
1349 Self {
1350 account_nodes: value.account_nodes.into_owned(),
1351 removed_nodes: value.removed_nodes.into_owned(),
1352 storage_tries: value
1353 .storage_tries
1354 .into_iter()
1355 .map(|(k, v)| (k, v.into()))
1356 .collect(),
1357 }
1358 }
1359 }
1360
1361 impl SerializeAs<super::TrieUpdates> for TrieUpdates<'_> {
1362 fn serialize_as<S>(source: &super::TrieUpdates, serializer: S) -> Result<S::Ok, S::Error>
1363 where
1364 S: Serializer,
1365 {
1366 TrieUpdates::from(source).serialize(serializer)
1367 }
1368 }
1369
1370 impl<'de> DeserializeAs<'de, super::TrieUpdates> for TrieUpdates<'de> {
1371 fn deserialize_as<D>(deserializer: D) -> Result<super::TrieUpdates, D::Error>
1372 where
1373 D: Deserializer<'de>,
1374 {
1375 TrieUpdates::deserialize(deserializer).map(Into::into)
1376 }
1377 }
1378
1379 #[derive(Debug, Serialize, Deserialize)]
1395 pub struct StorageTrieUpdates<'a> {
1396 storage_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
1397 removed_nodes: Cow<'a, HashSet<Nibbles>>,
1398 }
1399
1400 impl<'a> From<&'a super::StorageTrieUpdates> for StorageTrieUpdates<'a> {
1401 fn from(value: &'a super::StorageTrieUpdates) -> Self {
1402 Self {
1403 storage_nodes: Cow::Borrowed(&value.storage_nodes),
1404 removed_nodes: Cow::Borrowed(&value.removed_nodes),
1405 }
1406 }
1407 }
1408
1409 impl<'a> From<StorageTrieUpdates<'a>> for super::StorageTrieUpdates {
1410 fn from(value: StorageTrieUpdates<'a>) -> Self {
1411 Self {
1412 storage_nodes: value.storage_nodes.into_owned(),
1413 removed_nodes: value.removed_nodes.into_owned(),
1414 }
1415 }
1416 }
1417
1418 impl SerializeAs<super::StorageTrieUpdates> for StorageTrieUpdates<'_> {
1419 fn serialize_as<S>(
1420 source: &super::StorageTrieUpdates,
1421 serializer: S,
1422 ) -> Result<S::Ok, S::Error>
1423 where
1424 S: Serializer,
1425 {
1426 StorageTrieUpdates::from(source).serialize(serializer)
1427 }
1428 }
1429
1430 impl<'de> DeserializeAs<'de, super::StorageTrieUpdates> for StorageTrieUpdates<'de> {
1431 fn deserialize_as<D>(deserializer: D) -> Result<super::StorageTrieUpdates, D::Error>
1432 where
1433 D: Deserializer<'de>,
1434 {
1435 StorageTrieUpdates::deserialize(deserializer).map(Into::into)
1436 }
1437 }
1438
1439 #[derive(Debug, Serialize, Deserialize)]
1455 pub struct TrieUpdatesSorted<'a> {
1456 account_nodes: Cow<'a, [(Nibbles, Option<BranchNodeCompact>)]>,
1457 storage_tries: B256Map<StorageTrieUpdatesSorted<'a>>,
1458 }
1459
1460 impl<'a> From<&'a super::TrieUpdatesSorted> for TrieUpdatesSorted<'a> {
1461 fn from(value: &'a super::TrieUpdatesSorted) -> Self {
1462 Self {
1463 account_nodes: Cow::Borrowed(&value.account_nodes),
1464 storage_tries: value.storage_tries.iter().map(|(k, v)| (*k, v.into())).collect(),
1465 }
1466 }
1467 }
1468
1469 impl<'a> From<TrieUpdatesSorted<'a>> for super::TrieUpdatesSorted {
1470 fn from(value: TrieUpdatesSorted<'a>) -> Self {
1471 Self {
1472 account_nodes: value.account_nodes.into_owned(),
1473 storage_tries: value
1474 .storage_tries
1475 .into_iter()
1476 .map(|(k, v)| (k, v.into()))
1477 .collect(),
1478 }
1479 }
1480 }
1481
1482 impl SerializeAs<super::TrieUpdatesSorted> for TrieUpdatesSorted<'_> {
1483 fn serialize_as<S>(
1484 source: &super::TrieUpdatesSorted,
1485 serializer: S,
1486 ) -> Result<S::Ok, S::Error>
1487 where
1488 S: Serializer,
1489 {
1490 TrieUpdatesSorted::from(source).serialize(serializer)
1491 }
1492 }
1493
1494 impl<'de> DeserializeAs<'de, super::TrieUpdatesSorted> for TrieUpdatesSorted<'de> {
1495 fn deserialize_as<D>(deserializer: D) -> Result<super::TrieUpdatesSorted, D::Error>
1496 where
1497 D: Deserializer<'de>,
1498 {
1499 TrieUpdatesSorted::deserialize(deserializer).map(Into::into)
1500 }
1501 }
1502
1503 #[derive(Debug, Serialize)]
1519 pub struct StorageTrieUpdatesSorted<'a> {
1520 storage_nodes: Cow<'a, [(Nibbles, Option<BranchNodeCompact>)]>,
1521 }
1522
1523 impl<'de, 'a> Deserialize<'de> for StorageTrieUpdatesSorted<'a> {
1524 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1525 where
1526 D: Deserializer<'de>,
1527 {
1528 struct StorageTrieUpdatesSortedVisitor;
1529
1530 impl<'de> Visitor<'de> for StorageTrieUpdatesSortedVisitor {
1531 type Value = Vec<(Nibbles, Option<BranchNodeCompact>)>;
1532
1533 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1534 formatter.write_str("storage trie updates with an optional legacy wipe marker")
1535 }
1536
1537 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1538 where
1539 A: SeqAccess<'de>,
1540 {
1541 let len = seq.size_hint().unwrap_or_default();
1542 let storage_nodes = match len {
1543 1 => {
1544 seq.next_element()?.ok_or_else(|| A::Error::invalid_length(0, &self))?
1545 }
1546 2 => {
1547 let _: bool = seq
1548 .next_element()?
1549 .ok_or_else(|| A::Error::invalid_length(0, &self))?;
1550 seq.next_element()?.ok_or_else(|| A::Error::invalid_length(1, &self))?
1551 }
1552 _ => return Err(A::Error::invalid_length(len, &self)),
1553 };
1554
1555 Ok(storage_nodes)
1556 }
1557 }
1558
1559 deserializer
1562 .deserialize_tuple(1, StorageTrieUpdatesSortedVisitor)
1563 .map(|storage_nodes| Self { storage_nodes: Cow::Owned(storage_nodes) })
1564 }
1565 }
1566
1567 impl<'a> From<&'a super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'a> {
1568 fn from(value: &'a super::StorageTrieUpdatesSorted) -> Self {
1569 Self { storage_nodes: Cow::Borrowed(&value.storage_nodes) }
1570 }
1571 }
1572
1573 impl<'a> From<StorageTrieUpdatesSorted<'a>> for super::StorageTrieUpdatesSorted {
1574 fn from(value: StorageTrieUpdatesSorted<'a>) -> Self {
1575 Self { storage_nodes: value.storage_nodes.into_owned() }
1576 }
1577 }
1578
1579 impl SerializeAs<super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'_> {
1580 fn serialize_as<S>(
1581 source: &super::StorageTrieUpdatesSorted,
1582 serializer: S,
1583 ) -> Result<S::Ok, S::Error>
1584 where
1585 S: Serializer,
1586 {
1587 StorageTrieUpdatesSorted::from(source).serialize(serializer)
1588 }
1589 }
1590
1591 impl<'de> DeserializeAs<'de, super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'de> {
1592 fn deserialize_as<D>(deserializer: D) -> Result<super::StorageTrieUpdatesSorted, D::Error>
1593 where
1594 D: Deserializer<'de>,
1595 {
1596 StorageTrieUpdatesSorted::deserialize(deserializer).map(Into::into)
1597 }
1598 }
1599
1600 #[cfg(test)]
1601 mod tests {
1602 use crate::{
1603 serde_bincode_compat,
1604 updates::{
1605 StorageTrieUpdates, StorageTrieUpdatesSorted, TrieUpdates, TrieUpdatesSorted,
1606 },
1607 BranchNodeCompact, Nibbles,
1608 };
1609 use alloy_primitives::B256;
1610 use serde::{Deserialize, Serialize};
1611 use serde_with::serde_as;
1612
1613 #[test]
1614 fn test_trie_updates_bincode_roundtrip() {
1615 #[serde_as]
1616 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1617 struct Data {
1618 #[serde_as(as = "serde_bincode_compat::updates::TrieUpdates")]
1619 trie_updates: TrieUpdates,
1620 }
1621
1622 let mut data = Data { trie_updates: TrieUpdates::default() };
1623 let encoded = bincode::serialize(&data).unwrap();
1624 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1625 assert_eq!(decoded, data);
1626
1627 data.trie_updates
1628 .removed_nodes
1629 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1630 let encoded = bincode::serialize(&data).unwrap();
1631 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1632 assert_eq!(decoded, data);
1633
1634 data.trie_updates.account_nodes.insert(
1635 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1636 BranchNodeCompact::default(),
1637 );
1638 let encoded = bincode::serialize(&data).unwrap();
1639 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1640 assert_eq!(decoded, data);
1641
1642 data.trie_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
1643 let encoded = bincode::serialize(&data).unwrap();
1644 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1645 assert_eq!(decoded, data);
1646 }
1647
1648 #[test]
1649 fn test_storage_trie_updates_bincode_roundtrip() {
1650 #[serde_as]
1651 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1652 struct Data {
1653 #[serde_as(as = "serde_bincode_compat::updates::StorageTrieUpdates")]
1654 trie_updates: StorageTrieUpdates,
1655 }
1656
1657 let mut data = Data { trie_updates: StorageTrieUpdates::default() };
1658 let encoded = bincode::serialize(&data).unwrap();
1659 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1660 assert_eq!(decoded, data);
1661
1662 data.trie_updates
1663 .removed_nodes
1664 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1665 let encoded = bincode::serialize(&data).unwrap();
1666 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1667 assert_eq!(decoded, data);
1668
1669 data.trie_updates.storage_nodes.insert(
1670 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1671 BranchNodeCompact::default(),
1672 );
1673 let encoded = bincode::serialize(&data).unwrap();
1674 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1675 assert_eq!(decoded, data);
1676 }
1677
1678 #[test]
1679 fn test_trie_updates_sorted_bincode_roundtrip() {
1680 #[serde_as]
1681 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1682 struct Data {
1683 #[serde_as(as = "serde_bincode_compat::updates::TrieUpdatesSorted")]
1684 trie_updates: TrieUpdatesSorted,
1685 }
1686
1687 let mut data = Data { trie_updates: TrieUpdatesSorted::default() };
1688 let encoded = bincode::serialize(&data).unwrap();
1689 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1690 assert_eq!(decoded, data);
1691
1692 data.trie_updates.account_nodes.push((
1693 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1694 Some(BranchNodeCompact::default()),
1695 ));
1696 let encoded = bincode::serialize(&data).unwrap();
1697 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1698 assert_eq!(decoded, data);
1699
1700 data.trie_updates
1701 .account_nodes
1702 .push((Nibbles::from_nibbles_unchecked([0x0f, 0x0f, 0x0f, 0x0f]), None));
1703 let encoded = bincode::serialize(&data).unwrap();
1704 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1705 assert_eq!(decoded, data);
1706
1707 data.trie_updates
1708 .storage_tries
1709 .insert(B256::default(), StorageTrieUpdatesSorted::default());
1710 let encoded = bincode::serialize(&data).unwrap();
1711 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1712 assert_eq!(decoded, data);
1713 }
1714
1715 #[test]
1716 fn test_storage_trie_updates_sorted_bincode_roundtrip() {
1717 #[serde_as]
1718 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1719 struct Data {
1720 #[serde_as(as = "serde_bincode_compat::updates::StorageTrieUpdatesSorted")]
1721 trie_updates: StorageTrieUpdatesSorted,
1722 }
1723
1724 let mut data = Data { trie_updates: StorageTrieUpdatesSorted::default() };
1725 let encoded = bincode::serialize(&data).unwrap();
1726 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1727 assert_eq!(decoded, data);
1728
1729 data.trie_updates.storage_nodes.push((
1730 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1731 Some(BranchNodeCompact::default()),
1732 ));
1733 let encoded = bincode::serialize(&data).unwrap();
1734 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1735 assert_eq!(decoded, data);
1736
1737 data.trie_updates
1738 .storage_nodes
1739 .push((Nibbles::from_nibbles_unchecked([0x0a, 0x0a, 0x0a, 0x0a]), None));
1740 let encoded = bincode::serialize(&data).unwrap();
1741 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1742 assert_eq!(decoded, data);
1743 }
1744 }
1745}
1746
1747#[cfg(all(test, feature = "serde"))]
1748mod serde_tests {
1749 use super::*;
1750
1751 #[test]
1752 fn test_trie_updates_serde_roundtrip() {
1753 let mut default_updates = TrieUpdates::default();
1754 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1755 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1756 assert_eq!(updates_deserialized, default_updates);
1757
1758 default_updates
1759 .removed_nodes
1760 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1761 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1762 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1763 assert_eq!(updates_deserialized, default_updates);
1764
1765 default_updates.account_nodes.insert(
1766 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1767 BranchNodeCompact::default(),
1768 );
1769 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1770 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1771 assert_eq!(updates_deserialized, default_updates);
1772
1773 default_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
1774 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1775 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1776 assert_eq!(updates_deserialized, default_updates);
1777 }
1778
1779 #[test]
1780 fn test_storage_trie_updates_serde_roundtrip() {
1781 let mut default_updates = StorageTrieUpdates::default();
1782 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1783 let updates_deserialized: StorageTrieUpdates =
1784 serde_json::from_str(&updates_serialized).unwrap();
1785 assert_eq!(updates_deserialized, default_updates);
1786
1787 default_updates
1788 .removed_nodes
1789 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1790 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1791 let updates_deserialized: StorageTrieUpdates =
1792 serde_json::from_str(&updates_serialized).unwrap();
1793 assert_eq!(updates_deserialized, default_updates);
1794
1795 default_updates.storage_nodes.insert(
1796 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1797 BranchNodeCompact::default(),
1798 );
1799 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1800 let updates_deserialized: StorageTrieUpdates =
1801 serde_json::from_str(&updates_serialized).unwrap();
1802 assert_eq!(updates_deserialized, default_updates);
1803 }
1804}