Skip to main content

ethrex_trie/
rlp.rs

1#[cfg(not(feature = "std"))]
2use alloc::{string::ToString, vec::Vec};
3use core::array;
4
5// Contains RLP encoding and decoding implementations for Trie Nodes
6// This encoding is only used to store the nodes in the DB, it is not the encoding used for hash computation
7use ethrex_rlp::{
8    constants::RLP_NULL,
9    decode::{RLPDecode, decode_bytes},
10    encode::{RLPEncode, encode_length},
11    error::RLPDecodeError,
12    structs::{Decoder, Encoder},
13};
14
15use ethrex_crypto::NativeCrypto;
16
17use super::node::{BranchNode, ExtensionNode, LeafNode, Node};
18use crate::{Nibbles, NodeHash};
19
20// SAFETY: `NativeCrypto` is used here instead of a `&dyn Crypto` parameter because
21// `RLPEncode` is a fixed trait signature that cannot accept extra parameters.
22// This is safe in the `commit()` path: `NodeRef::commit()` recursively populates
23// child `OnceLock` hashes before calling `encode()`, so `compute_hash_ref` returns
24// cached values without invoking keccak. If `encode()` were called on uncommitted
25// nodes (e.g. from `put_batch_no_alloc`), `NativeCrypto` would be used and the
26// result stored in the `OnceLock` — but this only happens in native storage paths
27// where `NativeCrypto` is the correct provider.
28impl RLPEncode for BranchNode {
29    fn encode(&self, buf: &mut dyn bytes::BufMut) {
30        let value_len = <[u8] as RLPEncode>::length(&self.value);
31        let payload_len = self.choices.iter().fold(value_len, |acc, child| {
32            acc + RLPEncode::length(child.compute_hash_ref(&NativeCrypto))
33        });
34
35        encode_length(payload_len, buf);
36        for child in self.choices.iter() {
37            match child.compute_hash_ref(&NativeCrypto) {
38                NodeHash::Hashed(hash) => hash.0.encode(buf),
39                NodeHash::Inline((_, 0)) => buf.put_u8(RLP_NULL),
40                NodeHash::Inline((encoded, len)) => buf.put_slice(&encoded[..*len as usize]),
41            }
42        }
43        <[u8] as RLPEncode>::encode(&self.value, buf);
44    }
45
46    // Duplicated to prealloc the buffer and avoid calculating the payload length twice
47    fn encode_to_vec(&self) -> Vec<u8> {
48        let value_len = <[u8] as RLPEncode>::length(&self.value);
49        let choices_len = self.choices.iter().fold(0, |acc, child| {
50            acc + RLPEncode::length(child.compute_hash_ref(&NativeCrypto))
51        });
52        let payload_len = choices_len + value_len;
53
54        let mut buf: Vec<u8> = Vec::with_capacity(payload_len + 3); // 3 byte prefix headroom
55
56        encode_length(payload_len, &mut buf);
57        for child in self.choices.iter() {
58            match child.compute_hash_ref(&NativeCrypto) {
59                NodeHash::Hashed(hash) => hash.0.encode(&mut buf),
60                NodeHash::Inline((_, 0)) => buf.push(RLP_NULL),
61                NodeHash::Inline((encoded, len)) => {
62                    buf.extend_from_slice(&encoded[..*len as usize])
63                }
64            }
65        }
66        <[u8] as RLPEncode>::encode(&self.value, &mut buf);
67
68        buf
69    }
70}
71
72impl RLPEncode for ExtensionNode {
73    fn encode(&self, buf: &mut dyn bytes::BufMut) {
74        let mut encoder = Encoder::new(buf).encode_bytes(&self.prefix.encode_compact());
75        encoder = self.child.compute_hash(&NativeCrypto).encode(encoder);
76        encoder.finish();
77    }
78}
79
80impl RLPEncode for LeafNode {
81    fn encode(&self, buf: &mut dyn bytes::BufMut) {
82        Encoder::new(buf)
83            .encode_bytes(&self.partial.encode_compact())
84            .encode_bytes(&self.value)
85            .finish()
86    }
87}
88
89impl RLPEncode for Node {
90    fn encode(&self, buf: &mut dyn bytes::BufMut) {
91        match self {
92            Node::Branch(n) => n.encode(buf),
93            Node::Extension(n) => n.encode(buf),
94            Node::Leaf(n) => n.encode(buf),
95        }
96    }
97}
98
99impl RLPDecode for Node {
100    fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
101        let mut rlp_items_len = 0;
102        let mut rlp_items: [Option<&[u8]>; 17] = Default::default();
103        let mut decoder = Decoder::new(rlp)?;
104        let mut item;
105        // Get encoded fields
106
107        // Check if we reached the end or if we decoded more items than the ones we need
108        while !decoder.is_done() && rlp_items_len < 17 {
109            (item, decoder) = decoder.get_encoded_item_ref()?;
110            rlp_items[rlp_items_len] = Some(item);
111            rlp_items_len += 1;
112        }
113        if !decoder.is_done() {
114            return Err(RLPDecodeError::Custom(
115                "Invalid arg count for Node, expected 2 or 17, got more than 17".to_string(),
116            ));
117        }
118        // Deserialize into node depending on the available fields
119        let node = match rlp_items_len {
120            // Leaf or Extension Node
121            2 => {
122                let (path, _) = decode_bytes(rlp_items[0].expect("we already checked the length"))?;
123                let path = Nibbles::decode_compact(path);
124                if path.is_leaf() {
125                    // Decode as Leaf
126                    let (value, _) =
127                        decode_bytes(rlp_items[1].expect("we already checked the length"))?;
128                    LeafNode {
129                        partial: path,
130                        value: value.to_vec(),
131                    }
132                    .into()
133                } else {
134                    // Decode as Extension
135                    ExtensionNode {
136                        prefix: path,
137                        child: decode_child(rlp_items[1].expect("we already checked the length"))
138                            .into(),
139                    }
140                    .into()
141                }
142            }
143            // Branch Node
144            17 => {
145                let choices = array::from_fn(|i| {
146                    decode_child(rlp_items[i].expect("we already checked the length")).into()
147                });
148                let (value, _) =
149                    decode_bytes(rlp_items[16].expect("we already checked the length"))?;
150                BranchNode {
151                    choices,
152                    value: value.to_vec(),
153                }
154                .into()
155            }
156            n => {
157                return Err(RLPDecodeError::Custom(format!(
158                    "Invalid arg count for Node, expected 2 or 17, got {n}"
159                )));
160            }
161        };
162        Ok((node, decoder.finish()?))
163    }
164}
165
166fn decode_child(rlp: &[u8]) -> NodeHash {
167    match decode_bytes(rlp) {
168        Ok((hash, &[])) if hash.len() == 32 => NodeHash::from_slice(hash),
169        Ok((&[], &[])) => NodeHash::default(),
170        _ => NodeHash::from_slice(rlp),
171    }
172}