1use crate::{BranchNodeCompact, HashBuilder, Nibbles};
2use alloc::{
3 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
4 vec::Vec,
5};
6use alloy_primitives::{
7 map::{B256Map, B256Set, HashMap, HashSet},
8 FixedBytes, B256,
9};
10
11#[derive(PartialEq, Eq, Clone, Default, Debug)]
13#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
14pub struct TrieUpdates {
15 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_map"))]
17 pub account_nodes: HashMap<Nibbles, BranchNodeCompact>,
18 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_set"))]
20 pub removed_nodes: HashSet<Nibbles>,
21 pub storage_tries: B256Map<StorageTrieUpdates>,
23}
24
25impl TrieUpdates {
26 pub fn is_empty(&self) -> bool {
28 self.account_nodes.is_empty() &&
29 self.removed_nodes.is_empty() &&
30 self.storage_tries.is_empty()
31 }
32
33 pub const fn account_nodes_ref(&self) -> &HashMap<Nibbles, BranchNodeCompact> {
35 &self.account_nodes
36 }
37
38 pub const fn removed_nodes_ref(&self) -> &HashSet<Nibbles> {
40 &self.removed_nodes
41 }
42
43 pub const fn storage_tries_ref(&self) -> &B256Map<StorageTrieUpdates> {
45 &self.storage_tries
46 }
47
48 pub fn extend(&mut self, other: Self) {
50 self.extend_common(&other);
51 self.account_nodes.extend(exclude_empty_from_pair(other.account_nodes));
52 self.removed_nodes.extend(exclude_empty(other.removed_nodes));
53 for (hashed_address, storage_trie) in other.storage_tries {
54 self.storage_tries.entry(hashed_address).or_default().extend(storage_trie);
55 }
56 }
57
58 pub fn extend_ref(&mut self, other: &Self) {
62 self.extend_common(other);
63 self.account_nodes.extend(exclude_empty_from_pair(
64 other.account_nodes.iter().map(|(k, v)| (*k, v.clone())),
65 ));
66 self.removed_nodes.extend(exclude_empty(other.removed_nodes.iter().copied()));
67 for (hashed_address, storage_trie) in &other.storage_tries {
68 self.storage_tries.entry(*hashed_address).or_default().extend_ref(storage_trie);
69 }
70 }
71
72 fn extend_common(&mut self, other: &Self) {
73 self.account_nodes.retain(|nibbles, _| !other.removed_nodes.contains(nibbles));
74 }
75
76 pub fn insert_storage_updates(
78 &mut self,
79 hashed_address: B256,
80 storage_updates: StorageTrieUpdates,
81 ) {
82 if storage_updates.is_empty() {
83 return;
84 }
85 let existing = self.storage_tries.insert(hashed_address, storage_updates);
86 debug_assert!(existing.is_none());
87 }
88
89 pub fn finalize(
91 &mut self,
92 hash_builder: HashBuilder,
93 removed_keys: HashSet<Nibbles>,
94 destroyed_accounts: B256Set,
95 ) {
96 let (_, updated_nodes) = hash_builder.split();
98 self.account_nodes.extend(exclude_empty_from_pair(updated_nodes));
99
100 self.removed_nodes.extend(exclude_empty(removed_keys));
102
103 for destroyed in destroyed_accounts {
105 self.storage_tries.entry(destroyed).or_default().set_deleted(true);
106 }
107 }
108
109 pub fn into_sorted(mut self) -> TrieUpdatesSorted {
111 self.drain_into_sorted()
112 }
113
114 pub fn drain_into_sorted(&mut self) -> TrieUpdatesSorted {
122 let mut account_nodes = self
123 .account_nodes
124 .drain()
125 .map(|(path, node)| {
126 self.removed_nodes.remove(&path);
128 (path, Some(node))
129 })
130 .collect::<Vec<_>>();
131
132 account_nodes.extend(self.removed_nodes.drain().map(|path| (path, None)));
133 account_nodes.sort_unstable_by(|a, b| a.0.cmp(&b.0));
134
135 let storage_tries = self
136 .storage_tries
137 .drain()
138 .map(|(hashed_address, updates)| (hashed_address, updates.into_sorted()))
139 .collect();
140 TrieUpdatesSorted { account_nodes, storage_tries }
141 }
142
143 pub fn into_sorted_ref<'a>(&'a self) -> TrieUpdatesSortedRef<'a> {
145 let mut account_nodes = self.account_nodes.iter().collect::<Vec<_>>();
146 account_nodes.sort_unstable_by(|a, b| a.0.cmp(b.0));
147
148 TrieUpdatesSortedRef {
149 removed_nodes: self.removed_nodes.iter().collect::<BTreeSet<_>>(),
150 account_nodes,
151 storage_tries: self
152 .storage_tries
153 .iter()
154 .map(|m| (*m.0, m.1.into_sorted_ref().clone()))
155 .collect(),
156 }
157 }
158
159 pub fn clear(&mut self) {
161 self.account_nodes.clear();
162 self.removed_nodes.clear();
163 self.storage_tries.clear();
164 }
165}
166
167#[derive(PartialEq, Eq, Clone, Default, Debug)]
169#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
170pub struct StorageTrieUpdates {
171 pub is_deleted: bool,
173 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_map"))]
175 pub storage_nodes: HashMap<Nibbles, BranchNodeCompact>,
176 #[cfg_attr(any(test, feature = "serde"), serde(with = "serde_nibbles_set"))]
178 pub removed_nodes: HashSet<Nibbles>,
179}
180
181#[cfg(feature = "test-utils")]
182impl StorageTrieUpdates {
183 pub fn new(updates: impl IntoIterator<Item = (Nibbles, BranchNodeCompact)>) -> Self {
185 Self { storage_nodes: exclude_empty_from_pair(updates).collect(), ..Default::default() }
186 }
187}
188
189impl StorageTrieUpdates {
190 pub fn deleted() -> Self {
192 Self {
193 is_deleted: true,
194 storage_nodes: HashMap::default(),
195 removed_nodes: HashSet::default(),
196 }
197 }
198
199 pub fn len(&self) -> usize {
201 (self.is_deleted as usize) + self.storage_nodes.len() + self.removed_nodes.len()
202 }
203
204 pub const fn is_deleted(&self) -> bool {
206 self.is_deleted
207 }
208
209 pub const fn storage_nodes_ref(&self) -> &HashMap<Nibbles, BranchNodeCompact> {
211 &self.storage_nodes
212 }
213
214 pub const fn removed_nodes_ref(&self) -> &HashSet<Nibbles> {
216 &self.removed_nodes
217 }
218
219 pub fn is_empty(&self) -> bool {
221 !self.is_deleted && self.storage_nodes.is_empty() && self.removed_nodes.is_empty()
222 }
223
224 pub const fn set_deleted(&mut self, deleted: bool) {
226 self.is_deleted = deleted;
227 }
228
229 pub fn extend(&mut self, other: Self) {
231 self.extend_common(&other);
232 self.storage_nodes.extend(exclude_empty_from_pair(other.storage_nodes));
233 self.removed_nodes.extend(exclude_empty(other.removed_nodes));
234 }
235
236 pub fn extend_ref(&mut self, other: &Self) {
240 self.extend_common(other);
241 self.storage_nodes.extend(exclude_empty_from_pair(
242 other.storage_nodes.iter().map(|(k, v)| (*k, v.clone())),
243 ));
244 self.removed_nodes.extend(exclude_empty(other.removed_nodes.iter().copied()));
245 }
246
247 fn extend_common(&mut self, other: &Self) {
248 if other.is_deleted {
249 self.storage_nodes.clear();
250 self.removed_nodes.clear();
251 }
252 self.is_deleted |= other.is_deleted;
253 self.storage_nodes.retain(|nibbles, _| !other.removed_nodes.contains(nibbles));
254 }
255
256 pub fn finalize(&mut self, hash_builder: HashBuilder, removed_keys: HashSet<Nibbles>) {
258 let (_, updated_nodes) = hash_builder.split();
260 self.storage_nodes.extend(exclude_empty_from_pair(updated_nodes));
261
262 self.removed_nodes.extend(exclude_empty(removed_keys));
264 }
265
266 pub fn into_sorted(mut self) -> StorageTrieUpdatesSorted {
268 let mut storage_nodes = self
269 .storage_nodes
270 .into_iter()
271 .map(|(path, node)| {
272 self.removed_nodes.remove(&path);
274 (path, Some(node))
275 })
276 .collect::<Vec<_>>();
277
278 storage_nodes.extend(self.removed_nodes.into_iter().map(|path| (path, None)));
279 storage_nodes.sort_unstable_by(|a, b| a.0.cmp(&b.0));
280
281 StorageTrieUpdatesSorted { is_deleted: self.is_deleted, storage_nodes }
282 }
283
284 pub fn into_sorted_ref(&self) -> StorageTrieUpdatesSortedRef<'_> {
286 StorageTrieUpdatesSortedRef {
287 is_deleted: self.is_deleted,
288 removed_nodes: self.removed_nodes.iter().collect::<BTreeSet<_>>(),
289 storage_nodes: self.storage_nodes.iter().collect::<BTreeMap<_, _>>(),
290 }
291 }
292}
293
294#[cfg(any(test, feature = "serde"))]
299mod serde_nibbles_set {
300 use crate::Nibbles;
301 use alloc::{
302 string::{String, ToString},
303 vec::Vec,
304 };
305 use alloy_primitives::map::HashSet;
306 use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
307
308 pub(super) fn serialize<S>(map: &HashSet<Nibbles>, serializer: S) -> Result<S::Ok, S::Error>
309 where
310 S: Serializer,
311 {
312 let mut storage_nodes =
313 map.iter().map(|elem| alloy_primitives::hex::encode(elem.pack())).collect::<Vec<_>>();
314 storage_nodes.sort_unstable();
315 storage_nodes.serialize(serializer)
316 }
317
318 pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<HashSet<Nibbles>, D::Error>
319 where
320 D: Deserializer<'de>,
321 {
322 Vec::<String>::deserialize(deserializer)?
323 .into_iter()
324 .map(|node| {
325 Ok(Nibbles::unpack(
326 alloy_primitives::hex::decode(node)
327 .map_err(|err| D::Error::custom(err.to_string()))?,
328 ))
329 })
330 .collect::<Result<HashSet<_>, _>>()
331 }
332}
333
334#[cfg(any(test, feature = "serde"))]
339mod serde_nibbles_map {
340 use crate::Nibbles;
341 use alloc::{
342 string::{String, ToString},
343 vec::Vec,
344 };
345 use alloy_primitives::{hex, map::HashMap};
346 use core::marker::PhantomData;
347 use serde::{
348 de::{Error, MapAccess, Visitor},
349 ser::SerializeMap,
350 Deserialize, Deserializer, Serialize, Serializer,
351 };
352
353 pub(super) fn serialize<S, T>(
354 map: &HashMap<Nibbles, T>,
355 serializer: S,
356 ) -> Result<S::Ok, S::Error>
357 where
358 S: Serializer,
359 T: Serialize,
360 {
361 let mut map_serializer = serializer.serialize_map(Some(map.len()))?;
362 let mut storage_nodes = Vec::from_iter(map);
363 storage_nodes.sort_unstable_by_key(|node| node.0);
364 for (k, v) in storage_nodes {
365 let packed = alloy_primitives::hex::encode(k.pack());
367 map_serializer.serialize_entry(&packed, &v)?;
368 }
369 map_serializer.end()
370 }
371
372 pub(super) fn deserialize<'de, D, T>(deserializer: D) -> Result<HashMap<Nibbles, T>, D::Error>
373 where
374 D: Deserializer<'de>,
375 T: Deserialize<'de>,
376 {
377 struct NibblesMapVisitor<T> {
378 marker: PhantomData<T>,
379 }
380
381 impl<'de, T> Visitor<'de> for NibblesMapVisitor<T>
382 where
383 T: Deserialize<'de>,
384 {
385 type Value = HashMap<Nibbles, T>;
386
387 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
388 formatter.write_str("a map with hex-encoded Nibbles keys")
389 }
390
391 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
392 where
393 A: MapAccess<'de>,
394 {
395 let mut result = HashMap::with_capacity_and_hasher(
396 map.size_hint().unwrap_or(0),
397 Default::default(),
398 );
399
400 while let Some((key, value)) = map.next_entry::<String, T>()? {
401 let decoded_key =
402 hex::decode(&key).map_err(|err| Error::custom(err.to_string()))?;
403
404 let nibbles = Nibbles::unpack(&decoded_key);
405
406 result.insert(nibbles, value);
407 }
408
409 Ok(result)
410 }
411 }
412
413 deserializer.deserialize_map(NibblesMapVisitor { marker: PhantomData })
414 }
415}
416
417#[derive(PartialEq, Eq, Clone, Default, Debug)]
419#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
420pub struct TrieUpdatesSortedRef<'a> {
421 pub account_nodes: Vec<(&'a Nibbles, &'a BranchNodeCompact)>,
423 pub removed_nodes: BTreeSet<&'a Nibbles>,
425 pub storage_tries: BTreeMap<FixedBytes<32>, StorageTrieUpdatesSortedRef<'a>>,
427}
428
429#[derive(PartialEq, Eq, Clone, Default, Debug)]
431#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
432pub struct TrieUpdatesSorted {
433 pub account_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
436 pub storage_tries: B256Map<StorageTrieUpdatesSorted>,
438}
439
440impl TrieUpdatesSorted {
441 pub fn account_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
443 &self.account_nodes
444 }
445
446 pub const fn storage_tries_ref(&self) -> &B256Map<StorageTrieUpdatesSorted> {
448 &self.storage_tries
449 }
450}
451
452impl AsRef<Self> for TrieUpdatesSorted {
453 fn as_ref(&self) -> &Self {
454 self
455 }
456}
457
458#[derive(PartialEq, Eq, Clone, Default, Debug)]
460#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize))]
461pub struct StorageTrieUpdatesSortedRef<'a> {
462 pub is_deleted: bool,
464 pub storage_nodes: BTreeMap<&'a Nibbles, &'a BranchNodeCompact>,
466 pub removed_nodes: BTreeSet<&'a Nibbles>,
468}
469
470#[derive(PartialEq, Eq, Clone, Default, Debug)]
472#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
473pub struct StorageTrieUpdatesSorted {
474 pub is_deleted: bool,
476 pub storage_nodes: Vec<(Nibbles, Option<BranchNodeCompact>)>,
479}
480
481impl StorageTrieUpdatesSorted {
482 pub const fn is_deleted(&self) -> bool {
484 self.is_deleted
485 }
486
487 pub fn storage_nodes_ref(&self) -> &[(Nibbles, Option<BranchNodeCompact>)] {
489 &self.storage_nodes
490 }
491}
492
493fn exclude_empty(iter: impl IntoIterator<Item = Nibbles>) -> impl Iterator<Item = Nibbles> {
495 iter.into_iter().filter(|n| !n.is_empty())
496}
497
498fn exclude_empty_from_pair<V>(
500 iter: impl IntoIterator<Item = (Nibbles, V)>,
501) -> impl Iterator<Item = (Nibbles, V)> {
502 iter.into_iter().filter(|(n, _)| !n.is_empty())
503}
504
505#[cfg(feature = "serde-bincode-compat")]
507pub mod serde_bincode_compat {
508 use crate::{BranchNodeCompact, Nibbles};
509 use alloc::borrow::Cow;
510 use alloy_primitives::map::{B256Map, HashMap, HashSet};
511 use serde::{Deserialize, Deserializer, Serialize, Serializer};
512 use serde_with::{DeserializeAs, SerializeAs};
513
514 #[derive(Debug, Serialize, Deserialize)]
530 pub struct TrieUpdates<'a> {
531 account_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
532 removed_nodes: Cow<'a, HashSet<Nibbles>>,
533 storage_tries: B256Map<StorageTrieUpdates<'a>>,
534 }
535
536 impl<'a> From<&'a super::TrieUpdates> for TrieUpdates<'a> {
537 fn from(value: &'a super::TrieUpdates) -> Self {
538 Self {
539 account_nodes: Cow::Borrowed(&value.account_nodes),
540 removed_nodes: Cow::Borrowed(&value.removed_nodes),
541 storage_tries: value.storage_tries.iter().map(|(k, v)| (*k, v.into())).collect(),
542 }
543 }
544 }
545
546 impl<'a> From<TrieUpdates<'a>> for super::TrieUpdates {
547 fn from(value: TrieUpdates<'a>) -> Self {
548 Self {
549 account_nodes: value.account_nodes.into_owned(),
550 removed_nodes: value.removed_nodes.into_owned(),
551 storage_tries: value
552 .storage_tries
553 .into_iter()
554 .map(|(k, v)| (k, v.into()))
555 .collect(),
556 }
557 }
558 }
559
560 impl SerializeAs<super::TrieUpdates> for TrieUpdates<'_> {
561 fn serialize_as<S>(source: &super::TrieUpdates, serializer: S) -> Result<S::Ok, S::Error>
562 where
563 S: Serializer,
564 {
565 TrieUpdates::from(source).serialize(serializer)
566 }
567 }
568
569 impl<'de> DeserializeAs<'de, super::TrieUpdates> for TrieUpdates<'de> {
570 fn deserialize_as<D>(deserializer: D) -> Result<super::TrieUpdates, D::Error>
571 where
572 D: Deserializer<'de>,
573 {
574 TrieUpdates::deserialize(deserializer).map(Into::into)
575 }
576 }
577
578 #[derive(Debug, Serialize, Deserialize)]
594 pub struct StorageTrieUpdates<'a> {
595 is_deleted: bool,
596 storage_nodes: Cow<'a, HashMap<Nibbles, BranchNodeCompact>>,
597 removed_nodes: Cow<'a, HashSet<Nibbles>>,
598 }
599
600 impl<'a> From<&'a super::StorageTrieUpdates> for StorageTrieUpdates<'a> {
601 fn from(value: &'a super::StorageTrieUpdates) -> Self {
602 Self {
603 is_deleted: value.is_deleted,
604 storage_nodes: Cow::Borrowed(&value.storage_nodes),
605 removed_nodes: Cow::Borrowed(&value.removed_nodes),
606 }
607 }
608 }
609
610 impl<'a> From<StorageTrieUpdates<'a>> for super::StorageTrieUpdates {
611 fn from(value: StorageTrieUpdates<'a>) -> Self {
612 Self {
613 is_deleted: value.is_deleted,
614 storage_nodes: value.storage_nodes.into_owned(),
615 removed_nodes: value.removed_nodes.into_owned(),
616 }
617 }
618 }
619
620 impl SerializeAs<super::StorageTrieUpdates> for StorageTrieUpdates<'_> {
621 fn serialize_as<S>(
622 source: &super::StorageTrieUpdates,
623 serializer: S,
624 ) -> Result<S::Ok, S::Error>
625 where
626 S: Serializer,
627 {
628 StorageTrieUpdates::from(source).serialize(serializer)
629 }
630 }
631
632 impl<'de> DeserializeAs<'de, super::StorageTrieUpdates> for StorageTrieUpdates<'de> {
633 fn deserialize_as<D>(deserializer: D) -> Result<super::StorageTrieUpdates, D::Error>
634 where
635 D: Deserializer<'de>,
636 {
637 StorageTrieUpdates::deserialize(deserializer).map(Into::into)
638 }
639 }
640
641 #[cfg(test)]
642 mod tests {
643 use crate::{
644 serde_bincode_compat,
645 updates::{StorageTrieUpdates, TrieUpdates},
646 BranchNodeCompact, Nibbles,
647 };
648 use alloy_primitives::B256;
649 use serde::{Deserialize, Serialize};
650 use serde_with::serde_as;
651
652 #[test]
653 fn test_trie_updates_bincode_roundtrip() {
654 #[serde_as]
655 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
656 struct Data {
657 #[serde_as(as = "serde_bincode_compat::updates::TrieUpdates")]
658 trie_updates: TrieUpdates,
659 }
660
661 let mut data = Data { trie_updates: TrieUpdates::default() };
662 let encoded = bincode::serialize(&data).unwrap();
663 let decoded: Data = bincode::deserialize(&encoded).unwrap();
664 assert_eq!(decoded, data);
665
666 data.trie_updates
667 .removed_nodes
668 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
669 let encoded = bincode::serialize(&data).unwrap();
670 let decoded: Data = bincode::deserialize(&encoded).unwrap();
671 assert_eq!(decoded, data);
672
673 data.trie_updates.account_nodes.insert(
674 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
675 BranchNodeCompact::default(),
676 );
677 let encoded = bincode::serialize(&data).unwrap();
678 let decoded: Data = bincode::deserialize(&encoded).unwrap();
679 assert_eq!(decoded, data);
680
681 data.trie_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
682 let encoded = bincode::serialize(&data).unwrap();
683 let decoded: Data = bincode::deserialize(&encoded).unwrap();
684 assert_eq!(decoded, data);
685 }
686
687 #[test]
688 fn test_storage_trie_updates_bincode_roundtrip() {
689 #[serde_as]
690 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
691 struct Data {
692 #[serde_as(as = "serde_bincode_compat::updates::StorageTrieUpdates")]
693 trie_updates: StorageTrieUpdates,
694 }
695
696 let mut data = Data { trie_updates: StorageTrieUpdates::default() };
697 let encoded = bincode::serialize(&data).unwrap();
698 let decoded: Data = bincode::deserialize(&encoded).unwrap();
699 assert_eq!(decoded, data);
700
701 data.trie_updates
702 .removed_nodes
703 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
704 let encoded = bincode::serialize(&data).unwrap();
705 let decoded: Data = bincode::deserialize(&encoded).unwrap();
706 assert_eq!(decoded, data);
707
708 data.trie_updates.storage_nodes.insert(
709 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
710 BranchNodeCompact::default(),
711 );
712 let encoded = bincode::serialize(&data).unwrap();
713 let decoded: Data = bincode::deserialize(&encoded).unwrap();
714 assert_eq!(decoded, data);
715 }
716 }
717}
718
719#[cfg(all(test, feature = "serde"))]
720mod tests {
721 use super::*;
722
723 #[test]
724 fn test_trie_updates_serde_roundtrip() {
725 let mut default_updates = TrieUpdates::default();
726 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
727 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
728 assert_eq!(updates_deserialized, default_updates);
729
730 default_updates
731 .removed_nodes
732 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
733 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
734 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
735 assert_eq!(updates_deserialized, default_updates);
736
737 default_updates.account_nodes.insert(
738 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
739 BranchNodeCompact::default(),
740 );
741 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
742 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
743 assert_eq!(updates_deserialized, default_updates);
744
745 default_updates.storage_tries.insert(B256::default(), StorageTrieUpdates::default());
746 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
747 let updates_deserialized: TrieUpdates = serde_json::from_str(&updates_serialized).unwrap();
748 assert_eq!(updates_deserialized, default_updates);
749 }
750
751 #[test]
752 fn test_storage_trie_updates_serde_roundtrip() {
753 let mut default_updates = StorageTrieUpdates::default();
754 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
755 let updates_deserialized: StorageTrieUpdates =
756 serde_json::from_str(&updates_serialized).unwrap();
757 assert_eq!(updates_deserialized, default_updates);
758
759 default_updates
760 .removed_nodes
761 .insert(Nibbles::from_nibbles_unchecked([0x0b, 0x0e, 0x0e, 0x0f]));
762 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
763 let updates_deserialized: StorageTrieUpdates =
764 serde_json::from_str(&updates_serialized).unwrap();
765 assert_eq!(updates_deserialized, default_updates);
766
767 default_updates.storage_nodes.insert(
768 Nibbles::from_nibbles_unchecked([0x0d, 0x0e, 0x0a, 0x0d]),
769 BranchNodeCompact::default(),
770 );
771 let updates_serialized = serde_json::to_string(&default_updates).unwrap();
772 let updates_deserialized: StorageTrieUpdates =
773 serde_json::from_str(&updates_serialized).unwrap();
774 assert_eq!(updates_deserialized, default_updates);
775 }
776}