diff --git a/.github/workflows/light-system-programs-tests.yml b/.github/workflows/light-system-programs-tests.yml index 0e75fe6924..cd82d721da 100644 --- a/.github/workflows/light-system-programs-tests.yml +++ b/.github/workflows/light-system-programs-tests.yml @@ -8,6 +8,7 @@ on: - "circuit-lib/verifier/**" - "merkle-tree/**" - ".github/workflows/light-system-programs-tests.yml" + - "test-utils/**" pull_request: branches: - "*" @@ -17,6 +18,7 @@ on: - "circuit-lib/verifier/**" - "merkle-tree/**" - ".github/workflows/light-system-programs-tests.yml" + - "test-utils/**" types: - opened - synchronize diff --git a/test-programs/system-cpi-test/tests/test_program_owned_trees.rs b/test-programs/system-cpi-test/tests/test_program_owned_trees.rs index e499606354..810878cba0 100644 --- a/test-programs/system-cpi-test/tests/test_program_owned_trees.rs +++ b/test-programs/system-cpi-test/tests/test_program_owned_trees.rs @@ -7,8 +7,8 @@ use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, transaction use account_compression::sdk::create_insert_leaves_instruction; use account_compression::utils::constants::{CPI_AUTHORITY_PDA_SEED, STATE_NULLIFIER_QUEUE_VALUES}; use account_compression::{ - AddressMerkleTreeConfig, AddressQueueConfig, QueueAccount, StateMerkleTreeAccount, - StateMerkleTreeConfig, + AddressMerkleTreeConfig, AddressQueueConfig, NullifierQueueConfig, QueueAccount, + StateMerkleTreeAccount, StateMerkleTreeConfig, }; use light_compressed_token::mint_sdk::create_mint_to_instruction; use light_hasher::Poseidon; @@ -198,7 +198,8 @@ async fn test_invalid_registered_program() { &invalid_group_nullifier_queue, None, 3, - StateMerkleTreeConfig::default(), + &StateMerkleTreeConfig::default(), + &NullifierQueueConfig::default(), ) .await; let invalid_group_address_merkle_tree = Keypair::new(); diff --git a/test-utils/src/e2e_test_env.rs b/test-utils/src/e2e_test_env.rs index 2cae45a5fb..52760b337a 100644 --- a/test-utils/src/e2e_test_env.rs +++ b/test-utils/src/e2e_test_env.rs @@ -69,6 +69,7 @@ // refactor all tests to work with that so that we can run all tests with a test validator and concurrency use light_indexed_merkle_tree::HIGHEST_ADDRESS_PLUS_ONE; +use light_utils::rand::gen_prime; use solana_sdk::signature::Signature; use spl_token::solana_program::native_token::LAMPORTS_PER_SOL; @@ -101,6 +102,7 @@ use light_indexed_merkle_tree::{array::IndexedArray, reference::IndexedMerkleTre use account_compression::{ AddressMerkleTreeConfig, AddressQueueConfig, NullifierQueueConfig, StateMerkleTreeConfig, + SAFETY_MARGIN, }; use light_system_program::sdk::compressed_account::CompressedAccountWithMerkleContext; use light_utils::bigint::bigint_to_be_bytes_array; @@ -348,7 +350,7 @@ where } else { None }; - let config = if !self.keypair_action_config.fee_assert { + let merkle_tree_config = if !self.keypair_action_config.fee_assert { StateMerkleTreeConfig { height: 26, changelog_size: self.rng.gen_range(1..5000), @@ -361,7 +363,18 @@ where } else { StateMerkleTreeConfig::default() }; - println!("config: {:?}", config); + println!("merkle tree config: {:?}", merkle_tree_config); + let queue_config = if !self.keypair_action_config.fee_assert { + let capacity: f64 = gen_prime(&mut self.rng, 1.0..10000.0).unwrap(); + NullifierQueueConfig { + capacity: capacity as u16, + sequence_threshold: merkle_tree_config.roots_size + SAFETY_MARGIN, + network_fee: None, + } + } else { + NullifierQueueConfig::default() + }; + println!("queue config: {:?}", queue_config); create_state_merkle_tree_and_queue_account( &self.payer, &self.indexer.group_pda, @@ -370,7 +383,8 @@ where &nullifier_queue_keypair, None, 1, - config, + &merkle_tree_config, + &queue_config, ) .await; let merkle_tree = Box::new(light_merkle_tree_reference::MerkleTree::::new( diff --git a/test-utils/src/indexer/test_indexer.rs b/test-utils/src/indexer/test_indexer.rs index 2599ab4946..0dd6bd00ba 100644 --- a/test-utils/src/indexer/test_indexer.rs +++ b/test-utils/src/indexer/test_indexer.rs @@ -4,7 +4,9 @@ use solana_sdk::bs58; use std::marker::PhantomData; use std::sync::{Arc, Mutex}; -use account_compression::{AddressMerkleTreeConfig, AddressQueueConfig, StateMerkleTreeConfig}; +use account_compression::{ + AddressMerkleTreeConfig, AddressQueueConfig, NullifierQueueConfig, StateMerkleTreeConfig, +}; use light_compressed_token::constants::TOKEN_COMPRESSED_ACCOUNT_DISCRIMINATOR; use light_compressed_token::mint_sdk::create_create_token_pool_instruction; use light_compressed_token::{get_token_pool_pda, TokenData}; @@ -519,7 +521,8 @@ impl TestIndexer( nullifier_queue_keypair: &Keypair, program_owner: Option, index: u64, - config: StateMerkleTreeConfig, + merkle_tree_config: &StateMerkleTreeConfig, + queue_config: &NullifierQueueConfig, ) { let size = account_compression::state::StateMerkleTreeAccount::size( - config.height as usize, - config.changelog_size as usize, - config.roots_size as usize, - config.canopy_depth as usize, + merkle_tree_config.height as usize, + merkle_tree_config.changelog_size as usize, + merkle_tree_config.roots_size as usize, + merkle_tree_config.canopy_depth as usize, ); let merkle_tree_account_create_ix = create_account_instruction( @@ -375,10 +377,9 @@ pub async fn create_state_merkle_tree_and_queue_account( &account_compression::ID, Some(merkle_tree_keypair), ); - let size = account_compression::state::queue::QueueAccount::size( - account_compression::utils::constants::STATE_NULLIFIER_QUEUE_VALUES as usize, - ) - .unwrap(); + let size = + account_compression::state::queue::QueueAccount::size(queue_config.capacity as usize) + .unwrap(); let nullifier_queue_account_create_ix = create_account_instruction( &payer.pubkey(), size, @@ -394,8 +395,8 @@ pub async fn create_state_merkle_tree_and_queue_account( *owner, merkle_tree_keypair.pubkey(), nullifier_queue_keypair.pubkey(), - config, - NullifierQueueConfig::default(), + merkle_tree_config.clone(), + queue_config.clone(), program_owner, index, 0, // TODO: replace with CPI_CONTEXT_ACCOUNT_RENT once enabled diff --git a/test-utils/src/test_forester.rs b/test-utils/src/test_forester.rs index cd5d6d47ae..1e56e5e7a7 100644 --- a/test-utils/src/test_forester.rs +++ b/test-utils/src/test_forester.rs @@ -216,7 +216,7 @@ async fn assert_value_is_marked_in_queue<'a, R: RpcConnection>( array_element.sequence_number(), Some( onchain_merkle_tree.sequence_number() - + account_compression::utils::constants::STATE_MERKLE_TREE_ROOTS as usize + + onchain_merkle_tree.roots.capacity() as usize + SAFETY_MARGIN as usize ) ); diff --git a/utils/src/rand.rs b/utils/src/rand.rs index 66572b8a4c..729d756010 100644 --- a/utils/src/rand.rs +++ b/utils/src/rand.rs @@ -1,8 +1,46 @@ +use std::ops::{Bound, RangeBounds}; + use rand::{ distributions::uniform::{SampleRange, SampleUniform}, Rng, }; +use crate::prime::find_next_prime; + +const PRIME_RETRIES: usize = 10; + +/// Generates a random prime number in the given range. It returns `None` when +/// generating such number was not possible. +pub fn gen_prime(rng: &mut N, range: R) -> Option +where + N: Rng, + R: Clone + RangeBounds + SampleRange, + T: Into + From + Copy + PartialOrd + SampleUniform, +{ + for _ in 0..PRIME_RETRIES { + let sample: T = rng.gen_range(range.clone()); + let next_prime = find_next_prime(sample.into()); + + match range.end_bound() { + Bound::Included(end) => { + if next_prime > (*end).into() { + continue; + } + } + Bound::Excluded(end) => { + if next_prime >= (*end).into() { + continue; + } + } + _ => {} + }; + + return Some(T::from(next_prime)); + } + + None +} + /// Generates a random value in the given range, excluding the values provided /// in `exclude`. pub fn gen_range_exclude(rng: &mut N, range: R, exclude: &[T]) -> T @@ -26,8 +64,27 @@ where mod test { use rand::Rng; + use crate::prime::is_prime; + use super::*; + #[test] + fn test_gen_prime() { + let mut rng = rand::thread_rng(); + + let mut successful_gens = 0; + for i in 0..10_000 { + let sample: Option = gen_prime(&mut rng, 1.0..10_000.0); + println!("sample {i}: {sample:?}"); + if let Some(sample) = sample { + successful_gens += 1; + assert!(is_prime(sample)); + } + } + + println!("generated {successful_gens} prime numbers out of 10000 iterations"); + } + #[test] fn test_gen_range_exclude() { let mut rng = rand::thread_rng();