reth_codecs/alloy/
trie.rs1use crate::Compact;
4use alloc::vec::Vec;
5use alloy_primitives::{FixedBytesSliceExt, B256};
6use alloy_trie::{
7 hash_builder::{HashBuilderValue, HashBuilderValueRef},
8 BranchNodeCompact, TrieMask,
9};
10use bytes::{Buf, BufMut};
11
12const HASH_BUILDER_TYPE_HASH: u8 = 0;
14
15const HASH_BUILDER_TYPE_BYTES: u8 = 1;
17
18impl Compact for HashBuilderValue {
19 fn to_compact<B>(&self, buf: &mut B) -> usize
20 where
21 B: BufMut + AsMut<[u8]>,
22 {
23 match self.as_ref() {
24 HashBuilderValueRef::Hash(hash) => {
25 buf.put_u8(HASH_BUILDER_TYPE_HASH);
26 1 + hash.to_compact(buf)
27 }
28 HashBuilderValueRef::Bytes(bytes) => {
29 buf.put_u8(HASH_BUILDER_TYPE_BYTES);
30 1 + bytes.to_compact(buf)
31 }
32 }
33 }
34
35 fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
36 let mut this = Self::default();
37 let buf = match buf.get_u8() {
38 HASH_BUILDER_TYPE_HASH => {
39 let (hash, buf) = B256::from_compact(buf, 32);
40 this.set_from_ref(HashBuilderValueRef::Hash(&hash));
41 buf
42 }
43 HASH_BUILDER_TYPE_BYTES => {
44 let (bytes, buf) = Vec::from_compact(buf, 0);
45 this.set_bytes_owned(bytes);
46 buf
47 }
48 _ => unreachable!("Junk data in database: unknown HashBuilderValue variant"),
49 };
50 (this, buf)
51 }
52}
53
54impl Compact for BranchNodeCompact {
55 fn to_compact<B>(&self, buf: &mut B) -> usize
56 where
57 B: bytes::BufMut + AsMut<[u8]>,
58 {
59 let mut buf_size = 0;
60
61 buf_size += self.state_mask.to_compact(buf);
62 buf_size += self.tree_mask.to_compact(buf);
63 buf_size += self.hash_mask.to_compact(buf);
64
65 if let Some(root_hash) = self.root_hash {
66 buf_size += B256::len_bytes();
67 buf.put_slice(root_hash.as_slice());
68 }
69
70 let hashes = self.hashes.as_slice().as_flattened();
71 buf_size += hashes.len();
72 buf.put_slice(hashes);
73
74 buf_size
75 }
76
77 fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
78 let hash_len = B256::len_bytes();
79
80 assert_eq!(buf.len() % hash_len, 6);
82
83 let (state_mask, buf) = TrieMask::from_compact(buf, 0);
85 let (tree_mask, buf) = TrieMask::from_compact(buf, 0);
86 let (hash_mask, buf) = TrieMask::from_compact(buf, 0);
87
88 let mut buf = buf;
89 let mut num_hashes = buf.len() / hash_len;
90 let mut root_hash = None;
91
92 if hash_mask.count_ones() as usize + 1 == num_hashes {
94 root_hash = Some(B256::from_slice(&buf[..hash_len]));
95 buf.advance(hash_len);
96 num_hashes -= 1;
97 }
98
99 let hashes_bytes = hash_len * num_hashes;
101 let mut hashes = Vec::<B256>::with_capacity(num_hashes);
102 unsafe {
104 hashes.as_mut_ptr().cast::<u8>().copy_from_nonoverlapping(buf.as_ptr(), hashes_bytes);
105 hashes.set_len(num_hashes);
106 buf.advance(hashes_bytes);
107 }
108
109 (Self::new(state_mask, tree_mask, hash_mask, hashes, root_hash), buf)
110 }
111}
112
113impl Compact for TrieMask {
114 fn to_compact<B>(&self, buf: &mut B) -> usize
115 where
116 B: bytes::BufMut + AsMut<[u8]>,
117 {
118 buf.put_u16(self.get());
119 2
120 }
121
122 fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
123 let mask = buf.get_u16();
124 (Self::new(mask), buf)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use alloy_primitives::hex;
132
133 #[test]
134 fn node_encoding() {
135 let n = BranchNodeCompact::new(
136 0xf607,
137 0x0005,
138 0x4004,
139 vec![
140 hex!("90d53cd810cc5d4243766cd4451e7b9d14b736a1148b26b3baac7617f617d321").into(),
141 hex!("cc35c964dda53ba6c0b87798073a9628dbc9cd26b5cce88eb69655a9c609caf1").into(),
142 ],
143 Some(hex!("aaaabbbb0006767767776fffffeee44444000005567645600000000eeddddddd").into()),
144 );
145
146 let mut out = Vec::new();
147 let compact_len = n.to_compact(&mut out);
148 assert_eq!(BranchNodeCompact::from_compact(&out, compact_len).0, n);
149 }
150}