reth_trie_common/
subnode.rs
1use super::BranchNodeCompact;
2use alloc::vec::Vec;
3
4#[derive(Debug, Clone, PartialEq, Eq, Default)]
6pub struct StoredSubNode {
7 pub key: Vec<u8>,
9 pub nibble: Option<u8>,
11 pub node: Option<BranchNodeCompact>,
13}
14
15#[cfg(any(test, feature = "reth-codec"))]
16impl reth_codecs::Compact for StoredSubNode {
17 fn to_compact<B>(&self, buf: &mut B) -> usize
18 where
19 B: bytes::BufMut + AsMut<[u8]>,
20 {
21 let mut len = 0;
22
23 buf.put_u16(self.key.len() as u16);
24 buf.put_slice(&self.key[..]);
25 len += 2 + self.key.len();
26
27 if let Some(nibble) = self.nibble {
28 buf.put_u8(1);
29 buf.put_u8(nibble);
30 len += 2;
31 } else {
32 buf.put_u8(0);
33 len += 1;
34 }
35
36 if let Some(node) = &self.node {
37 buf.put_u8(1);
38 len += 1;
39 len += node.to_compact(buf);
40 } else {
41 len += 1;
42 buf.put_u8(0);
43 }
44
45 len
46 }
47
48 fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
49 use bytes::Buf;
50
51 let key_len = buf.get_u16() as usize;
52 let key = Vec::from(&buf[..key_len]);
53 buf.advance(key_len);
54
55 let nibbles_exists = buf.get_u8() != 0;
56 let nibble = nibbles_exists.then(|| buf.get_u8());
57
58 let node_exists = buf.get_u8() != 0;
59 let node = node_exists.then(|| {
60 let (node, rest) = BranchNodeCompact::from_compact(buf, 0);
61 buf = rest;
62 node
63 });
64
65 (Self { key, nibble, node }, buf)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::TrieMask;
73 use alloy_primitives::B256;
74 use reth_codecs::Compact;
75
76 #[test]
77 fn subnode_roundtrip() {
78 let subnode = StoredSubNode {
79 key: vec![],
80 nibble: None,
81 node: Some(BranchNodeCompact {
82 state_mask: TrieMask::new(1),
83 tree_mask: TrieMask::new(0),
84 hash_mask: TrieMask::new(1),
85 hashes: vec![B256::ZERO],
86 root_hash: None,
87 }),
88 };
89
90 let mut encoded = vec![];
91 subnode.to_compact(&mut encoded);
92 let (decoded, _) = StoredSubNode::from_compact(&encoded[..], 0);
93
94 assert_eq!(subnode, decoded);
95 }
96}