1use crate::test_env::NOOP_PROGRAM_ID;
2use account_compression::instruction::UpdateAddressMerkleTree;
3use account_compression::state::QueueAccount;
4use account_compression::utils::constants::{
5 ADDRESS_MERKLE_TREE_HEIGHT, ADDRESS_MERKLE_TREE_ROOTS,
6};
7use account_compression::{instruction::InsertAddresses, StateMerkleTreeAccount, ID};
8use account_compression::{AddressMerkleTreeAccount, SAFETY_MARGIN};
9use anchor_lang::system_program;
10use anchor_lang::{InstructionData, ToAccountMetas};
11use light_client::rpc::errors::RpcError;
12use light_client::rpc::RpcConnection;
13use light_concurrent_merkle_tree::event::MerkleTreeEvent;
14use light_hasher::Poseidon;
15use light_indexed_merkle_tree::copy::IndexedMerkleTreeCopy;
16
17use forester_utils::indexer::{AddressMerkleTreeBundle, StateMerkleTreeBundle};
18use forester_utils::{get_concurrent_merkle_tree, get_hash_set, get_indexed_merkle_tree};
19use light_registry::account_compression_cpi::sdk::{
20 create_nullify_instruction, create_update_address_merkle_tree_instruction,
21 CreateNullifyInstructionInputs, UpdateAddressMerkleTreeInstructionInputs,
22};
23use light_registry::utils::get_forester_epoch_pda_from_authority;
24use light_registry::{ForesterEpochPda, RegisterForester};
25use light_utils::bigint::bigint_to_be_bytes_array;
26use log::debug;
27use solana_sdk::signature::Signature;
28use solana_sdk::{
29 instruction::{AccountMeta, Instruction},
30 pubkey::Pubkey,
31 signature::{Keypair, Signer},
32 transaction::Transaction,
33};
34use thiserror::Error;
35pub async fn nullify_compressed_accounts<R: RpcConnection>(
51 rpc: &mut R,
52 forester: &Keypair,
53 state_tree_bundle: &mut StateMerkleTreeBundle,
54 epoch: u64,
55 is_metadata_forester: bool,
56) -> Result<(), RpcError> {
57 let nullifier_queue = unsafe {
58 get_hash_set::<QueueAccount, R>(rpc, state_tree_bundle.accounts.nullifier_queue).await
59 };
60 let pre_forester_counter = if is_metadata_forester {
61 0
62 } else {
63 rpc.get_anchor_account::<ForesterEpochPda>(
64 &get_forester_epoch_pda_from_authority(&forester.pubkey(), epoch).0,
65 )
66 .await
67 .unwrap()
68 .unwrap()
69 .work_counter
70 };
71 let onchain_merkle_tree =
72 get_concurrent_merkle_tree::<StateMerkleTreeAccount, R, Poseidon, 26>(
73 rpc,
74 state_tree_bundle.accounts.merkle_tree,
75 )
76 .await;
77 assert_eq!(
78 onchain_merkle_tree.root(),
79 state_tree_bundle.merkle_tree.root()
80 );
81 let pre_root = onchain_merkle_tree.root();
82 let change_log_index = onchain_merkle_tree.changelog_index() as u64;
83
84 let mut compressed_account_to_nullify = Vec::new();
85
86 let first = nullifier_queue.first_no_seq().unwrap();
87
88 for i in 0..nullifier_queue.get_capacity() {
89 let bucket = nullifier_queue.get_bucket(i).unwrap();
90 if let Some(bucket) = bucket {
91 if bucket.sequence_number.is_none() {
92 debug!("element to nullify: {:?}", bucket.value_bytes());
93 let leaf_index: usize = state_tree_bundle
94 .merkle_tree
95 .get_leaf_index(&bucket.value_bytes())
96 .unwrap();
97 debug!("leaf_index: {:?}", leaf_index);
98 compressed_account_to_nullify.push((i, bucket.value_bytes()));
99 }
100 }
101 }
102
103 debug!(
104 "nullifying {:?} accounts ",
105 compressed_account_to_nullify.len()
106 );
107
108 for (i, (index_in_nullifier_queue, compressed_account)) in
109 compressed_account_to_nullify.iter().enumerate()
110 {
111 let leaf_index: usize = state_tree_bundle
112 .merkle_tree
113 .get_leaf_index(compressed_account)
114 .unwrap();
115 debug!("nullifying leaf: {:?}", leaf_index);
116
117 let proof: Vec<[u8; 32]> = state_tree_bundle
118 .merkle_tree
119 .get_proof_of_leaf(leaf_index, false)
120 .unwrap()
121 .to_array::<16>()
122 .unwrap()
123 .to_vec();
124 let ix = create_nullify_instruction(
125 CreateNullifyInstructionInputs {
126 authority: forester.pubkey(),
127 nullifier_queue: state_tree_bundle.accounts.nullifier_queue,
128 merkle_tree: state_tree_bundle.accounts.merkle_tree,
129 change_log_indices: vec![change_log_index],
130 leaves_queue_indices: vec![*index_in_nullifier_queue as u16],
131 indices: vec![leaf_index as u64],
132 proofs: vec![proof],
133 derivation: forester.pubkey(),
134 is_metadata_forester,
135 },
136 epoch,
137 );
138 let instructions = [ix];
139
140 let event = rpc
141 .create_and_send_transaction_with_event::<MerkleTreeEvent>(
142 &instructions,
143 &forester.pubkey(),
144 &[forester],
145 None,
146 )
147 .await?
148 .unwrap();
149
150 match event.0 {
151 MerkleTreeEvent::V2(event) => {
152 assert_eq!(event.id, state_tree_bundle.accounts.merkle_tree.to_bytes());
153 assert_eq!(
154 event.seq,
155 onchain_merkle_tree.sequence_number() as u64 + 1 + i as u64
156 );
157 assert_eq!(event.nullified_leaves_indices.len(), 1);
158 assert_eq!(event.nullified_leaves_indices[0], leaf_index as u64);
159 }
160 _ => {
161 panic!("Wrong event type.");
162 }
163 }
164
165 assert_value_is_marked_in_queue(
166 rpc,
167 state_tree_bundle,
168 index_in_nullifier_queue,
169 compressed_account,
170 )
171 .await;
172 }
173
174 let num_nullified = compressed_account_to_nullify.len() as u64;
175 for (_, compressed_account) in compressed_account_to_nullify.iter() {
177 let leaf_index = state_tree_bundle
178 .merkle_tree
179 .get_leaf_index(compressed_account)
180 .unwrap();
181 debug!("locally nullifying leaf_index {}", leaf_index);
182 debug!("compressed_account {:?}", compressed_account);
183 debug!(
184 "merkle tree pubkey {:?}",
185 state_tree_bundle.accounts.merkle_tree
186 );
187
188 state_tree_bundle
189 .merkle_tree
190 .update(&[0u8; 32], leaf_index)
191 .unwrap();
192 }
193 let onchain_merkle_tree =
194 get_concurrent_merkle_tree::<StateMerkleTreeAccount, R, Poseidon, 26>(
195 rpc,
196 state_tree_bundle.accounts.merkle_tree,
197 )
198 .await;
199 assert_eq!(
200 onchain_merkle_tree.root(),
201 state_tree_bundle.merkle_tree.root()
202 );
203 if !is_metadata_forester {
204 assert_forester_counter(
205 rpc,
206 &get_forester_epoch_pda_from_authority(&forester.pubkey(), epoch).0,
207 pre_forester_counter,
208 num_nullified,
209 )
210 .await
211 .unwrap();
212 }
213 if first.is_some() {
215 assert_ne!(pre_root, onchain_merkle_tree.root());
216 }
217 Ok(())
218}
219
220async fn assert_value_is_marked_in_queue<'a, R: RpcConnection>(
221 rpc: &mut R,
222 state_tree_bundle: &mut StateMerkleTreeBundle,
223 index_in_nullifier_queue: &usize,
224 compressed_account: &[u8; 32],
225) {
226 let nullifier_queue = unsafe {
227 get_hash_set::<QueueAccount, R>(rpc, state_tree_bundle.accounts.nullifier_queue).await
228 };
229 let array_element = nullifier_queue
230 .get_bucket(*index_in_nullifier_queue)
231 .unwrap()
232 .unwrap();
233 assert_eq!(&array_element.value_bytes(), compressed_account);
234 let onchain_merkle_tree =
235 get_concurrent_merkle_tree::<StateMerkleTreeAccount, R, Poseidon, 26>(
236 rpc,
237 state_tree_bundle.accounts.merkle_tree,
238 )
239 .await;
240 assert_eq!(
241 array_element.sequence_number(),
242 Some(
243 onchain_merkle_tree.sequence_number()
244 + onchain_merkle_tree.roots.capacity()
245 + SAFETY_MARGIN as usize
246 )
247 );
248}
249
250pub async fn assert_forester_counter<R: RpcConnection>(
251 rpc: &mut R,
252 pubkey: &Pubkey,
253 pre: u64,
254 num_nullified: u64,
255) -> Result<(), RpcError> {
256 let account = rpc
257 .get_anchor_account::<ForesterEpochPda>(pubkey)
258 .await?
259 .unwrap();
260 if account.work_counter != pre + num_nullified {
261 debug!("account.work_counter: {}", account.work_counter);
262 debug!("pre: {}", pre);
263 debug!("num_nullified: {}", num_nullified);
264 debug!("forester pubkey: {:?}", pubkey);
265 return Err(RpcError::CustomError(
266 "ForesterEpochPda counter not updated correctly".to_string(),
267 ));
268 }
269 Ok(())
270}
271
272#[derive(Error, Debug)]
273pub enum RelayerUpdateError {
274 #[error("Error in relayer update")]
275 RpcError,
276}
277pub async fn empty_address_queue_test<R: RpcConnection>(
286 forester: &Keypair,
287 rpc: &mut R,
288 address_tree_bundle: &mut AddressMerkleTreeBundle,
289 signer_is_owner: bool,
290 epoch: u64,
291 is_metadata_forester: bool,
292) -> Result<(), RelayerUpdateError> {
293 let address_merkle_tree_pubkey = address_tree_bundle.accounts.merkle_tree;
294 let address_queue_pubkey = address_tree_bundle.accounts.queue;
295 let initial_merkle_tree_state = address_tree_bundle.merkle_tree.clone();
296 let initial_indexed_array_state = address_tree_bundle.indexed_array.clone();
297 let relayer_merkle_tree = &mut address_tree_bundle.merkle_tree;
298 let relayer_indexing_array = &mut address_tree_bundle.indexed_array;
299 let mut update_errors: Vec<RpcError> = Vec::new();
300 let address_merkle_tree =
301 get_indexed_merkle_tree::<AddressMerkleTreeAccount, R, Poseidon, usize, 26, 16>(
302 rpc,
303 address_merkle_tree_pubkey,
304 )
305 .await;
306 let indexed_changelog_index = address_merkle_tree.indexed_changelog_index() as u16;
307 let changelog_index = address_merkle_tree.changelog_index() as u16;
308 let mut counter = 0;
309 loop {
310 let pre_forester_counter = if !signer_is_owner {
311 rpc.get_anchor_account::<ForesterEpochPda>(
312 &get_forester_epoch_pda_from_authority(&forester.pubkey(), epoch).0,
313 )
314 .await
315 .map_err(|e| RelayerUpdateError::RpcError)?
316 .unwrap()
317 .work_counter
318 } else {
319 0
320 };
321 let address_merkle_tree =
322 get_indexed_merkle_tree::<AddressMerkleTreeAccount, R, Poseidon, usize, 26, 16>(
323 rpc,
324 address_merkle_tree_pubkey,
325 )
326 .await;
327 assert_eq!(relayer_merkle_tree.root(), address_merkle_tree.root());
328 let address_queue =
329 unsafe { get_hash_set::<QueueAccount, R>(rpc, address_queue_pubkey).await };
330
331 let address = address_queue.first_no_seq().unwrap();
332
333 if address.is_none() {
334 break;
335 }
336 let (address, address_hashset_index) = address.unwrap();
337 let (old_low_address, old_low_address_next_value) = initial_indexed_array_state
339 .find_low_element_for_nonexistent(&address.value_biguint())
340 .unwrap();
341 let address_bundle = initial_indexed_array_state
342 .new_element_with_low_element_index(old_low_address.index, &address.value_biguint())
343 .unwrap();
344
345 let low_address_proof = initial_merkle_tree_state
347 .get_proof_of_leaf(old_low_address.index, false)
348 .unwrap();
349
350 let old_sequence_number = address_merkle_tree.sequence_number();
351 let old_root = address_merkle_tree.root();
352 let update_successful = match update_merkle_tree(
354 rpc,
355 forester,
356 address_queue_pubkey,
357 address_merkle_tree_pubkey,
358 address_hashset_index,
359 old_low_address.index as u64,
360 bigint_to_be_bytes_array(&old_low_address.value).unwrap(),
361 old_low_address.next_index as u64,
362 bigint_to_be_bytes_array(&old_low_address_next_value).unwrap(),
363 low_address_proof.to_array().unwrap(),
364 Some(changelog_index),
365 Some(indexed_changelog_index),
366 signer_is_owner,
367 epoch,
368 is_metadata_forester,
369 )
370 .await
371 {
372 Ok(event) => {
373 let event = event.unwrap();
374 match event.0 {
375 MerkleTreeEvent::V3(event) => {
376 if counter == 0 {
379 assert_eq!(event.id, address_merkle_tree_pubkey.to_bytes());
380 assert_eq!(event.seq, old_sequence_number as u64 + 1);
381 assert_eq!(event.updates.len(), 1);
382 let event = &event.updates[0];
383 assert_eq!(
384 event.new_low_element.index, address_bundle.new_low_element.index,
385 "Empty Address Queue Test: invalid new_low_element.index"
386 );
387 assert_eq!(
388 event.new_low_element.next_index,
389 address_bundle.new_low_element.next_index,
390 "Empty Address Queue Test: invalid new_low_element.next_index"
391 );
392 assert_eq!(
393 event.new_low_element.value,
394 bigint_to_be_bytes_array::<32>(
395 &address_bundle.new_low_element.value
396 )
397 .unwrap(),
398 "Empty Address Queue Test: invalid new_low_element.value"
399 );
400 assert_eq!(
401 event.new_low_element.next_value,
402 bigint_to_be_bytes_array::<32>(&address_bundle.new_element.value)
403 .unwrap(),
404 "Empty Address Queue Test: invalid new_low_element.next_value"
405 );
406 let leaf_hash = address_bundle
407 .new_low_element
408 .hash::<Poseidon>(&address_bundle.new_element.value)
409 .unwrap();
410 assert_eq!(
411 event.new_low_element_hash, leaf_hash,
412 "Empty Address Queue Test: invalid new_low_element_hash"
413 );
414 let leaf_hash = address_bundle
415 .new_element
416 .hash::<Poseidon>(&address_bundle.new_element_next_value)
417 .unwrap();
418 assert_eq!(
419 event.new_high_element_hash, leaf_hash,
420 "Empty Address Queue Test: invalid new_high_element_hash"
421 );
422 assert_eq!(
423 event.new_high_element.index, address_bundle.new_element.index,
424 "Empty Address Queue Test: invalid new_high_element.index"
425 );
426 assert_eq!(
427 event.new_high_element.next_index,
428 address_bundle.new_element.next_index,
429 "Empty Address Queue Test: invalid new_high_element.next_index"
430 );
431 assert_eq!(
432 event.new_high_element.value,
433 bigint_to_be_bytes_array::<32>(&address_bundle.new_element.value)
434 .unwrap(),
435 "Empty Address Queue Test: invalid new_high_element.value"
436 );
437 assert_eq!(
438 event.new_high_element.next_value,
439 bigint_to_be_bytes_array::<32>(
440 &address_bundle.new_element_next_value
441 )
442 .unwrap(),
443 "Empty Address Queue Test: invalid new_high_element.next_value"
444 );
445 }
446 }
447 _ => {
448 panic!("Wrong event type.");
449 }
450 }
451 counter += 1;
452 true
453 }
454 Err(e) => {
455 update_errors.push(e);
456 break;
457 }
458 };
459
460 if update_successful {
461 if !signer_is_owner {
462 assert_forester_counter(
463 rpc,
464 &get_forester_epoch_pda_from_authority(&forester.pubkey(), epoch).0,
465 pre_forester_counter,
466 1,
467 )
468 .await
469 .unwrap();
470 }
471 let merkle_tree =
472 get_indexed_merkle_tree::<AddressMerkleTreeAccount, R, Poseidon, usize, 26, 16>(
473 rpc,
474 address_merkle_tree_pubkey,
475 )
476 .await;
477
478 let (old_low_address, _) = relayer_indexing_array
479 .find_low_element_for_nonexistent(&address.value_biguint())
480 .unwrap();
481 let address_bundle = relayer_indexing_array
482 .new_element_with_low_element_index(old_low_address.index, &address.value_biguint())
483 .unwrap();
484 let address_queue =
485 unsafe { get_hash_set::<QueueAccount, R>(rpc, address_queue_pubkey).await };
486
487 assert_eq!(
488 address_queue
489 .get_bucket(address_hashset_index as usize)
490 .unwrap()
491 .unwrap()
492 .sequence_number()
493 .unwrap(),
494 old_sequence_number + address_queue.sequence_threshold + 2 );
496
497 relayer_merkle_tree
498 .update(
499 &address_bundle.new_low_element,
500 &address_bundle.new_element,
501 &address_bundle.new_element_next_value,
502 )
503 .unwrap();
504 relayer_indexing_array
505 .append_with_low_element_index(
506 address_bundle.new_low_element.index,
507 &address_bundle.new_element.value,
508 )
509 .unwrap();
510 assert_eq!(merkle_tree.sequence_number(), old_sequence_number + 2);
511 assert_ne!(old_root, merkle_tree.root(), "Root did not change.");
512 assert_eq!(
513 relayer_merkle_tree.root(),
514 merkle_tree.root(),
515 "Root off-chain onchain inconsistent."
516 );
517
518 let changelog_entry = merkle_tree
519 .changelog
520 .get(merkle_tree.changelog_index())
521 .unwrap();
522 let path = relayer_merkle_tree
523 .get_path_of_leaf(merkle_tree.current_index(), true)
524 .unwrap();
525 for i in 0..ADDRESS_MERKLE_TREE_HEIGHT as usize {
526 let changelog_node = changelog_entry.path[i].unwrap();
527 let path_node = path[i];
528 assert_eq!(changelog_node, path_node);
529 }
530
531 let indexed_changelog_entry = merkle_tree
532 .indexed_changelog
533 .get(merkle_tree.indexed_changelog_index())
534 .unwrap();
535 let proof = relayer_merkle_tree
536 .get_proof_of_leaf(merkle_tree.current_index(), false)
537 .unwrap();
538 assert_eq!(
539 address_bundle.new_element,
540 indexed_changelog_entry.element.into(),
541 );
542 assert_eq!(indexed_changelog_entry.proof.as_slice(), proof.as_slice());
543 assert_eq!(
544 indexed_changelog_entry.changelog_index,
545 merkle_tree.changelog_index()
546 );
547 }
548 }
549
550 if update_errors.is_empty() {
551 Ok(())
552 } else {
553 panic!("Errors: {:?}", update_errors);
554 }
555}
556
557#[allow(clippy::too_many_arguments)]
558pub async fn update_merkle_tree<R: RpcConnection>(
559 rpc: &mut R,
560 forester: &Keypair,
561 address_queue_pubkey: Pubkey,
562 address_merkle_tree_pubkey: Pubkey,
563 value: u16,
564 low_address_index: u64,
565 low_address_value: [u8; 32],
566 low_address_next_index: u64,
567 low_address_next_value: [u8; 32],
568 low_address_proof: [[u8; 32]; 16],
569 changelog_index: Option<u16>,
570 indexed_changelog_index: Option<u16>,
571 signer_is_owner: bool,
572 epoch: u64,
573 is_metadata_forester: bool,
574) -> Result<Option<(MerkleTreeEvent, Signature, u64)>, RpcError> {
575 let changelog_index = match changelog_index {
576 Some(changelog_index) => changelog_index,
577 None => {
578 let address_merkle_tree =
579 get_indexed_merkle_tree::<AddressMerkleTreeAccount, R, Poseidon, usize, 26, 16>(
580 rpc,
581 address_merkle_tree_pubkey,
582 )
583 .await;
584
585 address_merkle_tree.changelog_index() as u16
586 }
587 };
588 let indexed_changelog_index = match indexed_changelog_index {
589 Some(indexed_changelog_index) => indexed_changelog_index,
590 None => {
591 let address_merkle_tree =
592 get_indexed_merkle_tree::<AddressMerkleTreeAccount, R, Poseidon, usize, 26, 16>(
593 rpc,
594 address_merkle_tree_pubkey,
595 )
596 .await;
597
598 address_merkle_tree.indexed_changelog_index() as u16
599 }
600 };
601 let update_ix = if !signer_is_owner {
602 create_update_address_merkle_tree_instruction(
603 UpdateAddressMerkleTreeInstructionInputs {
604 authority: forester.pubkey(),
605 address_merkle_tree: address_merkle_tree_pubkey,
606 address_queue: address_queue_pubkey,
607 changelog_index,
608 indexed_changelog_index,
609 value,
610 low_address_index,
611 low_address_value,
612 low_address_next_index,
613 low_address_next_value,
614 low_address_proof,
615 is_metadata_forester,
616 },
617 epoch,
618 )
619 } else {
620 let instruction_data = UpdateAddressMerkleTree {
621 changelog_index,
622 indexed_changelog_index,
623 value,
624 low_address_index,
625 low_address_value,
626 low_address_next_index,
627 low_address_next_value,
628 low_address_proof,
629 };
630 Instruction {
631 program_id: ID,
632 accounts: vec![
633 AccountMeta::new(forester.pubkey(), true),
634 AccountMeta::new(ID, false),
635 AccountMeta::new(address_queue_pubkey, false),
636 AccountMeta::new(address_merkle_tree_pubkey, false),
637 AccountMeta::new(NOOP_PROGRAM_ID, false),
638 ],
639 data: instruction_data.data(),
640 }
641 };
642
643 rpc.create_and_send_transaction_with_event::<MerkleTreeEvent>(
644 &[update_ix],
645 &forester.pubkey(),
646 &[forester],
647 None,
648 )
649 .await
650}
651
652pub async fn insert_addresses<R: RpcConnection>(
653 context: &mut R,
654 address_queue_pubkey: Pubkey,
655 address_merkle_tree_pubkey: Pubkey,
656 addresses: Vec<[u8; 32]>,
657) -> Result<Signature, RpcError> {
658 let num_addresses = addresses.len();
659 let instruction_data = InsertAddresses { addresses };
660 let accounts = account_compression::accounts::InsertIntoQueues {
661 fee_payer: context.get_payer().pubkey(),
662 authority: context.get_payer().pubkey(),
663 registered_program_pda: None,
664 system_program: system_program::ID,
665 };
666 let insert_ix = Instruction {
667 program_id: ID,
668 accounts: [
669 accounts.to_account_metas(Some(true)),
670 vec![
671 vec![
672 AccountMeta::new(address_queue_pubkey, false),
673 AccountMeta::new(address_merkle_tree_pubkey, false)
674 ];
675 num_addresses
676 ]
677 .iter()
678 .flat_map(|x| x.to_vec())
679 .collect::<Vec<AccountMeta>>(),
680 ]
681 .concat(),
682 data: instruction_data.data(),
683 };
684 let latest_blockhash = context.get_latest_blockhash().await.unwrap();
685 let transaction = Transaction::new_signed_with_payer(
686 &[insert_ix],
687 Some(&context.get_payer().pubkey()),
688 &[&context.get_payer()],
689 latest_blockhash,
690 );
691 context.process_transaction(transaction).await
692}