light-program-test 0.23.0

A fast local test environment for Solana programs using compressed accounts and tokens.
Documentation
use account_compression::{
    instruction::InitializeAddressMerkleTreeAndQueue, AddressMerkleTreeConfig, AddressQueueConfig,
};
use anchor_lang::InstructionData;
use light_client::rpc::{errors::RpcError, Rpc};
use solana_sdk::{
    compute_budget::ComputeBudgetInstruction,
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    signature::{Keypair, Signature, Signer},
    transaction::Transaction,
};

use crate::utils::create_account::create_account_instruction;

#[allow(clippy::too_many_arguments)]
pub fn create_initialize_address_merkle_tree_and_queue_instruction(
    index: u64,
    payer: Pubkey,
    registered_program_pda: Option<Pubkey>,
    program_owner: Option<Pubkey>,
    forester: Option<Pubkey>,
    merkle_tree_pubkey: Pubkey,
    queue_pubkey: Pubkey,
    address_merkle_tree_config: AddressMerkleTreeConfig,
    address_queue_config: AddressQueueConfig,
) -> Instruction {
    let instruction_data = InitializeAddressMerkleTreeAndQueue {
        index,
        program_owner,
        forester,
        address_merkle_tree_config,
        address_queue_config,
    };
    let registered_program = match registered_program_pda {
        Some(registered_program_pda) => AccountMeta::new(registered_program_pda, false),
        None => AccountMeta::new(account_compression::ID, false),
    };
    Instruction {
        program_id: account_compression::ID,
        accounts: vec![
            AccountMeta::new(payer, true),
            AccountMeta::new(merkle_tree_pubkey, false),
            AccountMeta::new(queue_pubkey, false),
            registered_program,
        ],
        data: instruction_data.data(),
    }
}

#[allow(clippy::too_many_arguments)]
#[inline(never)]
pub async fn create_address_merkle_tree_and_queue_account<R: Rpc>(
    payer: &Keypair,
    registry: bool,
    context: &mut R,
    address_merkle_tree_keypair: &Keypair,
    address_queue_keypair: &Keypair,
    program_owner: Option<Pubkey>,
    forester: Option<Pubkey>,
    merkle_tree_config: &AddressMerkleTreeConfig,
    queue_config: &AddressQueueConfig,
    index: u64,
) -> Result<Signature, RpcError> {
    use light_registry::account_compression_cpi::sdk::create_initialize_address_merkle_tree_and_queue_instruction as create_initialize_address_merkle_tree_and_queue_instruction_registry;

    let size =
        account_compression::state::QueueAccount::size(queue_config.capacity as usize).unwrap();
    let account_create_ix = create_account_instruction(
        &payer.pubkey(),
        size,
        context
            .get_minimum_balance_for_rent_exemption(size)
            .await
            .unwrap(),
        &account_compression::ID,
        Some(address_queue_keypair),
    );

    let size = account_compression::state::AddressMerkleTreeAccount::size(
        merkle_tree_config.height as usize,
        merkle_tree_config.changelog_size as usize,
        merkle_tree_config.roots_size as usize,
        merkle_tree_config.canopy_depth as usize,
        merkle_tree_config.address_changelog_size as usize,
    );
    let mt_account_create_ix = create_account_instruction(
        &payer.pubkey(),
        size,
        context
            .get_minimum_balance_for_rent_exemption(size)
            .await
            .unwrap(),
        &account_compression::ID,
        Some(address_merkle_tree_keypair),
    );
    let instruction = if registry {
        create_initialize_address_merkle_tree_and_queue_instruction_registry(
            payer.pubkey(),
            forester,
            program_owner,
            address_merkle_tree_keypair.pubkey(),
            address_queue_keypair.pubkey(),
            merkle_tree_config.clone(),
            queue_config.clone(),
        )
    } else {
        create_initialize_address_merkle_tree_and_queue_instruction(
            index,
            payer.pubkey(),
            None,
            program_owner,
            forester,
            address_merkle_tree_keypair.pubkey(),
            address_queue_keypair.pubkey(),
            merkle_tree_config.clone(),
            queue_config.clone(),
        )
    };

    let transaction = Transaction::new_signed_with_payer(
        &[
            ComputeBudgetInstruction::set_compute_unit_limit(500_000),
            account_create_ix,
            mt_account_create_ix,
            instruction,
        ],
        Some(&payer.pubkey()),
        &vec![&payer, &address_queue_keypair, &address_merkle_tree_keypair],
        context.get_latest_blockhash().await?.0,
    );
    let result = context.process_transaction(transaction).await;
    #[allow(clippy::question_mark)]
    if let Err(e) = result {
        return Err(e);
    }
    result
}