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 into_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
218 .storage_tries
219 .iter()
220 .map(|m| (*m.0, m.1.into_sorted_ref()))
221 .collect(),
222 }
223 }
224
225 pub fn clear(&mut self) {
227 self.account_nodes.clear();
228 self.removed_nodes.clear();
229 self.storage_tries.clear();
230 }
231}
232
233#[derive(PartialEq, Eq, Clone, Default, Debug)]
235#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
236pub struct StorageTrieUpdates {
237 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_map"))]
239 pub storage_nodes: HashMap<Nibbles, BranchNodeCompact>,
240 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_set"))]
242 pub removed_nodes: HashSet<Nibbles>,
243}
244
245#[cfg(feature = "test-utils")]
246impl StorageTrieUpdates {
247 pub fn new(updates: impl IntoIterator<Item = (Nibbles, BranchNodeCompact)>) -> Self {
249 Self { storage_nodes: exclude_empty_from_pair(updates).collect(), ..Default::default() }
250 }
251}
252
253impl StorageTrieUpdates {
254 pub fn len(&self) -> usize {
256 self.storage_nodes.len() + self.removed_nodes.len()
257 }
258
259 pub const fn storage_nodes_ref(&self) -> &HashMap<Nibbles, BranchNodeCompact> {
261 &self.storage_nodes
262 }
263
264 pub const fn removed_nodes_ref(&self) -> &HashSet<Nibbles> {
266 &self.removed_nodes
267 }
268
269 pub fn is_empty(&self) -> bool {
271 self.storage_nodes.is_empty() && self.removed_nodes.is_empty()
272 }
273
274 pub fn extend(&mut self, other: Self) {
276 self.extend_common(&other);
277 self.storage_nodes.extend(exclude_empty_from_pair(other.storage_nodes));
278 self.removed_nodes.extend(exclude_empty(other.removed_nodes));
279 }
280
281 pub fn extend_ref(&mut self, other: &Self) {
285 self.extend_common(other);
286 self.storage_nodes.extend(exclude_empty_from_pair(
287 other.storage_nodes.iter().map(|(k, v)| (*k, v.clone())),
288 ));
289 self.removed_nodes.extend(exclude_empty(other.removed_nodes.iter().copied()));
290 }
291
292 fn extend_common(&mut self, other: &Self) {
293 self.storage_nodes.retain(|nibbles, _| !other.removed_nodes.contains(nibbles));
294 }
295
296 pub fn extend_from_sorted(&mut self, sorted: &StorageTrieUpdatesSorted) {
303 let new_nodes_count = sorted.storage_nodes.len();
305 self.storage_nodes.reserve(new_nodes_count);
306
307 for (nibbles, maybe_node) in &sorted.storage_nodes {
309 if nibbles.is_empty() {
310 continue;
311 }
312 if let Some(node) = maybe_node {
313 self.removed_nodes.remove(nibbles);
314 self.storage_nodes.insert(*nibbles, node.clone());
315 } else {
316 self.storage_nodes.remove(nibbles);
317 self.removed_nodes.insert(*nibbles);
318 }
319 }
320 }
321
322 pub fn finalize(&mut self, hash_builder: HashBuilder, removed_keys: HashSet<Nibbles>) {
324 let (_, updated_nodes) = hash_builder.split();
326 self.storage_nodes.extend(exclude_empty_from_pair(updated_nodes));
327
328 self.removed_nodes.extend(exclude_empty(removed_keys));
330 }
331
332 pub fn into_sorted(mut self) -> StorageTrieUpdatesSorted {
334 let mut storage_nodes = self
335 .storage_nodes
336 .into_iter()
337 .map(|(path, node)| {
338 self.removed_nodes.remove(&path);
340 (path, Some(node))
341 })
342 .collect::<Vec<_>>();
343
344 storage_nodes.extend(self.removed_nodes.into_iter().map(|path| (path, None)));
345 storage_nodes.sort_unstable_by_key(|a| a.0);
346
347 StorageTrieUpdatesSorted { storage_nodes }
348 }
349
350 pub fn clone_into_sorted(&self) -> StorageTrieUpdatesSorted {
353 let mut storage_nodes = self
354 .storage_nodes
355 .iter()
356 .map(|(path, node)| (*path, Some(node.clone())))
357 .collect::<Vec<_>>();
358
359 storage_nodes.extend(
361 self.removed_nodes
362 .iter()
363 .filter(|path| !self.storage_nodes.contains_key(*path))
364 .map(|path| (*path, None)),
365 );
366 storage_nodes.sort_unstable_by_key(|a| a.0);
367
368 StorageTrieUpdatesSorted { storage_nodes }
369 }
370
371 pub fn into_sorted_ref(&self) -> StorageTrieUpdatesSortedRef<'_> {
373 StorageTrieUpdatesSortedRef {
374 removed_nodes: self.removed_nodes.iter().collect::<BTreeSet<_>>(),
375 storage_nodes: self.storage_nodes.iter().collect::<BTreeMap<_, _>>(),
376 }
377 }
378}
379
380#[cfg(any(test, feature = "serde"))]
385mod serde_nibbles_set {
386 use crate::Nibbles;
387 use alloc::{
388 string::{String, ToString},
389 vec::Vec,
390 };
391 use alloy_primitives::map::HashSet;
392 use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
393
394 pub(super) fn serialize<S>(map: &HashSet<Nibbles>, serializer: S) -> Result<S::Ok, S::Error>
395 where
396 S: Serializer,
397 {
398 let mut storage_nodes =
399 map.iter().map(|elem| alloy_primitives::hex::encode(elem.pack())).collect::<Vec<_>>();
400 storage_nodes.sort_unstable();
401 storage_nodes.serialize(serializer)
402 }
403
404 pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<HashSet<Nibbles>, D::Error>
405 where
406 D: Deserializer<'de>,
407 {
408 Vec::<String>::deserialize(deserializer)?
409 .into_iter()
410 .map(|node| {
411 Ok(Nibbles::unpack(
412 alloy_primitives::hex::decode(node)
413 .map_err(|err| D::Error::custom(err.to_string()))?,
414 ))
415 })
416 .collect::<Result<HashSet<_>, _>>()
417 }
418}
419
420#[cfg(any(test, feature = "serde"))]
425mod serde_nibbles_map {
426 use crate::Nibbles;
427 use alloc::{
428 string::{String, ToString},
429 vec::Vec,
430 };
431 use alloy_primitives::{hex, map::HashMap};
432 use core::marker::PhantomData;
433 use serde::{
434 de::{Error, MapAccess, Visitor},
435 ser::SerializeMap,
436 Deserialize, Deserializer, Serialize, Serializer,
437 };
438
439 pub(super) fn serialize<S, T>(
440 map: &HashMap<Nibbles, T>,
441 serializer: S,
442 ) -> Result<S::Ok, S::Error>
443 where
444 S: Serializer,
445 T: Serialize,
446 {
447 let mut map_serializer = serializer.serialize_map(Some(map.len()))?;
448 let mut storage_nodes = Vec::from_iter(map);
449 storage_nodes.sort_unstable_by_key(|node| node.0);
450 for (k, v) in storage_nodes {
451 let packed = alloy_primitives::hex::encode(k.pack());
453 map_serializer.serialize_entry(&packed, &v)?;
454 }
455 map_serializer.end()
456 }
457
458 pub(super) fn deserialize<'de, D, T>(deserializer: D) -> Result<HashMap<Nibbles, T>, D::Error>
459 where
460 D: Deserializer<'de>,
461 T: Deserialize<'de>,
462 {
463 struct NibblesMapVisitor<T> {
464 marker: PhantomData<T>,
465 }
466
467 impl<'de, T> Visitor<'de> for NibblesMapVisitor<T>
468 where
469 T: Deserialize<'de>,
470 {
471 type Value = HashMap<Nibbles, T>;
472
473 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
474 formatter.write_str("a map with hex-encoded Nibbles keys")
475 }
476
477 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
478 where
479 A: MapAccess<'de>,
480 {
481 let mut result = HashMap::with_capacity_and_hasher(
482 map.size_hint().unwrap_or(0),
483 Default::default(),
484 );
485
486 while let Some((key, value)) = map.next_entry::<String, T>()? {
487 let decoded_key =
488 hex::decode(&key).map_err(|err| Error::custom(err.to_string()))?;
489
490 let nibbles = Nibbles::unpack(&decoded_key);
491
492 result.insert(nibbles, value);
493 }
494
495 Ok(result)
496 }
497 }
498
499 deserializer.deserialize_map(NibblesMapVisitor { marker: PhantomData })
500 }
501}
502
503#[derive(PartialEq, Eq, Clone, Default, Debug)]
505#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
506pub struct TrieUpdatesSortedRef<'a> {
507 pub account_nodes: Vec<(&'a Nibbles, &'a BranchNodeCompact)>,
509 pub removed_nodes: BTreeSet<&'a Nibbles>,
511 pub storage_tries: BTreeMap<FixedBytes<32>, StorageTrieUpdatesSortedRef<'a>>,
513}
514
515#[derive(PartialEq, Eq, Clone, Default, Debug)]
517#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
518pub struct TrieUpdatesSorted {
519 account_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
522 storage_tries: B256Map<StorageTrieUpdatesSorted>,
524}
525
526impl TrieUpdatesSorted {
527 pub fn new(
534 account_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
535 storage_tries: B256Map<StorageTrieUpdatesSorted>,
536 ) -> Self {
537 debug_assert!(
538 account_nodes.is_sorted_by_key(|item| &item.0),
539 "account_nodes must be sorted by Nibbles key"
540 );
541 debug_assert!(
542 storage_tries.values().all(|storage_trie| {
543 storage_trie.storage_nodes.is_sorted_by_key(|item| &item.0)
544 }),
545 "all storage_nodes in storage_tries must be sorted by Nibbles key"
546 );
547 Self { account_nodes, storage_tries }
548 }
549
550 pub fn is_empty(&self) -> bool {
552 self.account_nodes.is_empty() && self.storage_tries.is_empty()
553 }
554
555 pub fn account_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
557 &self.account_nodes
558 }
559
560 pub const fn storage_tries_ref(&self) -> &B256Map<StorageTrieUpdatesSorted> {
562 &self.storage_tries
563 }
564
565 pub fn total_len(&self) -> usize {
567 self.account_nodes.len() +
568 self.storage_tries.values().map(|storage| storage.len()).sum::<usize>()
569 }
570
571 pub fn extend_ref_and_sort(&mut self, other: &Self) {
580 extend_sorted_vec(&mut self.account_nodes, &other.account_nodes);
582
583 for (hashed_address, storage_trie) in &other.storage_tries {
585 self.storage_tries
586 .entry(*hashed_address)
587 .and_modify(|existing| existing.extend_ref(storage_trie))
588 .or_insert_with(|| storage_trie.clone());
589 }
590 }
591
592 pub fn clear(&mut self) {
594 self.account_nodes.clear();
595 self.storage_tries.clear();
596 }
597
598 pub fn merge_batch<T: AsRef<Self> + From<Self>>(iter: impl IntoIterator<Item = T>) -> T {
603 let items: alloc::vec::Vec<_> = iter.into_iter().collect();
604 match items.len() {
605 0 => Self::default().into(),
606 1 => items.into_iter().next().expect("len == 1"),
607 _ => Self::merge_slice(&items).into(),
608 }
609 }
610
611 pub fn merge_slice<T: AsRef<Self>>(items: &[T]) -> Self {
617 const THRESHOLD: usize = 30;
618
619 let k = items.len();
620
621 if k == 0 {
622 return Self::default();
623 }
624 if k == 1 {
625 return items[0].as_ref().clone();
626 }
627
628 if k < THRESHOLD {
629 let mut iter = items.iter().rev();
631 let mut acc = iter.next().expect("k > 0").as_ref().clone();
632 for next in iter {
633 acc.extend_ref_and_sort(next.as_ref());
634 }
635 return acc;
636 }
637
638 let account_nodes =
640 kway_merge_sorted(items.iter().map(|i| i.as_ref().account_nodes.as_slice()));
641
642 struct StorageAcc<'a> {
643 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
644 }
645
646 let mut acc: B256Map<StorageAcc<'_>> = B256Map::default();
647
648 for item in items {
649 for (addr, storage) in &item.as_ref().storage_tries {
650 let entry = acc.entry(*addr).or_insert_with(|| StorageAcc { slices: Vec::new() });
651 entry.slices.push(storage.storage_nodes.as_slice());
652 }
653 }
654
655 let storage_tries = acc
656 .into_iter()
657 .map(|(addr, entry)| {
658 let storage_nodes = kway_merge_sorted(entry.slices);
659 (addr, StorageTrieUpdatesSorted { storage_nodes })
660 })
661 .collect();
662
663 Self { account_nodes, storage_tries }
664 }
665
666 pub fn disjointed_merge_batch<'a>(batch: &[&'a Self], mask: &[&'a Self]) -> Self {
674 let account_node_count = batch.iter().map(|item| item.account_nodes.len()).sum();
675 let mut account_nodes = Vec::with_capacity(account_node_count);
676 account_nodes.extend(kway_merge_disjoint_sorted(
677 batch.iter().rev().map(|item| item.account_nodes.as_slice()),
678 mask.iter().map(|item| item.account_nodes.as_slice()),
679 ));
680
681 struct StorageAcc<'a> {
682 node_count: usize,
683 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
684 }
685
686 #[derive(Default)]
687 struct StorageMaskAcc<'a> {
688 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
689 }
690
691 let mut storage_tries = B256Map::with_capacity_and_hasher(
692 batch.iter().map(|item| item.storage_tries.len()).sum(),
693 Default::default(),
694 );
695
696 for item in batch.iter().rev() {
697 for (hashed_address, storage_trie) in &item.storage_tries {
698 let entry = storage_tries
699 .entry(*hashed_address)
700 .or_insert_with(|| StorageAcc { node_count: 0, slices: Vec::new() });
701 entry.slices.push(storage_trie.storage_nodes.as_slice());
702 entry.node_count += storage_trie.storage_nodes.len();
703 }
704 }
705
706 let mut storage_masks: B256Map<StorageMaskAcc<'a>> = B256Map::with_capacity_and_hasher(
707 mask.iter().map(|item| item.storage_tries.len()).sum(),
708 Default::default(),
709 );
710 for item in mask {
711 for (hashed_address, storage_trie) in &item.storage_tries {
712 let entry = storage_masks.entry(*hashed_address).or_default();
713 entry.slices.push(storage_trie.storage_nodes.as_slice());
714 }
715 }
716
717 let storage_tries = storage_tries
718 .into_iter()
719 .filter_map(|(hashed_address, entry)| {
720 let node_count = entry.node_count;
721 let storage_nodes = match storage_masks.get(&hashed_address) {
722 Some(mask_entry) => {
723 let mut storage_nodes = Vec::with_capacity(node_count);
724 storage_nodes.extend(kway_merge_disjoint_sorted(
725 entry.slices,
726 mask_entry.slices.iter().copied(),
727 ));
728 storage_nodes
729 }
730 None => kway_merge_sorted(entry.slices),
731 };
732
733 (!storage_nodes.is_empty() || mask.is_empty())
734 .then_some((hashed_address, StorageTrieUpdatesSorted { storage_nodes }))
735 })
736 .collect();
737
738 Self::new(account_nodes, storage_tries)
739 }
740}
741
742impl AsRef<Self> for TrieUpdatesSorted {
743 fn as_ref(&self) -> &Self {
744 self
745 }
746}
747
748impl From<TrieUpdatesSorted> for TrieUpdates {
749 fn from(sorted: TrieUpdatesSorted) -> Self {
750 let mut account_nodes = HashMap::default();
751 let mut removed_nodes = HashSet::default();
752
753 for (nibbles, node) in sorted.account_nodes {
754 if let Some(node) = node {
755 account_nodes.insert(nibbles, node);
756 } else {
757 removed_nodes.insert(nibbles);
758 }
759 }
760
761 let storage_tries = sorted
762 .storage_tries
763 .into_iter()
764 .map(|(address, storage)| (address, storage.into()))
765 .collect();
766
767 Self { account_nodes, removed_nodes, storage_tries }
768 }
769}
770
771#[derive(PartialEq, Eq, Clone, Default, Debug)]
773#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
774pub struct StorageTrieUpdatesSortedRef<'a> {
775 pub storage_nodes: BTreeMap<&'a Nibbles, &'a BranchNodeCompact>,
777 pub removed_nodes: BTreeSet<&'a Nibbles>,
779}
780
781#[derive(PartialEq, Eq, Clone, Default, Debug)]
783#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
784pub struct StorageTrieUpdatesSorted {
785 pub storage_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
788}
789
790impl StorageTrieUpdatesSorted {
791 pub fn storage_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
793 &self.storage_nodes
794 }
795
796 pub const fn len(&self) -> usize {
798 self.storage_nodes.len()
799 }
800
801 pub const fn is_empty(&self) -> bool {
803 self.storage_nodes.is_empty()
804 }
805
806 pub fn extend_ref(&mut self, other: &Self) {
808 extend_sorted_vec(&mut self.storage_nodes, &other.storage_nodes);
809 }
810
811 pub fn merge_batch<'a>(updates: impl IntoIterator<Item = &'a Self>) -> Self {
813 let updates: Vec<_> = updates.into_iter().collect();
814 Self {
815 storage_nodes: kway_merge_sorted(updates.iter().map(|u| u.storage_nodes.as_slice())),
816 }
817 }
818}
819
820fn exclude_empty(iter: impl IntoIterator<Item = Nibbles>) -> impl Iterator<Item = Nibbles> {
822 iter.into_iter().filter(|n| !n.is_empty())
823}
824
825fn exclude_empty_from_pair<V>(
827 iter: impl IntoIterator<Item = (Nibbles, V)>,
828) -> impl Iterator<Item = (Nibbles, V)> {
829 iter.into_iter().filter(|(n, _)| !n.is_empty())
830}
831
832impl From<StorageTrieUpdatesSorted> for StorageTrieUpdates {
833 fn from(sorted: StorageTrieUpdatesSorted) -> Self {
834 let mut storage_nodes = HashMap::default();
835 let mut removed_nodes = HashSet::default();
836
837 for (nibbles, node) in sorted.storage_nodes {
838 if let Some(node) = node {
839 storage_nodes.insert(nibbles, node);
840 } else {
841 removed_nodes.insert(nibbles);
842 }
843 }
844
845 Self { storage_nodes, removed_nodes }
846 }
847}
848
849#[cfg(test)]
850mod tests {
851 use super::*;
852 use alloy_primitives::B256;
853
854 #[test]
855 fn test_finalize_keeps_storage_updates_after_destroyed_node_removal() {
856 let hashed_address = B256::with_last_byte(1);
857 let path = Nibbles::from_nibbles_unchecked([0x01]);
858 let node = BranchNodeCompact::default();
859 let mut updates = TrieUpdates {
860 storage_tries: B256Map::from_iter([(
861 hashed_address,
862 StorageTrieUpdates {
863 storage_nodes: HashMap::from_iter([(path, node.clone())]),
864 ..Default::default()
865 },
866 )]),
867 ..Default::default()
868 };
869
870 updates.finalize(
871 HashBuilder::default(),
872 Default::default(),
873 B256Map::from_iter([(hashed_address, vec![path])]),
874 );
875
876 assert_eq!(
877 updates.into_sorted().storage_tries[&hashed_address].storage_nodes,
878 vec![(path, Some(node))]
879 );
880 }
881
882 #[test]
883 fn test_trie_updates_sorted_extend_ref() {
884 let mut updates1 = TrieUpdatesSorted::default();
886 let updates2 = TrieUpdatesSorted::default();
887 updates1.extend_ref_and_sort(&updates2);
888 assert_eq!(updates1.account_nodes.len(), 0);
889 assert_eq!(updates1.storage_tries.len(), 0);
890
891 let mut updates1 = TrieUpdatesSorted {
893 account_nodes: vec![
894 (Nibbles::from_nibbles_unchecked([0x01]), Some(BranchNodeCompact::default())),
895 (Nibbles::from_nibbles_unchecked([0x03]), None),
896 ],
897 storage_tries: B256Map::default(),
898 };
899 let updates2 = TrieUpdatesSorted {
900 account_nodes: vec![
901 (Nibbles::from_nibbles_unchecked([0x02]), Some(BranchNodeCompact::default())),
902 (Nibbles::from_nibbles_unchecked([0x03]), Some(BranchNodeCompact::default())), ],
904 storage_tries: B256Map::default(),
905 };
906 updates1.extend_ref_and_sort(&updates2);
907 assert_eq!(updates1.account_nodes.len(), 3);
908 assert_eq!(updates1.account_nodes[0].0, Nibbles::from_nibbles_unchecked([0x01]));
910 assert_eq!(updates1.account_nodes[1].0, Nibbles::from_nibbles_unchecked([0x02]));
911 assert_eq!(updates1.account_nodes[2].0, Nibbles::from_nibbles_unchecked([0x03]));
912 assert!(updates1.account_nodes[2].1.is_some());
914
915 let storage_trie1 = StorageTrieUpdatesSorted {
917 storage_nodes: vec![(
918 Nibbles::from_nibbles_unchecked([0x0a]),
919 Some(BranchNodeCompact::default()),
920 )],
921 };
922 let storage_trie2 = StorageTrieUpdatesSorted {
923 storage_nodes: vec![(Nibbles::from_nibbles_unchecked([0x0b]), None)],
924 };
925
926 let hashed_address1 = B256::from([1; 32]);
927 let hashed_address2 = B256::from([2; 32]);
928
929 let mut updates1 = TrieUpdatesSorted {
930 account_nodes: vec![],
931 storage_tries: B256Map::from_iter([(hashed_address1, storage_trie1.clone())]),
932 };
933 let updates2 = TrieUpdatesSorted {
934 account_nodes: vec![],
935 storage_tries: B256Map::from_iter([
936 (hashed_address1, storage_trie2),
937 (hashed_address2, storage_trie1),
938 ]),
939 };
940 updates1.extend_ref_and_sort(&updates2);
941 assert_eq!(updates1.storage_tries.len(), 2);
942 assert!(updates1.storage_tries.contains_key(&hashed_address1));
943 assert!(updates1.storage_tries.contains_key(&hashed_address2));
944 let merged_storage = &updates1.storage_tries[&hashed_address1];
946 assert_eq!(merged_storage.storage_nodes.len(), 2);
947 }
948
949 #[test]
950 fn test_trie_updates_sorted_disjointed_merge_batch() {
951 let kept_node = Nibbles::from_nibbles_unchecked([0x01]);
952 let removed_node = Nibbles::from_nibbles_unchecked([0x02]);
953 let kept_storage = B256::from([3; 32]);
954 let slot1 = Nibbles::from_nibbles_unchecked([0x0a]);
955 let slot2 = Nibbles::from_nibbles_unchecked([0x0b]);
956
957 let older = TrieUpdatesSorted::new(
958 vec![(kept_node, Some(BranchNodeCompact::default())), (removed_node, None)],
959 B256Map::from_iter([(
960 kept_storage,
961 StorageTrieUpdatesSorted { storage_nodes: vec![(slot1, None)] },
962 )]),
963 );
964
965 let newer = TrieUpdatesSorted::new(
966 vec![(kept_node, None)],
967 B256Map::from_iter([(
968 kept_storage,
969 StorageTrieUpdatesSorted {
970 storage_nodes: vec![(slot1, Some(BranchNodeCompact::default())), (slot2, None)],
971 },
972 )]),
973 );
974
975 let remove_a = TrieUpdatesSorted::new(
976 vec![(removed_node, Some(BranchNodeCompact::default()))],
977 B256Map::from_iter([(
978 kept_storage,
979 StorageTrieUpdatesSorted {
980 storage_nodes: vec![(slot2, Some(BranchNodeCompact::default()))],
981 },
982 )]),
983 );
984
985 let remove_b = TrieUpdatesSorted::new(
986 vec![(Nibbles::from_nibbles_unchecked([0x0f]), Some(BranchNodeCompact::default()))],
987 B256Map::default(),
988 );
989
990 let result =
991 TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[&remove_b, &remove_a]);
992
993 assert_eq!(result.account_nodes, vec![(kept_node, None)]);
994 assert_eq!(result.storage_tries.len(), 1);
995 assert_eq!(
996 result.storage_tries.get(&kept_storage),
997 Some(&StorageTrieUpdatesSorted {
998 storage_nodes: vec![(slot1, Some(BranchNodeCompact::default()))],
999 })
1000 );
1001 }
1002
1003 #[test]
1004 fn test_trie_updates_sorted_disjointed_merge_batch_empty_mask_merges_batch() {
1005 let node = Nibbles::from_nibbles_unchecked([0x01]);
1006 let storage = B256::with_last_byte(2);
1007 let storage_node = Nibbles::from_nibbles_unchecked([0x03]);
1008 let empty_storage = B256::with_last_byte(4);
1009 let older = TrieUpdatesSorted::new(
1010 vec![(node, Some(BranchNodeCompact::default()))],
1011 B256Map::from_iter([
1012 (storage, StorageTrieUpdatesSorted { storage_nodes: vec![(storage_node, None)] }),
1013 (empty_storage, StorageTrieUpdatesSorted::default()),
1014 ]),
1015 );
1016 let newer = TrieUpdatesSorted::new(
1017 vec![(node, None)],
1018 B256Map::from_iter([(
1019 storage,
1020 StorageTrieUpdatesSorted {
1021 storage_nodes: vec![(storage_node, Some(BranchNodeCompact::default()))],
1022 },
1023 )]),
1024 );
1025 let expected = TrieUpdatesSorted::merge_batch(vec![newer.clone(), older.clone()]);
1026
1027 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[]);
1028
1029 assert_eq!(result, expected);
1030 }
1031
1032 #[test]
1033 fn test_trie_updates_sorted_disjointed_merge_batch_removes_overlapping_batch_key() {
1034 let overlapping_node = Nibbles::from_nibbles_unchecked([0x03]);
1035
1036 let older = TrieUpdatesSorted::new(
1037 vec![(overlapping_node, Some(BranchNodeCompact::default()))],
1038 B256Map::default(),
1039 );
1040
1041 let newer = TrieUpdatesSorted::new(vec![(overlapping_node, None)], B256Map::default());
1042
1043 let remove = TrieUpdatesSorted::new(
1044 vec![(overlapping_node, Some(BranchNodeCompact::default()))],
1045 B256Map::default(),
1046 );
1047
1048 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[&remove]);
1049
1050 assert!(result.account_nodes.is_empty());
1051 }
1052
1053 #[test]
1054 fn test_trie_updates_sorted_disjointed_merge_batch_keeps_equal_overlaps() {
1055 fn branch(mask: u16) -> BranchNodeCompact {
1056 BranchNodeCompact::new(mask, 0, 0, vec![], None)
1057 }
1058
1059 let node_path = Nibbles::from_nibbles_unchecked([0x03]);
1060 let deleted_node_path = Nibbles::from_nibbles_unchecked([0x04]);
1061 let storage = B256::from([5; 32]);
1062 let deleted_storage = B256::from([6; 32]);
1063 let storage_node_path = Nibbles::from_nibbles_unchecked([0x0c]);
1064 let deleted_storage_node_path = Nibbles::from_nibbles_unchecked([0x0d]);
1065 let batch = TrieUpdatesSorted::new(
1066 vec![(node_path, Some(branch(0b1010_0101))), (deleted_node_path, None)],
1067 B256Map::from_iter([
1068 (
1069 storage,
1070 StorageTrieUpdatesSorted {
1071 storage_nodes: vec![(storage_node_path, Some(branch(0b0011_1100)))],
1072 },
1073 ),
1074 (
1075 deleted_storage,
1076 StorageTrieUpdatesSorted {
1077 storage_nodes: vec![(deleted_storage_node_path, None)],
1078 },
1079 ),
1080 ]),
1081 );
1082 let different_mask = TrieUpdatesSorted::new(
1083 vec![
1084 (node_path, Some(branch(0b0101_1010))),
1085 (deleted_node_path, Some(branch(0b1111_0000))),
1086 ],
1087 B256Map::from_iter([
1088 (
1089 storage,
1090 StorageTrieUpdatesSorted {
1091 storage_nodes: vec![(storage_node_path, Some(branch(0b1100_0011)))],
1092 },
1093 ),
1094 (
1095 deleted_storage,
1096 StorageTrieUpdatesSorted {
1097 storage_nodes: vec![(deleted_storage_node_path, Some(branch(0b0000_1111)))],
1098 },
1099 ),
1100 ]),
1101 );
1102 let equal_mask = batch.clone();
1103
1104 let result =
1105 TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&different_mask, &equal_mask]);
1106 let reversed =
1107 TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&equal_mask, &different_mask]);
1108
1109 assert_eq!(result, batch);
1110 assert_eq!(reversed, result);
1111 }
1112
1113 #[test]
1114 fn test_trie_updates_sorted_disjointed_merge_batch_uses_exact_key_masking() {
1115 let hashed_address = B256::from([7; 32]);
1116 let grandparent = Nibbles::from_nibbles_unchecked([0x05]);
1117 let parent = Nibbles::from_nibbles_unchecked([0x05, 0x04]);
1118 let child = Nibbles::from_nibbles_unchecked([0x05, 0x04, 0x03]);
1119 let different_node = BranchNodeCompact::new(1, 0, 0, vec![], None);
1120
1121 let batch = TrieUpdatesSorted::new(
1122 vec![
1123 (grandparent, Some(BranchNodeCompact::default())),
1124 (parent, Some(BranchNodeCompact::default())),
1125 (child, Some(BranchNodeCompact::default())),
1126 ],
1127 B256Map::from_iter([(
1128 hashed_address,
1129 StorageTrieUpdatesSorted {
1130 storage_nodes: vec![
1131 (grandparent, Some(BranchNodeCompact::default())),
1132 (parent, Some(BranchNodeCompact::default())),
1133 (child, Some(BranchNodeCompact::default())),
1134 ],
1135 },
1136 )]),
1137 );
1138 let mask = TrieUpdatesSorted::new(
1139 vec![
1140 (grandparent, Some(different_node.clone())),
1141 (parent, Some(different_node.clone())),
1142 ],
1143 B256Map::from_iter([(
1144 hashed_address,
1145 StorageTrieUpdatesSorted {
1146 storage_nodes: vec![
1147 (grandparent, Some(different_node.clone())),
1148 (parent, Some(different_node)),
1149 ],
1150 },
1151 )]),
1152 );
1153
1154 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1155
1156 assert_eq!(result.account_nodes, vec![(child, Some(BranchNodeCompact::default()))]);
1157 assert_eq!(
1158 result.storage_tries.get(&hashed_address),
1159 Some(&StorageTrieUpdatesSorted {
1160 storage_nodes: vec![(child, Some(BranchNodeCompact::default()))],
1161 })
1162 );
1163 }
1164
1165 #[test]
1166 fn test_trie_updates_sorted_disjointed_merge_batch_ignores_empty_storage_mask() {
1167 let storage = B256::from([6; 32]);
1168 let slot = Nibbles::from_nibbles_unchecked([0x0d]);
1169
1170 let batch = TrieUpdatesSorted::new(
1171 vec![],
1172 B256Map::from_iter([(
1173 storage,
1174 StorageTrieUpdatesSorted {
1175 storage_nodes: vec![(slot, Some(BranchNodeCompact::default()))],
1176 },
1177 )]),
1178 );
1179 let mask = TrieUpdatesSorted::new(
1180 vec![],
1181 B256Map::from_iter([(storage, StorageTrieUpdatesSorted { storage_nodes: vec![] })]),
1182 );
1183
1184 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1185
1186 assert_eq!(
1187 result.storage_tries.get(&storage),
1188 Some(&StorageTrieUpdatesSorted {
1189 storage_nodes: vec![(slot, Some(BranchNodeCompact::default()))],
1190 })
1191 );
1192 }
1193
1194 #[test]
1196 fn test_trie_updates_extend_from_sorted_with_storage_tries() {
1197 let hashed_address = B256::from([1; 32]);
1198
1199 let mut updates = TrieUpdates::default();
1200
1201 let storage_trie = StorageTrieUpdatesSorted {
1202 storage_nodes: vec![
1203 (Nibbles::from_nibbles_unchecked([0x0a]), Some(BranchNodeCompact::default())),
1204 (Nibbles::from_nibbles_unchecked([0x0b]), None),
1205 ],
1206 };
1207
1208 let sorted = TrieUpdatesSorted {
1209 account_nodes: vec![],
1210 storage_tries: B256Map::from_iter([(hashed_address, storage_trie)]),
1211 };
1212
1213 updates.extend_from_sorted(&sorted);
1214
1215 assert_eq!(updates.storage_tries.len(), 1);
1216 let storage = updates.storage_tries.get(&hashed_address).unwrap();
1217 assert_eq!(storage.storage_nodes.len(), 1);
1218 assert!(storage.removed_nodes.contains(&Nibbles::from_nibbles_unchecked([0x0b])));
1219 }
1220
1221 #[test]
1223 fn test_storage_trie_updates_extend_from_sorted_non_deleted() {
1224 let mut storage = StorageTrieUpdates {
1225 storage_nodes: HashMap::from_iter([(
1226 Nibbles::from_nibbles_unchecked([0x01]),
1227 BranchNodeCompact::default(),
1228 )]),
1229 removed_nodes: Default::default(),
1230 };
1231
1232 let sorted = StorageTrieUpdatesSorted {
1233 storage_nodes: vec![
1234 (Nibbles::from_nibbles_unchecked([0x02]), Some(BranchNodeCompact::default())),
1235 (Nibbles::from_nibbles_unchecked([0x03]), None),
1236 ],
1237 };
1238
1239 storage.extend_from_sorted(&sorted);
1240 assert_eq!(storage.storage_nodes.len(), 2);
1241 assert!(storage.removed_nodes.contains(&Nibbles::from_nibbles_unchecked([0x03])));
1242 }
1243
1244 #[test]
1246 fn test_trie_updates_extend_from_sorted_filters_empty_nibbles() {
1247 let mut updates = TrieUpdates::default();
1248
1249 let sorted = TrieUpdatesSorted {
1250 account_nodes: vec![
1251 (Nibbles::default(), Some(BranchNodeCompact::default())), (Nibbles::from_nibbles_unchecked([0x01]), Some(BranchNodeCompact::default())),
1253 ],
1254 storage_tries: B256Map::default(),
1255 };
1256
1257 updates.extend_from_sorted(&sorted);
1258
1259 assert_eq!(updates.account_nodes.len(), 1);
1261 assert!(updates.account_nodes.contains_key(&Nibbles::from_nibbles_unchecked([0x01])));
1262 assert!(!updates.account_nodes.contains_key(&Nibbles::default()));
1263 }
1264}
1265
1266#[cfg(feature = "serde-bincode-compat")]
1268pub mod serde_bincode_compat {
1269 use crate::{BranchNodeCompact, Nibbles};
1270 use alloc::{borrow::Cow, vec::Vec};
1271 use alloy_primitives::map::{B256Map, HashMap, HashSet};
1272 use core::fmt;
1273 use serde::{
1274 de::{Error as _, SeqAccess, Visitor},
1275 Deserialize, Deserializer, Serialize, Serializer,
1276 };
1277 use serde_with::{DeserializeAs, SerializeAs};
1278
1279 #[derive(Debug, Serialize, Deserialize)]
1295 pub struct TrieUpdates<'a> {
1296 account_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
1297 removed_nodes: Cow<'a, HashSet<Nibbles>>,
1298 storage_tries: B256Map<StorageTrieUpdates<'a>>,
1299 }
1300
1301 impl<'a> From<&'a super::TrieUpdates> for TrieUpdates<'a> {
1302 fn from(value: &'a super::TrieUpdates) -> Self {
1303 Self {
1304 account_nodes: Cow::Borrowed(&value.account_nodes),
1305 removed_nodes: Cow::Borrowed(&value.removed_nodes),
1306 storage_tries: value.storage_tries.iter().map(|(k, v)| (*k, v.into())).collect(),
1307 }
1308 }
1309 }
1310
1311 impl<'a> From<TrieUpdates<'a>> for super::TrieUpdates {
1312 fn from(value: TrieUpdates<'a>) -> Self {
1313 Self {
1314 account_nodes: value.account_nodes.into_owned(),
1315 removed_nodes: value.removed_nodes.into_owned(),
1316 storage_tries: value
1317 .storage_tries
1318 .into_iter()
1319 .map(|(k, v)| (k, v.into()))
1320 .collect(),
1321 }
1322 }
1323 }
1324
1325 impl SerializeAs<super::TrieUpdates> for TrieUpdates<'_> {
1326 fn serialize_as<S>(source: &super::TrieUpdates, serializer: S) -> Result<S::Ok, S::Error>
1327 where
1328 S: Serializer,
1329 {
1330 TrieUpdates::from(source).serialize(serializer)
1331 }
1332 }
1333
1334 impl<'de> DeserializeAs<'de, super::TrieUpdates> for TrieUpdates<'de> {
1335 fn deserialize_as<D>(deserializer: D) -> Result<super::TrieUpdates, D::Error>
1336 where
1337 D: Deserializer<'de>,
1338 {
1339 TrieUpdates::deserialize(deserializer).map(Into::into)
1340 }
1341 }
1342
1343 #[derive(Debug, Serialize, Deserialize)]
1359 pub struct StorageTrieUpdates<'a> {
1360 storage_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
1361 removed_nodes: Cow<'a, HashSet<Nibbles>>,
1362 }
1363
1364 impl<'a> From<&'a super::StorageTrieUpdates> for StorageTrieUpdates<'a> {
1365 fn from(value: &'a super::StorageTrieUpdates) -> Self {
1366 Self {
1367 storage_nodes: Cow::Borrowed(&value.storage_nodes),
1368 removed_nodes: Cow::Borrowed(&value.removed_nodes),
1369 }
1370 }
1371 }
1372
1373 impl<'a> From<StorageTrieUpdates<'a>> for super::StorageTrieUpdates {
1374 fn from(value: StorageTrieUpdates<'a>) -> Self {
1375 Self {
1376 storage_nodes: value.storage_nodes.into_owned(),
1377 removed_nodes: value.removed_nodes.into_owned(),
1378 }
1379 }
1380 }
1381
1382 impl SerializeAs<super::StorageTrieUpdates> for StorageTrieUpdates<'_> {
1383 fn serialize_as<S>(
1384 source: &super::StorageTrieUpdates,
1385 serializer: S,
1386 ) -> Result<S::Ok, S::Error>
1387 where
1388 S: Serializer,
1389 {
1390 StorageTrieUpdates::from(source).serialize(serializer)
1391 }
1392 }
1393
1394 impl<'de> DeserializeAs<'de, super::StorageTrieUpdates> for StorageTrieUpdates<'de> {
1395 fn deserialize_as<D>(deserializer: D) -> Result<super::StorageTrieUpdates, D::Error>
1396 where
1397 D: Deserializer<'de>,
1398 {
1399 StorageTrieUpdates::deserialize(deserializer).map(Into::into)
1400 }
1401 }
1402
1403 #[derive(Debug, Serialize, Deserialize)]
1419 pub struct TrieUpdatesSorted<'a> {
1420 account_nodes: Cow<'a, [(Nibbles, Option<BranchNodeCompact>)]>,
1421 storage_tries: B256Map<StorageTrieUpdatesSorted<'a>>,
1422 }
1423
1424 impl<'a> From<&'a super::TrieUpdatesSorted> for TrieUpdatesSorted<'a> {
1425 fn from(value: &'a super::TrieUpdatesSorted) -> Self {
1426 Self {
1427 account_nodes: Cow::Borrowed(&value.account_nodes),
1428 storage_tries: value.storage_tries.iter().map(|(k, v)| (*k, v.into())).collect(),
1429 }
1430 }
1431 }
1432
1433 impl<'a> From<TrieUpdatesSorted<'a>> for super::TrieUpdatesSorted {
1434 fn from(value: TrieUpdatesSorted<'a>) -> Self {
1435 Self {
1436 account_nodes: value.account_nodes.into_owned(),
1437 storage_tries: value
1438 .storage_tries
1439 .into_iter()
1440 .map(|(k, v)| (k, v.into()))
1441 .collect(),
1442 }
1443 }
1444 }
1445
1446 impl SerializeAs<super::TrieUpdatesSorted> for TrieUpdatesSorted<'_> {
1447 fn serialize_as<S>(
1448 source: &super::TrieUpdatesSorted,
1449 serializer: S,
1450 ) -> Result<S::Ok, S::Error>
1451 where
1452 S: Serializer,
1453 {
1454 TrieUpdatesSorted::from(source).serialize(serializer)
1455 }
1456 }
1457
1458 impl<'de> DeserializeAs<'de, super::TrieUpdatesSorted> for TrieUpdatesSorted<'de> {
1459 fn deserialize_as<D>(deserializer: D) -> Result<super::TrieUpdatesSorted, D::Error>
1460 where
1461 D: Deserializer<'de>,
1462 {
1463 TrieUpdatesSorted::deserialize(deserializer).map(Into::into)
1464 }
1465 }
1466
1467 #[derive(Debug, Serialize)]
1483 pub struct StorageTrieUpdatesSorted<'a> {
1484 storage_nodes: Cow<'a, [(Nibbles, Option<BranchNodeCompact>)]>,
1485 }
1486
1487 impl<'de, 'a> Deserialize<'de> for StorageTrieUpdatesSorted<'a> {
1488 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1489 where
1490 D: Deserializer<'de>,
1491 {
1492 struct StorageTrieUpdatesSortedVisitor;
1493
1494 impl<'de> Visitor<'de> for StorageTrieUpdatesSortedVisitor {
1495 type Value = Vec<(Nibbles, Option<BranchNodeCompact>)>;
1496
1497 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1498 formatter.write_str("storage trie updates with an optional legacy wipe marker")
1499 }
1500
1501 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1502 where
1503 A: SeqAccess<'de>,
1504 {
1505 let len = seq.size_hint().unwrap_or_default();
1506 let storage_nodes = match len {
1507 1 => {
1508 seq.next_element()?.ok_or_else(|| A::Error::invalid_length(0, &self))?
1509 }
1510 2 => {
1511 let _: bool = seq
1512 .next_element()?
1513 .ok_or_else(|| A::Error::invalid_length(0, &self))?;
1514 seq.next_element()?.ok_or_else(|| A::Error::invalid_length(1, &self))?
1515 }
1516 _ => return Err(A::Error::invalid_length(len, &self)),
1517 };
1518
1519 Ok(storage_nodes)
1520 }
1521 }
1522
1523 deserializer
1526 .deserialize_tuple(1, StorageTrieUpdatesSortedVisitor)
1527 .map(|storage_nodes| Self { storage_nodes: Cow::Owned(storage_nodes) })
1528 }
1529 }
1530
1531 impl<'a> From<&'a super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'a> {
1532 fn from(value: &'a super::StorageTrieUpdatesSorted) -> Self {
1533 Self { storage_nodes: Cow::Borrowed(&value.storage_nodes) }
1534 }
1535 }
1536
1537 impl<'a> From<StorageTrieUpdatesSorted<'a>> for super::StorageTrieUpdatesSorted {
1538 fn from(value: StorageTrieUpdatesSorted<'a>) -> Self {
1539 Self { storage_nodes: value.storage_nodes.into_owned() }
1540 }
1541 }
1542
1543 impl SerializeAs<super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'_> {
1544 fn serialize_as<S>(
1545 source: &super::StorageTrieUpdatesSorted,
1546 serializer: S,
1547 ) -> Result<S::Ok, S::Error>
1548 where
1549 S: Serializer,
1550 {
1551 StorageTrieUpdatesSorted::from(source).serialize(serializer)
1552 }
1553 }
1554
1555 impl<'de> DeserializeAs<'de, super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'de> {
1556 fn deserialize_as<D>(deserializer: D) -> Result<super::StorageTrieUpdatesSorted, D::Error>
1557 where
1558 D: Deserializer<'de>,
1559 {
1560 StorageTrieUpdatesSorted::deserialize(deserializer).map(Into::into)
1561 }
1562 }
1563
1564 #[cfg(test)]
1565 mod tests {
1566 use crate::{
1567 serde_bincode_compat,
1568 updates::{
1569 StorageTrieUpdates, StorageTrieUpdatesSorted, TrieUpdates, TrieUpdatesSorted,
1570 },
1571 BranchNodeCompact, Nibbles,
1572 };
1573 use alloy_primitives::B256;
1574 use serde::{Deserialize, Serialize};
1575 use serde_with::serde_as;
1576
1577 #[test]
1578 fn test_trie_updates_bincode_roundtrip() {
1579 #[serde_as]
1580 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1581 struct Data {
1582 #[serde_as(as = "serde_bincode_compat::updates::TrieUpdates")]
1583 trie_updates: TrieUpdates,
1584 }
1585
1586 let mut data = Data { trie_updates: TrieUpdates::default() };
1587 let encoded = bincode::serialize(&data).unwrap();
1588 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1589 assert_eq!(decoded, data);
1590
1591 data.trie_updates
1592 .removed_nodes
1593 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1594 let encoded = bincode::serialize(&data).unwrap();
1595 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1596 assert_eq!(decoded, data);
1597
1598 data.trie_updates.account_nodes.insert(
1599 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1600 BranchNodeCompact::default(),
1601 );
1602 let encoded = bincode::serialize(&data).unwrap();
1603 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1604 assert_eq!(decoded, data);
1605
1606 data.trie_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
1607 let encoded = bincode::serialize(&data).unwrap();
1608 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1609 assert_eq!(decoded, data);
1610 }
1611
1612 #[test]
1613 fn test_storage_trie_updates_bincode_roundtrip() {
1614 #[serde_as]
1615 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1616 struct Data {
1617 #[serde_as(as = "serde_bincode_compat::updates::StorageTrieUpdates")]
1618 trie_updates: StorageTrieUpdates,
1619 }
1620
1621 let mut data = Data { trie_updates: StorageTrieUpdates::default() };
1622 let encoded = bincode::serialize(&data).unwrap();
1623 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1624 assert_eq!(decoded, data);
1625
1626 data.trie_updates
1627 .removed_nodes
1628 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1629 let encoded = bincode::serialize(&data).unwrap();
1630 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1631 assert_eq!(decoded, data);
1632
1633 data.trie_updates.storage_nodes.insert(
1634 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1635 BranchNodeCompact::default(),
1636 );
1637 let encoded = bincode::serialize(&data).unwrap();
1638 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1639 assert_eq!(decoded, data);
1640 }
1641
1642 #[test]
1643 fn test_trie_updates_sorted_bincode_roundtrip() {
1644 #[serde_as]
1645 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1646 struct Data {
1647 #[serde_as(as = "serde_bincode_compat::updates::TrieUpdatesSorted")]
1648 trie_updates: TrieUpdatesSorted,
1649 }
1650
1651 let mut data = Data { trie_updates: TrieUpdatesSorted::default() };
1652 let encoded = bincode::serialize(&data).unwrap();
1653 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1654 assert_eq!(decoded, data);
1655
1656 data.trie_updates.account_nodes.push((
1657 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1658 Some(BranchNodeCompact::default()),
1659 ));
1660 let encoded = bincode::serialize(&data).unwrap();
1661 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1662 assert_eq!(decoded, data);
1663
1664 data.trie_updates
1665 .account_nodes
1666 .push((Nibbles::from_nibbles_unchecked([0x0f, 0x0f, 0x0f, 0x0f]), None));
1667 let encoded = bincode::serialize(&data).unwrap();
1668 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1669 assert_eq!(decoded, data);
1670
1671 data.trie_updates
1672 .storage_tries
1673 .insert(B256::default(), StorageTrieUpdatesSorted::default());
1674 let encoded = bincode::serialize(&data).unwrap();
1675 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1676 assert_eq!(decoded, data);
1677 }
1678
1679 #[test]
1680 fn test_storage_trie_updates_sorted_bincode_roundtrip() {
1681 #[serde_as]
1682 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1683 struct Data {
1684 #[serde_as(as = "serde_bincode_compat::updates::StorageTrieUpdatesSorted")]
1685 trie_updates: StorageTrieUpdatesSorted,
1686 }
1687
1688 let mut data = Data { trie_updates: StorageTrieUpdatesSorted::default() };
1689 let encoded = bincode::serialize(&data).unwrap();
1690 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1691 assert_eq!(decoded, data);
1692
1693 data.trie_updates.storage_nodes.push((
1694 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1695 Some(BranchNodeCompact::default()),
1696 ));
1697 let encoded = bincode::serialize(&data).unwrap();
1698 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1699 assert_eq!(decoded, data);
1700
1701 data.trie_updates
1702 .storage_nodes
1703 .push((Nibbles::from_nibbles_unchecked([0x0a, 0x0a, 0x0a, 0x0a]), None));
1704 let encoded = bincode::serialize(&data).unwrap();
1705 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1706 assert_eq!(decoded, data);
1707 }
1708 }
1709}
1710
1711#[cfg(all(test, feature = "serde"))]
1712mod serde_tests {
1713 use super::*;
1714
1715 #[test]
1716 fn test_trie_updates_serde_roundtrip() {
1717 let mut default_updates = TrieUpdates::default();
1718 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1719 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1720 assert_eq!(updates_deserialized, default_updates);
1721
1722 default_updates
1723 .removed_nodes
1724 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1725 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1726 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1727 assert_eq!(updates_deserialized, default_updates);
1728
1729 default_updates.account_nodes.insert(
1730 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1731 BranchNodeCompact::default(),
1732 );
1733 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1734 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1735 assert_eq!(updates_deserialized, default_updates);
1736
1737 default_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
1738 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1739 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1740 assert_eq!(updates_deserialized, default_updates);
1741 }
1742
1743 #[test]
1744 fn test_storage_trie_updates_serde_roundtrip() {
1745 let mut default_updates = StorageTrieUpdates::default();
1746 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1747 let updates_deserialized: StorageTrieUpdates =
1748 serde_json::from_str(&updates_serialized).unwrap();
1749 assert_eq!(updates_deserialized, default_updates);
1750
1751 default_updates
1752 .removed_nodes
1753 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1754 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1755 let updates_deserialized: StorageTrieUpdates =
1756 serde_json::from_str(&updates_serialized).unwrap();
1757 assert_eq!(updates_deserialized, default_updates);
1758
1759 default_updates.storage_nodes.insert(
1760 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1761 BranchNodeCompact::default(),
1762 );
1763 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1764 let updates_deserialized: StorageTrieUpdates =
1765 serde_json::from_str(&updates_serialized).unwrap();
1766 assert_eq!(updates_deserialized, default_updates);
1767 }
1768}