spl_account_compression::concurrent_tree_wrapper

Struct ConcurrentMerkleTree

source
#[repr(C)]
pub struct ConcurrentMerkleTree<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> { pub sequence_number: u64, pub active_index: u64, pub buffer_size: u64, pub change_logs: [ChangeLog<MAX_DEPTH>; MAX_BUFFER_SIZE], pub rightmost_proof: Path<MAX_DEPTH>, }
Expand description

Exported for Anchor / Solita Conurrent Merkle Tree is a Merkle Tree that allows multiple tree operations targeted for the same tree root to succeed.

In a normal merkle tree, only the first tree operation will succeed because the following operations will have proofs for the unmodified tree state. ConcurrentMerkleTree avoids this by storing a buffer of modified nodes (change_logs) which allows it to implement fast-forwarding of concurrent merkle tree operations.

As long as the concurrent merkle tree operations have proofs that are valid for a previous state of the tree that can be found in the stored buffer, that tree operation’s proof can be fast-forwarded and the tree operation can be applied.

There are two primitive operations for Concurrent Merkle Trees: set_leaf and append. Setting a leaf value requires passing a proof to perform that tree operation, but appending does not require a proof.

An additional key property of ConcurrentMerkleTree is support for append operations, which do not require any proofs to be passed. This is accomplished by keeping track of the proof to the rightmost leaf in the tree (rightmost_proof).

The ConcurrentMerkleTree is a generic struct that may be interacted with using macros. Those macros may wrap up the construction and both mutable and immutable calls to the ConcurrentMerkleTree struct. If the macro contains a big match statement over different sizes of a tree and buffer, it might create a huge stack footprint. This in turn might lead to a stack overflow given the max stack offset of just 4kb. In order to minimize the stack frame size, the arguments for the ConcurrentMerkleTree methods that contain the proofs are passed as references to structs.

Fields§

§sequence_number: u64§active_index: u64

Index of most recent root & changes

§buffer_size: u64

Number of active changes we are tracking

§change_logs: [ChangeLog<MAX_DEPTH>; MAX_BUFFER_SIZE]

Proof for respective root

§rightmost_proof: Path<MAX_DEPTH>

Implementations§

source§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

source

pub fn new() -> ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

source

pub fn is_initialized(&self) -> bool

source

pub fn initialize(&mut self) -> Result<[u8; 32], ConcurrentMerkleTreeError>

This is the trustless initialization method that should be used in most cases.

source

pub fn initialize_with_root( &mut self, args: &InitializeWithRootArgs, ) -> Result<[u8; 32], ConcurrentMerkleTreeError>

This is a trustful initialization method that assumes the root contains the expected leaves.

At the time of this crate’s publishing, there is no supported way to efficiently verify a pre-initialized root on-chain. Using this method before having a method for on-chain verification will prevent other applications from indexing the leaf data stored in this tree.

source

pub fn prove_tree_is_empty(&self) -> Result<(), ConcurrentMerkleTreeError>

Errors if one of the leaves of the current merkle tree is non-EMPTY

source

pub fn get_root(&self) -> [u8; 32]

Returns the current root of the merkle tree

source

pub fn get_change_log(&self) -> Box<ChangeLog<MAX_DEPTH>>

Returns the most recent changelog

source

pub fn prove_leaf( &self, args: &ProveLeafArgs, ) -> Result<(), ConcurrentMerkleTreeError>

This method will fail if the leaf cannot be proven to exist in the current tree root.

This method will attempts to prove the leaf first using the proof nodes provided. However if this fails, then a proof will be constructed by inferring a proof from the changelog buffer.

Note: this is not the same as verifying that a (proof, leaf) combination is valid for the given root. That functionality is provided by check_valid_proof.

source

pub fn append( &mut self, node: [u8; 32], ) -> Result<[u8; 32], ConcurrentMerkleTreeError>

Appending a non-empty Node will always succeed .

source

pub fn fill_empty_or_append( &mut self, args: &FillEmptyOrAppendArgs, ) -> Result<[u8; 32], ConcurrentMerkleTreeError>

Convenience function for set_leaf

This method will set_leaf if the leaf at index is an empty node, otherwise it will append the new leaf.

source

pub fn set_leaf( &mut self, args: &SetLeafArgs, ) -> Result<[u8; 32], ConcurrentMerkleTreeError>

This method will update the leaf at index.

However if the proof cannot be verified, this method will fail.

source

pub fn get_seq(&self) -> u64

Returns the Current Seq of the tree, the seq is the monotonic counter of the tree operations that is incremented every time a mutable operation is performed on the tree.

source

pub fn check_valid_proof( &self, leaf: [u8; 32], proof: &[[u8; 32]; MAX_DEPTH], leaf_index: u32, ) -> bool

Checks that the proof provided is valid for the current root.

Trait Implementations§

source§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Clone for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

source§

fn clone(&self) -> ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Default for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

source§

fn default() -> ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

Returns the “default value” for a type. Read more
source§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> ZeroCopy for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

source§

fn load_mut_bytes<'a>(data: &'a mut [u8]) -> Result<&'a mut Self>

source§

fn load_bytes<'a>(data: &'a [u8]) -> Result<&'a Self>

source§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Zeroable for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

source§

fn zeroed() -> Self

source§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Copy for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

source§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Pod for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

Auto Trait Implementations§

§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Freeze for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> RefUnwindSafe for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Send for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Sync for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> Unpin for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

§

impl<const MAX_DEPTH: usize, const MAX_BUFFER_SIZE: usize> UnwindSafe for ConcurrentMerkleTree<MAX_DEPTH, MAX_BUFFER_SIZE>

Blanket Implementations§

source§

impl<T> AbiExample for T

source§

default fn example() -> T

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CheckedBitPattern for T
where T: AnyBitPattern,

source§

type Bits = T

Self must have the same layout as the specified Bits except for the possible invalid bit patterns being checked during is_valid_bit_pattern.
source§

fn is_valid_bit_pattern(_bits: &T) -> bool

If this function returns true, then it must be valid to reinterpret bits as &Self.
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<T> Pointable for T

source§

const ALIGN: usize = _

The alignment of pointer.
source§

type Init = T

The type for initializers.
source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same for T

source§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

source§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

source§

impl<T> AnyBitPattern for T
where T: Pod,

source§

impl<T> NoUninit for T
where T: Pod,