reth_trie_common/
subnode.rs

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