Skip to main content

ethrex_trie/
node_hash.rs

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