use light_sdk::instruction::{PackedAccounts, SystemAccountMetaConfig};
pub use light_sdk::instruction::{PackedAddressTreeInfo, PackedStateTreeInfo};
use solana_instruction::AccountMeta;
use solana_pubkey::Pubkey;
use thiserror::Error;
use crate::indexer::{TreeInfo, ValidityProofWithContext};
#[derive(Debug, Error)]
pub enum PackError {
#[error("Failed to add system accounts: {0}")]
SystemAccounts(#[from] light_sdk::error::LightSdkError),
}
#[derive(Clone, Default, Debug)]
pub struct PackedStateTreeInfos {
pub packed_tree_infos: Vec<PackedStateTreeInfo>,
pub output_tree_index: u8,
}
#[derive(Clone, Default, Debug)]
pub struct PackedTreeInfos {
pub state_trees: Option<PackedStateTreeInfos>,
pub address_trees: Vec<PackedAddressTreeInfo>,
}
pub struct PackedProofResult {
pub remaining_accounts: Vec<AccountMeta>,
pub packed_tree_infos: PackedTreeInfos,
pub output_tree_index: u8,
pub state_tree_index: Option<u8>,
pub system_accounts_offset: u8,
}
pub fn pack_proof(
program_id: &Pubkey,
proof: ValidityProofWithContext,
output_tree: &TreeInfo,
cpi_context: Option<Pubkey>,
) -> Result<PackedProofResult, PackError> {
pack_proof_internal(program_id, proof, output_tree, cpi_context, false)
}
pub fn pack_proof_for_mints(
program_id: &Pubkey,
proof: ValidityProofWithContext,
output_tree: &TreeInfo,
cpi_context: Option<Pubkey>,
) -> Result<PackedProofResult, PackError> {
pack_proof_internal(program_id, proof, output_tree, cpi_context, true)
}
fn pack_proof_internal(
program_id: &Pubkey,
proof: ValidityProofWithContext,
output_tree: &TreeInfo,
cpi_context: Option<Pubkey>,
include_state_tree: bool,
) -> Result<PackedProofResult, PackError> {
let mut packed = PackedAccounts::default();
let system_config = match cpi_context {
Some(ctx) => SystemAccountMetaConfig::new_with_cpi_context(*program_id, ctx),
None => SystemAccountMetaConfig::new(*program_id),
};
packed.add_system_accounts_v2(system_config)?;
let output_queue = output_tree
.next_tree_info
.as_ref()
.map(|n| n.queue)
.unwrap_or(output_tree.queue);
let output_tree_index = packed.insert_or_get(output_queue);
let (client_packed_tree_infos, state_tree_index) = if include_state_tree {
let tree_infos = proof.pack_tree_infos(&mut packed);
let state_tree = output_tree
.next_tree_info
.as_ref()
.map(|n| n.tree)
.unwrap_or(output_tree.tree);
let state_idx = packed.insert_or_get(state_tree);
(tree_infos, Some(state_idx))
} else {
let tree_infos = proof.pack_tree_infos(&mut packed);
(tree_infos, None)
};
let (remaining_accounts, system_offset, _) = packed.to_account_metas();
let packed_tree_infos = PackedTreeInfos {
state_trees: client_packed_tree_infos
.state_trees
.map(|st| PackedStateTreeInfos {
packed_tree_infos: st.packed_tree_infos,
output_tree_index: st.output_tree_index,
}),
address_trees: client_packed_tree_infos.address_trees,
};
Ok(PackedProofResult {
remaining_accounts,
packed_tree_infos,
output_tree_index,
state_tree_index,
system_accounts_offset: system_offset as u8,
})
}