2023-02-23 02:02:57 -08:00
|
|
|
use {
|
|
|
|
log::{error, info},
|
|
|
|
serde_json,
|
|
|
|
solana_bench_mango::{
|
|
|
|
cli,
|
|
|
|
confirmation_strategies::confirmations_by_blocks,
|
2023-03-06 02:05:25 -08:00
|
|
|
crank,
|
2023-02-23 02:02:57 -08:00
|
|
|
helpers::{
|
|
|
|
get_latest_blockhash, get_mango_market_perps_cache, start_blockhash_polling_service,
|
|
|
|
write_block_data_into_csv, write_transaction_data_into_csv,
|
|
|
|
},
|
|
|
|
keeper::start_keepers,
|
|
|
|
mango::{AccountKeys, MangoConfig},
|
|
|
|
market_markers::start_market_making_threads,
|
|
|
|
states::{BlockData, PerpMarketCache, TransactionConfirmRecord, TransactionSendRecord},
|
2023-02-15 08:08:55 -08:00
|
|
|
},
|
2023-02-23 02:02:57 -08:00
|
|
|
solana_client::{
|
|
|
|
connection_cache::ConnectionCache, rpc_client::RpcClient, tpu_client::TpuClient,
|
2022-09-02 07:26:44 -07:00
|
|
|
},
|
2023-03-09 07:20:49 -08:00
|
|
|
solana_metrics::datapoint_info,
|
2023-02-24 06:12:14 -08:00
|
|
|
solana_program::pubkey::Pubkey,
|
2023-02-23 02:02:57 -08:00
|
|
|
solana_sdk::commitment_config::CommitmentConfig,
|
|
|
|
std::{
|
|
|
|
fs,
|
|
|
|
net::{IpAddr, Ipv4Addr},
|
2023-02-24 06:12:14 -08:00
|
|
|
str::FromStr,
|
2023-02-23 02:02:57 -08:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, AtomicU64, Ordering},
|
|
|
|
Arc, RwLock,
|
|
|
|
},
|
2023-03-09 07:20:49 -08:00
|
|
|
thread::sleep,
|
2023-02-23 02:02:57 -08:00
|
|
|
thread::{Builder, JoinHandle},
|
2023-03-09 07:20:49 -08:00
|
|
|
time::Duration,
|
|
|
|
},
|
2022-09-02 07:26:44 -07:00
|
|
|
};
|
|
|
|
|
2023-03-03 08:52:33 -08:00
|
|
|
#[derive(Default)]
|
|
|
|
struct MangoBencherStats {
|
|
|
|
recv_limit: usize,
|
|
|
|
num_confirmed_txs: usize,
|
|
|
|
num_error_txs: usize,
|
|
|
|
num_timeout_txs: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MangoBencherStats {
|
|
|
|
fn report(&self, name: &'static str) {
|
|
|
|
datapoint_info!(
|
|
|
|
name,
|
|
|
|
("recv_limit", self.recv_limit, i64),
|
|
|
|
("num_confirmed_txs", self.num_confirmed_txs, i64),
|
|
|
|
("num_error_txs", self.num_error_txs, i64),
|
|
|
|
("num_timeout_txs", self.num_timeout_txs, i64),
|
2023-03-09 07:20:49 -08:00
|
|
|
(
|
|
|
|
"percent_confirmed_txs",
|
|
|
|
(self.num_confirmed_txs * 100) / self.recv_limit,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"percent_error_txs",
|
|
|
|
(self.num_error_txs * 100) / self.recv_limit,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"percent_timeout_txs",
|
|
|
|
(self.num_timeout_txs * 100) / self.recv_limit,
|
|
|
|
i64
|
|
|
|
),
|
2023-03-03 15:01:19 -08:00
|
|
|
);
|
2023-03-03 08:52:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-06 00:37:42 -08:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
2022-09-02 07:26:44 -07:00
|
|
|
solana_logger::setup_with_default("solana=info");
|
|
|
|
solana_metrics::set_panic_hook("bench-mango", /*version:*/ None);
|
|
|
|
|
|
|
|
let matches = cli::build_args(solana_version::version!()).get_matches();
|
|
|
|
let cli_config = cli::extract_args(&matches);
|
|
|
|
|
|
|
|
let cli::Config {
|
|
|
|
json_rpc_url,
|
|
|
|
websocket_url,
|
|
|
|
id,
|
|
|
|
account_keys,
|
|
|
|
mango_keys,
|
|
|
|
duration,
|
|
|
|
quotes_per_second,
|
|
|
|
transaction_save_file,
|
2022-09-14 06:48:33 -07:00
|
|
|
block_data_save_file,
|
2022-10-01 05:51:46 -07:00
|
|
|
mango_cluster,
|
2022-11-14 09:46:04 -08:00
|
|
|
txs_batch_size,
|
2023-02-21 02:04:02 -08:00
|
|
|
priority_fees_proba,
|
2023-02-23 02:02:57 -08:00
|
|
|
keeper_authority,
|
2023-02-24 06:48:08 -08:00
|
|
|
number_of_markers_per_mm,
|
2022-09-02 07:26:44 -07:00
|
|
|
..
|
|
|
|
} = &cli_config;
|
2023-02-24 06:48:08 -08:00
|
|
|
let number_of_markers_per_mm = *number_of_markers_per_mm;
|
2022-09-02 07:26:44 -07:00
|
|
|
|
2022-09-08 12:52:18 -07:00
|
|
|
let transaction_save_file = transaction_save_file.clone();
|
2022-09-14 06:48:33 -07:00
|
|
|
let block_data_save_file = block_data_save_file.clone();
|
2022-09-08 12:52:18 -07:00
|
|
|
|
2023-02-21 00:49:20 -08:00
|
|
|
info!(
|
|
|
|
"Connecting to the cluster {}, {}",
|
|
|
|
json_rpc_url, websocket_url
|
|
|
|
);
|
2022-09-02 07:26:44 -07:00
|
|
|
|
|
|
|
let account_keys_json = fs::read_to_string(account_keys).expect("unable to read accounts file");
|
|
|
|
let account_keys_parsed: Vec<AccountKeys> =
|
|
|
|
serde_json::from_str(&account_keys_json).expect("accounts JSON was not well-formatted");
|
|
|
|
|
|
|
|
let mango_keys_json = fs::read_to_string(mango_keys).expect("unable to read mango keys file");
|
|
|
|
let mango_keys_parsed: MangoConfig =
|
|
|
|
serde_json::from_str(&mango_keys_json).expect("mango JSON was not well-formatted");
|
|
|
|
|
2022-10-01 05:51:46 -07:00
|
|
|
let mango_group_id = mango_cluster;
|
2022-09-02 07:26:44 -07:00
|
|
|
let mango_group_config = mango_keys_parsed
|
|
|
|
.groups
|
|
|
|
.iter()
|
2022-10-01 05:51:46 -07:00
|
|
|
.find(|g| g.name == *mango_group_id)
|
2022-09-02 07:26:44 -07:00
|
|
|
.unwrap();
|
|
|
|
|
2023-02-21 00:49:20 -08:00
|
|
|
let rpc_client = Arc::new(RpcClient::new_with_commitment(
|
|
|
|
json_rpc_url.to_string(),
|
|
|
|
CommitmentConfig::confirmed(),
|
|
|
|
));
|
2022-09-02 07:26:44 -07:00
|
|
|
|
2023-02-17 04:01:18 -08:00
|
|
|
let connection_cache = ConnectionCache::new_with_client_options(
|
|
|
|
4,
|
|
|
|
None,
|
|
|
|
Some((id, IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))),
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
let quic_connection_cache = if let ConnectionCache::Quic(connection_cache) = connection_cache {
|
|
|
|
Some(connection_cache)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2023-02-21 00:49:20 -08:00
|
|
|
let tpu_client = Arc::new(
|
|
|
|
TpuClient::new_with_connection_cache(
|
|
|
|
rpc_client.clone(),
|
|
|
|
&websocket_url,
|
|
|
|
solana_client::tpu_client::TpuClientConfig::default(),
|
|
|
|
quic_connection_cache.unwrap(),
|
2023-02-21 02:04:02 -08:00
|
|
|
)
|
2023-02-21 00:49:20 -08:00
|
|
|
.unwrap(),
|
|
|
|
);
|
2022-09-02 07:26:44 -07:00
|
|
|
|
|
|
|
info!(
|
|
|
|
"accounts:{:?} markets:{:?} quotes_per_second:{:?} expected_tps:{:?} duration:{:?}",
|
|
|
|
account_keys_parsed.len(),
|
|
|
|
mango_group_config.perp_markets.len(),
|
|
|
|
quotes_per_second,
|
|
|
|
account_keys_parsed.len()
|
|
|
|
* mango_group_config.perp_markets.len()
|
|
|
|
* quotes_per_second.clone() as usize,
|
|
|
|
duration
|
|
|
|
);
|
|
|
|
|
|
|
|
// continuosly fetch blockhash
|
|
|
|
let rpc_client = Arc::new(RpcClient::new_with_commitment(
|
|
|
|
json_rpc_url.to_string(),
|
|
|
|
CommitmentConfig::confirmed(),
|
|
|
|
));
|
|
|
|
let exit_signal = Arc::new(AtomicBool::new(false));
|
|
|
|
let blockhash = Arc::new(RwLock::new(get_latest_blockhash(&rpc_client.clone())));
|
2022-09-04 10:27:30 -07:00
|
|
|
let current_slot = Arc::new(AtomicU64::new(0));
|
2023-02-15 08:08:55 -08:00
|
|
|
let blockhash_thread = start_blockhash_polling_service(
|
|
|
|
exit_signal.clone(),
|
|
|
|
blockhash.clone(),
|
|
|
|
current_slot.clone(),
|
|
|
|
rpc_client.clone(),
|
|
|
|
);
|
2022-09-02 07:26:44 -07:00
|
|
|
|
2023-02-15 08:08:55 -08:00
|
|
|
let perp_market_caches: Vec<PerpMarketCache> =
|
2023-03-06 00:37:42 -08:00
|
|
|
get_mango_market_perps_cache(rpc_client.clone(), mango_group_config);
|
2023-02-15 08:08:55 -08:00
|
|
|
|
2023-02-24 06:48:08 -08:00
|
|
|
let quote_root_bank =
|
|
|
|
Pubkey::from_str(mango_group_config.tokens.last().unwrap().root_key.as_str()).unwrap();
|
|
|
|
let quote_node_banks = mango_group_config
|
|
|
|
.tokens
|
|
|
|
.last()
|
|
|
|
.unwrap()
|
2023-02-24 06:12:14 -08:00
|
|
|
.node_keys
|
|
|
|
.iter()
|
|
|
|
.map(|x| Pubkey::from_str(x.as_str()).unwrap())
|
|
|
|
.collect();
|
2023-02-23 02:02:57 -08:00
|
|
|
// start keeper if keeper authority is present
|
|
|
|
let keepers_jl = if let Some(keeper_authority) = keeper_authority {
|
|
|
|
let jl = start_keepers(
|
|
|
|
exit_signal.clone(),
|
|
|
|
tpu_client.clone(),
|
|
|
|
perp_market_caches.clone(),
|
|
|
|
blockhash.clone(),
|
|
|
|
keeper_authority,
|
2023-02-24 06:12:14 -08:00
|
|
|
quote_root_bank,
|
|
|
|
quote_node_banks,
|
2023-02-23 02:02:57 -08:00
|
|
|
);
|
|
|
|
Some(jl)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2023-02-15 08:08:55 -08:00
|
|
|
let (tx_record_sx, tx_record_rx) = crossbeam_channel::unbounded();
|
2023-02-23 05:41:12 -08:00
|
|
|
let from_slot = current_slot.load(Ordering::Relaxed);
|
2023-02-15 08:08:55 -08:00
|
|
|
|
2023-03-06 00:37:42 -08:00
|
|
|
crank::start(
|
|
|
|
tx_record_sx.clone(),
|
|
|
|
exit_signal.clone(),
|
|
|
|
blockhash.clone(),
|
|
|
|
current_slot.clone(),
|
2023-03-06 02:05:25 -08:00
|
|
|
tpu_client.clone(),
|
2023-03-06 00:37:42 -08:00
|
|
|
mango_group_config,
|
2023-03-09 07:20:49 -08:00
|
|
|
id,
|
2023-03-06 00:37:42 -08:00
|
|
|
);
|
|
|
|
|
2023-02-15 08:08:55 -08:00
|
|
|
let mm_threads: Vec<JoinHandle<()>> = start_market_making_threads(
|
|
|
|
account_keys_parsed.clone(),
|
|
|
|
perp_market_caches.clone(),
|
2023-03-06 00:37:42 -08:00
|
|
|
tx_record_sx.clone(),
|
2023-02-15 08:08:55 -08:00
|
|
|
exit_signal.clone(),
|
|
|
|
blockhash.clone(),
|
|
|
|
current_slot.clone(),
|
2023-02-21 00:49:20 -08:00
|
|
|
tpu_client.clone(),
|
2023-02-15 08:08:55 -08:00
|
|
|
&duration,
|
|
|
|
*quotes_per_second,
|
|
|
|
*txs_batch_size,
|
2023-02-21 02:04:02 -08:00
|
|
|
*priority_fees_proba,
|
2023-02-24 06:48:08 -08:00
|
|
|
number_of_markers_per_mm,
|
2023-02-15 08:08:55 -08:00
|
|
|
);
|
2023-03-06 00:37:42 -08:00
|
|
|
|
2022-09-02 07:26:44 -07:00
|
|
|
let duration = duration.clone();
|
|
|
|
let quotes_per_second = quotes_per_second.clone();
|
|
|
|
let account_keys_parsed = account_keys_parsed.clone();
|
|
|
|
let tx_confirm_records: Arc<RwLock<Vec<TransactionConfirmRecord>>> =
|
|
|
|
Arc::new(RwLock::new(Vec::new()));
|
|
|
|
let tx_timeout_records: Arc<RwLock<Vec<TransactionSendRecord>>> =
|
|
|
|
Arc::new(RwLock::new(Vec::new()));
|
|
|
|
|
2022-09-08 12:52:18 -07:00
|
|
|
let tx_block_data = Arc::new(RwLock::new(Vec::<BlockData>::new()));
|
|
|
|
|
2022-09-02 07:26:44 -07:00
|
|
|
let confirmation_thread = Builder::new()
|
|
|
|
.name("solana-client-sender".to_string())
|
|
|
|
.spawn(move || {
|
2023-03-03 08:52:33 -08:00
|
|
|
let mut stats = MangoBencherStats::default();
|
|
|
|
|
|
|
|
stats.recv_limit = account_keys_parsed.len()
|
2023-02-24 06:48:08 -08:00
|
|
|
* number_of_markers_per_mm as usize
|
2022-09-08 12:52:18 -07:00
|
|
|
* duration.as_secs() as usize
|
|
|
|
* quotes_per_second as usize;
|
2022-09-02 07:26:44 -07:00
|
|
|
|
2022-09-07 11:58:07 -07:00
|
|
|
//confirmation_by_querying_rpc(recv_limit, rpc_client.clone(), &tx_record_rx, tx_confirm_records.clone(), tx_timeout_records.clone());
|
2022-09-08 12:52:18 -07:00
|
|
|
confirmations_by_blocks(
|
2023-02-21 00:49:20 -08:00
|
|
|
rpc_client.clone(),
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.recv_limit,
|
2022-09-08 12:52:18 -07:00
|
|
|
tx_record_rx,
|
|
|
|
tx_confirm_records.clone(),
|
|
|
|
tx_timeout_records.clone(),
|
|
|
|
tx_block_data.clone(),
|
2023-02-23 05:41:12 -08:00
|
|
|
from_slot,
|
2022-09-08 12:52:18 -07:00
|
|
|
);
|
2022-09-02 07:26:44 -07:00
|
|
|
|
|
|
|
let confirmed: Vec<TransactionConfirmRecord> = {
|
|
|
|
let lock = tx_confirm_records.write().unwrap();
|
|
|
|
(*lock).clone()
|
|
|
|
};
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.num_confirmed_txs = confirmed.len();
|
2023-02-24 06:48:08 -08:00
|
|
|
|
2022-09-02 07:26:44 -07:00
|
|
|
info!(
|
|
|
|
"confirmed {} signatures of {} rate {}%",
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.num_confirmed_txs,
|
|
|
|
stats.recv_limit,
|
|
|
|
(stats.num_confirmed_txs * 100) / stats.recv_limit
|
2022-09-02 07:26:44 -07:00
|
|
|
);
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.num_error_txs = confirmed.iter().filter(|tx| !tx.error.is_empty()).count();
|
2022-09-02 07:26:44 -07:00
|
|
|
info!(
|
|
|
|
"errors counted {} rate {}%",
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.num_error_txs,
|
|
|
|
(stats.num_error_txs as usize * 100) / stats.recv_limit
|
2022-09-02 07:26:44 -07:00
|
|
|
);
|
|
|
|
let timeouts: Vec<TransactionSendRecord> = {
|
|
|
|
let timeouts = tx_timeout_records.clone();
|
|
|
|
let lock = timeouts.write().unwrap();
|
|
|
|
(*lock).clone()
|
|
|
|
};
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.num_timeout_txs = timeouts.len();
|
2022-09-02 07:26:44 -07:00
|
|
|
info!(
|
|
|
|
"timeouts counted {} rate {}%",
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.num_timeout_txs,
|
|
|
|
(stats.num_timeout_txs * 100) / stats.recv_limit
|
2022-09-02 07:26:44 -07:00
|
|
|
);
|
2023-03-03 08:52:33 -08:00
|
|
|
stats.report("mango-bencher");
|
2023-03-03 15:01:19 -08:00
|
|
|
// metrics are submitted every 10s,
|
|
|
|
// it is necessary only because we do it once before the end of the execution
|
|
|
|
sleep(Duration::from_secs(10));
|
2022-09-02 07:26:44 -07:00
|
|
|
|
2023-02-15 08:08:55 -08:00
|
|
|
// let mut confirmation_times = confirmed
|
|
|
|
// .iter()
|
|
|
|
// .map(|r| {
|
|
|
|
// r.confirmed_at
|
|
|
|
// .signed_duration_since(r.sent_at)
|
|
|
|
// .num_milliseconds()
|
|
|
|
// })
|
|
|
|
// .collect::<Vec<_>>();
|
|
|
|
// confirmation_times.sort();
|
|
|
|
// info!(
|
|
|
|
// "confirmation times min={} max={} median={}",
|
|
|
|
// confirmation_times.first().unwrap(),
|
|
|
|
// confirmation_times.last().unwrap(),
|
|
|
|
// confirmation_times[confirmation_times.len() / 2]
|
|
|
|
// );
|
2022-09-08 12:52:18 -07:00
|
|
|
|
|
|
|
write_transaction_data_into_csv(
|
|
|
|
transaction_save_file,
|
|
|
|
tx_confirm_records,
|
|
|
|
tx_timeout_records,
|
|
|
|
);
|
2022-09-14 06:48:33 -07:00
|
|
|
|
2022-11-02 07:39:26 -07:00
|
|
|
write_block_data_into_csv(block_data_save_file, tx_block_data);
|
2022-09-02 07:26:44 -07:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
for t in mm_threads {
|
|
|
|
if let Err(err) = t.join() {
|
|
|
|
error!("mm join failed with: {:?}", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("joined all mm_threads");
|
|
|
|
|
|
|
|
if let Err(err) = confirmation_thread.join() {
|
|
|
|
error!("confirmation join fialed with: {:?}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("joined confirmation thread");
|
|
|
|
|
|
|
|
exit_signal.store(true, Ordering::Relaxed);
|
|
|
|
|
|
|
|
if let Err(err) = blockhash_thread.join() {
|
|
|
|
error!("blockhash join failed with: {:?}", err);
|
|
|
|
}
|
2023-02-23 02:02:57 -08:00
|
|
|
|
|
|
|
if let Some(keepers_jl) = keepers_jl {
|
|
|
|
if let Err(err) = keepers_jl.join() {
|
|
|
|
error!("keeper join failed with: {:?}", err);
|
|
|
|
}
|
|
|
|
}
|
2022-09-02 07:26:44 -07:00
|
|
|
}
|