use crate::{
errors::AccountCompressionErrorCode,
initialize_concurrent_merkle_tree::process_initialize_state_merkle_tree,
initialize_nullifier_queue::process_initialize_nullifier_queue,
state::{QueueAccount, StateMerkleTreeAccount},
utils::{
check_account::check_account_balance_is_rent_exempt,
check_signer_is_registered_or_authority::{
check_signer_is_registered_or_authority, GroupAccounts,
},
constants::{
STATE_MERKLE_TREE_CANOPY_DEPTH, STATE_MERKLE_TREE_CHANGELOG, STATE_MERKLE_TREE_HEIGHT,
STATE_MERKLE_TREE_ROOTS, STATE_NULLIFIER_QUEUE_SEQUENCE_THRESHOLD,
STATE_NULLIFIER_QUEUE_VALUES,
},
},
RegisteredProgram,
};
use anchor_lang::prelude::*;
use std::default;
#[derive(Accounts)]
pub struct InitializeStateMerkleTreeAndNullifierQueue<'info> {
#[account(mut)]
pub authority: Signer<'info>,
#[account(zero)]
pub merkle_tree: AccountLoader<'info, StateMerkleTreeAccount>,
#[account(zero)]
pub nullifier_queue: AccountLoader<'info, QueueAccount>,
pub registered_program_pda: Option<Account<'info, RegisteredProgram>>,
}
#[derive(Debug, Clone, AnchorDeserialize, AnchorSerialize, PartialEq)]
pub struct StateMerkleTreeConfig {
pub height: u32,
pub changelog_size: u64,
pub roots_size: u64,
pub canopy_depth: u64,
pub network_fee: Option<u64>,
pub rollover_threshold: Option<u64>,
pub close_threshold: Option<u64>,
}
impl default::Default for StateMerkleTreeConfig {
fn default() -> Self {
Self {
height: STATE_MERKLE_TREE_HEIGHT as u32,
changelog_size: STATE_MERKLE_TREE_CHANGELOG,
roots_size: STATE_MERKLE_TREE_ROOTS,
canopy_depth: STATE_MERKLE_TREE_CANOPY_DEPTH,
network_fee: Some(5000),
rollover_threshold: Some(95),
close_threshold: None,
}
}
}
impl<'info> GroupAccounts<'info> for InitializeStateMerkleTreeAndNullifierQueue<'info> {
fn get_authority(&self) -> &Signer<'info> {
&self.authority
}
fn get_registered_program_pda(&self) -> &Option<Account<'info, RegisteredProgram>> {
&self.registered_program_pda
}
}
#[derive(Debug, Clone, AnchorDeserialize, AnchorSerialize, PartialEq)]
pub struct NullifierQueueConfig {
pub capacity: u16,
pub sequence_threshold: u64,
pub network_fee: Option<u64>,
}
pub const SAFETY_MARGIN: u64 = 10;
impl default::Default for NullifierQueueConfig {
fn default() -> Self {
Self {
capacity: STATE_NULLIFIER_QUEUE_VALUES,
sequence_threshold: STATE_NULLIFIER_QUEUE_SEQUENCE_THRESHOLD + SAFETY_MARGIN,
network_fee: None,
}
}
}
pub fn process_initialize_state_merkle_tree_and_nullifier_queue<'info>(
ctx: Context<'_, '_, '_, 'info, InitializeStateMerkleTreeAndNullifierQueue<'info>>,
index: u64,
program_owner: Option<Pubkey>,
forester: Option<Pubkey>,
state_merkle_tree_config: StateMerkleTreeConfig,
nullifier_queue_config: NullifierQueueConfig,
_additional_bytes: u64,
) -> Result<()> {
if state_merkle_tree_config.height as u64 != STATE_MERKLE_TREE_HEIGHT {
msg!(
"Unsupported Merkle tree height: {}. The only currently supported height is: {}",
state_merkle_tree_config.height,
STATE_MERKLE_TREE_HEIGHT
);
return err!(AccountCompressionErrorCode::UnsupportedHeight);
}
if state_merkle_tree_config.canopy_depth != STATE_MERKLE_TREE_CANOPY_DEPTH {
msg!(
"Unsupported canopy depth: {}. The only currently supported depth is: {}",
state_merkle_tree_config.canopy_depth,
STATE_MERKLE_TREE_CANOPY_DEPTH
);
return err!(AccountCompressionErrorCode::UnsupportedCanopyDepth);
}
if state_merkle_tree_config.close_threshold.is_some() {
msg!("close_threshold is not supported yet");
return err!(AccountCompressionErrorCode::UnsupportedCloseThreshold);
}
let minimum_sequence_threshold = state_merkle_tree_config.roots_size + SAFETY_MARGIN;
if nullifier_queue_config.sequence_threshold < minimum_sequence_threshold {
msg!(
"Invalid sequence threshold: {}. Should be at least: {}",
nullifier_queue_config.sequence_threshold,
minimum_sequence_threshold
);
return err!(AccountCompressionErrorCode::InvalidSequenceThreshold);
}
let merkle_tree_expected_size = StateMerkleTreeAccount::size(
state_merkle_tree_config.height as usize,
state_merkle_tree_config.changelog_size as usize,
state_merkle_tree_config.roots_size as usize,
state_merkle_tree_config.canopy_depth as usize,
);
let queue_expected_size = QueueAccount::size(nullifier_queue_config.capacity as usize)?;
let merkle_tree_rent = check_account_balance_is_rent_exempt(
&ctx.accounts.merkle_tree.to_account_info(),
merkle_tree_expected_size,
)?;
let queue_rent = check_account_balance_is_rent_exempt(
&ctx.accounts.nullifier_queue.to_account_info(),
queue_expected_size,
)?;
let owner = match ctx.accounts.registered_program_pda.as_ref() {
Some(registered_program_pda) => {
check_signer_is_registered_or_authority::<
InitializeStateMerkleTreeAndNullifierQueue,
RegisteredProgram,
>(&ctx, registered_program_pda)?;
registered_program_pda.group_authority_pda
}
None => ctx.accounts.authority.key(),
};
process_initialize_state_merkle_tree(
&ctx.accounts.merkle_tree,
index,
owner,
program_owner,
forester,
&state_merkle_tree_config.height,
&state_merkle_tree_config.changelog_size,
&state_merkle_tree_config.roots_size,
&state_merkle_tree_config.canopy_depth,
ctx.accounts.nullifier_queue.key(),
state_merkle_tree_config.network_fee.unwrap_or(0),
state_merkle_tree_config.rollover_threshold,
state_merkle_tree_config.close_threshold,
merkle_tree_rent,
queue_rent,
)?;
process_initialize_nullifier_queue(
ctx.accounts.nullifier_queue.to_account_info(),
&ctx.accounts.nullifier_queue,
index,
owner,
program_owner,
forester,
ctx.accounts.merkle_tree.key(),
nullifier_queue_config.capacity,
nullifier_queue_config.sequence_threshold,
state_merkle_tree_config.rollover_threshold,
state_merkle_tree_config.close_threshold,
nullifier_queue_config.network_fee.unwrap_or(0),
)?;
Ok(())
}