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 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}