130 lines
5.3 KiB
Rust
130 lines
5.3 KiB
Rust
use std::{
|
|
collections::HashSet,
|
|
str::FromStr,
|
|
sync::{atomic::AtomicU64, Arc},
|
|
};
|
|
|
|
use async_trait::async_trait;
|
|
use const_env::from_env;
|
|
use rand::{seq::IteratorRandom, SeedableRng};
|
|
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
|
|
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer};
|
|
use tokio::time::Instant;
|
|
|
|
use crate::{config::Config, test_registry::TestingTask};
|
|
|
|
#[from_env]
|
|
const NB_ACCOUNT_FETCHING_TASKS: usize = 10;
|
|
|
|
#[from_env]
|
|
const NB_OF_ACCOUNTS_FETCHED_PER_TASK: usize = 100;
|
|
|
|
pub struct AccountsFetchingTests;
|
|
|
|
impl AccountsFetchingTests {
|
|
pub fn create_random_address(count: usize) -> Vec<Pubkey> {
|
|
(0..count).map(|_| Keypair::new().pubkey()).collect()
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl TestingTask for AccountsFetchingTests {
|
|
async fn test(&self, args: crate::cli::Args, config: Config) -> anyhow::Result<()> {
|
|
let rpc_client = Arc::new(RpcClient::new(args.rpc_addr.clone()));
|
|
let total_fetches = Arc::new(AtomicU64::new(0));
|
|
|
|
let known_accounts = config
|
|
.known_accounts
|
|
.iter()
|
|
.map(|x| Pubkey::from_str(x.as_str()).unwrap())
|
|
.collect::<Vec<_>>();
|
|
let unknown_accounts: Vec<Pubkey> =
|
|
AccountsFetchingTests::create_random_address(known_accounts.len());
|
|
let number_of_fetched_accounts = NB_OF_ACCOUNTS_FETCHED_PER_TASK.min(known_accounts.len());
|
|
|
|
let hash_set_known = Arc::new(known_accounts.iter().copied().collect::<HashSet<_>>());
|
|
|
|
let mut tasks = vec![];
|
|
for i in 0..NB_ACCOUNT_FETCHING_TASKS {
|
|
// each new task will fetch (100/NB_ACCOUNT_FETCHING_TASKS) * i percent of unknown accounts
|
|
// so first task will fetch no unknown accounts and last will fetch almost all unknown accounts
|
|
let known_accounts = known_accounts.clone();
|
|
let unknown_accounts = unknown_accounts.clone();
|
|
let duration = args.get_duration_to_run_test();
|
|
let rpc_client = rpc_client.clone();
|
|
let hash_set_known = hash_set_known.clone();
|
|
let total_fetches = total_fetches.clone();
|
|
let task = tokio::spawn(async move {
|
|
let percentage_of_unknown_tasks =
|
|
(100.0 / (NB_ACCOUNT_FETCHING_TASKS as f64)) * (i as f64);
|
|
|
|
println!("started fetching accounts task #{}", i);
|
|
let unknown_accounts_to_take = ((number_of_fetched_accounts as f64)
|
|
* percentage_of_unknown_tasks
|
|
/ 100.0) as usize;
|
|
let known_accounts_to_take =
|
|
number_of_fetched_accounts.saturating_sub(unknown_accounts_to_take);
|
|
|
|
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(i as u64);
|
|
|
|
let instant = Instant::now();
|
|
while instant.elapsed() < duration {
|
|
let known_accounts = known_accounts
|
|
.iter()
|
|
.choose_multiple(&mut rng, known_accounts_to_take);
|
|
let unknown_accounts = unknown_accounts
|
|
.iter()
|
|
.choose_multiple(&mut rng, unknown_accounts_to_take);
|
|
let accounts_to_fetch = [known_accounts, unknown_accounts]
|
|
.concat()
|
|
.iter()
|
|
.map(|x| *(*x))
|
|
.collect::<Vec<_>>();
|
|
let res = rpc_client
|
|
.get_multiple_accounts(accounts_to_fetch.as_slice())
|
|
.await;
|
|
total_fetches.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
|
match res {
|
|
Ok(res) => {
|
|
if res.len() == accounts_to_fetch.len() {
|
|
for i in 0..accounts_to_fetch.len() {
|
|
if hash_set_known.contains(&accounts_to_fetch[i]) {
|
|
if res[i].is_none() {
|
|
println!(
|
|
"unable to fetch known account {}",
|
|
accounts_to_fetch[i]
|
|
);
|
|
}
|
|
} else if res[i].is_some() {
|
|
println!("fetched unknown account should not be possible");
|
|
}
|
|
}
|
|
} else {
|
|
println!("fetched accounts results mismatched");
|
|
}
|
|
}
|
|
Err(e) => {
|
|
println!("accounts fetching failed because {}", e);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
tasks.push(task);
|
|
}
|
|
|
|
futures::future::join_all(tasks).await;
|
|
println!(
|
|
"Accounts fetching did {} requests of {} accounts in {} tasks",
|
|
total_fetches.load(std::sync::atomic::Ordering::Relaxed),
|
|
number_of_fetched_accounts,
|
|
NB_ACCOUNT_FETCHING_TASKS
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn get_name(&self) -> String {
|
|
"Accounts Fetching".to_string()
|
|
}
|
|
}
|