From 17cf033a3f3d9ce99da76e04dfa9f2e5647c0ec6 Mon Sep 17 00:00:00 2001 From: Michal Rostecki Date: Tue, 7 May 2024 11:28:34 +0200 Subject: [PATCH] refactor: Use a regular `Vec` inside `BoundedVec`, add more tests * There is no need to use manual allocations in `BoundedVec`. Instead, we can just embed a regular `Vec`, make it private and make sure that the methods we expose never reallocate it. * Add more test cases covering all error variants. --- merkle-tree/bounded-vec/src/lib.rs | 326 +++++++++--------- merkle-tree/concurrent/src/changelog.rs | 4 +- merkle-tree/concurrent/src/lib.rs | 20 +- merkle-tree/indexed/src/copy.rs | 42 +-- merkle-tree/indexed/src/lib.rs | 41 +-- merkle-tree/indexed/src/reference.rs | 4 +- merkle-tree/indexed/src/zero_copy.rs | 73 ++-- .../account-compression/src/state/address.rs | 2 +- .../src/state/public_state_merkle_tree.rs | 6 +- 9 files changed, 224 insertions(+), 294 deletions(-) diff --git a/merkle-tree/bounded-vec/src/lib.rs b/merkle-tree/bounded-vec/src/lib.rs index 54a5715b0e..0b1e8a0221 100644 --- a/merkle-tree/bounded-vec/src/lib.rs +++ b/merkle-tree/bounded-vec/src/lib.rs @@ -1,8 +1,7 @@ use std::{ - alloc::{self, handle_alloc_error, Layout}, - fmt, mem, + fmt, ops::{Index, IndexMut}, - slice::{self, Iter, IterMut, SliceIndex}, + slice::{Iter, IterMut, SliceIndex}, }; use thiserror::Error; @@ -32,70 +31,27 @@ impl From for solana_program::program_error::ProgramError { } } -/// Plain Old Data. +/// `BoundedVec` is a custom vector implementation which forbids +/// post-initialization reallocations. /// -/// # Safety +/// The purpose is an ability to set an initial limit, but: /// -/// This trait should be implemented only for types with size known at compile -/// time, like primitives or arrays of primitives. -pub unsafe trait Pod {} - -unsafe impl Pod for i8 {} -unsafe impl Pod for i16 {} -unsafe impl Pod for i32 {} -unsafe impl Pod for i64 {} -unsafe impl Pod for isize {} -unsafe impl Pod for u8 {} -unsafe impl Pod for u16 {} -unsafe impl Pod for u32 {} -unsafe impl Pod for u64 {} -unsafe impl Pod for usize {} - -unsafe impl Pod for [u8; N] {} - -/// `BoundedVec` is a custom vector implementation which: +/// * Still be able to define the limit on runtime, not on compile time. +/// * Allocate the memory on heap (not on stack, like arrays). /// -/// * Forbids post-initialization reallocations. The size is not known during -/// compile time (that makes it different from arrays), but can be defined -/// only once (that makes it different from [`Vec`](std::vec::Vec)). -/// * Can store only Plain Old Data ([`Pod`](bytemuck::Pod)). It cannot nest -/// any other dynamically sized types. -pub struct BoundedVec<'a, T> +/// `Vec` is still used as the underlying data structure, `BoundedVec` exposes +/// only the methods which don't trigger reallocations. +pub struct BoundedVec(Vec) where - T: Clone + Pod, -{ - capacity: usize, - length: usize, - data: &'a mut [T], -} + T: Clone; -impl<'a, T> BoundedVec<'a, T> +impl BoundedVec where - T: Clone + Pod, + T: Clone, { #[inline] pub fn with_capacity(capacity: usize) -> Self { - let size = mem::size_of::() * capacity; - let align = mem::align_of::(); - // SAFETY: `size` is a multiplication of `capacity`, therefore the - // layout is guaranteed to be aligned. - let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - - // SAFETY: As long as the provided `Pod` type is correct, this global - // allocator call should be correct too. - // - // We are handling the null pointer case gracefully. - let ptr = unsafe { alloc::alloc(layout) }; - if ptr.is_null() { - handle_alloc_error(layout); - } - let data = unsafe { slice::from_raw_parts_mut(ptr as *mut T, capacity) }; - - Self { - capacity, - length: 0, - data, - } + Self(Vec::with_capacity(capacity)) } pub fn from_array(array: &[T; N]) -> Self { @@ -108,6 +64,16 @@ where vec } + pub fn from_slice(slice: &[T]) -> Self { + let mut vec = Self::with_capacity(slice.len()); + for element in slice { + // SAFETY: We are sure that the array and the vector have equal + // sizes, there is no chance for the error to occur. + vec.push(element.clone()).unwrap(); + } + vec + } + /// Creates a `BoundedVec` directly from a pointer, a capacity, and a length. /// /// # Safety @@ -131,13 +97,8 @@ where /// See the safety documentation of [`pointer::offset`]. #[inline] pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { - let data = slice::from_raw_parts_mut(ptr, capacity); - - Self { - capacity, - length, - data, - } + let vec = Vec::from_raw_parts(ptr, length, capacity); + Self(vec) } /// Returns the total number of elements the vector can hold without @@ -152,12 +113,12 @@ where /// ``` #[inline] pub fn capacity(&self) -> usize { - self.capacity + self.0.capacity() } #[inline] pub fn as_slice(&self) -> &[T] { - &self.data[..self.length] + self.0.as_slice() } /// Appends an element to the back of a collection. @@ -175,70 +136,61 @@ where /// ``` #[inline] pub fn push(&mut self, value: T) -> Result<(), BoundedVecError> { - if self.length == self.capacity { + if self.0.len() == self.0.capacity() { return Err(BoundedVecError::Full); } - - self.data[self.length] = value; - self.length += 1; - + self.0.push(value); Ok(()) } #[inline] pub fn len(&self) -> usize { - self.length + self.0.len() } pub fn is_empty(&self) -> bool { - self.len() == 0 + self.0.is_empty() } #[inline] pub fn get(&self, index: usize) -> Option<&T> { - self.data[..self.length].get(index) + self.0.get(index) } #[inline] pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - self.data[..self.length].get_mut(index) + self.0.get_mut(index) } #[inline] pub fn iter(&self) -> Iter<'_, T> { - self.data[..self.length].iter() + self.0.iter() } #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, T> { - self.data[..self.length].iter_mut() + self.0.iter_mut() } #[inline] pub fn last(&self) -> Option<&T> { - if self.length < 1 { - return None; - } - self.get(self.length - 1) + self.0.last() } #[inline] pub fn last_mut(&mut self) -> Option<&mut T> { - if self.length < 1 { - return None; - } - self.get_mut(self.length - 1) + self.0.last_mut() } pub fn to_array(&self) -> Result<[T; N], BoundedVecError> { if self.len() != N { return Err(BoundedVecError::ArraySize(N, self.len())); } - Ok(std::array::from_fn(|i| self.data[i].clone())) + Ok(std::array::from_fn(|i| self.0[i].clone())) } pub fn to_vec(self) -> Vec { - self.data[..self.length].to_vec() + self.0 } pub fn extend>(&mut self, iter: U) -> Result<(), BoundedVecError> { @@ -249,50 +201,48 @@ where } } -impl<'a, T> fmt::Debug for BoundedVec<'a, T> +impl fmt::Debug for BoundedVec where - T: Clone + fmt::Debug + Pod, + T: Clone + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", &self.data[..self.length]) + self.0.fmt(f) } } -impl<'a, T, I: SliceIndex<[T]>> Index for BoundedVec<'a, T> +impl> Index for BoundedVec where - T: Clone + Pod, + T: Clone, I: SliceIndex<[T]>, { type Output = I::Output; #[inline] fn index(&self, index: I) -> &Self::Output { - self.data[..self.length].index(index) + self.0.index(index) } } -impl<'a, T, I> IndexMut for BoundedVec<'a, T> +impl IndexMut for BoundedVec where - T: Clone + Pod, + T: Clone, I: SliceIndex<[T]>, { fn index_mut(&mut self, index: I) -> &mut Self::Output { - self.data[..self.length].index_mut(index) + self.0.index_mut(index) } } -impl<'a, T> PartialEq for BoundedVec<'a, T> +impl PartialEq for BoundedVec where - T: Clone + PartialEq + Pod, + T: Clone + PartialEq, { fn eq(&self, other: &Self) -> bool { - self.data[..self.length] - .iter() - .eq(other.data[..other.length].iter()) + self.0.eq(&other.0) } } -impl<'a, T> Eq for BoundedVec<'a, T> where T: Clone + Eq + Pod {} +impl Eq for BoundedVec where T: Clone + Eq {} /// `CyclicBoundedVec` is a wrapper around [`Vec`](std::vec::Vec) which: /// @@ -300,44 +250,42 @@ impl<'a, T> Eq for BoundedVec<'a, T> where T: Clone + Eq + Pod {} /// * Starts overwriting elements from the beginning once it reaches its /// capacity. #[derive(Debug)] -pub struct CyclicBoundedVec<'a, T> +pub struct CyclicBoundedVec where - T: Clone + Pod, + T: Clone, { - capacity: usize, - length: usize, + vec: Vec, next_index: usize, - data: &'a mut [T], } -impl<'a, T> CyclicBoundedVec<'a, T> +impl CyclicBoundedVec where - T: Clone + Pod, + T: Clone, { #[inline] pub fn with_capacity(capacity: usize) -> Self { - let size = mem::size_of::() * capacity; - let align = mem::align_of::(); - // SAFETY: `size` is a multiplication of `capacity`, therefore the - // layout is guaranteed to be aligned. - let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - - // SAFETY: As long as the provided `Pod` type is correct, this global - // allocator call should be correct too. - // - // We are handling the null pointer case gracefully. - let ptr = unsafe { alloc::alloc(layout) }; - if ptr.is_null() { - handle_alloc_error(layout); + let vec = Vec::with_capacity(capacity); + Self { vec, next_index: 0 } + } + + pub fn from_array(array: &[T; N]) -> Self { + let mut vec = Self::with_capacity(N); + for element in array { + // SAFETY: We are sure that the array and the vector have equal + // sizes, there is no chance for the error to occur. + vec.push(element.clone()).unwrap(); } - let data = unsafe { slice::from_raw_parts_mut(ptr as *mut T, capacity) }; + vec + } - Self { - capacity, - length: 0, - next_index: 0, - data, + pub fn from_slice(slice: &[T]) -> Self { + let mut vec = Self::with_capacity(slice.len()); + for element in slice { + // SAFETY: We are sure that the array and the vector have equal + // sizes, there is no chance for the error to occur. + vec.push(element.clone()).unwrap(); } + vec } /// Creates a `CyclicBoundedVec` directly from a pointer, a capacity, and a length. @@ -368,13 +316,8 @@ where length: usize, capacity: usize, ) -> Self { - let data = slice::from_raw_parts_mut(ptr, capacity); - Self { - capacity, - length, - next_index, - data, - } + let vec = Vec::from_raw_parts(ptr, length, capacity); + Self { vec, next_index } } /// Returns the total number of elements the vector can hold without @@ -389,12 +332,12 @@ where /// ``` #[inline] pub fn capacity(&self) -> usize { - self.capacity + self.vec.capacity() } #[inline] pub fn as_slice(&self) -> &[T] { - &self.data[..self.length] + self.vec.as_slice() } /// Appends an element to the back of a collection. @@ -412,12 +355,14 @@ where /// ``` #[inline] pub fn push(&mut self, value: T) -> Result<(), BoundedVecError> { - if self.len() < self.capacity() { - self.length += 1; - } else if self.next_index == self.capacity() { - self.next_index = 0; + if self.vec.len() < self.vec.capacity() { + self.vec.push(value); + } else { + if self.next_index == self.capacity() { + self.next_index = 0; + } + *self.get_mut(self.next_index).ok_or(BoundedVecError::Full)? = value; } - *self.get_mut(self.next_index).ok_or(BoundedVecError::Full)? = value; self.next_index += 1; Ok(()) @@ -430,31 +375,31 @@ where #[inline] pub fn len(&self) -> usize { - self.length + self.vec.len() } pub fn is_empty(&self) -> bool { - self.len() == 0 + self.vec.is_empty() } #[inline] pub fn get(&self, index: usize) -> Option<&T> { - self.data[..self.length].get(index) + self.vec.get(index) } #[inline] pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - self.data[..self.length].get_mut(index) + self.vec.get_mut(index) } #[inline] pub fn iter(&self) -> Iter<'_, T> { - self.data[..self.length].iter() + self.vec.iter() } #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, T> { - self.data[..self.length].iter_mut() + self.vec.iter_mut() } #[inline] @@ -463,9 +408,9 @@ where if self.is_empty() { return None; } - self.get(self.length - 1) + self.get(self.len() - 1) } else if self.next_index == 0 { - self.get(self.capacity - 1) + self.get(self.capacity() - 1) } else { self.get(self.next_index - 1) } @@ -477,53 +422,108 @@ where if self.is_empty() { return None; } - self.get_mut(self.length - 1) + self.get_mut(self.len() - 1) } else if self.next_index == 0 { - self.get_mut(self.capacity - 1) + self.get_mut(self.capacity() - 1) } else { self.get_mut(self.next_index - 1) } } } -impl<'a, T, I> Index for CyclicBoundedVec<'a, T> +impl Index for CyclicBoundedVec where - T: Clone + Pod, + T: Clone, I: SliceIndex<[T]>, { type Output = I::Output; #[inline] fn index(&self, index: I) -> &Self::Output { - self.data[..self.length].index(index) + self.vec.index(index) } } -impl<'a, T, I> IndexMut for CyclicBoundedVec<'a, T> +impl IndexMut for CyclicBoundedVec where - T: Clone + Pod, + T: Clone, I: SliceIndex<[T]>, { fn index_mut(&mut self, index: I) -> &mut Self::Output { - self.data[..self.length].index_mut(index) + self.vec.index_mut(index) } } -impl<'a, T> PartialEq for CyclicBoundedVec<'a, T> +impl PartialEq for CyclicBoundedVec where - T: Clone + Pod + PartialEq, + T: Clone + PartialEq, { fn eq(&self, other: &Self) -> bool { - self.data[..self.length].iter().eq(other.data.iter()) + self.vec.eq(&other.vec) } } -impl<'a, T> Eq for CyclicBoundedVec<'a, T> where T: Clone + Eq + Pod {} +impl Eq for CyclicBoundedVec where T: Clone + Eq {} #[cfg(test)] mod test { use super::*; + fn bounded_vec_full() { + let mut bounded_vec = BoundedVec::with_capacity(CAPACITY); + + // Append up to capaciity. + for i in 0..CAPACITY { + bounded_vec.push(i).unwrap(); + } + // Try pushing over capacity - should result in an error. + for i in 0..CAPACITY { + let res = bounded_vec.push(i); + assert!(matches!(res, Err(BoundedVecError::Full))); + } + } + + #[test] + fn test_bounded_vec_full_8() { + bounded_vec_full::<8>() + } + + #[test] + fn test_bounded_vec_full_16() { + bounded_vec_full::<16>() + } + + #[test] + fn test_bounded_vec_full_32() { + bounded_vec_full::<32>() + } + + #[test] + fn test_bounded_vec_full_64() { + bounded_vec_full::<64>() + } + + #[test] + fn test_bounded_vec_full_128() { + bounded_vec_full::<128>() + } + + #[test] + fn test_bounded_vec_to_array() { + let bounded_vec = BoundedVec::from_array(&[1u8; 32]); + + assert!(bounded_vec.to_array::<32>().is_ok()); + + assert!(matches!( + bounded_vec.to_array::<31>(), + Err(BoundedVecError::ArraySize(_, _)) + )); + assert!(matches!( + bounded_vec.to_array::<33>(), + Err(BoundedVecError::ArraySize(_, _)) + )); + } + #[test] fn test_cyclic_bounded_vec_correct_values() { let mut cyclic_bounded_vec = CyclicBoundedVec::with_capacity(8); diff --git a/merkle-tree/concurrent/src/changelog.rs b/merkle-tree/concurrent/src/changelog.rs index ceadaeecfb..b049f3b0d1 100644 --- a/merkle-tree/concurrent/src/changelog.rs +++ b/merkle-tree/concurrent/src/changelog.rs @@ -1,4 +1,4 @@ -use light_bounded_vec::{BoundedVec, Pod}; +use light_bounded_vec::BoundedVec; use crate::errors::ConcurrentMerkleTreeError; @@ -18,8 +18,6 @@ pub type ChangelogEntry26 = ChangelogEntry<26>; pub type ChangelogEntry32 = ChangelogEntry<32>; pub type ChangelogEntry40 = ChangelogEntry<40>; -unsafe impl Pod for ChangelogEntry {} - impl ChangelogEntry { pub fn new(root: [u8; 32], path: [[u8; 32]; HEIGHT], index: usize) -> Self { let index = index as u64; diff --git a/merkle-tree/concurrent/src/lib.rs b/merkle-tree/concurrent/src/lib.rs index 73f8faeb6d..ff1db04942 100644 --- a/merkle-tree/concurrent/src/lib.rs +++ b/merkle-tree/concurrent/src/lib.rs @@ -32,7 +32,7 @@ use crate::{ // const generic here is that removing it would require keeping a `BoundecVec` // inside `CyclicBoundedVec`. Casting byte slices to such nested vector is not // a trivial task, but we might eventually do it at some point. -pub struct ConcurrentMerkleTree<'a, H, const HEIGHT: usize> +pub struct ConcurrentMerkleTree where H: Hasher, { @@ -53,23 +53,23 @@ where pub rightmost_leaf: [u8; 32], /// Hashes of subtrees. - pub filled_subtrees: BoundedVec<'a, [u8; 32]>, + pub filled_subtrees: BoundedVec<[u8; 32]>, /// History of Merkle proofs. - pub changelog: CyclicBoundedVec<'a, ChangelogEntry>, + pub changelog: CyclicBoundedVec>, /// History of roots. - pub roots: CyclicBoundedVec<'a, [u8; 32]>, + pub roots: CyclicBoundedVec<[u8; 32]>, /// Cached upper nodes. - pub canopy: BoundedVec<'a, [u8; 32]>, + pub canopy: BoundedVec<[u8; 32]>, pub _hasher: PhantomData, } -pub type ConcurrentMerkleTree22<'a, H> = ConcurrentMerkleTree<'a, H, 22>; -pub type ConcurrentMerkleTree26<'a, H> = ConcurrentMerkleTree<'a, H, 26>; -pub type ConcurrentMerkleTree32<'a, H> = ConcurrentMerkleTree<'a, H, 32>; -pub type ConcurrentMerkleTree40<'a, H> = ConcurrentMerkleTree<'a, H, 40>; +pub type ConcurrentMerkleTree22 = ConcurrentMerkleTree; +pub type ConcurrentMerkleTree26 = ConcurrentMerkleTree; +pub type ConcurrentMerkleTree32 = ConcurrentMerkleTree; +pub type ConcurrentMerkleTree40 = ConcurrentMerkleTree; -impl<'a, H, const HEIGHT: usize> ConcurrentMerkleTree<'a, H, HEIGHT> +impl<'a, H, const HEIGHT: usize> ConcurrentMerkleTree where H: Hasher, { diff --git a/merkle-tree/indexed/src/copy.rs b/merkle-tree/indexed/src/copy.rs index 8da1d66741..75b689c66b 100644 --- a/merkle-tree/indexed/src/copy.rs +++ b/merkle-tree/indexed/src/copy.rs @@ -1,6 +1,6 @@ use std::{marker::PhantomData, mem, slice}; -use light_bounded_vec::{BoundedVec, CyclicBoundedVec, Pod}; +use light_bounded_vec::{BoundedVec, CyclicBoundedVec}; use light_concurrent_merkle_tree::{ changelog::ChangelogEntry, errors::ConcurrentMerkleTreeError, ConcurrentMerkleTree, }; @@ -10,39 +10,21 @@ use num_traits::{CheckedAdd, CheckedSub, ToBytes, Unsigned}; use crate::{errors::IndexedMerkleTreeError, IndexedMerkleTree, RawIndexedElement}; #[derive(Debug)] -pub struct IndexedMerkleTreeCopy<'a, H, I, const HEIGHT: usize>( - pub IndexedMerkleTree<'a, H, I, HEIGHT>, -) +pub struct IndexedMerkleTreeCopy(pub IndexedMerkleTree) where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From; -pub type IndexedMerkleTreeCopy22<'a, H, I> = IndexedMerkleTreeCopy<'a, H, I, 22>; -pub type IndexedMerkleTreeCopy26<'a, H, I> = IndexedMerkleTreeCopy<'a, H, I, 26>; -pub type IndexedMerkleTreeCopy32<'a, H, I> = IndexedMerkleTreeCopy<'a, H, I, 32>; -pub type IndexedMerkleTreeCopy40<'a, H, I> = IndexedMerkleTreeCopy<'a, H, I, 40>; +pub type IndexedMerkleTreeCopy22 = IndexedMerkleTreeCopy; +pub type IndexedMerkleTreeCopy26 = IndexedMerkleTreeCopy; +pub type IndexedMerkleTreeCopy32 = IndexedMerkleTreeCopy; +pub type IndexedMerkleTreeCopy40 = IndexedMerkleTreeCopy; -impl<'a, H, I, const HEIGHT: usize> IndexedMerkleTreeCopy<'a, H, I, HEIGHT> +impl IndexedMerkleTreeCopy where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From, { /// Casts a byte slice into wrapped `IndexedMerkleTree` structure reference, @@ -66,9 +48,9 @@ where bytes_changelog: &[u8], bytes_roots: &[u8], bytes_canopy: &[u8], - bytes_indexed_changelog: &'a [u8], + bytes_indexed_changelog: &[u8], ) -> Result { - let expected_bytes_struct_size = mem::size_of::>(); + let expected_bytes_struct_size = mem::size_of::>(); if bytes_struct.len() != expected_bytes_struct_size { return Err(IndexedMerkleTreeError::ConcurrentMerkleTree( ConcurrentMerkleTreeError::StructBufferSize( @@ -77,7 +59,7 @@ where ), )); } - let struct_ref: *mut IndexedMerkleTree<'a, H, I, HEIGHT> = bytes_struct.as_ptr() as _; + let struct_ref: *mut IndexedMerkleTree = bytes_struct.as_ptr() as _; let mut merkle_tree = unsafe { ConcurrentMerkleTree { diff --git a/merkle-tree/indexed/src/lib.rs b/merkle-tree/indexed/src/lib.rs index 1c731b9323..39c8353ba0 100644 --- a/merkle-tree/indexed/src/lib.rs +++ b/merkle-tree/indexed/src/lib.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use array::{IndexedArray, IndexedElement}; -use light_bounded_vec::{BoundedVec, CyclicBoundedVec, Pod}; +use light_bounded_vec::{BoundedVec, CyclicBoundedVec}; use light_concurrent_merkle_tree::{ errors::ConcurrentMerkleTreeError, light_hasher::Hasher, ConcurrentMerkleTree, }; @@ -23,54 +23,37 @@ pub const FIELD_SIZE_SUB_ONE: &str = #[derive(Debug, Default, Clone, Copy)] pub struct RawIndexedElement where - I: Clone + Pod, + I: Clone, { pub value: [u8; 32], pub next_index: I, pub next_value: [u8; 32], pub index: I, } -unsafe impl Pod for RawIndexedElement where I: Pod + Clone {} #[derive(Debug)] #[repr(C)] -pub struct IndexedMerkleTree<'a, H, I, const HEIGHT: usize> +pub struct IndexedMerkleTree where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From, { - pub merkle_tree: ConcurrentMerkleTree<'a, H, HEIGHT>, - pub changelog: CyclicBoundedVec<'a, RawIndexedElement>, + pub merkle_tree: ConcurrentMerkleTree, + pub changelog: CyclicBoundedVec>, _index: PhantomData, } -pub type IndexedMerkleTree22<'a, H, I> = IndexedMerkleTree<'a, H, I, 22>; -pub type IndexedMerkleTree26<'a, H, I> = IndexedMerkleTree<'a, H, I, 26>; -pub type IndexedMerkleTree32<'a, H, I> = IndexedMerkleTree<'a, H, I, 32>; -pub type IndexedMerkleTree40<'a, H, I> = IndexedMerkleTree<'a, H, I, 40>; +pub type IndexedMerkleTree22 = IndexedMerkleTree; +pub type IndexedMerkleTree26 = IndexedMerkleTree; +pub type IndexedMerkleTree32 = IndexedMerkleTree; +pub type IndexedMerkleTree40 = IndexedMerkleTree; -impl<'a, H, I, const HEIGHT: usize> IndexedMerkleTree<'a, H, I, HEIGHT> +impl IndexedMerkleTree where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From, { pub fn new( diff --git a/merkle-tree/indexed/src/reference.rs b/merkle-tree/indexed/src/reference.rs index ce3b7cae51..46f84621c9 100644 --- a/merkle-tree/indexed/src/reference.rs +++ b/merkle-tree/indexed/src/reference.rs @@ -172,12 +172,12 @@ where /// We prove non-inclusion by: /// 1. Showing that value is greater than leaf_lower_range_value and less than leaf_higher_range_value /// 2. Showing that the leaf_hash H(leaf_lower_range_value, leaf_next_index, leaf_higher_value) is included in the root (Merkle tree) -pub struct NonInclusionProof<'a> { +pub struct NonInclusionProof { pub root: [u8; 32], pub value: [u8; 32], pub leaf_lower_range_value: [u8; 32], pub leaf_higher_range_value: [u8; 32], pub leaf_index: usize, pub next_index: usize, - pub merkle_proof: BoundedVec<'a, [u8; 32]>, + pub merkle_proof: BoundedVec<[u8; 32]>, } diff --git a/merkle-tree/indexed/src/zero_copy.rs b/merkle-tree/indexed/src/zero_copy.rs index 20af1ad5f1..49b1b31d2f 100644 --- a/merkle-tree/indexed/src/zero_copy.rs +++ b/merkle-tree/indexed/src/zero_copy.rs @@ -1,6 +1,6 @@ use std::mem; -use light_bounded_vec::{BoundedVec, CyclicBoundedVec, Pod}; +use light_bounded_vec::{BoundedVec, CyclicBoundedVec}; use light_concurrent_merkle_tree::{ changelog::ChangelogEntry, errors::ConcurrentMerkleTreeError, ConcurrentMerkleTree, }; @@ -13,18 +13,10 @@ use crate::{errors::IndexedMerkleTreeError, IndexedMerkleTree, RawIndexedElement pub struct IndexedMerkleTreeZeroCopy<'a, H, I, const HEIGHT: usize> where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From, { - pub merkle_tree: &'a IndexedMerkleTree<'a, H, I, HEIGHT>, + pub merkle_tree: &'a IndexedMerkleTree, } pub type IndexedMerkleTreeZeroCopy22<'a, H, I> = IndexedMerkleTreeZeroCopy<'a, H, I, 22>; @@ -35,15 +27,7 @@ pub type IndexedMerkleTreeZeroCopy40<'a, H, I> = IndexedMerkleTreeZeroCopy<'a, H impl<'a, H, I, const HEIGHT: usize> IndexedMerkleTreeZeroCopy<'a, H, I, HEIGHT> where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From, { /// Casts a byte slice into wrapped `IndexedMerkleTree` structure reference, @@ -64,7 +48,7 @@ where pub unsafe fn struct_from_bytes_zero_copy( bytes_struct: &'a [u8], ) -> Result { - let expected_bytes_struct_size = mem::size_of::>(); + let expected_bytes_struct_size = mem::size_of::>(); if bytes_struct.len() != expected_bytes_struct_size { return Err(IndexedMerkleTreeError::ConcurrentMerkleTree( ConcurrentMerkleTreeError::StructBufferSize( @@ -73,7 +57,7 @@ where ), )); } - let tree: *const IndexedMerkleTree<'a, H, I, HEIGHT> = bytes_struct.as_ptr() as _; + let tree: *const IndexedMerkleTree = bytes_struct.as_ptr() as _; Ok(Self { merkle_tree: &*tree, @@ -162,15 +146,14 @@ where ), )); } - tree.merkle_tree.merkle_tree.roots = - ConcurrentMerkleTree::<'a, H, HEIGHT>::roots_from_bytes( - bytes_roots, - tree.merkle_tree.merkle_tree.current_root_index + 1, - tree.merkle_tree.merkle_tree.roots_length, - tree.merkle_tree.merkle_tree.roots_capacity, - )?; - - let canopy_size = ConcurrentMerkleTree::<'a, H, HEIGHT>::canopy_size( + tree.merkle_tree.merkle_tree.roots = ConcurrentMerkleTree::::roots_from_bytes( + bytes_roots, + tree.merkle_tree.merkle_tree.current_root_index + 1, + tree.merkle_tree.merkle_tree.roots_length, + tree.merkle_tree.merkle_tree.roots_capacity, + )?; + + let canopy_size = ConcurrentMerkleTree::::canopy_size( tree.merkle_tree.merkle_tree.canopy_depth, ); let expected_canopy_size = mem::size_of::<[u8; 32]>() * canopy_size; @@ -210,18 +193,10 @@ where pub struct IndexedMerkleTreeZeroCopyMut<'a, H, I, const HEIGHT: usize> where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From, { - pub merkle_tree: &'a mut IndexedMerkleTree<'a, H, I, HEIGHT>, + pub merkle_tree: &'a mut IndexedMerkleTree, } pub type IndexedMerkleTreeZeroCopyMut22<'a, H, I> = IndexedMerkleTreeZeroCopyMut<'a, H, I, 22>; @@ -232,15 +207,7 @@ pub type IndexedMerkleTreeZeroCopyMut40<'a, H, I> = IndexedMerkleTreeZeroCopyMut impl<'a, H, I, const HEIGHT: usize> IndexedMerkleTreeZeroCopyMut<'a, H, I, HEIGHT> where H: Hasher, - I: CheckedAdd - + CheckedSub - + Copy - + Clone - + PartialOrd - + ToBytes - + TryFrom - + Unsigned - + Pod, + I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom + Unsigned, usize: From, { /// Casts a byte slice into wrapped `IndexedMerkleTree` structure mutable @@ -261,7 +228,7 @@ where pub unsafe fn struct_from_bytes_zero_copy_mut( bytes_struct: &'a [u8], ) -> Result { - let expected_bytes_struct_size = mem::size_of::>(); + let expected_bytes_struct_size = mem::size_of::>(); if bytes_struct.len() != expected_bytes_struct_size { return Err(IndexedMerkleTreeError::ConcurrentMerkleTree( ConcurrentMerkleTreeError::StructBufferSize( @@ -270,7 +237,7 @@ where ), )); } - let tree: *mut IndexedMerkleTree<'a, H, I, HEIGHT> = bytes_struct.as_ptr() as _; + let tree: *mut IndexedMerkleTree = bytes_struct.as_ptr() as _; Ok(Self { merkle_tree: &mut *tree, @@ -427,7 +394,7 @@ where tree.merkle_tree.merkle_tree.changelog_length, tree.merkle_tree.merkle_tree.current_root_index + 1, tree.merkle_tree.merkle_tree.roots_length, - ConcurrentMerkleTree::<'a, H, HEIGHT>::canopy_size( + ConcurrentMerkleTree::::canopy_size( tree.merkle_tree.merkle_tree.canopy_depth, ), bytes_indexed_changelog, diff --git a/programs/account-compression/src/state/address.rs b/programs/account-compression/src/state/address.rs index 923e14c540..9c487c0786 100644 --- a/programs/account-compression/src/state/address.rs +++ b/programs/account-compression/src/state/address.rs @@ -116,7 +116,7 @@ pub struct AddressMerkleTreeAccount { pub owner: Pubkey, /// Delegate of the Merkle tree. This will be used for program owned Merkle trees. pub delegate: Pubkey, - pub merkle_tree_struct: [u8; 296], + pub merkle_tree_struct: [u8; 256], pub merkle_tree_filled_subtrees: [u8; 832], pub merkle_tree_changelog: [u8; 1220800], pub merkle_tree_roots: [u8; 76800], diff --git a/programs/account-compression/src/state/public_state_merkle_tree.rs b/programs/account-compression/src/state/public_state_merkle_tree.rs index fd9acbf55e..ee8d563404 100644 --- a/programs/account-compression/src/state/public_state_merkle_tree.rs +++ b/programs/account-compression/src/state/public_state_merkle_tree.rs @@ -4,7 +4,7 @@ use light_bounded_vec::CyclicBoundedVec; use light_concurrent_merkle_tree::ConcurrentMerkleTree26; use light_hasher::Poseidon; -pub type StateMerkleTree<'a> = ConcurrentMerkleTree26<'a, Poseidon>; +pub type StateMerkleTree = ConcurrentMerkleTree26; /// Concurrent state Merkle tree used for public compressed transactions. #[account(zero_copy)] @@ -33,7 +33,7 @@ pub struct StateMerkleTreeAccount { pub associated_queue: Pubkey, /// Merkle tree for the transaction state. - pub state_merkle_tree_struct: [u8; 256], + pub state_merkle_tree_struct: [u8; 224], pub state_merkle_tree_filled_subtrees: [u8; 832], pub state_merkle_tree_changelog: [u8; 1220800], pub state_merkle_tree_roots: [u8; 76800], @@ -155,7 +155,7 @@ mod test { owner: Pubkey::new_from_array([2u8; 32]), delegate: Pubkey::new_from_array([3u8; 32]), associated_queue: Pubkey::new_from_array([4u8; 32]), - state_merkle_tree_struct: [0u8; 256], + state_merkle_tree_struct: [0u8; 224], state_merkle_tree_filled_subtrees: [0u8; 832], state_merkle_tree_changelog: [0u8; 1220800], state_merkle_tree_roots: [0u8; 76800],