size fixed
This commit is contained in:
parent
f828cb7bce
commit
8f29e2bb1e
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
Loading…
Reference in New Issue