account_compression/instructions/
initialize_state_merkle_tree_and_nullifier_queue.rs1use 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}
75pub 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}