account_compression/state/
queue.rs

1use crate::InsertIntoQueues;
2use crate::{errors::AccountCompressionErrorCode, AccessMetadata, RolloverMetadata};
3use crate::{
4    utils::check_signer_is_registered_or_authority::{GroupAccess, GroupAccounts},
5    RegisteredProgram,
6};
7use aligned_sized::aligned_sized;
8use anchor_lang::prelude::*;
9use light_hash_set::{zero_copy::HashSetZeroCopy, HashSet};
10use std::mem;
11
12#[account(zero_copy)]
13#[derive(AnchorDeserialize, Debug, PartialEq)]
14pub struct QueueMetadata {
15    pub access_metadata: AccessMetadata,
16    pub rollover_metadata: RolloverMetadata,
17
18    // Queue associated with this Merkle tree.
19    pub associated_merkle_tree: Pubkey,
20    // Next queue to be used after rollover.
21    pub next_queue: Pubkey,
22    pub queue_type: u64,
23}
24
25#[derive(AnchorDeserialize, AnchorSerialize, Debug, PartialEq, Clone, Copy)]
26#[repr(u8)]
27pub enum QueueType {
28    NullifierQueue = 1,
29    AddressQueue = 2,
30}
31
32pub fn check_queue_type(queue_type: &u64, expected_queue_type: &QueueType) -> Result<()> {
33    if *queue_type != (*expected_queue_type) as u64 {
34        err!(AccountCompressionErrorCode::InvalidQueueType)
35    } else {
36        Ok(())
37    }
38}
39impl QueueMetadata {
40    pub fn init(
41        &mut self,
42        access_metadata: AccessMetadata,
43        rollover_metadata: RolloverMetadata,
44        associated_merkle_tree: Pubkey,
45        queue_type: QueueType,
46    ) {
47        self.access_metadata = access_metadata;
48        self.rollover_metadata = rollover_metadata;
49        self.associated_merkle_tree = associated_merkle_tree;
50        self.queue_type = queue_type as u64;
51    }
52
53    pub fn rollover(
54        &mut self,
55        old_associated_merkle_tree: Pubkey,
56        next_queue: Pubkey,
57    ) -> Result<()> {
58        if self.associated_merkle_tree != old_associated_merkle_tree {
59            return err!(AccountCompressionErrorCode::MerkleTreeAndQueueNotAssociated);
60        }
61
62        self.rollover_metadata.rollover()?;
63        self.next_queue = next_queue;
64
65        Ok(())
66    }
67}
68
69#[account(zero_copy)]
70#[derive(AnchorDeserialize, Debug, PartialEq)]
71#[aligned_sized(anchor)]
72pub struct QueueAccount {
73    pub metadata: QueueMetadata,
74}
75
76impl QueueAccount {
77    pub fn init(
78        &mut self,
79        access_metadata: AccessMetadata,
80        rollover_meta_data: RolloverMetadata,
81        associated_merkle_tree: Pubkey,
82        queue_type: QueueType,
83    ) {
84        self.metadata.init(
85            access_metadata,
86            rollover_meta_data,
87            associated_merkle_tree,
88            queue_type,
89        )
90    }
91}
92
93impl GroupAccess for QueueAccount {
94    fn get_owner(&self) -> &Pubkey {
95        &self.metadata.access_metadata.owner
96    }
97
98    fn get_program_owner(&self) -> &Pubkey {
99        &self.metadata.access_metadata.program_owner
100    }
101}
102
103impl<'info> GroupAccounts<'info> for InsertIntoQueues<'info> {
104    fn get_authority(&self) -> &Signer<'info> {
105        &self.authority
106    }
107    fn get_registered_program_pda(&self) -> &Option<Account<'info, RegisteredProgram>> {
108        &self.registered_program_pda
109    }
110}
111
112impl QueueAccount {
113    pub fn size(capacity: usize) -> Result<usize> {
114        Ok(8 + mem::size_of::<Self>() + HashSet::size_in_account(capacity))
115    }
116}
117
118/// Creates a copy of `HashSet` from the given account data.
119///
120/// # Safety
121///
122/// This operation is unsafe. It's the caller's responsibility to ensure that
123/// the provided account data have correct size and alignment.
124pub unsafe fn queue_from_bytes_copy(data: &mut [u8]) -> Result<HashSet> {
125    let data = &mut data[8 + mem::size_of::<QueueAccount>()..];
126    let queue = HashSet::from_bytes_copy(data).map_err(ProgramError::from)?;
127    Ok(queue)
128}
129
130/// Casts the given account data to an `HashSetZeroCopy` instance.
131///
132/// # Safety
133///
134/// This operation is unsafe. It's the caller's responsibility to ensure that
135/// the provided account data have correct size and alignment.
136pub unsafe fn queue_from_bytes_zero_copy_mut(data: &mut [u8]) -> Result<HashSetZeroCopy> {
137    let data = &mut data[8 + mem::size_of::<QueueAccount>()..];
138    let queue = HashSetZeroCopy::from_bytes_zero_copy_mut(data).map_err(ProgramError::from)?;
139    Ok(queue)
140}
141/// Casts the given account data to an `HashSetZeroCopy` instance.
142///
143/// # Safety
144///
145/// This operation is unsafe. It's the caller's responsibility to ensure that
146/// the provided account data have correct size and alignment.
147pub unsafe fn queue_from_bytes_zero_copy_init(
148    data: &mut [u8],
149    capacity: usize,
150    sequence_threshold: usize,
151) -> Result<HashSetZeroCopy> {
152    let data = &mut data[8 + mem::size_of::<QueueAccount>()..];
153    let queue = HashSetZeroCopy::from_bytes_zero_copy_init(data, capacity, sequence_threshold)
154        .map_err(ProgramError::from)?;
155    Ok(queue)
156}