account_compression/instructions/
initialize_state_merkle_tree_and_nullifier_queue.rs

1use std::default;
2
3use anchor_lang::prelude::*;
4use light_account_checks::checks::check_account_balance_is_rent_exempt;
5
6use crate::{
7    errors::AccountCompressionErrorCode,
8    processor::{
9        initialize_concurrent_merkle_tree::process_initialize_state_merkle_tree,
10        initialize_nullifier_queue::process_initialize_nullifier_queue,
11    },
12    state::{QueueAccount, StateMerkleTreeAccount},
13    utils::{
14        check_signer_is_registered_or_authority::{
15            check_signer_is_registered_or_authority, GroupAccounts,
16        },
17        constants::{
18            STATE_MERKLE_TREE_CANOPY_DEPTH, STATE_MERKLE_TREE_CHANGELOG, STATE_MERKLE_TREE_HEIGHT,
19            STATE_MERKLE_TREE_ROOTS, STATE_NULLIFIER_QUEUE_SEQUENCE_THRESHOLD,
20            STATE_NULLIFIER_QUEUE_VALUES,
21        },
22    },
23    RegisteredProgram,
24};
25
26#[derive(Accounts)]
27pub struct InitializeStateMerkleTreeAndNullifierQueue<'info> {
28    #[account(mut)]
29    pub authority: Signer<'info>,
30    #[account(zero)]
31    pub merkle_tree: AccountLoader<'info, StateMerkleTreeAccount>,
32    #[account(zero)]
33    pub nullifier_queue: AccountLoader<'info, QueueAccount>,
34    pub registered_program_pda: Option<Account<'info, RegisteredProgram>>,
35}
36
37#[derive(Debug, Clone, AnchorDeserialize, AnchorSerialize, PartialEq)]
38pub struct StateMerkleTreeConfig {
39    pub height: u32,
40    pub changelog_size: u64,
41    pub roots_size: u64,
42    pub canopy_depth: u64,
43    pub network_fee: Option<u64>,
44    pub rollover_threshold: Option<u64>,
45    pub close_threshold: Option<u64>,
46}
47
48impl default::Default for StateMerkleTreeConfig {
49    fn default() -> Self {
50        Self {
51            height: STATE_MERKLE_TREE_HEIGHT as u32,
52            changelog_size: STATE_MERKLE_TREE_CHANGELOG,
53            roots_size: STATE_MERKLE_TREE_ROOTS,
54            canopy_depth: STATE_MERKLE_TREE_CANOPY_DEPTH,
55            network_fee: Some(5000),
56            rollover_threshold: Some(95),
57            close_threshold: None,
58        }
59    }
60}
61impl<'info> GroupAccounts<'info> for InitializeStateMerkleTreeAndNullifierQueue<'info> {
62    fn get_authority(&self) -> &Signer<'info> {
63        &self.authority
64    }
65    fn get_registered_program_pda(&self) -> &Option<Account<'info, RegisteredProgram>> {
66        &self.registered_program_pda
67    }
68}
69#[derive(Debug, Clone, AnchorDeserialize, AnchorSerialize, PartialEq)]
70pub struct NullifierQueueConfig {
71    pub capacity: u16,
72    pub sequence_threshold: u64,
73    pub network_fee: Option<u64>,
74}
75// Arbitrary safety margin.
76pub const SAFETY_MARGIN: u64 = 10;
77
78impl default::Default for NullifierQueueConfig {
79    fn default() -> Self {
80        Self {
81            capacity: STATE_NULLIFIER_QUEUE_VALUES,
82            sequence_threshold: STATE_NULLIFIER_QUEUE_SEQUENCE_THRESHOLD + SAFETY_MARGIN,
83            network_fee: None,
84        }
85    }
86}
87
88pub fn process_initialize_state_merkle_tree_and_nullifier_queue<'info>(
89    ctx: Context<'_, '_, '_, 'info, InitializeStateMerkleTreeAndNullifierQueue<'info>>,
90    index: u64,
91    program_owner: Option<Pubkey>,
92    forester: Option<Pubkey>,
93    state_merkle_tree_config: StateMerkleTreeConfig,
94    nullifier_queue_config: NullifierQueueConfig,
95    _additional_bytes: u64,
96) -> Result<()> {
97    if state_merkle_tree_config.height as u64 != STATE_MERKLE_TREE_HEIGHT {
98        msg!(
99            "Unsupported Merkle tree height: {}. The only currently supported height is: {}",
100            state_merkle_tree_config.height,
101            STATE_MERKLE_TREE_HEIGHT
102        );
103        return err!(AccountCompressionErrorCode::UnsupportedHeight);
104    }
105    if state_merkle_tree_config.canopy_depth != STATE_MERKLE_TREE_CANOPY_DEPTH {
106        msg!(
107            "Unsupported canopy depth: {}. The only currently supported depth is: {}",
108            state_merkle_tree_config.canopy_depth,
109            STATE_MERKLE_TREE_CANOPY_DEPTH
110        );
111        return err!(AccountCompressionErrorCode::UnsupportedCanopyDepth);
112    }
113    if state_merkle_tree_config.close_threshold.is_some() {
114        msg!("close_threshold is not supported yet");
115        return err!(AccountCompressionErrorCode::UnsupportedCloseThreshold);
116    }
117    let minimum_sequence_threshold = state_merkle_tree_config.roots_size + SAFETY_MARGIN;
118    if nullifier_queue_config.sequence_threshold < minimum_sequence_threshold {
119        msg!(
120            "Invalid sequence threshold: {}. Should be at least: {}",
121            nullifier_queue_config.sequence_threshold,
122            minimum_sequence_threshold
123        );
124        return err!(AccountCompressionErrorCode::InvalidSequenceThreshold);
125    }
126    let merkle_tree_expected_size = StateMerkleTreeAccount::size(
127        state_merkle_tree_config.height as usize,
128        state_merkle_tree_config.changelog_size as usize,
129        state_merkle_tree_config.roots_size as usize,
130        state_merkle_tree_config.canopy_depth as usize,
131    );
132    let queue_expected_size = QueueAccount::size(nullifier_queue_config.capacity as usize)?;
133    let merkle_tree_rent = check_account_balance_is_rent_exempt(
134        &ctx.accounts.merkle_tree.to_account_info(),
135        merkle_tree_expected_size,
136    )
137    .map_err(ProgramError::from)?;
138    let queue_rent = check_account_balance_is_rent_exempt(
139        &ctx.accounts.nullifier_queue.to_account_info(),
140        queue_expected_size,
141    )
142    .map_err(ProgramError::from)?;
143    let owner = match ctx.accounts.registered_program_pda.as_ref() {
144        Some(registered_program_pda) => {
145            check_signer_is_registered_or_authority::<
146                InitializeStateMerkleTreeAndNullifierQueue,
147                RegisteredProgram,
148            >(&ctx, registered_program_pda)?;
149            registered_program_pda.group_authority_pda
150        }
151        None => ctx.accounts.authority.key(),
152    };
153    process_initialize_state_merkle_tree(
154        &ctx.accounts.merkle_tree,
155        index,
156        owner,
157        program_owner,
158        forester,
159        &state_merkle_tree_config.height,
160        &state_merkle_tree_config.changelog_size,
161        &state_merkle_tree_config.roots_size,
162        &state_merkle_tree_config.canopy_depth,
163        ctx.accounts.nullifier_queue.key(),
164        state_merkle_tree_config.network_fee.unwrap_or(0),
165        state_merkle_tree_config.rollover_threshold,
166        state_merkle_tree_config.close_threshold,
167        merkle_tree_rent,
168        queue_rent,
169    )?;
170    process_initialize_nullifier_queue(
171        ctx.accounts.nullifier_queue.to_account_info(),
172        &ctx.accounts.nullifier_queue,
173        index,
174        owner,
175        program_owner,
176        forester,
177        ctx.accounts.merkle_tree.key(),
178        nullifier_queue_config.capacity,
179        nullifier_queue_config.sequence_threshold,
180        state_merkle_tree_config.rollover_threshold,
181        state_merkle_tree_config.close_threshold,
182        nullifier_queue_config.network_fee.unwrap_or(0),
183    )?;
184    Ok(())
185}