use anchor_lang::prelude::*;
use light_batched_merkle_tree::merkle_tree::BatchedMerkleTreeAccount;
use light_compressed_account::instruction_data::insert_into_queues::InsertAddressInput;
use num_bigint::BigUint;
use crate::{
context::AcpAccount, errors::AccountCompressionErrorCode,
insert_into_queues::get_queue_and_tree_accounts, queue_from_bytes_zero_copy_mut, QueueAccount,
};
#[inline(always)]
pub fn insert_addresses(
num_queues: u8,
addresses: &[InsertAddressInput],
accounts: &mut [AcpAccount<'_, '_>],
current_slot: &u64,
) -> Result<()> {
if addresses.is_empty() {
return Ok(());
}
let mut inserted_addresses = 0;
let mut visited = Vec::with_capacity(num_queues as usize);
visited.push((addresses[0].tree_index, addresses[0].queue_index));
for nf in addresses.iter().skip(1) {
if visited.len() == num_queues as usize {
break;
}
if visited.iter().all(|&(_, q)| q != nf.queue_index) {
visited.push((nf.tree_index, nf.queue_index));
}
}
for &(tree_index, queue_index) in &visited {
let queue_account = &mut accounts[queue_index as usize];
match queue_account {
AcpAccount::BatchedAddressTree(address_tree) => {
inserted_addresses +=
batched_addresses(address_tree, addresses, queue_index, current_slot)?;
anchor_lang::Result::Ok(())
}
AcpAccount::V1Queue(_) => {
let (queue_account, merkle_tree_account) = get_queue_and_tree_accounts(
accounts,
queue_index as usize,
tree_index as usize,
)?;
let queue_account_info =
if let AcpAccount::V1Queue(queue_account_info) = queue_account {
queue_account_info
} else {
msg!("Queue account is not a queue account");
return err!(AccountCompressionErrorCode::InvalidAccount);
};
inserted_addresses += process_address_v1(
merkle_tree_account,
queue_account_info,
addresses,
queue_index,
tree_index,
)?;
Ok(())
}
AcpAccount::AddressTree(_) => unimplemented!("AddressTree"),
_ => Err(
AccountCompressionErrorCode::AddressMerkleTreeAccountDiscriminatorMismatch.into(),
),
}?;
}
if inserted_addresses != addresses.len() {
msg!("inserted_addresses {:?}", inserted_addresses);
msg!("addresses.len() {:?}", addresses.len());
return err!(AccountCompressionErrorCode::NotAllLeavesProcessed);
}
Ok(())
}
fn batched_addresses(
addresse_tree: &mut BatchedMerkleTreeAccount<'_>,
addresses: &[InsertAddressInput],
current_queue_index: u8,
current_slot: &u64,
) -> Result<usize> {
let addresses = addresses
.iter()
.filter(|x| x.queue_index == current_queue_index);
#[cfg(feature = "bench-sbf")]
light_heap::bench_sbf_start!("acp_insert_address_into_queue_v2");
let mut num_elements = 0;
for address in addresses {
num_elements += 1;
addresse_tree
.insert_address_into_queue(&address.address, current_slot)
.map_err(ProgramError::from)?;
#[cfg(feature = "bench-sbf")]
light_heap::bench_sbf_end!("acp_insert_address_into_queue_v2");
}
Ok(num_elements)
}
fn process_address_v1<'info>(
merkle_tree: &mut AcpAccount<'_, 'info>,
address_queue: &mut AccountInfo<'info>,
addresses: &[InsertAddressInput],
current_queue_index: u8,
current_tree_index: u8,
) -> Result<usize> {
let addresses = addresses
.iter()
.filter(|x| x.queue_index == current_queue_index && x.tree_index == current_tree_index);
let (merkle_pubkey, merkle_tree) = if let AcpAccount::AddressTree(tree) = merkle_tree {
tree
} else {
return err!(AccountCompressionErrorCode::AddressMerkleTreeAccountDiscriminatorMismatch);
};
{
let queue_data = address_queue.try_borrow_data()?;
let queue = bytemuck::from_bytes::<QueueAccount>(&queue_data[8..QueueAccount::LEN]);
if queue.metadata.associated_merkle_tree != *merkle_pubkey {
msg!(
"Queue account {:?} is not associated with Merkle tree {:?}",
address_queue.key(),
*merkle_pubkey
);
return err!(AccountCompressionErrorCode::MerkleTreeAndQueueNotAssociated);
}
}
let mut num_elements = 0;
let sequence_number = merkle_tree.sequence_number();
let mut queue = address_queue.try_borrow_mut_data()?;
let mut queue =
unsafe { queue_from_bytes_zero_copy_mut(&mut queue).map_err(ProgramError::from)? };
#[cfg(feature = "bench-sbf")]
light_heap::bench_sbf_start!("acp_insert_nf_into_queue");
for address in addresses {
num_elements += 1;
let element = BigUint::from_bytes_be(address.address.as_slice());
queue
.insert(&element, sequence_number)
.map_err(ProgramError::from)?;
}
#[cfg(feature = "bench-sbf")]
light_heap::bench_sbf_end!("acp_insert_nf_into_queue");
Ok(num_elements)
}