reth_trie_common/
subnode.rs

1use super::BranchNodeCompact;
2
3/// Walker sub node for storing intermediate state root calculation state in the database.
4#[derive(Debug, Clone, PartialEq, Eq, Default)]
5pub struct StoredSubNode {
6    /// The key of the current node.
7    pub key: Vec<u8>,
8    /// The index of the next child to visit.
9    pub nibble: Option<u8>,
10    /// The node itself.
11    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}