light_concurrent_merkle_tree/
copy.rs1use std::ops::Deref;
2
3use light_bounded_vec::{BoundedVecMetadata, CyclicBoundedVecMetadata};
4use light_hasher::Hasher;
5use memoffset::{offset_of, span_of};
6
7use crate::{
8 errors::ConcurrentMerkleTreeError,
9 offset::copy::{read_bounded_vec_at, read_cyclic_bounded_vec_at, read_value_at},
10 ConcurrentMerkleTree,
11};
12
13#[derive(Debug)]
14pub struct ConcurrentMerkleTreeCopy<H, const HEIGHT: usize>(ConcurrentMerkleTree<H, HEIGHT>)
15where
16 H: Hasher;
17
18impl<H, const HEIGHT: usize> ConcurrentMerkleTreeCopy<H, HEIGHT>
19where
20 H: Hasher,
21{
22 pub fn struct_from_bytes_copy(
23 bytes: &[u8],
24 ) -> Result<(ConcurrentMerkleTree<H, HEIGHT>, usize), ConcurrentMerkleTreeError> {
25 let expected_size = ConcurrentMerkleTree::<H, HEIGHT>::non_dyn_fields_size();
26 if bytes.len() < expected_size {
27 return Err(ConcurrentMerkleTreeError::BufferSize(
28 expected_size,
29 bytes.len(),
30 ));
31 }
32
33 let height = usize::from_le_bytes(
34 bytes[span_of!(ConcurrentMerkleTree<H, HEIGHT>, height)]
35 .try_into()
36 .unwrap(),
37 );
38 let canopy_depth = usize::from_le_bytes(
39 bytes[span_of!(ConcurrentMerkleTree<H, HEIGHT>, canopy_depth)]
40 .try_into()
41 .unwrap(),
42 );
43
44 let mut offset = offset_of!(ConcurrentMerkleTree<H, HEIGHT>, next_index);
45
46 let next_index = unsafe { read_value_at(bytes, &mut offset) };
47 let sequence_number = unsafe { read_value_at(bytes, &mut offset) };
48 let rightmost_leaf = unsafe { read_value_at(bytes, &mut offset) };
49 let filled_subtrees_metadata: BoundedVecMetadata =
50 unsafe { read_value_at(bytes, &mut offset) };
51 let changelog_metadata: CyclicBoundedVecMetadata =
52 unsafe { read_value_at(bytes, &mut offset) };
53 let roots_metadata: CyclicBoundedVecMetadata = unsafe { read_value_at(bytes, &mut offset) };
54 let canopy_metadata: BoundedVecMetadata = unsafe { read_value_at(bytes, &mut offset) };
55
56 let expected_size = ConcurrentMerkleTree::<H, HEIGHT>::size_in_account(
57 height,
58 changelog_metadata.capacity(),
59 roots_metadata.capacity(),
60 canopy_depth,
61 );
62 if bytes.len() < expected_size {
63 return Err(ConcurrentMerkleTreeError::BufferSize(
64 expected_size,
65 bytes.len(),
66 ));
67 }
68
69 let filled_subtrees =
70 unsafe { read_bounded_vec_at(bytes, &mut offset, &filled_subtrees_metadata) };
71 let changelog =
72 unsafe { read_cyclic_bounded_vec_at(bytes, &mut offset, &changelog_metadata) };
73 let roots = unsafe { read_cyclic_bounded_vec_at(bytes, &mut offset, &roots_metadata) };
74 let canopy = unsafe { read_bounded_vec_at(bytes, &mut offset, &canopy_metadata) };
75
76 let mut merkle_tree = ConcurrentMerkleTree::new(
77 height,
78 changelog_metadata.capacity(),
79 roots_metadata.capacity(),
80 canopy_depth,
81 )?;
82 unsafe {
84 *merkle_tree.next_index = next_index;
85 *merkle_tree.sequence_number = sequence_number;
86 *merkle_tree.rightmost_leaf = rightmost_leaf;
87 }
88 merkle_tree.filled_subtrees = filled_subtrees;
89 merkle_tree.changelog = changelog;
90 merkle_tree.roots = roots;
91 merkle_tree.canopy = canopy;
92
93 Ok((merkle_tree, offset))
94 }
95
96 pub fn from_bytes_copy(bytes: &[u8]) -> Result<Self, ConcurrentMerkleTreeError> {
97 let (merkle_tree, _) = Self::struct_from_bytes_copy(bytes)?;
98 merkle_tree.check_size_constraints()?;
99 Ok(Self(merkle_tree))
100 }
101}
102
103impl<H, const HEIGHT: usize> Deref for ConcurrentMerkleTreeCopy<H, HEIGHT>
104where
105 H: Hasher,
106{
107 type Target = ConcurrentMerkleTree<H, HEIGHT>;
108
109 fn deref(&self) -> &Self::Target {
110 &self.0
111 }
112}
113
114#[cfg(test)]
115mod test {
116 use ark_bn254::Fr;
117 use ark_ff::{BigInteger, PrimeField, UniformRand};
118 use light_hasher::Poseidon;
119 use rand::{thread_rng, Rng};
120
121 use super::*;
122 use crate::zero_copy::ConcurrentMerkleTreeZeroCopyMut;
123
124 fn from_bytes_copy<
125 const HEIGHT: usize,
126 const CHANGELOG: usize,
127 const ROOTS: usize,
128 const CANOPY_DEPTH: usize,
129 const OPERATIONS: usize,
130 >() {
131 let mut mt_1 =
132 ConcurrentMerkleTree::<Poseidon, HEIGHT>::new(HEIGHT, CHANGELOG, ROOTS, CANOPY_DEPTH)
133 .unwrap();
134 mt_1.init().unwrap();
135
136 let mut bytes = vec![
140 0u8;
141 ConcurrentMerkleTree::<Poseidon, HEIGHT>::size_in_account(
142 HEIGHT,
143 CHANGELOG,
144 ROOTS,
145 CANOPY_DEPTH
146 )
147 ];
148 thread_rng().fill(bytes.as_mut_slice());
149
150 {
152 let mut mt =
153 ConcurrentMerkleTreeZeroCopyMut::<Poseidon, HEIGHT>::from_bytes_zero_copy_init(
154 bytes.as_mut_slice(),
155 HEIGHT,
156 CANOPY_DEPTH,
157 CHANGELOG,
158 ROOTS,
159 )
160 .unwrap();
161 mt.init().unwrap();
162
163 assert_eq!(mt.height, HEIGHT);
165 assert_eq!(mt.canopy_depth, CANOPY_DEPTH);
166 assert_eq!(mt.next_index(), 0);
167 assert_eq!(mt.sequence_number(), 0);
168 assert_eq!(mt.rightmost_leaf(), Poseidon::zero_bytes()[0]);
169
170 assert_eq!(mt.filled_subtrees.capacity(), HEIGHT);
171 assert_eq!(mt.filled_subtrees.len(), HEIGHT);
172
173 assert_eq!(mt.changelog.capacity(), CHANGELOG);
174 assert_eq!(mt.changelog.len(), 1);
175
176 assert_eq!(mt.roots.capacity(), ROOTS);
177 assert_eq!(mt.roots.len(), 1);
178
179 assert_eq!(
180 mt.canopy.capacity(),
181 ConcurrentMerkleTree::<Poseidon, HEIGHT>::canopy_size(CANOPY_DEPTH)
182 );
183
184 assert_eq!(mt.root(), Poseidon::zero_bytes()[HEIGHT]);
185 }
186
187 let mut rng = thread_rng();
188
189 for _ in 0..OPERATIONS {
190 let mut mt_2 =
192 ConcurrentMerkleTreeZeroCopyMut::<Poseidon, HEIGHT>::from_bytes_zero_copy_mut(
193 &mut bytes,
194 )
195 .unwrap();
196
197 let leaf: [u8; 32] = Fr::rand(&mut rng)
198 .into_bigint()
199 .to_bytes_be()
200 .try_into()
201 .unwrap();
202
203 mt_1.append(&leaf).unwrap();
204 mt_2.append(&leaf).unwrap();
205
206 assert_eq!(mt_1, *mt_2);
207 }
208
209 let mt_2 = ConcurrentMerkleTreeCopy::<Poseidon, HEIGHT>::from_bytes_copy(&bytes).unwrap();
211
212 assert_eq!(mt_1.height, mt_2.height);
213 assert_eq!(mt_1.canopy_depth, mt_2.canopy_depth);
214 assert_eq!(mt_1.next_index(), mt_2.next_index());
215 assert_eq!(mt_1.sequence_number(), mt_2.sequence_number());
216 assert_eq!(mt_1.rightmost_leaf(), mt_2.rightmost_leaf());
217 assert_eq!(
218 mt_1.filled_subtrees.as_slice(),
219 mt_2.filled_subtrees.as_slice()
220 );
221 }
222
223 #[test]
224 fn test_from_bytes_copy_26_1400_2400_10_256_1024() {
225 const HEIGHT: usize = 26;
226 const CHANGELOG_SIZE: usize = 1400;
227 const ROOTS: usize = 2400;
228 const CANOPY_DEPTH: usize = 10;
229
230 const OPERATIONS: usize = 1024;
231
232 from_bytes_copy::<HEIGHT, CHANGELOG_SIZE, ROOTS, CANOPY_DEPTH, OPERATIONS>()
233 }
234}