Skip to main content

ethrex_trie/
node_hash.rs

1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3use ethereum_types::H256;
4use ethrex_crypto::Crypto;
5use ethrex_rlp::{decode::RLPDecode, encode::RLPEncode, error::RLPDecodeError, structs::Encoder};
6
7use crate::rkyv_utils::H256Wrapper;
8
9/// Struct representing a trie node hash
10/// If the encoded node is less than 32 bits, contains the encoded node itself
11// TODO: Check if we can omit the Inline variant, as nodes will always be bigger than 32 bits in our use case
12// TODO: Check if making this `Copy` can make the code less verbose at a reasonable performance cost
13#[derive(
14    Debug,
15    Clone,
16    Copy,
17    PartialEq,
18    Hash,
19    PartialOrd,
20    Ord,
21    Eq,
22    serde::Serialize,
23    serde::Deserialize,
24    rkyv::Serialize,
25    rkyv::Deserialize,
26    rkyv::Archive,
27)]
28pub enum NodeHash {
29    Hashed(#[rkyv(with=H256Wrapper)] H256),
30    // Inline is always len < 32. We need to store the length of the data, a u8 is enough.
31    Inline(([u8; 31], u8)),
32}
33
34impl AsRef<[u8]> for NodeHash {
35    fn as_ref(&self) -> &[u8] {
36        match self {
37            NodeHash::Inline((slice, len)) => &slice[0..(*len as usize)],
38            NodeHash::Hashed(x) => x.as_bytes(),
39        }
40    }
41}
42
43impl NodeHash {
44    /// Returns the `NodeHash` of an encoded node (encoded using the NodeEncoder)
45    pub fn from_encoded(encoded: &[u8], crypto: &dyn Crypto) -> NodeHash {
46        if encoded.len() >= 32 {
47            let hash = crypto.keccak256(encoded);
48            NodeHash::Hashed(H256::from_slice(&hash))
49        } else {
50            NodeHash::from_slice(encoded)
51        }
52    }
53
54    /// Converts a slice of an already hashed data (in case it's not inlineable) to a NodeHash.
55    /// Panics if the slice is over 32 bytes
56    /// If you need to hash it in case its len >= 32 see `from_encoded`
57    pub(crate) fn from_slice(slice: &[u8]) -> NodeHash {
58        match slice.len() {
59            0..32 => {
60                let mut buffer = [0; 31];
61                buffer[0..slice.len()].copy_from_slice(slice);
62                NodeHash::Inline((buffer, slice.len() as u8))
63            }
64            _ => NodeHash::Hashed(H256::from_slice(slice)),
65        }
66    }
67
68    /// Returns the finalized hash
69    /// NOTE: This will hash smaller nodes, only use to get the final root hash, not for intermediate node hashes
70    pub fn finalize(self, crypto: &dyn Crypto) -> H256 {
71        match self {
72            NodeHash::Inline(_) => H256(crypto.keccak256(self.as_ref())),
73            NodeHash::Hashed(x) => x,
74        }
75    }
76
77    /// Returns true if the hash is valid
78    /// The hash will only be considered invalid if it is empty
79    /// Aka if it has a default value instead of being a product of hash computation
80    pub fn is_valid(&self) -> bool {
81        !matches!(self, NodeHash::Inline(v) if v.1 == 0)
82    }
83
84    /// Encodes this NodeHash with the given encoder.
85    pub fn encode<'a>(&self, mut encoder: Encoder<'a>) -> Encoder<'a> {
86        match self {
87            NodeHash::Inline(_) => {
88                encoder = encoder.encode_raw(self.as_ref());
89            }
90            NodeHash::Hashed(_) => {
91                encoder = encoder.encode_bytes(self.as_ref());
92            }
93        }
94        encoder
95    }
96
97    pub fn len(&self) -> usize {
98        match self {
99            NodeHash::Hashed(h256) => h256.as_bytes().len(),
100            NodeHash::Inline(value) => value.1 as usize,
101        }
102    }
103
104    pub fn is_empty(&self) -> bool {
105        match self {
106            NodeHash::Hashed(h256) => h256.as_bytes().is_empty(),
107            NodeHash::Inline(value) => value.1 == 0,
108        }
109    }
110}
111
112impl From<H256> for NodeHash {
113    fn from(value: H256) -> Self {
114        NodeHash::Hashed(value)
115    }
116}
117
118impl From<NodeHash> for Vec<u8> {
119    fn from(val: NodeHash) -> Self {
120        val.as_ref().to_vec()
121    }
122}
123
124impl From<&NodeHash> for Vec<u8> {
125    fn from(val: &NodeHash) -> Self {
126        val.as_ref().to_vec()
127    }
128}
129
130impl Default for NodeHash {
131    fn default() -> Self {
132        NodeHash::Inline(([0; 31], 0))
133    }
134}
135
136// Encoded as Vec<u8>
137impl RLPEncode for NodeHash {
138    fn encode(&self, buf: &mut dyn bytes::BufMut) {
139        RLPEncode::encode(&Into::<Vec<u8>>::into(self), buf)
140    }
141
142    fn length(&self) -> usize {
143        match self {
144            NodeHash::Hashed(_) => 33,                   // 1 byte prefix + 32 bytes
145            NodeHash::Inline((_, 0)) => 1,               // if empty then it's encoded to RLP_NULL
146            NodeHash::Inline((_, len)) => *len as usize, // already encoded
147        }
148    }
149}
150
151impl RLPDecode for NodeHash {
152    fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), ethrex_rlp::error::RLPDecodeError> {
153        let (hash, rest): (Vec<u8>, &[u8]);
154        (hash, rest) = RLPDecode::decode_unfinished(rlp)?;
155        if hash.len() > 32 {
156            return Err(RLPDecodeError::InvalidLength);
157        }
158        let hash = NodeHash::from_slice(&hash);
159        Ok((hash, rest))
160    }
161}