adding openbook_v2 simulate transaction to bencher

This commit is contained in:
Godmode Galactus 2023-05-16 13:33:26 +02:00
parent caffe84b73
commit 7b4b869cf8
No known key found for this signature in database
GPG Key ID: A04142C71ABB0DEA
7 changed files with 159 additions and 148 deletions

View File

@ -8,13 +8,12 @@ use solana_program::hash::Hash;
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
use tokio::sync::RwLock;
use crate::cli::Args;
use crate::config::{Config};
pub type BlockHashGetter = Arc<RwLock<Hash>>;
#[async_trait::async_trait]
pub trait Benchmark: Clone + Send + 'static {
async fn run(self, rpc_client: Arc<RpcClient>, duration: Duration, args: Args, config: Config, random_number: u64) -> anyhow::Result<Run>;
async fn run(self, rpc_client: Arc<RpcClient>, duration: Duration, random_number: u64) -> anyhow::Result<Run>;
}
#[derive(Default, Serialize)]
@ -40,18 +39,16 @@ pub struct Stats {
pub struct Bencher;
impl Bencher {
pub async fn bench<B: Benchmark + Send + Clone>(instant: B, args: Args, config: Config) -> anyhow::Result<Stats> {
pub async fn bench<B: Benchmark + Send + Clone>(instant: B, args: Args) -> anyhow::Result<Stats> {
let start = Instant::now();
let mut random = StdRng::seed_from_u64(0);
let futs = (0..args.threads).map(|_| {
let rpc_client = args.get_rpc_client();
let duration = args.get_duration_to_run_test();
let args = args.clone();
let config = config.clone();
let random_number = random.gen();
let instant = instant.clone();
tokio::spawn(async move {
instant.run(rpc_client.clone(), duration, args, config, random_number).await.unwrap()
instant.run(rpc_client.clone(), duration, random_number).await.unwrap()
})
});

View File

@ -33,6 +33,11 @@ async fn main() -> anyhow::Result<()> {
bail!("No payers");
}
if config_json.markets.is_empty() {
log::error!("Config file is missing markets");
bail!("No markets")
}
let rpc_client = args.get_rpc_client();
let current_hash = rpc_client.get_latest_blockhash().await.unwrap();
let block_hash: Arc<RwLock<Hash>> = Arc::new(RwLock::new(current_hash));

View File

@ -1,7 +1,13 @@
use crate::bencher::{Benchmark, Run, Bencher};
use crate::config::{Market, User};
use crate::test_registry::TestingTask;
use crate::utils::noop;
use async_trait::async_trait;
use rand::seq::SliceRandom;
use rand::{SeedableRng, Rng};
use rand::rngs::StdRng;
use serde::{Deserialize, Serialize};
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::compute_budget;
use solana_sdk::hash::Hash;
use solana_sdk::{
@ -12,7 +18,6 @@ use solana_sdk::{
transaction::Transaction,
};
use std::mem::size_of;
use std::sync::atomic::{AtomicU64, Ordering};
use std::{str::FromStr, sync::Arc, time::Instant};
use tokio::sync::RwLock;
@ -52,14 +57,13 @@ impl TestingTask for SimulateOpenbookV2PlaceOrder {
args: crate::cli::Args,
config: crate::config::Config,
) -> anyhow::Result<()> {
let mut tasks = vec![];
let openbook_data = config
.programs
.iter()
.find(|x| x.name == "openbook_v2")
.unwrap()
.clone();
let openbook_pk = Pubkey::from_str(openbook_data.program_id.as_str()).unwrap();
let openbook_pid: Pubkey = Pubkey::from_str(openbook_data.program_id.as_str()).unwrap();
let place_order_cmd = openbook_data
.commands
.iter()
@ -68,130 +72,16 @@ impl TestingTask for SimulateOpenbookV2PlaceOrder {
.clone();
assert!(place_order_cmd.instruction.len() == 8 + size_of::<PlaceOrderArgs>());
let successful_orders_count = Arc::new(AtomicU64::new(0));
for user in &config.users {
for market in &config.markets {
let market = market.clone();
let user = user.clone();
let args = args.clone();
let place_order_cmd = place_order_cmd.clone();
let openbook_pk = openbook_pk.clone();
let block_hash = self.block_hash.clone();
let open_orders = user.open_orders[market.market_index]
.open_orders
.to_pubkey();
let base_token_account = user.token_data[market.market_index + 1]
.token_account
.to_pubkey();
let quote_token_account = user.token_data[0].token_account.to_pubkey();
let successful_orders_count = successful_orders_count.clone();
let task = tokio::spawn(async move {
let start = Instant::now();
let mut place_order_ix = place_order_cmd.instruction;
let rpc_client = args.get_rpc_client();
let mut side = false;
let mut price_diff: i64 = 1;
let mut max_base_lots = 1;
while start.elapsed().as_secs() < args.duration_in_seconds {
let order_type: u8 = 0;
let price_lots: i64 = if side {
1000 - price_diff
} else {
1000 + price_diff
};
let place_order_params = PlaceOrderArgs {
client_order_id: 100,
side: side as u8,
price_lots,
max_base_lots,
max_quote_lots_including_fees: i64::MAX,
order_type,
reduce_only: false,
expiry_timestamp: u64::MAX,
limit: 10,
};
let bytes: Vec<u8> = bincode::serialize(&place_order_params).unwrap();
assert!(bytes.len() + 8 == place_order_ix.len());
// copy the instruction data
for i in 0..bytes.len() {
place_order_ix[8 + i] = bytes[i];
}
let token_account = if side {
base_token_account
} else {
quote_token_account
};
let accounts = vec![
AccountMeta::new(open_orders, false),
AccountMeta::new(user.pubkey(), false),
AccountMeta::new(market.market_pk.to_pubkey(), false),
AccountMeta::new(market.bids.to_pubkey(), false),
AccountMeta::new(market.asks.to_pubkey(), false),
AccountMeta::new(token_account, false),
AccountMeta::new(market.base_vault.to_pubkey(), false),
AccountMeta::new(market.quote_vault.to_pubkey(), false),
AccountMeta::new(market.event_queue.to_pubkey(), false),
AccountMeta::new_readonly(market.oracle.to_pubkey(), false),
AccountMeta::new_readonly(spl_token::ID, false),
AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
];
let ix = Instruction::new_with_bytes(
openbook_pk,
place_order_ix.as_slice(),
accounts,
);
let recent_blockhash = *block_hash.read().await;
// to generate new signature each time
let noop_ix = noop::timestamp();
// to have higher compute budget limit
let cu_limits_ix =
compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(
1000000,
);
let transaction = Transaction::new(
&[&user.get_keypair()],
Message::new(&[noop_ix, cu_limits_ix, ix], Some(&user.pubkey())),
recent_blockhash,
);
let signature = transaction.signatures[0];
if let Err(e) = rpc_client.simulate_transaction(&transaction).await {
log::error!(
"error while simulating openbook place order {} sig {}",
e,
signature
);
} else {
successful_orders_count.fetch_add(1, Ordering::Relaxed);
}
// update side and price diff
side = !side;
price_diff = price_diff % 6 + 1;
max_base_lots = max_base_lots % 10 + 1;
}
});
tasks.push(task);
}
}
futures::future::join_all(tasks).await;
log::info!(
"Simulated {} transactions with {} users and {} markets",
successful_orders_count.load(Ordering::Relaxed),
config.users.len(),
config.markets.len()
);
let instant = SimulateOpenbookV2PlaceOrderBench {
block_hash: self.block_hash.clone(),
markets: config.markets.clone(),
users: config.users.clone(),
place_order_cmd: place_order_cmd.instruction,
openbook_pid,
};
let metric = Bencher::bench::<SimulateOpenbookV2PlaceOrderBench>( instant, args).await?;
log::info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
Ok(())
}
@ -199,3 +89,120 @@ impl TestingTask for SimulateOpenbookV2PlaceOrder {
format!("Simulating openbook place orders")
}
}
#[derive(Clone)]
pub struct SimulateOpenbookV2PlaceOrderBench {
pub block_hash: Arc<RwLock<Hash>>,
pub markets: Vec<Market>,
pub users: Vec<User>,
pub place_order_cmd: Vec<u8>,
pub openbook_pid: Pubkey,
}
#[async_trait::async_trait]
impl Benchmark for SimulateOpenbookV2PlaceOrderBench {
async fn run(self, rpc_client: Arc<RpcClient>, duration: std::time::Duration, random_number: u64) -> anyhow::Result<crate::bencher::Run> {
let mut result = Run::default();
let mut rng = StdRng::seed_from_u64(random_number);
let start = Instant::now();
while start.elapsed() < duration {
let mut place_order_ix = self.place_order_cmd.clone();
let market = self.markets.choose(&mut rng).cloned().unwrap();
let user = self.users.choose(&mut rng).cloned().unwrap();
let open_orders = user.open_orders[market.market_index]
.open_orders
.to_pubkey();
let base_token_account = user.token_data[market.market_index + 1]
.token_account
.to_pubkey();
let quote_token_account = user.token_data[0].token_account.to_pubkey();
let side = rng.gen_bool(0.5);
let order_type: u8 = 0;
let price_diff = 3;
let price_lots: i64 = if side {
1000 - price_diff
} else {
1000 + price_diff
};
let max_base_lots = 5;
let place_order_params = PlaceOrderArgs {
client_order_id: 100,
side: side as u8,
price_lots,
max_base_lots,
max_quote_lots_including_fees: i64::MAX,
order_type,
reduce_only: false,
expiry_timestamp: u64::MAX,
limit: 10,
};
let bytes: Vec<u8> = bincode::serialize(&place_order_params).unwrap();
assert!(bytes.len() + 8 == place_order_ix.len());
// copy the instruction data
for i in 0..bytes.len() {
place_order_ix[8 + i] = bytes[i];
}
let token_account = if side {
base_token_account
} else {
quote_token_account
};
let accounts = vec![
AccountMeta::new(open_orders, false),
AccountMeta::new(user.pubkey(), false),
AccountMeta::new(market.market_pk.to_pubkey(), false),
AccountMeta::new(market.bids.to_pubkey(), false),
AccountMeta::new(market.asks.to_pubkey(), false),
AccountMeta::new(token_account, false),
AccountMeta::new(market.base_vault.to_pubkey(), false),
AccountMeta::new(market.quote_vault.to_pubkey(), false),
AccountMeta::new(market.event_queue.to_pubkey(), false),
AccountMeta::new_readonly(market.oracle.to_pubkey(), false),
AccountMeta::new_readonly(spl_token::ID, false),
AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
];
let ix = Instruction::new_with_bytes(
self.openbook_pid,
place_order_ix.as_slice(),
accounts,
);
let recent_blockhash = *self.block_hash.read().await;
// to generate new signature each time
let noop_ix = noop::timestamp();
// to have higher compute budget limit
let cu_limits_ix =
compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(
1000000,
);
let transaction = Transaction::new(
&[&user.get_keypair()],
Message::new(&[noop_ix, cu_limits_ix, ix], Some(&user.pubkey())),
recent_blockhash,
);
match rpc_client.simulate_transaction(&transaction).await {
Ok(_) => {
result.requests_completed += 1;
result.bytes_received += 0;
}
Err(e) => {
result.requests_failed += 1;
result.errors.push(format!("{:?}", e.kind()));
}
}
result.bytes_sent += 0;
}
Ok(result)
}
}

View File

@ -36,8 +36,8 @@ impl TestingTask for AccountsFetchingTests {
let instant = GetAccountsBench {
accounts_list: [accounts, unknown_accounts].concat(),
};
let metric = Bencher::bench::<GetAccountsBench>(instant, args, config).await?;
log::info!("{}", serde_json::to_string(&metric)?);
let metric = Bencher::bench::<GetAccountsBench>(instant, args).await?;
log::info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
Ok(())
}
@ -54,7 +54,7 @@ pub struct GetAccountsBench {
#[async_trait::async_trait]
impl Benchmark for GetAccountsBench {
async fn run(self, rpc_client: Arc<RpcClient>, duration: std::time::Duration, _: crate::cli::Args, _: Config, random_number: u64) -> anyhow::Result<crate::bencher::Run> {
async fn run(self, rpc_client: Arc<RpcClient>, duration: std::time::Duration, random_number: u64) -> anyhow::Result<crate::bencher::Run> {
let mut result = Run::default();
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());

View File

@ -18,15 +18,15 @@ pub struct GetBlockTest;
#[async_trait::async_trait]
impl TestingTask for GetBlockTest {
async fn test(&self, args: Args, config: Config) -> anyhow::Result<()> {
async fn test(&self, args: Args, _: Config) -> anyhow::Result<()> {
let slot = {
args.get_rpc_client().get_slot().await.unwrap()
};
let instant = GetBlockBench {
slot
};
let metric = Bencher::bench::<GetBlockBench>( instant, args, config).await?;
info!("{}", serde_json::to_string(&metric)?);
let metric = Bencher::bench::<GetBlockBench>( instant, args).await?;
info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
Ok(())
}
@ -43,7 +43,7 @@ pub struct GetBlockBench {
#[async_trait::async_trait]
impl Benchmark for GetBlockBench {
async fn run(self, rpc_client: Arc<RpcClient>, duration: Duration, _: Args, _: Config, _: u64) -> anyhow::Result<Run> {
async fn run(self, rpc_client: Arc<RpcClient>, duration: Duration, _: u64) -> anyhow::Result<Run> {
let mut result = Run::default();
let start = Instant::now();

View File

@ -12,10 +12,10 @@ pub struct GetSlotTest;
#[async_trait::async_trait]
impl TestingTask for GetSlotTest {
async fn test(&self, args: Args, config: Config) -> anyhow::Result<()> {
async fn test(&self, args: Args, _: Config) -> anyhow::Result<()> {
let instant = GetSlotTest;
let stats = Bencher::bench::<Self>(instant, args, config).await?;
info!("GetSlotTest {}", serde_json::to_string(&stats)?);
let stats = Bencher::bench::<Self>(instant, args).await?;
info!("{} {}", self.get_name(), serde_json::to_string(&stats)?);
Ok(())
}
@ -27,7 +27,7 @@ impl TestingTask for GetSlotTest {
#[async_trait::async_trait]
impl Benchmark for GetSlotTest {
async fn run(self, rpc_client: Arc<RpcClient>, duration: Duration, _: Args, _: Config, _: u64) -> anyhow::Result<Run> {
async fn run(self, rpc_client: Arc<RpcClient>, duration: Duration, _: u64) -> anyhow::Result<Run> {
let mut result = Run::default();
let start = Instant::now();

View File

@ -1,4 +1,4 @@
use crate::{test_registry::TestingTask, bencher::{Benchmark, Run, Bencher}, config::Config};
use crate::{test_registry::TestingTask, bencher::{Benchmark, Run, Bencher}};
use async_trait::async_trait;
use rand::{distributions::Alphanumeric, prelude::Distribution, seq::SliceRandom, SeedableRng};
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
@ -36,8 +36,9 @@ impl TestingTask for SendAndConfrimTesting {
) -> anyhow::Result<()> {
let instant = SendMemoTransactionsBench {
block_hash: self.block_hash.clone(),
payers: config.users.iter().map(|x| Arc::new(x.get_keypair())).collect()
};
let metric = Bencher::bench::<SendMemoTransactionsBench>( instant, args, config).await?;
let metric = Bencher::bench::<SendMemoTransactionsBench>( instant, args).await?;
log::info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
Ok(())
}
@ -50,22 +51,23 @@ impl TestingTask for SendAndConfrimTesting {
#[derive(Clone)]
struct SendMemoTransactionsBench {
block_hash: Arc<RwLock<Hash>>,
payers: Vec<Arc<Keypair>>,
}
#[async_trait::async_trait]
impl Benchmark for SendMemoTransactionsBench {
async fn run(self, rpc_client: Arc<RpcClient>, duration: std::time::Duration, _: crate::cli::Args, config: Config, random_number: u64) -> anyhow::Result<crate::bencher::Run> {
async fn run(self, rpc_client: Arc<RpcClient>, duration: std::time::Duration, random_number: u64) -> anyhow::Result<crate::bencher::Run> {
let mut result = Run::default();
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(random_number);
let start = Instant::now();
while start.elapsed() < duration {
let msg: Vec<u8> = Alphanumeric.sample_iter(&mut rng).take(10).collect();
let payer = config.users.choose(&mut rng).unwrap();
let payer = self.payers.choose(&mut rng).unwrap();
let blockhash = { *self.block_hash.read().await };
let tx = create_memo_tx(&msg, &payer.get_keypair(), blockhash);
let tx = create_memo_tx(&msg, &payer, blockhash);
match rpc_client.send_transaction(&tx).await {
Ok(_) => {
result.requests_completed += 1;