Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: e2e with queues with random capacities #903

Merged
merged 4 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/light-system-programs-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- "circuit-lib/verifier/**"
- "merkle-tree/**"
- ".github/workflows/light-system-programs-tests.yml"
- "test-utils/**"
pull_request:
branches:
- "*"
Expand All @@ -17,6 +18,7 @@ on:
- "circuit-lib/verifier/**"
- "merkle-tree/**"
- ".github/workflows/light-system-programs-tests.yml"
- "test-utils/**"
types:
- opened
- synchronize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
20 changes: 17 additions & 3 deletions test-utils/src/e2e_test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand All @@ -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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should work with any number primes are just about efficiency right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without prime numbers there is a higher chance of collisions and quadratic probe not doing the job properly, therefore the queue might fill up very quick

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is just about ensuring that the account layout works for any input though not about efficiency

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,
Expand All @@ -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::<Poseidon>::new(
Expand Down
7 changes: 5 additions & 2 deletions test-utils/src/indexer/test_indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -519,7 +521,8 @@ impl<const INDEXED_ARRAY_SIZE: usize, R: RpcConnection> TestIndexer<INDEXED_ARRA
nullifier_queue_keypair,
owning_program_id,
self.state_merkle_trees.len() as u64,
StateMerkleTreeConfig::default(),
&StateMerkleTreeConfig::default(),
&NullifierQueueConfig::default(),
)
.await;
crate::test_env::init_cpi_context_account(
Expand Down
25 changes: 13 additions & 12 deletions test-utils/src/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ pub async fn setup_test_programs_with_accounts(
&nullifier_queue_keypair,
None,
1,
StateMerkleTreeConfig::default(),
&StateMerkleTreeConfig::default(),
&NullifierQueueConfig::default(),
)
.await;

Expand Down Expand Up @@ -357,13 +358,14 @@ pub async fn create_state_merkle_tree_and_queue_account<R: RpcConnection>(
nullifier_queue_keypair: &Keypair,
program_owner: Option<Pubkey>,
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(
Expand All @@ -375,10 +377,9 @@ pub async fn create_state_merkle_tree_and_queue_account<R: RpcConnection>(
&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,
Expand All @@ -394,8 +395,8 @@ pub async fn create_state_merkle_tree_and_queue_account<R: RpcConnection>(
*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
Expand Down
2 changes: 1 addition & 1 deletion test-utils/src/test_forester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
);
Expand Down
57 changes: 57 additions & 0 deletions utils/src/rand.rs
Original file line number Diff line number Diff line change
@@ -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<N, R, T>(rng: &mut N, range: R) -> Option<T>
where
N: Rng,
R: Clone + RangeBounds<T> + SampleRange<T>,
T: Into<f64> + From<f64> + 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<N, R, T>(rng: &mut N, range: R, exclude: &[T]) -> T
Expand All @@ -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<f64> = 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();
Expand Down