size fixed

This commit is contained in:
aniketfuryrocks 2023-07-03 05:52:14 +05:30
parent f828cb7bce
commit 8f29e2bb1e
No known key found for this signature in database
GPG Key ID: 1B75EA596D89FF06
6 changed files with 155 additions and 133 deletions

View File

@ -1,62 +1,77 @@
import { import {
Connection, Connection,
Keypair, Keypair,
SystemProgram, SystemProgram,
PublicKey, PublicKey,
Transaction, Transaction,
sendAndConfirmTransaction, sendAndConfirmTransaction,
} from "@solana/web3.js"; } from "@solana/web3.js";
export async function configure_accounts( export class AccountGenerator {
connection: Connection, private connection: Connection;
authority: Keypair, private feePayer: Keypair;
count: number,
programs: PublicKey[] public STABLE_SIZE = 7340032; // 7 MB
): Promise<PublicKey[]> {
let all_accounts: PublicKey[] = []; constructor(connection: Connection, feePayer: Keypair) {
// create accounts in batches of 16 this.connection = connection;
for (let i = 0; i < count; i += 16) { this.feePayer = feePayer;
let end = Math.min(i + 16, count); }
let nbOfAccs = end - i;
let accounts = await Promise.all(
Array.from(Array(nbOfAccs).keys()).map(async (_) => { async find_max_size_fetchable(): Promise<number> {
let size = Math.random() * 10_000_000; // create Solana accounts till a size of 5 mega bytes
if (size < 100) { let good_size = 0;
size = 100;
for (let i = 1; i < 10; i++) {
const size = i * 1024 * 1024;
const account = await this.createSolanaAccount(size);
// get account info
try {
const accountInfo = await this.connection.getAccountInfo(account.publicKey);
good_size = size;
console.log(`account size possible ${accountInfo?.data.length} Bytes`);
} catch (err) {
console.log(`maximum possible size is ${i - 1} MB or ${good_size} Bytes`, err);
break;
}
} }
size = Math.floor(size);
const lamports = await connection.getMinimumBalanceForRentExemption( return good_size;
size }
);
let kp = Keypair.generate();
const program = programs[Math.floor(Math.random() * programs.length)];
async generate_fetchable_accounts(amount: number): Promise<Keypair[]> {
return await Promise.all(Array.from(Array(amount).keys()).map(async (i) => {
const size = this.STABLE_SIZE + (i * 1024); // add a KB to each account
return await this.createSolanaAccount(size);
}));
}
async createSolanaAccount(space: number): Promise<Keypair> {
// Generate a new keypair for the account
const accountKeyPair = Keypair.generate();
// Fetch the minimum required balance for creating an account
const minimumBalance = await this.connection.getMinimumBalanceForRentExemption(space);
// Build the transaction to create the account
const transaction = new Transaction().add( const transaction = new Transaction().add(
SystemProgram.createAccount({ SystemProgram.createAccount({
fromPubkey: authority.publicKey, fromPubkey: this.feePayer.publicKey,
newAccountPubkey: kp.publicKey, newAccountPubkey: accountKeyPair.publicKey,
lamports, lamports: minimumBalance,
space: size, space,
programId: program, programId: new PublicKey('11111111111111111111111111111111'), // Replace with the desired program ID
}) })
); );
transaction.feePayer = authority.publicKey; // send and confirm transaction
let hash = await connection.getRecentBlockhash(); await sendAndConfirmTransaction(this.connection, transaction, [this.feePayer, accountKeyPair]);
transaction.recentBlockhash = hash.blockhash;
// Sign transaction, broadcast, and confirm
await sendAndConfirmTransaction(
connection,
transaction,
[authority, kp],
{ commitment: "confirmed" }
);
return kp.publicKey; return accountKeyPair;
}) }
);
all_accounts = all_accounts.concat(accounts);
}
return all_accounts;
} }

View File

@ -12,7 +12,7 @@ import {
import { getKeypairFromFile } from "./common_utils"; import { getKeypairFromFile } from "./common_utils";
import { deploy_programs } from "./deploy_programs"; import { deploy_programs } from "./deploy_programs";
import { User, createUser, mintUser } from "./general/create_users"; import { User, createUser, mintUser } from "./general/create_users";
import { configure_accounts } from "./general/accounts"; import { AccountGenerator } from "./general/accounts";
import { Command, OutputFile } from "./output_file"; import { Command, OutputFile } from "./output_file";
import { MintUtils } from "./general/mint_utils"; import { MintUtils } from "./general/mint_utils";
import { OpenbookConfigurator } from "./openbook-v2/configure_openbook"; import { OpenbookConfigurator } from "./openbook-v2/configure_openbook";
@ -257,42 +257,15 @@ async function configure(
} }
console.log("Creating accounts"); console.log("Creating accounts");
let accounts = await configure_accounts(
connection,
authority,
numberOfAccountsToBeCreated,
programIds
);
// adding known accounts const accounts = await (new AccountGenerator(connection, authority)).generate_fetchable_accounts(numberOfAccountsToBeCreated);
const marketAccountsList = markets const known_accounts = accounts.map((x) => x.publicKey);
.map((market) => [
market.asks,
market.bids,
market.market_pk,
market.oracle,
market.quote_vault,
market.base_vault,
market.base_mint,
market.quote_mint,
])
.flat();
const userAccountsList = userData
.map((user) => {
const allOpenOrdersAccounts = user.open_orders
.map((x) => x.open_orders)
.flat();
const allTokenAccounts = user.token_data.map((x) => x.token_account);
return allOpenOrdersAccounts.concat(allTokenAccounts);
})
.flat();
accounts = accounts.concat(marketAccountsList).concat(userAccountsList);
console.log("Accounts created"); console.log("Accounts created");
let outputFile: OutputFile = { let outputFile: OutputFile = {
programs: programOutputData, programs: programOutputData,
known_accounts: accounts, known_accounts,
users: userData, users: userData,
mints, mints,
markets, markets,

View File

@ -3,21 +3,21 @@ import { Market } from "./openbook-v2/create_markets";
import { User } from "./general/create_users"; import { User } from "./general/create_users";
export interface Command { export interface Command {
name: String; name: String;
instruction: number[]; instruction: number[];
argument_sizes: number[]; argument_sizes: number[];
} }
export interface ProgramOutputData { export interface ProgramOutputData {
name: String; name: String;
program_id: PublicKey; program_id: PublicKey;
commands: Command[]; commands: Command[];
} }
export interface OutputFile { export interface OutputFile {
users: User[]; users: User[];
programs: ProgramOutputData[]; programs: ProgramOutputData[];
known_accounts: PublicKey[]; known_accounts: PublicKey[];
mints: PublicKey[]; mints: PublicKey[];
markets: Market[]; markets: Market[];
} }

59
run_bench.sh Executable file
View File

@ -0,0 +1,59 @@
#!/bin/bash
# exit on error
set -e
# directory and url
directory="metrics/$1"
url="$2"
# write a function to print error message in red color and exit
function error_exit() {
echo -e "\e[31m$1\e[0m"
exit 1
}
# write a function to print message in green color
function info() {
echo -e "\e[32m$1\e[0m"
}
# exit error if $1 is not provided
if [ -z "$1" ]; then
echo "Error: Please provide a directory name"
exit 1
fi
# set url to localhost if not provided
if [ -z "$url" ]; then
url="http://localhost:8899"
fi
# Fetch hard limit
hard_limit=$(ulimit -Hn)
# Soft limit 9/10th of hard limit
soft_limit=$((hard_limit * 9 / 10))
# set
ulimit -Sn "$soft_limit"
info "Hard limit: $hard_limit"
info "Soft limit: $(ulimit -Sn)"
# check for directory
if [ ! -d "$directoy" ]; then
info "Creating directory: $directory"
mkdir -p "$directory"
else
error_exit "Directory already exists: $directory"
fi
# airdrop
info "Airdropping..."
solana airdrop 100000 -u "$url"
# configure
info "Configuring..."
yarn configure -u "$url"
# run bench
info "Running bench..."
./bench-rpc-by-threads.sh "$directory" -r "$url"

View File

@ -4,9 +4,7 @@ use bytes::Bytes;
use reqwest::header::CONTENT_TYPE; use reqwest::header::CONTENT_TYPE;
use serde_json::{json, Value}; use serde_json::{json, Value};
use solana_client::rpc_request::RpcRequest; use solana_client::rpc_request::RpcRequest;
use solana_program::pubkey::Pubkey; use solana_rpc_client::{nonblocking::rpc_client::RpcClient, rpc_client::SerializableTransaction};
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
use solana_rpc_client::rpc_client::SerializableTransaction;
use crate::bencher::Run; use crate::bencher::Run;
@ -58,13 +56,13 @@ impl CustomRpcClient {
self.send(RpcRequest::GetBlock, json! {[slot.into()]}).await self.send(RpcRequest::GetBlock, json! {[slot.into()]}).await
} }
pub async fn raw_get_multiple_accounts(&mut self, accounts: Vec<Pubkey>) { //pub async fn raw_get_multiple_accounts(&mut self, accounts: &[&str]) {
let accounts: Vec<String> = accounts // self.send(RpcRequest::GetMultipleAccounts, json!([accounts]))
.into_iter() // .await
.map(|pubkey| pubkey.to_string()) //}
.collect();
self.send(RpcRequest::GetMultipleAccounts, json!([accounts])) pub async fn raw_get_account_info(&mut self, account: &str) {
self.send(RpcRequest::GetAccountInfo, json!([account, { "encoding" : "base64" }]))
.await .await
} }

View File

@ -1,8 +1,6 @@
use async_trait::async_trait; use async_trait::async_trait;
use const_env::from_env;
use rand::{seq::IteratorRandom, SeedableRng}; use rand::{seq::IteratorRandom, SeedableRng};
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer}; use std::sync::Arc;
use std::{str::FromStr, sync::Arc};
use tokio::time::Instant; use tokio::time::Instant;
use crate::{ use crate::{
@ -13,36 +11,19 @@ use crate::{
test_registry::TestingTask, test_registry::TestingTask,
}; };
#[from_env]
const NB_OF_ACCOUNTS_FETCHED_PER_TASK: usize = 100;
pub struct AccountsFetchingTests; pub struct AccountsFetchingTests;
impl AccountsFetchingTests {
pub fn create_random_address(count: usize) -> Vec<Pubkey> {
(0..count).map(|_| Keypair::new().pubkey()).collect()
}
}
#[async_trait] #[async_trait]
impl TestingTask for AccountsFetchingTests { impl TestingTask for AccountsFetchingTests {
async fn test(&self, args: &Args, config: &Config) -> anyhow::Result<Stats> { async fn test(&self, args: &Args, config: &Config) -> anyhow::Result<Stats> {
let 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(accounts.len());
let instant = GetAccountsBench { let instant = GetAccountsBench {
accounts_list: Arc::new([accounts, unknown_accounts].concat()), accounts_list: Arc::new(config.known_accounts.clone()),
}; };
let metric = Bencher::bench::<GetAccountsBench>(instant, args).await?; let metric = Bencher::bench::<GetAccountsBench>(instant, args).await?;
Ok(metric) Ok(metric)
} }
fn get_name(&self) -> String { fn get_name(&self) -> String {
"Accounts Fetching".to_string() "Accounts Fetching".to_string()
} }
@ -50,7 +31,7 @@ impl TestingTask for AccountsFetchingTests {
#[derive(Clone)] #[derive(Clone)]
pub struct GetAccountsBench { pub struct GetAccountsBench {
accounts_list: Arc<Vec<Pubkey>>, accounts_list: Arc<Vec<String>>,
} }
#[async_trait::async_trait] #[async_trait::async_trait]
@ -62,18 +43,14 @@ impl Benchmark for GetAccountsBench {
random_number: u64, random_number: u64,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(random_number); let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(random_number);
let number_of_fetched_accounts =
NB_OF_ACCOUNTS_FETCHED_PER_TASK.min(self.accounts_list.len());
let start = Instant::now(); let start = Instant::now();
while start.elapsed() < duration { while start.elapsed() < duration {
let accounts = self // get single random account from accounts_list
.accounts_list let account = self.accounts_list.iter().choose(&mut rng).unwrap();
.iter()
.copied()
.choose_multiple(&mut rng, number_of_fetched_accounts);
rpc_client.raw_get_multiple_accounts(accounts).await rpc_client.raw_get_account_info(account).await
} }
Ok(()) Ok(())