Skip to main content

light_compressed_account/instruction_data/
insert_into_queues.rs

1use core::{
2    mem::size_of,
3    ops::{Deref, DerefMut},
4};
5
6use light_zero_copy::{
7    errors::ZeroCopyError, slice::ZeroCopySlice, slice_mut::ZeroCopySliceMut, traits::ZeroCopyAt,
8};
9use zerocopy::{
10    little_endian::{U32, U64},
11    FromBytes, Immutable, IntoBytes, KnownLayout, Ref, Unaligned,
12};
13
14use crate::{
15    discriminators::DISCRIMINATOR_INSERT_INTO_QUEUES, pubkey::Pubkey, InstructionDiscriminator,
16    TreeType,
17};
18
19#[repr(C)]
20#[derive(
21    KnownLayout, IntoBytes, Immutable, Copy, Clone, FromBytes, PartialEq, Debug, Unaligned,
22)]
23pub struct InsertNullifierInput {
24    pub account_hash: [u8; 32],
25    pub leaf_index: U32,
26    pub prove_by_index: u8,
27    pub tree_index: u8,
28    pub queue_index: u8,
29}
30
31impl InsertNullifierInput {
32    pub fn prove_by_index(&self) -> bool {
33        self.prove_by_index == 1
34    }
35}
36
37#[repr(C)]
38#[derive(
39    KnownLayout, IntoBytes, Immutable, Copy, Clone, FromBytes, PartialEq, Debug, Unaligned,
40)]
41pub struct AppendLeavesInput {
42    pub account_index: u8,
43    pub leaf: [u8; 32],
44}
45#[repr(C)]
46#[derive(
47    KnownLayout, IntoBytes, Immutable, Copy, Clone, FromBytes, PartialEq, Debug, Unaligned,
48)]
49pub struct InsertAddressInput {
50    pub address: [u8; 32],
51    pub tree_index: u8,
52    pub queue_index: u8,
53}
54
55#[repr(C)]
56#[derive(
57    FromBytes, IntoBytes, KnownLayout, Immutable, Copy, Clone, PartialEq, Debug, Unaligned,
58)]
59pub struct MerkleTreeSequenceNumber {
60    pub tree_pubkey: Pubkey,
61    pub queue_pubkey: Pubkey,
62    pub tree_type: U64,
63    /// For output queues the sequence number is the first leaf index.
64    pub seq: U64,
65}
66
67#[derive(Debug, Clone, PartialEq)]
68pub struct InsertIntoQueuesInstructionData<'a> {
69    meta: Ref<&'a [u8], InsertIntoQueuesInstructionDataMeta>,
70    pub leaves: ZeroCopySlice<'a, u8, AppendLeavesInput, false>,
71    pub nullifiers: ZeroCopySlice<'a, u8, InsertNullifierInput, false>,
72    pub addresses: ZeroCopySlice<'a, u8, InsertAddressInput, false>,
73    pub output_sequence_numbers: ZeroCopySlice<'a, u8, MerkleTreeSequenceNumber, false>,
74    pub input_sequence_numbers: ZeroCopySlice<'a, u8, MerkleTreeSequenceNumber, false>,
75    pub address_sequence_numbers: ZeroCopySlice<'a, u8, MerkleTreeSequenceNumber, false>,
76    pub output_leaf_indices: ZeroCopySlice<'a, u8, U32, false>,
77}
78
79impl InsertIntoQueuesInstructionData<'_> {
80    pub fn is_invoked_by_program(&self) -> bool {
81        self.meta.is_invoked_by_program == 1
82    }
83}
84
85impl Deref for InsertIntoQueuesInstructionData<'_> {
86    type Target = InsertIntoQueuesInstructionDataMeta;
87
88    fn deref(&self) -> &Self::Target {
89        &self.meta
90    }
91}
92
93impl InstructionDiscriminator for InsertIntoQueuesInstructionData<'_> {
94    fn discriminator(&self) -> &'static [u8] {
95        &DISCRIMINATOR_INSERT_INTO_QUEUES
96    }
97}
98
99impl<'a> ZeroCopyAt<'a> for InsertIntoQueuesInstructionData<'a> {
100    type ZeroCopyAt = Self;
101    fn zero_copy_at(bytes: &'a [u8]) -> core::result::Result<(Self, &'a [u8]), ZeroCopyError> {
102        let (meta, bytes) = Ref::<&[u8], InsertIntoQueuesInstructionDataMeta>::from_prefix(bytes)?;
103
104        let (leaves, bytes) = ZeroCopySlice::<u8, AppendLeavesInput, false>::from_bytes_at(bytes)?;
105
106        let (nullifiers, bytes) =
107            ZeroCopySlice::<u8, InsertNullifierInput, false>::from_bytes_at(bytes)?;
108
109        let (addresses, bytes) =
110            ZeroCopySlice::<u8, InsertAddressInput, false>::from_bytes_at(bytes)?;
111        let (output_sequence_numbers, bytes) =
112            ZeroCopySlice::<u8, MerkleTreeSequenceNumber, false>::from_bytes_at(bytes)?;
113        let (input_sequence_numbers, bytes) =
114            ZeroCopySlice::<u8, MerkleTreeSequenceNumber, false>::from_bytes_at(bytes)?;
115        let (address_sequence_numbers, bytes) =
116            ZeroCopySlice::<u8, MerkleTreeSequenceNumber, false>::from_bytes_at(bytes)?;
117        let (output_leaf_indices, bytes) =
118            ZeroCopySlice::<u8, zerocopy::little_endian::U32, false>::from_bytes_at(bytes)?;
119        Ok((
120            InsertIntoQueuesInstructionData {
121                meta,
122                leaves,
123                nullifiers,
124                addresses,
125                output_sequence_numbers,
126                input_sequence_numbers,
127                address_sequence_numbers,
128                output_leaf_indices,
129            },
130            bytes,
131        ))
132    }
133}
134
135#[repr(C)]
136#[derive(
137    FromBytes, IntoBytes, KnownLayout, Immutable, Copy, Clone, PartialEq, Debug, Unaligned,
138)]
139pub struct InsertIntoQueuesInstructionDataMeta {
140    is_invoked_by_program: u8,
141    pub bump: u8,
142    pub num_queues: u8,
143    pub num_output_queues: u8,
144    pub start_output_appends: u8,
145    pub num_address_queues: u8,
146    pub tx_hash: [u8; 32],
147}
148
149#[derive(Debug)]
150pub struct InsertIntoQueuesInstructionDataMut<'a> {
151    meta: Ref<&'a mut [u8], InsertIntoQueuesInstructionDataMeta>,
152    pub leaves: ZeroCopySliceMut<'a, u8, AppendLeavesInput, false>,
153    pub nullifiers: ZeroCopySliceMut<'a, u8, InsertNullifierInput, false>,
154    pub addresses: ZeroCopySliceMut<'a, u8, InsertAddressInput, false>,
155    pub output_sequence_numbers: ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
156    pub input_sequence_numbers: ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
157    pub address_sequence_numbers: ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
158    pub output_leaf_indices: ZeroCopySliceMut<'a, u8, U32, false>,
159}
160
161impl<'a> InsertIntoQueuesInstructionDataMut<'a> {
162    pub fn is_invoked_by_program(&self) -> bool {
163        self.meta.is_invoked_by_program == 1
164    }
165
166    pub fn set_invoked_by_program(&mut self, value: bool) {
167        self.meta.is_invoked_by_program = value as u8;
168    }
169
170    pub fn insert_input_sequence_number(
171        &mut self,
172        index: &mut usize,
173        tree_pubkey: &Pubkey,
174        queue_pubkey: &Pubkey,
175        tree_type: u64,
176        seq: u64,
177    ) {
178        Self::insert_sequence_number(
179            &mut self.input_sequence_numbers,
180            index,
181            tree_pubkey,
182            Some(queue_pubkey),
183            tree_type,
184            seq,
185        );
186    }
187
188    pub fn insert_address_sequence_number(
189        &mut self,
190        index: &mut usize,
191        tree_pubkey: &Pubkey,
192        seq: u64,
193    ) {
194        Self::insert_sequence_number(
195            &mut self.address_sequence_numbers,
196            index,
197            tree_pubkey,
198            None,
199            TreeType::AddressV2 as u64,
200            seq,
201        );
202    }
203
204    fn insert_sequence_number(
205        sequence_numbers: &mut ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
206        index: &mut usize,
207        tree_pubkey: &Pubkey,
208        queue_pubkey: Option<&Pubkey>,
209        tree_type: u64,
210        seq: u64,
211    ) {
212        let pos = sequence_numbers
213            .iter()
214            .position(|x| x.tree_pubkey == *tree_pubkey);
215        if pos.is_none() {
216            sequence_numbers[*index].tree_pubkey = *tree_pubkey;
217            if let Some(queue_pubkey) = queue_pubkey {
218                sequence_numbers[*index].queue_pubkey = *queue_pubkey;
219            }
220            sequence_numbers[*index].tree_type = tree_type.into();
221            sequence_numbers[*index].seq = seq.into();
222            *index += 1;
223        }
224    }
225
226    pub fn required_size_for_capacity(
227        leaves_capacity: u8,
228        nullifiers_capacity: u8,
229        addresses_capacity: u8,
230        num_output_trees: u8,
231        num_input_trees: u8,
232        num_address_trees: u8,
233    ) -> usize {
234        size_of::<InsertIntoQueuesInstructionDataMeta>()
235            + ZeroCopySliceMut::<u8, AppendLeavesInput, false>::required_size_for_capacity(
236                leaves_capacity,
237            )
238            + ZeroCopySliceMut::<u8, InsertNullifierInput, false>::required_size_for_capacity(
239                nullifiers_capacity,
240            )
241            + ZeroCopySliceMut::<u8, InsertAddressInput, false>::required_size_for_capacity(
242                addresses_capacity,
243            )
244            + ZeroCopySliceMut::<u8, MerkleTreeSequenceNumber, false>::required_size_for_capacity(
245                num_output_trees,
246            )
247            + ZeroCopySliceMut::<u8, MerkleTreeSequenceNumber, false>::required_size_for_capacity(
248                num_input_trees,
249            )
250            + ZeroCopySliceMut::<u8, MerkleTreeSequenceNumber, false>::required_size_for_capacity(
251                num_address_trees,
252            )
253            + ZeroCopySliceMut::<u8, U32, false>::required_size_for_capacity(leaves_capacity)
254    }
255
256    pub fn new_at(
257        bytes: &'a mut [u8],
258        leaves_capacity: u8,
259        nullifiers_capacity: u8,
260        addresses_capacity: u8,
261        num_output_trees: u8,
262        num_input_trees: u8,
263        num_address_trees: u8,
264    ) -> core::result::Result<(Self, &'a mut [u8]), ZeroCopyError> {
265        let (meta, bytes) =
266            Ref::<&mut [u8], InsertIntoQueuesInstructionDataMeta>::from_prefix(bytes)?;
267        let (leaves, bytes) =
268            ZeroCopySliceMut::<u8, AppendLeavesInput, false>::new_at(leaves_capacity, bytes)?;
269        let (nullifiers, bytes) = ZeroCopySliceMut::<u8, InsertNullifierInput, false>::new_at(
270            nullifiers_capacity,
271            bytes,
272        )?;
273        let (addresses, bytes) =
274            ZeroCopySliceMut::<u8, InsertAddressInput, false>::new_at(addresses_capacity, bytes)?;
275        let (output_sequence_numbers, bytes) = ZeroCopySliceMut::<
276            u8,
277            MerkleTreeSequenceNumber,
278            false,
279        >::new_at(num_output_trees, bytes)?;
280        let (input_sequence_numbers, bytes) = ZeroCopySliceMut::<
281            u8,
282            MerkleTreeSequenceNumber,
283            false,
284        >::new_at(num_input_trees, bytes)?;
285        let (address_sequence_numbers, bytes) = ZeroCopySliceMut::<
286            u8,
287            MerkleTreeSequenceNumber,
288            false,
289        >::new_at(num_address_trees, bytes)?;
290        let (output_leaf_indices, bytes) =
291            ZeroCopySliceMut::<u8, U32, false>::new_at(leaves_capacity, bytes)?;
292        Ok((
293            InsertIntoQueuesInstructionDataMut {
294                meta,
295                leaves,
296                nullifiers,
297                addresses,
298                output_sequence_numbers,
299                input_sequence_numbers,
300                address_sequence_numbers,
301                output_leaf_indices,
302            },
303            bytes,
304        ))
305    }
306}
307
308impl Deref for InsertIntoQueuesInstructionDataMut<'_> {
309    type Target = InsertIntoQueuesInstructionDataMeta;
310
311    fn deref(&self) -> &Self::Target {
312        &self.meta
313    }
314}
315
316impl DerefMut for InsertIntoQueuesInstructionDataMut<'_> {
317    fn deref_mut(&mut self) -> &mut Self::Target {
318        &mut self.meta
319    }
320}
321
322#[cfg(all(test, feature = "std"))]
323mod test {
324
325    use super::*;
326    #[test]
327    fn test_ix_data() {
328        {
329            let leaves_capacity: u8 = 20;
330            let nullifiers_capacity: u8 = 20;
331            let addresses_capacity: u8 = 0;
332            let num_output_trees: u8 = 10;
333            let num_input_trees: u8 = 10;
334            let num_address_trees: u8 = 0;
335            let size = InsertIntoQueuesInstructionDataMut::required_size_for_capacity(
336                leaves_capacity,
337                nullifiers_capacity,
338                addresses_capacity,
339                num_output_trees,
340                num_input_trees,
341                num_address_trees,
342            );
343            println!("size update 20 pdas {}", size);
344            assert_eq!(size, 3165, "size update 20 pdas");
345        }
346        {
347            let leaves_capacity: u8 = 20;
348            let nullifiers_capacity: u8 = 0;
349            let addresses_capacity: u8 = 20;
350            let num_output_trees: u8 = 10;
351            let num_input_trees: u8 = 0;
352            let num_address_trees: u8 = 1;
353            let size = InsertIntoQueuesInstructionDataMut::required_size_for_capacity(
354                leaves_capacity,
355                nullifiers_capacity,
356                addresses_capacity,
357                num_output_trees,
358                num_input_trees,
359                num_address_trees,
360            );
361            println!("size create 20 pdas {}", size);
362            assert_eq!(size, 2345, "size create 20 pdas");
363        }
364        {
365            let leaves_capacity: u8 = 30;
366            let nullifiers_capacity: u8 = 0;
367            let addresses_capacity: u8 = 0;
368            let num_output_trees: u8 = 10;
369            let num_input_trees: u8 = 0;
370            let num_address_trees: u8 = 0;
371            let size = InsertIntoQueuesInstructionDataMut::required_size_for_capacity(
372                leaves_capacity,
373                nullifiers_capacity,
374                addresses_capacity,
375                num_output_trees,
376                num_input_trees,
377                num_address_trees,
378            );
379            println!("size create 30 ctokens {}", size);
380            assert_eq!(size, 1955, "size create 30 ctokens");
381        }
382    }
383
384    #[test]
385    fn test_rnd_insert_into_queues_ix_data() {
386        use rand::{rngs::StdRng, thread_rng, Rng, SeedableRng};
387        let seed = thread_rng().gen();
388        println!("seed {}", seed);
389        let mut rng = StdRng::seed_from_u64(seed);
390        let num_iters = 1000;
391
392        for _ in 0..num_iters {
393            let leaves_capacity: u8 = rng.gen();
394            let nullifiers_capacity: u8 = rng.gen();
395            let addresses_capacity: u8 = rng.gen();
396            let num_output_trees: u8 = rng.gen();
397            let num_input_trees: u8 = rng.gen();
398            let num_address_trees: u8 = rng.gen();
399            let size = InsertIntoQueuesInstructionDataMut::required_size_for_capacity(
400                leaves_capacity,
401                nullifiers_capacity,
402                addresses_capacity,
403                num_output_trees,
404                num_input_trees,
405                num_address_trees,
406            );
407            let mut bytes = vec![0u8; size];
408            let (mut new_data, _) = InsertIntoQueuesInstructionDataMut::new_at(
409                &mut bytes,
410                leaves_capacity,
411                nullifiers_capacity,
412                addresses_capacity,
413                num_output_trees,
414                num_input_trees,
415                num_address_trees,
416            )
417            .unwrap();
418            *new_data.meta = InsertIntoQueuesInstructionDataMeta {
419                is_invoked_by_program: rng.gen(),
420                bump: rng.gen(),
421                num_queues: rng.gen(),
422                num_output_queues: rng.gen(),
423                start_output_appends: rng.gen(),
424                num_address_queues: rng.gen(),
425                tx_hash: rng.gen(),
426            };
427            for i in 0..leaves_capacity {
428                new_data.leaves[i as usize] = AppendLeavesInput {
429                    account_index: rng.gen(),
430                    leaf: rng.gen(),
431                };
432            }
433            for i in 0..nullifiers_capacity {
434                new_data.nullifiers[i as usize] = InsertNullifierInput {
435                    account_hash: rng.gen(),
436                    leaf_index: rng.gen::<u32>().into(),
437                    prove_by_index: rng.gen(),
438                    tree_index: rng.gen(),
439                    queue_index: rng.gen(),
440                };
441            }
442            for i in 0..addresses_capacity {
443                new_data.addresses[i as usize] = InsertAddressInput {
444                    address: rng.gen(),
445                    tree_index: rng.gen(),
446                    queue_index: rng.gen(),
447                };
448            }
449            let nullifiers = new_data.nullifiers.to_vec();
450            let leaves = new_data.leaves.to_vec();
451            let addresses = new_data.addresses.to_vec();
452            let meta = *new_data.meta;
453            let zero_copy = InsertIntoQueuesInstructionData::zero_copy_at(&bytes)
454                .unwrap()
455                .0;
456            assert_eq!(meta, *zero_copy.meta);
457            assert_eq!(leaves.as_slice(), zero_copy.leaves.as_slice());
458            assert_eq!(nullifiers.as_slice(), zero_copy.nullifiers.as_slice());
459            assert_eq!(addresses.as_slice(), zero_copy.addresses.as_slice());
460        }
461    }
462}