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