light_batched_merkle_tree/lib.rs
1//! # light-batched-merkle-tree
2//!
3//! The crate provides batched Merkle tree
4//! implementations for the account compression program.
5//! Instead of updating trees one leaf at a time, this library batches
6//! multiple insertions and updates them with zero-knowledge proofs (ZKPs),
7//! enabling efficient on-chain verification. Trees maintain a cyclic root
8//! history for validity proofs, and use bloom filters for non-inclusion
9//! proofs while batches are being filled.
10//!
11//! There are two tree types: **state trees** (two accounts tree account
12//! (input queue, tree metadata, roots), output queue account) for compressed
13//! accounts, and **address trees** (one account that contains the address queue,
14//! tree metadata, roots) for address registration.
15//!
16//! | Module | Description |
17//! |--------|-------------|
18//! | [`batch`] | Batch append and update operations |
19//! | [`merkle_tree`] | Batched Merkle tree account struct |
20//! | [`queue`] | Queue account for batched leaves |
21//! | [`queue_batch_metadata`] | Metadata for queue batches |
22//! | [`initialize_state_tree`] | Initialize a batched state tree |
23//! | [`initialize_address_tree`] | Initialize a batched address tree |
24//! | [`rollover_state_tree`] | Roll over a full state tree |
25//! | [`rollover_address_tree`] | Roll over a full address tree |
26//! | [`merkle_tree_metadata`] | Tree and queue metadata structs |
27//! | [`errors`] | Error types for batch operations |
28//!
29//! ## Accounts
30//!
31//! ### Account Types
32//!
33//! - **[TREE_ACCOUNT.md](TREE_ACCOUNT.md)** - BatchedMerkleTreeAccount (state and address trees)
34//! - **[QUEUE_ACCOUNT.md](QUEUE_ACCOUNT.md)** - BatchedQueueAccount (output queue for state trees)
35//!
36//! ### Overview
37//!
38//! The batched merkle tree library uses two main Solana account types:
39//!
40//! **BatchedMerkleTreeAccount:**
41//! The main tree account storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers or addresses). Used for both state trees and address trees.
42//!
43//! **Details:** [TREE_ACCOUNT.md](TREE_ACCOUNT.md)
44//!
45//! **BatchedQueueAccount:**
46//! Output queue account for state trees that temporarily stores compressed account hashes before tree insertion. Enables immediate spending via proof-by-index.
47//!
48//! **Details:** [QUEUE_ACCOUNT.md](QUEUE_ACCOUNT.md)
49//!
50//! ### State Trees vs Address Trees
51//!
52//! **State Trees (2 accounts):**
53//! - `BatchedMerkleTreeAccount` with integrated input queue (for nullifiers)
54//! - Separate `BatchedQueueAccount` for output operations (appending new compressed accounts)
55//!
56//! **Address Trees (1 account):**
57//! - `BatchedMerkleTreeAccount` with integrated input queue (for addresses)
58//! - No separate output queue
59//!
60//! ## Operations
61//!
62//! ### Initialization
63//! - **[INITIALIZE_STATE_TREE.md](INITIALIZE_STATE_TREE.md)** - Create state tree + output queue pair (2 solana accounts)
64//! - Source: [`src/initialize_state_tree.rs`](../src/initialize_state_tree.rs)
65//!
66//! - **[INITIALIZE_ADDRESS_TREE.md](INITIALIZE_ADDRESS_TREE.md)** - Create address tree with integrated queue (1 solana account)
67//! - Source: [`src/initialize_address_tree.rs`](../src/initialize_address_tree.rs)
68//!
69//! ### Queue Insertion Operations
70//! - **[INSERT_OUTPUT_QUEUE.md](INSERT_OUTPUT_QUEUE.md)** - Insert compressed account hash into output queue (state tree)
71//! - Source: [`src/queue.rs`](../src/queue.rs) - `BatchedQueueAccount::insert_into_current_batch`
72//!
73//! - **[INSERT_INPUT_QUEUE.md](INSERT_INPUT_QUEUE.md)** - Insert nullifiers into input queue (state tree)
74//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::insert_nullifier_into_queue`
75//!
76//! - **[INSERT_ADDRESS_QUEUE.md](INSERT_ADDRESS_QUEUE.md)** - Insert addresses into address queue
77//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::insert_address_into_queue`
78//!
79//! ### Tree Update Operations
80//! - **[UPDATE_FROM_OUTPUT_QUEUE.md](UPDATE_FROM_OUTPUT_QUEUE.md)** - Batch append with ZKP verification
81//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::update_tree_from_output_queue_account`
82//!
83//! - **[UPDATE_FROM_INPUT_QUEUE.md](UPDATE_FROM_INPUT_QUEUE.md)** - Batch nullify/address updates with ZKP
84//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `update_tree_from_input_queue`, `update_tree_from_address_queue`
85//!
86//! ## Key Concepts
87//!
88//! **Batching System:** Trees use 2 alternating batches. While one batch is being filled, the previous batch can be updated into the tree with a ZKP.
89//!
90//! **ZKP Batches:** Each batch is divided into smaller ZKP batches (`batch_size / zkp_batch_size`). Trees are updated incrementally by ZKP batch.
91//!
92//! **Bloom Filters:** Input queues (nullifier queue for state trees, address queue for address trees) use bloom filters for non-inclusion proofs. While a batch is filling, values are inserted into the bloom filter. After the batch is fully inserted into the tree and the next batch is 50% full, the bloom filter is zeroed to prevent false positives. Output queues do not use bloom filters.
93//!
94//! **Value Vecs:** Output queues store the actual compressed account hashes in value vectors (one per batch). Values can be accessed by leaf index even before they're inserted into the tree, enabling immediate spending of newly created compressed accounts.
95//!
96//! **Hash Chains:** Each ZKP batch has a hash chain storing the Poseidon hash of all values in that ZKP batch. These hash chains are used as public inputs for ZKP verification.
97//!
98//! **ZKP Verification:** Tree updates require zero-knowledge proofs proving the correctness of batch operations (old root + queue values → new root). Public inputs: old root, new root, hash chain (commitment to queue elements), and for appends: start_index (output queue) or next_index (address queue).
99//!
100//! **Root History:** Trees maintain a cyclic buffer of recent roots (default: 200). This enables validity proofs for recently spent compressed accounts even as the tree continues to update.
101//!
102//! **Rollover:** When a tree reaches capacity (2^height leaves), it must be replaced with a new tree. The rollover process creates a new tree and marks the old tree as rolled over, preserving the old tree's roots for ongoing validity proofs. A rollover can be performed once the rollover threshold is met (default: 95% full).
103//!
104//! **State vs Address Trees:**
105//! - **State trees** have a separate `BatchedQueueAccount` for output operations (appending new leaves). Input operations (nullifying) use the integrated input queue on the tree account.
106//! - **Address trees** have only an integrated input queue on the tree account - no separate output queue.
107//!
108//! ## ZKP Verification
109//!
110//! Batch update operations require zero-knowledge proofs generated by the Light Protocol prover:
111//!
112//! - **Prover Server:** `prover/server/` - Generates ZK proofs for batch operations
113//! - **Prover Client:** `prover/client/` - Client libraries for requesting proofs
114//! - **Batch Update Circuits:** `prover/server/prover/v2/` - Circuit definitions for batch append, batch update (nullify), and batch address append operations
115//!
116//! ## Dependencies
117//!
118//! This crate relies on several Light Protocol libraries:
119//!
120//! - **`light-bloom-filter`** - Bloom filter implementation for non-inclusion proofs
121//! - **`light-hasher`** - Poseidon hash implementation for hash chains and tree operations
122//! - **`light-verifier`** - ZKP verification for batch updates
123//! - **`light-zero-copy`** - Zero-copy serialization for efficient account data access
124//! - **`light-merkle-tree-metadata`** - Shared metadata structures for merkle trees
125//! - **`light-compressed-account`** - Compressed account types and utilities
126//! - **`light-account-checks`** - Account validation and discriminator checks
127//!
128//! ## Testing and Reference Implementations
129//!
130//! **IndexedMerkleTree Reference Implementation:**
131//! - **`light-merkle-tree-reference`** - Reference implementation of indexed Merkle trees (dev dependency)
132//! - Source: `program-tests/merkle-tree/src/indexed.rs` - Canonical IndexedMerkleTree implementation used for generating constants and testing
133//! - Used to generate constants like `ADDRESS_TREE_INIT_ROOT_40` in [`src/constants.rs`](../src/constants.rs)
134//! - Initializes address trees with a single leaf: `H(0, HIGHEST_ADDRESS_PLUS_ONE)`
135//!
136//! ## Source Code Structure
137//!
138//! **Core Account Types:**
139//! - [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount` (prove inclusion, nullify existing state, create new addresses)
140//! - [`src/queue.rs`](../src/queue.rs) - `BatchedQueueAccount` (add new state (transaction outputs))
141//! - [`src/batch.rs`](../src/batch.rs) - `Batch` state machine (Fill → Full → Inserted)
142//! - [`src/queue_batch_metadata.rs`](../src/queue_batch_metadata.rs) - `QueueBatches` metadata
143//!
144//! **Metadata and Configuration:**
145//! - [`src/merkle_tree_metadata.rs`](../src/merkle_tree_metadata.rs) - `BatchedMerkleTreeMetadata` and account size calculations
146//! - [`src/constants.rs`](../src/constants.rs) - Default configuration values
147//!
148//! **ZKP Infrastructure:**
149//! - `prover/server/` - Prover server that generates ZK proofs for batch operations
150//! - `prover/client/` - Client libraries for requesting proofs
151//! - `prover/server/prover/v2/` - Batch update circuit definitions (append, nullify, address append)
152//!
153//! **Initialization:**
154//! - [`src/initialize_state_tree.rs`](../src/initialize_state_tree.rs) - State tree initialization
155//! - [`src/initialize_address_tree.rs`](../src/initialize_address_tree.rs) - Address tree initialization
156//! - [`src/rollover_state_tree.rs`](../src/rollover_state_tree.rs) - State tree rollover
157//! - [`src/rollover_address_tree.rs`](../src/rollover_address_tree.rs) - Address tree rollover
158//!
159//! **Errors:**
160//! - [`src/errors.rs`](../src/errors.rs) - `BatchedMerkleTreeError` enum with all error types
161//!
162//! ## Error Codes
163//!
164//! All errors are defined in [`src/errors.rs`](../src/errors.rs) and map to u32 error codes (14301-14312 range):
165//! - `BatchNotReady` (14301) - Batch is not ready to be inserted
166//! - `BatchAlreadyInserted` (14302) - Batch is already inserted
167//! - `TreeIsFull` (14310) - Batched Merkle tree reached capacity
168//! - `NonInclusionCheckFailed` (14311) - Value exists in bloom filter
169//! - `BloomFilterNotZeroed` (14312) - Bloom filter must be zeroed before reuse
170//! - Additional errors from underlying libraries (hasher, zero-copy, verifier, etc.)
171
172#![allow(unexpected_cfgs)]
173pub mod batch;
174pub mod constants;
175pub mod errors;
176pub mod initialize_address_tree;
177pub mod initialize_state_tree;
178pub mod merkle_tree;
179pub mod merkle_tree_metadata;
180pub mod queue;
181pub mod queue_batch_metadata;
182pub mod rollover_address_tree;
183pub mod rollover_state_tree;
184
185// Use the appropriate BorshDeserialize and BorshSerialize based on feature
186use borsh::{BorshDeserialize, BorshSerialize};