light_compressed_pda/invoke/
nullify_state.rs

1use crate::{
2    invoke::InstructionDataInvoke,
3    invoke_cpi::verify_signer::check_program_owner_state_merkle_tree,
4    sdk::accounts::{InvokeAccounts, SignerAccounts},
5};
6use anchor_lang::{prelude::*, solana_program::pubkey::Pubkey, Bumps};
7use light_macros::heap_neutral;
8
9/// 1. Checks that the nullifier queue account is associated with a state Merkle tree account.
10/// 2. Checks that if nullifier queue has delegate it invoking_program is delegate.
11/// 3. Inserts nullifiers into the queue.
12#[heap_neutral]
13pub fn insert_nullifiers<
14    'a,
15    'b,
16    'c: 'info,
17    'info,
18    A: InvokeAccounts<'info> + SignerAccounts<'info> + Bumps,
19>(
20    inputs: &'a InstructionDataInvoke,
21    ctx: &'a Context<'a, 'b, 'c, 'info, A>,
22    nullifiers: &'a [[u8; 32]],
23    invoking_program: &Option<Pubkey>,
24) -> Result<()> {
25    light_heap::bench_sbf_start!("cpda_insert_nullifiers_prep_accs");
26    let mut account_infos = vec![
27        ctx.accounts.get_fee_payer().to_account_info(),
28        ctx.accounts
29            .get_account_compression_authority()
30            .to_account_info(),
31        ctx.accounts.get_registered_program_pda().to_account_info(),
32        ctx.accounts.get_system_program().to_account_info(),
33    ];
34    let mut accounts = vec![
35        AccountMeta {
36            pubkey: account_infos[0].key(),
37            is_signer: true,
38            is_writable: true,
39        },
40        AccountMeta {
41            pubkey: account_infos[1].key(),
42            is_signer: true,
43            is_writable: false,
44        },
45        AccountMeta {
46            pubkey: account_infos[2].key(),
47            is_signer: false,
48            is_writable: false,
49        },
50        AccountMeta::new_readonly(account_infos[3].key(), false),
51    ];
52    for account in inputs.input_compressed_accounts_with_merkle_context.iter() {
53        let account_info =
54            &ctx.remaining_accounts[account.merkle_context.nullifier_queue_pubkey_index as usize];
55        accounts.push(AccountMeta {
56            pubkey: account_info.key(),
57            is_signer: false,
58            is_writable: true,
59        });
60        account_infos.push(account_info.clone());
61    }
62    inputs
63        .input_compressed_accounts_with_merkle_context
64        .iter()
65        .try_for_each(|account| -> Result<()> {
66            check_program_owner_state_merkle_tree(
67                &ctx.remaining_accounts[account.merkle_context.merkle_tree_pubkey_index as usize],
68                invoking_program,
69            )?;
70            accounts.push(AccountMeta {
71                pubkey: ctx.remaining_accounts
72                    [account.merkle_context.merkle_tree_pubkey_index as usize]
73                    .key(),
74                is_signer: false,
75                is_writable: false,
76            });
77            account_infos.push(
78                ctx.remaining_accounts[account.merkle_context.merkle_tree_pubkey_index as usize]
79                    .clone(),
80            );
81            Ok(())
82        })?;
83    light_heap::bench_sbf_end!("cpda_insert_nullifiers_prep_accs");
84    light_heap::bench_sbf_start!("cpda_instruction_data");
85
86    use anchor_lang::InstructionData;
87    let instruction_data = account_compression::instruction::InsertIntoNullifierQueues {
88        elements: nullifiers.to_vec(),
89    };
90
91    let data = instruction_data.data();
92    light_heap::bench_sbf_end!("cpda_instruction_data");
93
94    // [91, 101, 183, 28, 35, 25, 67, 221]
95    let bump = &[254];
96    let seeds = &[&[b"cpi_authority".as_slice(), bump][..]];
97    let instruction = anchor_lang::solana_program::instruction::Instruction {
98        program_id: account_compression::ID,
99        accounts,
100        data,
101    };
102    anchor_lang::solana_program::program::invoke_signed(
103        &instruction,
104        account_infos.as_slice(),
105        seeds,
106    )?;
107    Ok(())
108}