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, B256Set, 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_accounts: B256Set,
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 destroyed in destroyed_accounts {
155 self.storage_tries.entry(destroyed).or_default().set_deleted(true);
156 }
157 }
158
159 pub fn into_sorted(mut self) -> TrieUpdatesSorted {
161 let mut account_nodes = self
162 .account_nodes
163 .drain()
164 .map(|(path, node)| {
165 self.removed_nodes.remove(&path);
167 (path, Some(node))
168 })
169 .collect::<Vec<_>>();
170
171 account_nodes.extend(self.removed_nodes.drain().map(|path| (path, None)));
172 account_nodes.sort_unstable_by_key(|a| a.0);
173
174 let storage_tries = self
175 .storage_tries
176 .drain()
177 .map(|(hashed_address, updates)| (hashed_address, updates.into_sorted()))
178 .collect();
179 TrieUpdatesSorted { account_nodes, storage_tries }
180 }
181
182 pub fn clone_into_sorted(&self) -> TrieUpdatesSorted {
185 let mut account_nodes = self
186 .account_nodes
187 .iter()
188 .map(|(path, node)| (*path, Some(node.clone())))
189 .collect::<Vec<_>>();
190
191 account_nodes.extend(
193 self.removed_nodes
194 .iter()
195 .filter(|path| !self.account_nodes.contains_key(*path))
196 .map(|path| (*path, None)),
197 );
198 account_nodes.sort_unstable_by_key(|a| a.0);
199
200 let storage_tries = self
201 .storage_tries
202 .iter()
203 .map(|(&hashed_address, updates)| (hashed_address, updates.clone_into_sorted()))
204 .collect();
205 TrieUpdatesSorted { account_nodes, storage_tries }
206 }
207
208 pub fn into_sorted_ref(&self) -> TrieUpdatesSortedRef<'_> {
210 let mut account_nodes = self.account_nodes.iter().collect::<Vec<_>>();
211 account_nodes.sort_unstable_by(|a, b| a.0.cmp(b.0));
212
213 TrieUpdatesSortedRef {
214 removed_nodes: self.removed_nodes.iter().collect::<BTreeSet<_>>(),
215 account_nodes,
216 storage_tries: self
217 .storage_tries
218 .iter()
219 .map(|m| (*m.0, m.1.into_sorted_ref()))
220 .collect(),
221 }
222 }
223
224 pub fn clear(&mut self) {
226 self.account_nodes.clear();
227 self.removed_nodes.clear();
228 self.storage_tries.clear();
229 }
230}
231
232#[derive(PartialEq, Eq, Clone, Default, Debug)]
234#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
235pub struct StorageTrieUpdates {
236 pub is_deleted: bool,
238 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_map"))]
240 pub storage_nodes: HashMap<Nibbles, BranchNodeCompact>,
241 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_set"))]
243 pub removed_nodes: HashSet<Nibbles>,
244}
245
246#[cfg(feature = "test-utils")]
247impl StorageTrieUpdates {
248 pub fn new(updates: impl IntoIterator<Item = (Nibbles, BranchNodeCompact)>) -> Self {
250 Self { storage_nodes: exclude_empty_from_pair(updates).collect(), ..Default::default() }
251 }
252}
253
254impl StorageTrieUpdates {
255 pub fn deleted() -> Self {
257 Self {
258 is_deleted: true,
259 storage_nodes: HashMap::default(),
260 removed_nodes: HashSet::default(),
261 }
262 }
263
264 pub fn len(&self) -> usize {
266 (self.is_deleted as usize) + self.storage_nodes.len() + self.removed_nodes.len()
267 }
268
269 pub const fn is_deleted(&self) -> bool {
271 self.is_deleted
272 }
273
274 pub const fn storage_nodes_ref(&self) -> &HashMap<Nibbles, BranchNodeCompact> {
276 &self.storage_nodes
277 }
278
279 pub const fn removed_nodes_ref(&self) -> &HashSet<Nibbles> {
281 &self.removed_nodes
282 }
283
284 pub fn is_empty(&self) -> bool {
286 !self.is_deleted && self.storage_nodes.is_empty() && self.removed_nodes.is_empty()
287 }
288
289 pub const fn set_deleted(&mut self, deleted: bool) {
291 self.is_deleted = deleted;
292 }
293
294 pub fn extend(&mut self, other: Self) {
296 self.extend_common(&other);
297 self.storage_nodes.extend(exclude_empty_from_pair(other.storage_nodes));
298 self.removed_nodes.extend(exclude_empty(other.removed_nodes));
299 }
300
301 pub fn extend_ref(&mut self, other: &Self) {
305 self.extend_common(other);
306 self.storage_nodes.extend(exclude_empty_from_pair(
307 other.storage_nodes.iter().map(|(k, v)| (*k, v.clone())),
308 ));
309 self.removed_nodes.extend(exclude_empty(other.removed_nodes.iter().copied()));
310 }
311
312 fn extend_common(&mut self, other: &Self) {
313 if other.is_deleted {
314 self.storage_nodes.clear();
315 self.removed_nodes.clear();
316 }
317 self.is_deleted |= other.is_deleted;
318 self.storage_nodes.retain(|nibbles, _| !other.removed_nodes.contains(nibbles));
319 }
320
321 pub fn extend_from_sorted(&mut self, sorted: &StorageTrieUpdatesSorted) {
328 if sorted.is_deleted {
329 self.storage_nodes.clear();
330 self.removed_nodes.clear();
331 }
332 self.is_deleted |= sorted.is_deleted;
333
334 let new_nodes_count = sorted.storage_nodes.len();
336 self.storage_nodes.reserve(new_nodes_count);
337
338 for (nibbles, maybe_node) in &sorted.storage_nodes {
340 if nibbles.is_empty() {
341 continue;
342 }
343 if let Some(node) = maybe_node {
344 self.removed_nodes.remove(nibbles);
345 self.storage_nodes.insert(*nibbles, node.clone());
346 } else {
347 self.storage_nodes.remove(nibbles);
348 self.removed_nodes.insert(*nibbles);
349 }
350 }
351 }
352
353 pub fn finalize(&mut self, hash_builder: HashBuilder, removed_keys: HashSet<Nibbles>) {
355 let (_, updated_nodes) = hash_builder.split();
357 self.storage_nodes.extend(exclude_empty_from_pair(updated_nodes));
358
359 self.removed_nodes.extend(exclude_empty(removed_keys));
361 }
362
363 pub fn into_sorted(mut self) -> StorageTrieUpdatesSorted {
365 let mut storage_nodes = self
366 .storage_nodes
367 .into_iter()
368 .map(|(path, node)| {
369 self.removed_nodes.remove(&path);
371 (path, Some(node))
372 })
373 .collect::<Vec<_>>();
374
375 storage_nodes.extend(self.removed_nodes.into_iter().map(|path| (path, None)));
376 storage_nodes.sort_unstable_by_key(|a| a.0);
377
378 StorageTrieUpdatesSorted { is_deleted: self.is_deleted, storage_nodes }
379 }
380
381 pub fn clone_into_sorted(&self) -> StorageTrieUpdatesSorted {
384 let mut storage_nodes = self
385 .storage_nodes
386 .iter()
387 .map(|(path, node)| (*path, Some(node.clone())))
388 .collect::<Vec<_>>();
389
390 storage_nodes.extend(
392 self.removed_nodes
393 .iter()
394 .filter(|path| !self.storage_nodes.contains_key(*path))
395 .map(|path| (*path, None)),
396 );
397 storage_nodes.sort_unstable_by_key(|a| a.0);
398
399 StorageTrieUpdatesSorted { is_deleted: self.is_deleted, storage_nodes }
400 }
401
402 pub fn into_sorted_ref(&self) -> StorageTrieUpdatesSortedRef<'_> {
404 StorageTrieUpdatesSortedRef {
405 is_deleted: self.is_deleted,
406 removed_nodes: self.removed_nodes.iter().collect::<BTreeSet<_>>(),
407 storage_nodes: self.storage_nodes.iter().collect::<BTreeMap<_, _>>(),
408 }
409 }
410}
411
412#[cfg(any(test, feature = "serde"))]
417mod serde_nibbles_set {
418 use crate::Nibbles;
419 use alloc::{
420 string::{String, ToString},
421 vec::Vec,
422 };
423 use alloy_primitives::map::HashSet;
424 use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
425
426 pub(super) fn serialize<S>(map: &HashSet<Nibbles>, serializer: S) -> Result<S::Ok, S::Error>
427 where
428 S: Serializer,
429 {
430 let mut storage_nodes =
431 map.iter().map(|elem| alloy_primitives::hex::encode(elem.pack())).collect::<Vec<_>>();
432 storage_nodes.sort_unstable();
433 storage_nodes.serialize(serializer)
434 }
435
436 pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<HashSet<Nibbles>, D::Error>
437 where
438 D: Deserializer<'de>,
439 {
440 Vec::<String>::deserialize(deserializer)?
441 .into_iter()
442 .map(|node| {
443 Ok(Nibbles::unpack(
444 alloy_primitives::hex::decode(node)
445 .map_err(|err| D::Error::custom(err.to_string()))?,
446 ))
447 })
448 .collect::<Result<HashSet<_>, _>>()
449 }
450}
451
452#[cfg(any(test, feature = "serde"))]
457mod serde_nibbles_map {
458 use crate::Nibbles;
459 use alloc::{
460 string::{String, ToString},
461 vec::Vec,
462 };
463 use alloy_primitives::{hex, map::HashMap};
464 use core::marker::PhantomData;
465 use serde::{
466 de::{Error, MapAccess, Visitor},
467 ser::SerializeMap,
468 Deserialize, Deserializer, Serialize, Serializer,
469 };
470
471 pub(super) fn serialize<S, T>(
472 map: &HashMap<Nibbles, T>,
473 serializer: S,
474 ) -> Result<S::Ok, S::Error>
475 where
476 S: Serializer,
477 T: Serialize,
478 {
479 let mut map_serializer = serializer.serialize_map(Some(map.len()))?;
480 let mut storage_nodes = Vec::from_iter(map);
481 storage_nodes.sort_unstable_by_key(|node| node.0);
482 for (k, v) in storage_nodes {
483 let packed = alloy_primitives::hex::encode(k.pack());
485 map_serializer.serialize_entry(&packed, &v)?;
486 }
487 map_serializer.end()
488 }
489
490 pub(super) fn deserialize<'de, D, T>(deserializer: D) -> Result<HashMap<Nibbles, T>, D::Error>
491 where
492 D: Deserializer<'de>,
493 T: Deserialize<'de>,
494 {
495 struct NibblesMapVisitor<T> {
496 marker: PhantomData<T>,
497 }
498
499 impl<'de, T> Visitor<'de> for NibblesMapVisitor<T>
500 where
501 T: Deserialize<'de>,
502 {
503 type Value = HashMap<Nibbles, T>;
504
505 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
506 formatter.write_str("a map with hex-encoded Nibbles keys")
507 }
508
509 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
510 where
511 A: MapAccess<'de>,
512 {
513 let mut result = HashMap::with_capacity_and_hasher(
514 map.size_hint().unwrap_or(0),
515 Default::default(),
516 );
517
518 while let Some((key, value)) = map.next_entry::<String, T>()? {
519 let decoded_key =
520 hex::decode(&key).map_err(|err| Error::custom(err.to_string()))?;
521
522 let nibbles = Nibbles::unpack(&decoded_key);
523
524 result.insert(nibbles, value);
525 }
526
527 Ok(result)
528 }
529 }
530
531 deserializer.deserialize_map(NibblesMapVisitor { marker: PhantomData })
532 }
533}
534
535#[derive(PartialEq, Eq, Clone, Default, Debug)]
537#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
538pub struct TrieUpdatesSortedRef<'a> {
539 pub account_nodes: Vec<(&'a Nibbles, &'a BranchNodeCompact)>,
541 pub removed_nodes: BTreeSet<&'a Nibbles>,
543 pub storage_tries: BTreeMap<FixedBytes<32>, StorageTrieUpdatesSortedRef<'a>>,
545}
546
547#[derive(PartialEq, Eq, Clone, Default, Debug)]
549#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
550pub struct TrieUpdatesSorted {
551 account_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
554 storage_tries: B256Map<StorageTrieUpdatesSorted>,
556}
557
558impl TrieUpdatesSorted {
559 pub fn new(
566 account_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
567 storage_tries: B256Map<StorageTrieUpdatesSorted>,
568 ) -> Self {
569 debug_assert!(
570 account_nodes.is_sorted_by_key(|item| &item.0),
571 "account_nodes must be sorted by Nibbles key"
572 );
573 debug_assert!(
574 storage_tries.values().all(|storage_trie| {
575 storage_trie.storage_nodes.is_sorted_by_key(|item| &item.0)
576 }),
577 "all storage_nodes in storage_tries must be sorted by Nibbles key"
578 );
579 Self { account_nodes, storage_tries }
580 }
581
582 pub fn is_empty(&self) -> bool {
584 self.account_nodes.is_empty() && self.storage_tries.is_empty()
585 }
586
587 pub fn account_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
589 &self.account_nodes
590 }
591
592 pub const fn storage_tries_ref(&self) -> &B256Map<StorageTrieUpdatesSorted> {
594 &self.storage_tries
595 }
596
597 pub fn total_len(&self) -> usize {
599 self.account_nodes.len() +
600 self.storage_tries.values().map(|storage| storage.len()).sum::<usize>()
601 }
602
603 pub fn extend_ref_and_sort(&mut self, other: &Self) {
612 extend_sorted_vec(&mut self.account_nodes, &other.account_nodes);
614
615 for (hashed_address, storage_trie) in &other.storage_tries {
617 self.storage_tries
618 .entry(*hashed_address)
619 .and_modify(|existing| existing.extend_ref(storage_trie))
620 .or_insert_with(|| storage_trie.clone());
621 }
622 }
623
624 pub fn clear(&mut self) {
626 self.account_nodes.clear();
627 self.storage_tries.clear();
628 }
629
630 pub fn merge_batch<T: AsRef<Self> + From<Self>>(iter: impl IntoIterator<Item = T>) -> T {
635 let items: alloc::vec::Vec<_> = iter.into_iter().collect();
636 match items.len() {
637 0 => Self::default().into(),
638 1 => items.into_iter().next().expect("len == 1"),
639 _ => Self::merge_slice(&items).into(),
640 }
641 }
642
643 pub fn merge_slice<T: AsRef<Self>>(items: &[T]) -> Self {
649 const THRESHOLD: usize = 30;
650
651 let k = items.len();
652
653 if k == 0 {
654 return Self::default();
655 }
656 if k == 1 {
657 return items[0].as_ref().clone();
658 }
659
660 if k < THRESHOLD {
661 let mut iter = items.iter().rev();
663 let mut acc = iter.next().expect("k > 0").as_ref().clone();
664 for next in iter {
665 acc.extend_ref_and_sort(next.as_ref());
666 }
667 return acc;
668 }
669
670 let account_nodes =
672 kway_merge_sorted(items.iter().map(|i| i.as_ref().account_nodes.as_slice()));
673
674 struct StorageAcc<'a> {
675 is_deleted: bool,
676 sealed: bool,
677 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
678 }
679
680 let mut acc: B256Map<StorageAcc<'_>> = B256Map::default();
681
682 for item in items {
683 for (addr, storage) in &item.as_ref().storage_tries {
684 let entry = acc.entry(*addr).or_insert_with(|| StorageAcc {
685 is_deleted: false,
686 sealed: false,
687 slices: Vec::new(),
688 });
689
690 if entry.sealed {
691 continue;
692 }
693
694 entry.slices.push(storage.storage_nodes.as_slice());
695
696 if storage.is_deleted {
697 entry.is_deleted = true;
698 entry.sealed = true;
699 }
700 }
701 }
702
703 let storage_tries = acc
704 .into_iter()
705 .map(|(addr, entry)| {
706 let storage_nodes = kway_merge_sorted(entry.slices);
707 (addr, StorageTrieUpdatesSorted { is_deleted: entry.is_deleted, storage_nodes })
708 })
709 .collect();
710
711 Self { account_nodes, storage_tries }
712 }
713
714 pub fn disjointed_merge_batch<'a>(batch: &[&'a Self], mask: &[&'a Self]) -> Self {
726 let account_node_count = batch.iter().map(|item| item.account_nodes.len()).sum();
727 let mut account_nodes = Vec::with_capacity(account_node_count);
728 account_nodes.extend(kway_merge_disjoint_sorted(
729 batch.iter().rev().map(|item| item.account_nodes.as_slice()),
730 mask.iter().map(|item| item.account_nodes.as_slice()),
731 ));
732
733 struct StorageAcc<'a> {
734 node_count: usize,
735 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
736 }
737
738 #[derive(Default)]
739 struct StorageMaskAcc<'a> {
740 slices: Vec<&'a [(Nibbles, Option<BranchNodeCompact>)]>,
741 }
742
743 let mut storage_tries = B256Map::with_capacity_and_hasher(
744 batch.iter().map(|item| item.storage_tries.len()).sum(),
745 Default::default(),
746 );
747
748 for item in batch.iter().rev() {
749 for (hashed_address, storage_trie) in &item.storage_tries {
750 assert!(
751 !storage_trie.is_deleted,
752 "storage wipes are not supported by disjointed_merge_batch"
753 );
754 let entry = storage_tries
755 .entry(*hashed_address)
756 .or_insert_with(|| StorageAcc { node_count: 0, slices: Vec::new() });
757 entry.slices.push(storage_trie.storage_nodes.as_slice());
758 entry.node_count += storage_trie.storage_nodes.len();
759 }
760 }
761
762 let mut storage_masks: B256Map<StorageMaskAcc<'a>> = B256Map::with_capacity_and_hasher(
763 mask.iter().map(|item| item.storage_tries.len()).sum(),
764 Default::default(),
765 );
766 for item in mask {
767 for (hashed_address, storage_trie) in &item.storage_tries {
768 assert!(
769 !storage_trie.is_deleted,
770 "storage wipes are not supported by disjointed_merge_batch"
771 );
772 let entry = storage_masks.entry(*hashed_address).or_default();
773 entry.slices.push(storage_trie.storage_nodes.as_slice());
774 }
775 }
776
777 let storage_tries = storage_tries
778 .into_iter()
779 .filter_map(|(hashed_address, entry)| {
780 let node_count = entry.node_count;
781 let storage_nodes = match storage_masks.get(&hashed_address) {
782 Some(mask_entry) => {
783 let mut storage_nodes = Vec::with_capacity(node_count);
784 storage_nodes.extend(kway_merge_disjoint_sorted(
785 entry.slices,
786 mask_entry.slices.iter().copied(),
787 ));
788 storage_nodes
789 }
790 None => kway_merge_sorted(entry.slices),
791 };
792
793 (!storage_nodes.is_empty() || mask.is_empty()).then_some((
794 hashed_address,
795 StorageTrieUpdatesSorted { is_deleted: false, storage_nodes },
796 ))
797 })
798 .collect();
799
800 Self::new(account_nodes, storage_tries)
801 }
802}
803
804impl AsRef<Self> for TrieUpdatesSorted {
805 fn as_ref(&self) -> &Self {
806 self
807 }
808}
809
810impl From<TrieUpdatesSorted> for TrieUpdates {
811 fn from(sorted: TrieUpdatesSorted) -> Self {
812 let mut account_nodes = HashMap::default();
813 let mut removed_nodes = HashSet::default();
814
815 for (nibbles, node) in sorted.account_nodes {
816 if let Some(node) = node {
817 account_nodes.insert(nibbles, node);
818 } else {
819 removed_nodes.insert(nibbles);
820 }
821 }
822
823 let storage_tries = sorted
824 .storage_tries
825 .into_iter()
826 .map(|(address, storage)| (address, storage.into()))
827 .collect();
828
829 Self { account_nodes, removed_nodes, storage_tries }
830 }
831}
832
833#[derive(PartialEq, Eq, Clone, Default, Debug)]
835#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
836pub struct StorageTrieUpdatesSortedRef<'a> {
837 pub is_deleted: bool,
839 pub storage_nodes: BTreeMap<&'a Nibbles, &'a BranchNodeCompact>,
841 pub removed_nodes: BTreeSet<&'a Nibbles>,
843}
844
845#[derive(PartialEq, Eq, Clone, Default, Debug)]
847#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
848pub struct StorageTrieUpdatesSorted {
849 pub is_deleted: bool,
851 pub storage_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
854}
855
856impl StorageTrieUpdatesSorted {
857 pub const fn is_deleted(&self) -> bool {
859 self.is_deleted
860 }
861
862 pub fn storage_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
864 &self.storage_nodes
865 }
866
867 pub const fn len(&self) -> usize {
869 self.storage_nodes.len()
870 }
871
872 pub const fn is_empty(&self) -> bool {
874 self.storage_nodes.is_empty()
875 }
876
877 pub fn extend_ref(&mut self, other: &Self) {
882 if other.is_deleted {
883 self.is_deleted = true;
884 self.storage_nodes.clear();
885 self.storage_nodes.extend(other.storage_nodes.iter().cloned());
886 return;
887 }
888
889 extend_sorted_vec(&mut self.storage_nodes, &other.storage_nodes);
891 self.is_deleted = self.is_deleted || other.is_deleted;
892 }
893
894 pub fn merge_batch<'a>(updates: impl IntoIterator<Item = &'a Self>) -> Self {
897 let updates: Vec<_> = updates.into_iter().collect();
898 if updates.is_empty() {
899 return Self::default();
900 }
901
902 let del_idx = updates.iter().position(|u| u.is_deleted);
904 let relevant = del_idx.map_or(&updates[..], |idx| &updates[..=idx]);
905 let storage_nodes = kway_merge_sorted(relevant.iter().map(|u| u.storage_nodes.as_slice()));
906
907 Self { is_deleted: del_idx.is_some(), storage_nodes }
908 }
909}
910
911fn exclude_empty(iter: impl IntoIterator<Item = Nibbles>) -> impl Iterator<Item = Nibbles> {
913 iter.into_iter().filter(|n| !n.is_empty())
914}
915
916fn exclude_empty_from_pair<V>(
918 iter: impl IntoIterator<Item = (Nibbles, V)>,
919) -> impl Iterator<Item = (Nibbles, V)> {
920 iter.into_iter().filter(|(n, _)| !n.is_empty())
921}
922
923impl From<StorageTrieUpdatesSorted> for StorageTrieUpdates {
924 fn from(sorted: StorageTrieUpdatesSorted) -> Self {
925 let mut storage_nodes = HashMap::default();
926 let mut removed_nodes = HashSet::default();
927
928 for (nibbles, node) in sorted.storage_nodes {
929 if let Some(node) = node {
930 storage_nodes.insert(nibbles, node);
931 } else {
932 removed_nodes.insert(nibbles);
933 }
934 }
935
936 Self { is_deleted: sorted.is_deleted, storage_nodes, removed_nodes }
937 }
938}
939
940#[cfg(test)]
941mod tests {
942 use super::*;
943 use alloy_primitives::B256;
944
945 #[test]
946 fn test_trie_updates_sorted_extend_ref() {
947 let mut updates1 = TrieUpdatesSorted::default();
949 let updates2 = TrieUpdatesSorted::default();
950 updates1.extend_ref_and_sort(&updates2);
951 assert_eq!(updates1.account_nodes.len(), 0);
952 assert_eq!(updates1.storage_tries.len(), 0);
953
954 let mut updates1 = TrieUpdatesSorted {
956 account_nodes: vec![
957 (Nibbles::from_nibbles_unchecked([0x01]), Some(BranchNodeCompact::default())),
958 (Nibbles::from_nibbles_unchecked([0x03]), None),
959 ],
960 storage_tries: B256Map::default(),
961 };
962 let updates2 = TrieUpdatesSorted {
963 account_nodes: vec![
964 (Nibbles::from_nibbles_unchecked([0x02]), Some(BranchNodeCompact::default())),
965 (Nibbles::from_nibbles_unchecked([0x03]), Some(BranchNodeCompact::default())), ],
967 storage_tries: B256Map::default(),
968 };
969 updates1.extend_ref_and_sort(&updates2);
970 assert_eq!(updates1.account_nodes.len(), 3);
971 assert_eq!(updates1.account_nodes[0].0, Nibbles::from_nibbles_unchecked([0x01]));
973 assert_eq!(updates1.account_nodes[1].0, Nibbles::from_nibbles_unchecked([0x02]));
974 assert_eq!(updates1.account_nodes[2].0, Nibbles::from_nibbles_unchecked([0x03]));
975 assert!(updates1.account_nodes[2].1.is_some());
977
978 let storage_trie1 = StorageTrieUpdatesSorted {
980 is_deleted: false,
981 storage_nodes: vec![(
982 Nibbles::from_nibbles_unchecked([0x0a]),
983 Some(BranchNodeCompact::default()),
984 )],
985 };
986 let storage_trie2 = StorageTrieUpdatesSorted {
987 is_deleted: false,
988 storage_nodes: vec![(Nibbles::from_nibbles_unchecked([0x0b]), None)],
989 };
990
991 let hashed_address1 = B256::from([1; 32]);
992 let hashed_address2 = B256::from([2; 32]);
993
994 let mut updates1 = TrieUpdatesSorted {
995 account_nodes: vec![],
996 storage_tries: B256Map::from_iter([(hashed_address1, storage_trie1.clone())]),
997 };
998 let updates2 = TrieUpdatesSorted {
999 account_nodes: vec![],
1000 storage_tries: B256Map::from_iter([
1001 (hashed_address1, storage_trie2),
1002 (hashed_address2, storage_trie1),
1003 ]),
1004 };
1005 updates1.extend_ref_and_sort(&updates2);
1006 assert_eq!(updates1.storage_tries.len(), 2);
1007 assert!(updates1.storage_tries.contains_key(&hashed_address1));
1008 assert!(updates1.storage_tries.contains_key(&hashed_address2));
1009 let merged_storage = &updates1.storage_tries[&hashed_address1];
1011 assert_eq!(merged_storage.storage_nodes.len(), 2);
1012 }
1013
1014 #[test]
1015 fn test_storage_trie_updates_sorted_extend_ref_deleted() {
1016 let mut storage1 = StorageTrieUpdatesSorted {
1018 is_deleted: false,
1019 storage_nodes: vec![
1020 (Nibbles::from_nibbles_unchecked([0x01]), Some(BranchNodeCompact::default())),
1021 (Nibbles::from_nibbles_unchecked([0x02]), None),
1022 ],
1023 };
1024
1025 let storage2 = StorageTrieUpdatesSorted {
1026 is_deleted: true,
1027 storage_nodes: vec![
1028 (Nibbles::from_nibbles_unchecked([0x03]), Some(BranchNodeCompact::default())),
1029 (Nibbles::from_nibbles_unchecked([0x04]), None),
1030 ],
1031 };
1032
1033 storage1.extend_ref(&storage2);
1034
1035 assert!(storage1.is_deleted);
1037 assert_eq!(storage1.storage_nodes.len(), 2);
1039 assert_eq!(storage1.storage_nodes[0].0, Nibbles::from_nibbles_unchecked([0x03]));
1040 assert_eq!(storage1.storage_nodes[1].0, Nibbles::from_nibbles_unchecked([0x04]));
1041
1042 let mut storage3 = StorageTrieUpdatesSorted {
1044 is_deleted: true,
1045 storage_nodes: vec![(
1046 Nibbles::from_nibbles_unchecked([0x05]),
1047 Some(BranchNodeCompact::default()),
1048 )],
1049 };
1050
1051 let storage4 = StorageTrieUpdatesSorted {
1052 is_deleted: true,
1053 storage_nodes: vec![
1054 (Nibbles::from_nibbles_unchecked([0x06]), Some(BranchNodeCompact::default())),
1055 (Nibbles::from_nibbles_unchecked([0x07]), None),
1056 ],
1057 };
1058
1059 storage3.extend_ref(&storage4);
1060
1061 assert!(storage3.is_deleted);
1063 assert_eq!(storage3.storage_nodes.len(), 2);
1065 assert_eq!(storage3.storage_nodes[0].0, Nibbles::from_nibbles_unchecked([0x06]));
1066 assert_eq!(storage3.storage_nodes[1].0, Nibbles::from_nibbles_unchecked([0x07]));
1067 }
1068
1069 #[test]
1070 fn test_trie_updates_sorted_disjointed_merge_batch() {
1071 let kept_node = Nibbles::from_nibbles_unchecked([0x01]);
1072 let removed_node = Nibbles::from_nibbles_unchecked([0x02]);
1073 let kept_storage = B256::from([3; 32]);
1074 let slot1 = Nibbles::from_nibbles_unchecked([0x0a]);
1075 let slot2 = Nibbles::from_nibbles_unchecked([0x0b]);
1076
1077 let older = TrieUpdatesSorted::new(
1078 vec![(kept_node, Some(BranchNodeCompact::default())), (removed_node, None)],
1079 B256Map::from_iter([(
1080 kept_storage,
1081 StorageTrieUpdatesSorted { is_deleted: false, storage_nodes: vec![(slot1, None)] },
1082 )]),
1083 );
1084
1085 let newer = TrieUpdatesSorted::new(
1086 vec![(kept_node, None)],
1087 B256Map::from_iter([(
1088 kept_storage,
1089 StorageTrieUpdatesSorted {
1090 is_deleted: false,
1091 storage_nodes: vec![(slot1, Some(BranchNodeCompact::default())), (slot2, None)],
1092 },
1093 )]),
1094 );
1095
1096 let remove_a = TrieUpdatesSorted::new(
1097 vec![(removed_node, Some(BranchNodeCompact::default()))],
1098 B256Map::from_iter([(
1099 kept_storage,
1100 StorageTrieUpdatesSorted {
1101 is_deleted: false,
1102 storage_nodes: vec![(slot2, Some(BranchNodeCompact::default()))],
1103 },
1104 )]),
1105 );
1106
1107 let remove_b = TrieUpdatesSorted::new(
1108 vec![(Nibbles::from_nibbles_unchecked([0x0f]), Some(BranchNodeCompact::default()))],
1109 B256Map::default(),
1110 );
1111
1112 let result =
1113 TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[&remove_b, &remove_a]);
1114
1115 assert_eq!(result.account_nodes, vec![(kept_node, None)]);
1116 assert_eq!(result.storage_tries.len(), 1);
1117 assert_eq!(
1118 result.storage_tries.get(&kept_storage),
1119 Some(&StorageTrieUpdatesSorted {
1120 is_deleted: false,
1121 storage_nodes: vec![(slot1, Some(BranchNodeCompact::default()))],
1122 })
1123 );
1124 }
1125
1126 #[test]
1127 fn test_trie_updates_sorted_disjointed_merge_batch_empty_mask_merges_batch() {
1128 let node = Nibbles::from_nibbles_unchecked([0x01]);
1129 let storage = B256::with_last_byte(2);
1130 let storage_node = Nibbles::from_nibbles_unchecked([0x03]);
1131 let empty_storage = B256::with_last_byte(4);
1132 let older = TrieUpdatesSorted::new(
1133 vec![(node, Some(BranchNodeCompact::default()))],
1134 B256Map::from_iter([
1135 (
1136 storage,
1137 StorageTrieUpdatesSorted {
1138 is_deleted: false,
1139 storage_nodes: vec![(storage_node, None)],
1140 },
1141 ),
1142 (empty_storage, StorageTrieUpdatesSorted::default()),
1143 ]),
1144 );
1145 let newer = TrieUpdatesSorted::new(
1146 vec![(node, None)],
1147 B256Map::from_iter([(
1148 storage,
1149 StorageTrieUpdatesSorted {
1150 is_deleted: false,
1151 storage_nodes: vec![(storage_node, Some(BranchNodeCompact::default()))],
1152 },
1153 )]),
1154 );
1155 let expected = TrieUpdatesSorted::merge_batch(vec![newer.clone(), older.clone()]);
1156
1157 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[]);
1158
1159 assert_eq!(result, expected);
1160 }
1161
1162 #[test]
1163 fn test_trie_updates_sorted_disjointed_merge_batch_removes_overlapping_batch_key() {
1164 let overlapping_node = Nibbles::from_nibbles_unchecked([0x03]);
1165
1166 let older = TrieUpdatesSorted::new(
1167 vec![(overlapping_node, Some(BranchNodeCompact::default()))],
1168 B256Map::default(),
1169 );
1170
1171 let newer = TrieUpdatesSorted::new(vec![(overlapping_node, None)], B256Map::default());
1172
1173 let remove = TrieUpdatesSorted::new(
1174 vec![(overlapping_node, Some(BranchNodeCompact::default()))],
1175 B256Map::default(),
1176 );
1177
1178 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&older, &newer], &[&remove]);
1179
1180 assert!(result.account_nodes.is_empty());
1181 }
1182
1183 #[test]
1184 fn test_trie_updates_sorted_disjointed_merge_batch_keeps_equal_overlaps() {
1185 fn branch(mask: u16) -> BranchNodeCompact {
1186 BranchNodeCompact::new(mask, 0, 0, vec![], None)
1187 }
1188
1189 let node_path = Nibbles::from_nibbles_unchecked([0x03]);
1190 let deleted_node_path = Nibbles::from_nibbles_unchecked([0x04]);
1191 let storage = B256::from([5; 32]);
1192 let deleted_storage = B256::from([6; 32]);
1193 let storage_node_path = Nibbles::from_nibbles_unchecked([0x0c]);
1194 let deleted_storage_node_path = Nibbles::from_nibbles_unchecked([0x0d]);
1195 let batch = TrieUpdatesSorted::new(
1196 vec![(node_path, Some(branch(0b1010_0101))), (deleted_node_path, None)],
1197 B256Map::from_iter([
1198 (
1199 storage,
1200 StorageTrieUpdatesSorted {
1201 is_deleted: false,
1202 storage_nodes: vec![(storage_node_path, Some(branch(0b0011_1100)))],
1203 },
1204 ),
1205 (
1206 deleted_storage,
1207 StorageTrieUpdatesSorted {
1208 is_deleted: false,
1209 storage_nodes: vec![(deleted_storage_node_path, None)],
1210 },
1211 ),
1212 ]),
1213 );
1214 let different_mask = TrieUpdatesSorted::new(
1215 vec![
1216 (node_path, Some(branch(0b0101_1010))),
1217 (deleted_node_path, Some(branch(0b1111_0000))),
1218 ],
1219 B256Map::from_iter([
1220 (
1221 storage,
1222 StorageTrieUpdatesSorted {
1223 is_deleted: false,
1224 storage_nodes: vec![(storage_node_path, Some(branch(0b1100_0011)))],
1225 },
1226 ),
1227 (
1228 deleted_storage,
1229 StorageTrieUpdatesSorted {
1230 is_deleted: false,
1231 storage_nodes: vec![(deleted_storage_node_path, Some(branch(0b0000_1111)))],
1232 },
1233 ),
1234 ]),
1235 );
1236 let equal_mask = batch.clone();
1237
1238 let result =
1239 TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&different_mask, &equal_mask]);
1240 let reversed =
1241 TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&equal_mask, &different_mask]);
1242
1243 assert_eq!(result, batch);
1244 assert_eq!(reversed, result);
1245 }
1246
1247 #[test]
1248 fn test_trie_updates_sorted_disjointed_merge_batch_uses_exact_key_masking() {
1249 let hashed_address = B256::from([7; 32]);
1250 let grandparent = Nibbles::from_nibbles_unchecked([0x05]);
1251 let parent = Nibbles::from_nibbles_unchecked([0x05, 0x04]);
1252 let child = Nibbles::from_nibbles_unchecked([0x05, 0x04, 0x03]);
1253 let different_node = BranchNodeCompact::new(1, 0, 0, vec![], None);
1254
1255 let batch = TrieUpdatesSorted::new(
1256 vec![
1257 (grandparent, Some(BranchNodeCompact::default())),
1258 (parent, Some(BranchNodeCompact::default())),
1259 (child, Some(BranchNodeCompact::default())),
1260 ],
1261 B256Map::from_iter([(
1262 hashed_address,
1263 StorageTrieUpdatesSorted {
1264 is_deleted: false,
1265 storage_nodes: vec![
1266 (grandparent, Some(BranchNodeCompact::default())),
1267 (parent, Some(BranchNodeCompact::default())),
1268 (child, Some(BranchNodeCompact::default())),
1269 ],
1270 },
1271 )]),
1272 );
1273 let mask = TrieUpdatesSorted::new(
1274 vec![
1275 (grandparent, Some(different_node.clone())),
1276 (parent, Some(different_node.clone())),
1277 ],
1278 B256Map::from_iter([(
1279 hashed_address,
1280 StorageTrieUpdatesSorted {
1281 is_deleted: false,
1282 storage_nodes: vec![
1283 (grandparent, Some(different_node.clone())),
1284 (parent, Some(different_node)),
1285 ],
1286 },
1287 )]),
1288 );
1289
1290 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1291
1292 assert_eq!(result.account_nodes, vec![(child, Some(BranchNodeCompact::default()))]);
1293 assert_eq!(
1294 result.storage_tries.get(&hashed_address),
1295 Some(&StorageTrieUpdatesSorted {
1296 is_deleted: false,
1297 storage_nodes: vec![(child, Some(BranchNodeCompact::default()))],
1298 })
1299 );
1300 }
1301
1302 #[test]
1303 fn test_trie_updates_sorted_disjointed_merge_batch_ignores_empty_storage_mask() {
1304 let storage = B256::from([6; 32]);
1305 let slot = Nibbles::from_nibbles_unchecked([0x0d]);
1306
1307 let batch = TrieUpdatesSorted::new(
1308 vec![],
1309 B256Map::from_iter([(
1310 storage,
1311 StorageTrieUpdatesSorted {
1312 is_deleted: false,
1313 storage_nodes: vec![(slot, Some(BranchNodeCompact::default()))],
1314 },
1315 )]),
1316 );
1317 let mask = TrieUpdatesSorted::new(
1318 vec![],
1319 B256Map::from_iter([(
1320 storage,
1321 StorageTrieUpdatesSorted { is_deleted: false, storage_nodes: vec![] },
1322 )]),
1323 );
1324
1325 let result = TrieUpdatesSorted::disjointed_merge_batch(&[&batch], &[&mask]);
1326
1327 assert_eq!(
1328 result.storage_tries.get(&storage),
1329 Some(&StorageTrieUpdatesSorted {
1330 is_deleted: false,
1331 storage_nodes: vec![(slot, Some(BranchNodeCompact::default()))],
1332 })
1333 );
1334 }
1335
1336 #[test]
1338 fn test_trie_updates_extend_from_sorted_with_storage_tries() {
1339 let hashed_address = B256::from([1; 32]);
1340
1341 let mut updates = TrieUpdates::default();
1342
1343 let storage_trie = StorageTrieUpdatesSorted {
1344 is_deleted: false,
1345 storage_nodes: vec![
1346 (Nibbles::from_nibbles_unchecked([0x0a]), Some(BranchNodeCompact::default())),
1347 (Nibbles::from_nibbles_unchecked([0x0b]), None),
1348 ],
1349 };
1350
1351 let sorted = TrieUpdatesSorted {
1352 account_nodes: vec![],
1353 storage_tries: B256Map::from_iter([(hashed_address, storage_trie)]),
1354 };
1355
1356 updates.extend_from_sorted(&sorted);
1357
1358 assert_eq!(updates.storage_tries.len(), 1);
1359 let storage = updates.storage_tries.get(&hashed_address).unwrap();
1360 assert!(!storage.is_deleted);
1361 assert_eq!(storage.storage_nodes.len(), 1);
1362 assert!(storage.removed_nodes.contains(&Nibbles::from_nibbles_unchecked([0x0b])));
1363 }
1364
1365 #[test]
1367 fn test_trie_updates_extend_from_sorted_with_deleted_storage() {
1368 let hashed_address = B256::from([1; 32]);
1369
1370 let mut updates = TrieUpdates::default();
1371 updates.storage_tries.insert(
1372 hashed_address,
1373 StorageTrieUpdates {
1374 is_deleted: false,
1375 storage_nodes: HashMap::from_iter([(
1376 Nibbles::from_nibbles_unchecked([0x01]),
1377 BranchNodeCompact::default(),
1378 )]),
1379 removed_nodes: Default::default(),
1380 },
1381 );
1382
1383 let storage_trie = StorageTrieUpdatesSorted {
1384 is_deleted: true,
1385 storage_nodes: vec![(
1386 Nibbles::from_nibbles_unchecked([0x0a]),
1387 Some(BranchNodeCompact::default()),
1388 )],
1389 };
1390
1391 let sorted = TrieUpdatesSorted {
1392 account_nodes: vec![],
1393 storage_tries: B256Map::from_iter([(hashed_address, storage_trie)]),
1394 };
1395
1396 updates.extend_from_sorted(&sorted);
1397
1398 let storage = updates.storage_tries.get(&hashed_address).unwrap();
1399 assert!(storage.is_deleted);
1400 assert_eq!(storage.storage_nodes.len(), 1);
1402 assert!(storage.storage_nodes.contains_key(&Nibbles::from_nibbles_unchecked([0x0a])));
1403 }
1404
1405 #[test]
1407 fn test_storage_trie_updates_extend_from_sorted_non_deleted() {
1408 let mut storage = StorageTrieUpdates {
1409 is_deleted: false,
1410 storage_nodes: HashMap::from_iter([(
1411 Nibbles::from_nibbles_unchecked([0x01]),
1412 BranchNodeCompact::default(),
1413 )]),
1414 removed_nodes: Default::default(),
1415 };
1416
1417 let sorted = StorageTrieUpdatesSorted {
1418 is_deleted: false,
1419 storage_nodes: vec![
1420 (Nibbles::from_nibbles_unchecked([0x02]), Some(BranchNodeCompact::default())),
1421 (Nibbles::from_nibbles_unchecked([0x03]), None),
1422 ],
1423 };
1424
1425 storage.extend_from_sorted(&sorted);
1426
1427 assert!(!storage.is_deleted);
1428 assert_eq!(storage.storage_nodes.len(), 2);
1429 assert!(storage.removed_nodes.contains(&Nibbles::from_nibbles_unchecked([0x03])));
1430 }
1431
1432 #[test]
1434 fn test_storage_trie_updates_extend_from_sorted_deleted() {
1435 let mut storage = StorageTrieUpdates {
1436 is_deleted: false,
1437 storage_nodes: HashMap::from_iter([(
1438 Nibbles::from_nibbles_unchecked([0x01]),
1439 BranchNodeCompact::default(),
1440 )]),
1441 removed_nodes: Default::default(),
1442 };
1443
1444 let sorted = StorageTrieUpdatesSorted {
1445 is_deleted: true,
1446 storage_nodes: vec![(
1447 Nibbles::from_nibbles_unchecked([0x0a]),
1448 Some(BranchNodeCompact::default()),
1449 )],
1450 };
1451
1452 storage.extend_from_sorted(&sorted);
1453
1454 assert!(storage.is_deleted);
1455 assert_eq!(storage.storage_nodes.len(), 1);
1457 assert!(storage.storage_nodes.contains_key(&Nibbles::from_nibbles_unchecked([0x0a])));
1458 }
1459
1460 #[test]
1462 fn test_trie_updates_extend_from_sorted_filters_empty_nibbles() {
1463 let mut updates = TrieUpdates::default();
1464
1465 let sorted = TrieUpdatesSorted {
1466 account_nodes: vec![
1467 (Nibbles::default(), Some(BranchNodeCompact::default())), (Nibbles::from_nibbles_unchecked([0x01]), Some(BranchNodeCompact::default())),
1469 ],
1470 storage_tries: B256Map::default(),
1471 };
1472
1473 updates.extend_from_sorted(&sorted);
1474
1475 assert_eq!(updates.account_nodes.len(), 1);
1477 assert!(updates.account_nodes.contains_key(&Nibbles::from_nibbles_unchecked([0x01])));
1478 assert!(!updates.account_nodes.contains_key(&Nibbles::default()));
1479 }
1480}
1481
1482#[cfg(feature = "serde-bincode-compat")]
1484pub mod serde_bincode_compat {
1485 use crate::{BranchNodeCompact, Nibbles};
1486 use alloc::borrow::Cow;
1487 use alloy_primitives::map::{B256Map, HashMap, HashSet};
1488 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1489 use serde_with::{DeserializeAs, SerializeAs};
1490
1491 #[derive(Debug, Serialize, Deserialize)]
1507 pub struct TrieUpdates<'a> {
1508 account_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
1509 removed_nodes: Cow<'a, HashSet<Nibbles>>,
1510 storage_tries: B256Map<StorageTrieUpdates<'a>>,
1511 }
1512
1513 impl<'a> From<&'a super::TrieUpdates> for TrieUpdates<'a> {
1514 fn from(value: &'a super::TrieUpdates) -> Self {
1515 Self {
1516 account_nodes: Cow::Borrowed(&value.account_nodes),
1517 removed_nodes: Cow::Borrowed(&value.removed_nodes),
1518 storage_tries: value.storage_tries.iter().map(|(k, v)| (*k, v.into())).collect(),
1519 }
1520 }
1521 }
1522
1523 impl<'a> From<TrieUpdates<'a>> for super::TrieUpdates {
1524 fn from(value: TrieUpdates<'a>) -> Self {
1525 Self {
1526 account_nodes: value.account_nodes.into_owned(),
1527 removed_nodes: value.removed_nodes.into_owned(),
1528 storage_tries: value
1529 .storage_tries
1530 .into_iter()
1531 .map(|(k, v)| (k, v.into()))
1532 .collect(),
1533 }
1534 }
1535 }
1536
1537 impl SerializeAs<super::TrieUpdates> for TrieUpdates<'_> {
1538 fn serialize_as<S>(source: &super::TrieUpdates, serializer: S) -> Result<S::Ok, S::Error>
1539 where
1540 S: Serializer,
1541 {
1542 TrieUpdates::from(source).serialize(serializer)
1543 }
1544 }
1545
1546 impl<'de> DeserializeAs<'de, super::TrieUpdates> for TrieUpdates<'de> {
1547 fn deserialize_as<D>(deserializer: D) -> Result<super::TrieUpdates, D::Error>
1548 where
1549 D: Deserializer<'de>,
1550 {
1551 TrieUpdates::deserialize(deserializer).map(Into::into)
1552 }
1553 }
1554
1555 #[derive(Debug, Serialize, Deserialize)]
1571 pub struct StorageTrieUpdates<'a> {
1572 is_deleted: bool,
1573 storage_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
1574 removed_nodes: Cow<'a, HashSet<Nibbles>>,
1575 }
1576
1577 impl<'a> From<&'a super::StorageTrieUpdates> for StorageTrieUpdates<'a> {
1578 fn from(value: &'a super::StorageTrieUpdates) -> Self {
1579 Self {
1580 is_deleted: value.is_deleted,
1581 storage_nodes: Cow::Borrowed(&value.storage_nodes),
1582 removed_nodes: Cow::Borrowed(&value.removed_nodes),
1583 }
1584 }
1585 }
1586
1587 impl<'a> From<StorageTrieUpdates<'a>> for super::StorageTrieUpdates {
1588 fn from(value: StorageTrieUpdates<'a>) -> Self {
1589 Self {
1590 is_deleted: value.is_deleted,
1591 storage_nodes: value.storage_nodes.into_owned(),
1592 removed_nodes: value.removed_nodes.into_owned(),
1593 }
1594 }
1595 }
1596
1597 impl SerializeAs<super::StorageTrieUpdates> for StorageTrieUpdates<'_> {
1598 fn serialize_as<S>(
1599 source: &super::StorageTrieUpdates,
1600 serializer: S,
1601 ) -> Result<S::Ok, S::Error>
1602 where
1603 S: Serializer,
1604 {
1605 StorageTrieUpdates::from(source).serialize(serializer)
1606 }
1607 }
1608
1609 impl<'de> DeserializeAs<'de, super::StorageTrieUpdates> for StorageTrieUpdates<'de> {
1610 fn deserialize_as<D>(deserializer: D) -> Result<super::StorageTrieUpdates, D::Error>
1611 where
1612 D: Deserializer<'de>,
1613 {
1614 StorageTrieUpdates::deserialize(deserializer).map(Into::into)
1615 }
1616 }
1617
1618 #[derive(Debug, Serialize, Deserialize)]
1634 pub struct TrieUpdatesSorted<'a> {
1635 account_nodes: Cow<'a, [(Nibbles, Option<BranchNodeCompact>)]>,
1636 storage_tries: B256Map<StorageTrieUpdatesSorted<'a>>,
1637 }
1638
1639 impl<'a> From<&'a super::TrieUpdatesSorted> for TrieUpdatesSorted<'a> {
1640 fn from(value: &'a super::TrieUpdatesSorted) -> Self {
1641 Self {
1642 account_nodes: Cow::Borrowed(&value.account_nodes),
1643 storage_tries: value.storage_tries.iter().map(|(k, v)| (*k, v.into())).collect(),
1644 }
1645 }
1646 }
1647
1648 impl<'a> From<TrieUpdatesSorted<'a>> for super::TrieUpdatesSorted {
1649 fn from(value: TrieUpdatesSorted<'a>) -> Self {
1650 Self {
1651 account_nodes: value.account_nodes.into_owned(),
1652 storage_tries: value
1653 .storage_tries
1654 .into_iter()
1655 .map(|(k, v)| (k, v.into()))
1656 .collect(),
1657 }
1658 }
1659 }
1660
1661 impl SerializeAs<super::TrieUpdatesSorted> for TrieUpdatesSorted<'_> {
1662 fn serialize_as<S>(
1663 source: &super::TrieUpdatesSorted,
1664 serializer: S,
1665 ) -> Result<S::Ok, S::Error>
1666 where
1667 S: Serializer,
1668 {
1669 TrieUpdatesSorted::from(source).serialize(serializer)
1670 }
1671 }
1672
1673 impl<'de> DeserializeAs<'de, super::TrieUpdatesSorted> for TrieUpdatesSorted<'de> {
1674 fn deserialize_as<D>(deserializer: D) -> Result<super::TrieUpdatesSorted, D::Error>
1675 where
1676 D: Deserializer<'de>,
1677 {
1678 TrieUpdatesSorted::deserialize(deserializer).map(Into::into)
1679 }
1680 }
1681
1682 #[derive(Debug, Serialize, Deserialize)]
1698 pub struct StorageTrieUpdatesSorted<'a> {
1699 is_deleted: bool,
1700 storage_nodes: Cow<'a, [(Nibbles, Option<BranchNodeCompact>)]>,
1701 }
1702
1703 impl<'a> From<&'a super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'a> {
1704 fn from(value: &'a super::StorageTrieUpdatesSorted) -> Self {
1705 Self {
1706 is_deleted: value.is_deleted,
1707 storage_nodes: Cow::Borrowed(&value.storage_nodes),
1708 }
1709 }
1710 }
1711
1712 impl<'a> From<StorageTrieUpdatesSorted<'a>> for super::StorageTrieUpdatesSorted {
1713 fn from(value: StorageTrieUpdatesSorted<'a>) -> Self {
1714 Self { is_deleted: value.is_deleted, storage_nodes: value.storage_nodes.into_owned() }
1715 }
1716 }
1717
1718 impl SerializeAs<super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'_> {
1719 fn serialize_as<S>(
1720 source: &super::StorageTrieUpdatesSorted,
1721 serializer: S,
1722 ) -> Result<S::Ok, S::Error>
1723 where
1724 S: Serializer,
1725 {
1726 StorageTrieUpdatesSorted::from(source).serialize(serializer)
1727 }
1728 }
1729
1730 impl<'de> DeserializeAs<'de, super::StorageTrieUpdatesSorted> for StorageTrieUpdatesSorted<'de> {
1731 fn deserialize_as<D>(deserializer: D) -> Result<super::StorageTrieUpdatesSorted, D::Error>
1732 where
1733 D: Deserializer<'de>,
1734 {
1735 StorageTrieUpdatesSorted::deserialize(deserializer).map(Into::into)
1736 }
1737 }
1738
1739 #[cfg(test)]
1740 mod tests {
1741 use crate::{
1742 serde_bincode_compat,
1743 updates::{
1744 StorageTrieUpdates, StorageTrieUpdatesSorted, TrieUpdates, TrieUpdatesSorted,
1745 },
1746 BranchNodeCompact, Nibbles,
1747 };
1748 use alloy_primitives::B256;
1749 use serde::{Deserialize, Serialize};
1750 use serde_with::serde_as;
1751
1752 #[test]
1753 fn test_trie_updates_bincode_roundtrip() {
1754 #[serde_as]
1755 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1756 struct Data {
1757 #[serde_as(as = "serde_bincode_compat::updates::TrieUpdates")]
1758 trie_updates: TrieUpdates,
1759 }
1760
1761 let mut data = Data { trie_updates: TrieUpdates::default() };
1762 let encoded = bincode::serialize(&data).unwrap();
1763 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1764 assert_eq!(decoded, data);
1765
1766 data.trie_updates
1767 .removed_nodes
1768 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1769 let encoded = bincode::serialize(&data).unwrap();
1770 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1771 assert_eq!(decoded, data);
1772
1773 data.trie_updates.account_nodes.insert(
1774 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1775 BranchNodeCompact::default(),
1776 );
1777 let encoded = bincode::serialize(&data).unwrap();
1778 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1779 assert_eq!(decoded, data);
1780
1781 data.trie_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
1782 let encoded = bincode::serialize(&data).unwrap();
1783 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1784 assert_eq!(decoded, data);
1785 }
1786
1787 #[test]
1788 fn test_storage_trie_updates_bincode_roundtrip() {
1789 #[serde_as]
1790 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1791 struct Data {
1792 #[serde_as(as = "serde_bincode_compat::updates::StorageTrieUpdates")]
1793 trie_updates: StorageTrieUpdates,
1794 }
1795
1796 let mut data = Data { trie_updates: StorageTrieUpdates::default() };
1797 let encoded = bincode::serialize(&data).unwrap();
1798 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1799 assert_eq!(decoded, data);
1800
1801 data.trie_updates
1802 .removed_nodes
1803 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1804 let encoded = bincode::serialize(&data).unwrap();
1805 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1806 assert_eq!(decoded, data);
1807
1808 data.trie_updates.storage_nodes.insert(
1809 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1810 BranchNodeCompact::default(),
1811 );
1812 let encoded = bincode::serialize(&data).unwrap();
1813 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1814 assert_eq!(decoded, data);
1815 }
1816
1817 #[test]
1818 fn test_trie_updates_sorted_bincode_roundtrip() {
1819 #[serde_as]
1820 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1821 struct Data {
1822 #[serde_as(as = "serde_bincode_compat::updates::TrieUpdatesSorted")]
1823 trie_updates: TrieUpdatesSorted,
1824 }
1825
1826 let mut data = Data { trie_updates: TrieUpdatesSorted::default() };
1827 let encoded = bincode::serialize(&data).unwrap();
1828 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1829 assert_eq!(decoded, data);
1830
1831 data.trie_updates.account_nodes.push((
1832 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1833 Some(BranchNodeCompact::default()),
1834 ));
1835 let encoded = bincode::serialize(&data).unwrap();
1836 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1837 assert_eq!(decoded, data);
1838
1839 data.trie_updates
1840 .account_nodes
1841 .push((Nibbles::from_nibbles_unchecked([0x0f, 0x0f, 0x0f, 0x0f]), None));
1842 let encoded = bincode::serialize(&data).unwrap();
1843 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1844 assert_eq!(decoded, data);
1845
1846 data.trie_updates
1847 .storage_tries
1848 .insert(B256::default(), StorageTrieUpdatesSorted::default());
1849 let encoded = bincode::serialize(&data).unwrap();
1850 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1851 assert_eq!(decoded, data);
1852 }
1853
1854 #[test]
1855 fn test_storage_trie_updates_sorted_bincode_roundtrip() {
1856 #[serde_as]
1857 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1858 struct Data {
1859 #[serde_as(as = "serde_bincode_compat::updates::StorageTrieUpdatesSorted")]
1860 trie_updates: StorageTrieUpdatesSorted,
1861 }
1862
1863 let mut data = Data { trie_updates: StorageTrieUpdatesSorted::default() };
1864 let encoded = bincode::serialize(&data).unwrap();
1865 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1866 assert_eq!(decoded, data);
1867
1868 data.trie_updates.storage_nodes.push((
1869 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1870 Some(BranchNodeCompact::default()),
1871 ));
1872 let encoded = bincode::serialize(&data).unwrap();
1873 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1874 assert_eq!(decoded, data);
1875
1876 data.trie_updates
1877 .storage_nodes
1878 .push((Nibbles::from_nibbles_unchecked([0x0a, 0x0a, 0x0a, 0x0a]), None));
1879 let encoded = bincode::serialize(&data).unwrap();
1880 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1881 assert_eq!(decoded, data);
1882
1883 data.trie_updates.is_deleted = true;
1884 let encoded = bincode::serialize(&data).unwrap();
1885 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1886 assert_eq!(decoded, data);
1887 }
1888 }
1889}
1890
1891#[cfg(all(test, feature = "serde"))]
1892mod serde_tests {
1893 use super::*;
1894
1895 #[test]
1896 fn test_trie_updates_serde_roundtrip() {
1897 let mut default_updates = TrieUpdates::default();
1898 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1899 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1900 assert_eq!(updates_deserialized, default_updates);
1901
1902 default_updates
1903 .removed_nodes
1904 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1905 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1906 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1907 assert_eq!(updates_deserialized, default_updates);
1908
1909 default_updates.account_nodes.insert(
1910 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1911 BranchNodeCompact::default(),
1912 );
1913 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1914 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1915 assert_eq!(updates_deserialized, default_updates);
1916
1917 default_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
1918 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1919 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
1920 assert_eq!(updates_deserialized, default_updates);
1921 }
1922
1923 #[test]
1924 fn test_storage_trie_updates_serde_roundtrip() {
1925 let mut default_updates = StorageTrieUpdates::default();
1926 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1927 let updates_deserialized: StorageTrieUpdates =
1928 serde_json::from_str(&updates_serialized).unwrap();
1929 assert_eq!(updates_deserialized, default_updates);
1930
1931 default_updates
1932 .removed_nodes
1933 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
1934 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1935 let updates_deserialized: StorageTrieUpdates =
1936 serde_json::from_str(&updates_serialized).unwrap();
1937 assert_eq!(updates_deserialized, default_updates);
1938
1939 default_updates.storage_nodes.insert(
1940 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
1941 BranchNodeCompact::default(),
1942 );
1943 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
1944 let updates_deserialized: StorageTrieUpdates =
1945 serde_json::from_str(&updates_serialized).unwrap();
1946 assert_eq!(updates_deserialized, default_updates);
1947 }
1948}