2022-09-02 07:26:44 -07:00
|
|
|
use {
|
|
|
|
clap::{crate_description, crate_name, App, Arg, ArgMatches},
|
2023-02-23 02:02:57 -08:00
|
|
|
solana_clap_utils::input_validators::{is_url, is_url_or_moniker, is_valid_percentage},
|
2022-09-02 07:26:44 -07:00
|
|
|
solana_cli_config::{ConfigInput, CONFIG_FILE},
|
|
|
|
solana_sdk::signature::{read_keypair_file, Keypair},
|
|
|
|
std::{net::SocketAddr, process::exit, time::Duration},
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Holds the configuration for a single run of the benchmark
|
|
|
|
pub struct Config {
|
|
|
|
pub entrypoint_addr: SocketAddr,
|
|
|
|
pub json_rpc_url: String,
|
|
|
|
pub websocket_url: String,
|
|
|
|
pub id: Keypair,
|
|
|
|
pub duration: Duration,
|
|
|
|
pub quotes_per_second: u64,
|
|
|
|
pub account_keys: String,
|
|
|
|
pub mango_keys: String,
|
|
|
|
pub transaction_save_file: String,
|
2022-09-14 06:48:33 -07:00
|
|
|
pub block_data_save_file: String,
|
2022-10-01 05:51:46 -07:00
|
|
|
pub mango_cluster: String,
|
2022-11-14 08:32:49 -08:00
|
|
|
pub txs_batch_size: Option<usize>,
|
2023-02-21 02:04:02 -08:00
|
|
|
pub priority_fees_proba: u8,
|
2023-04-15 03:39:26 -07:00
|
|
|
pub keeper_prioritization: u64,
|
2023-02-23 02:02:57 -08:00
|
|
|
pub keeper_authority: Option<Keypair>,
|
2023-02-24 06:48:08 -08:00
|
|
|
pub number_of_markers_per_mm: u8,
|
2022-09-02 07:26:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Config {
|
|
|
|
fn default() -> Config {
|
|
|
|
Config {
|
|
|
|
entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
|
|
|
|
json_rpc_url: ConfigInput::default().json_rpc_url,
|
|
|
|
websocket_url: ConfigInput::default().websocket_url,
|
|
|
|
id: Keypair::new(),
|
|
|
|
duration: Duration::new(std::u64::MAX, 0),
|
|
|
|
quotes_per_second: 1,
|
|
|
|
account_keys: String::new(),
|
|
|
|
mango_keys: String::new(),
|
2022-11-02 07:39:26 -07:00
|
|
|
transaction_save_file: String::new(),
|
|
|
|
block_data_save_file: String::new(),
|
|
|
|
mango_cluster: "testnet.0".to_string(),
|
2022-11-14 08:32:49 -08:00
|
|
|
txs_batch_size: None,
|
2023-02-21 02:04:02 -08:00
|
|
|
priority_fees_proba: 0,
|
2023-02-23 02:02:57 -08:00
|
|
|
keeper_authority: None,
|
2023-02-24 06:48:08 -08:00
|
|
|
number_of_markers_per_mm: 5,
|
2023-04-15 03:39:26 -07:00
|
|
|
keeper_prioritization: 1000,
|
2022-09-02 07:26:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Defines and builds the CLI args for a run of the benchmark
|
|
|
|
pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
|
|
|
|
App::new(crate_name!())
|
|
|
|
.about(crate_description!())
|
|
|
|
.version(version)
|
|
|
|
.arg({
|
2023-02-23 02:02:57 -08:00
|
|
|
let arg = Arg::with_name("config-file")
|
2022-09-02 07:26:44 -07:00
|
|
|
.short("C")
|
|
|
|
.long("config")
|
|
|
|
.value_name("FILEPATH")
|
|
|
|
.takes_value(true)
|
|
|
|
.global(true)
|
|
|
|
.help("Configuration file to use");
|
|
|
|
if let Some(ref config_file) = *CONFIG_FILE {
|
|
|
|
arg.default_value(config_file)
|
|
|
|
} else {
|
|
|
|
arg
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.arg(
|
2023-02-23 02:02:57 -08:00
|
|
|
Arg::with_name("json-rpc-url")
|
2022-09-02 07:26:44 -07:00
|
|
|
.short("u")
|
|
|
|
.long("url")
|
|
|
|
.value_name("URL_OR_MONIKER")
|
|
|
|
.takes_value(true)
|
|
|
|
.global(true)
|
|
|
|
.validator(is_url_or_moniker)
|
|
|
|
.help(
|
|
|
|
"URL for Solana's JSON RPC or moniker (or their first letter): \
|
|
|
|
[mainnet-beta, testnet, devnet, localhost]",
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.arg(
|
2023-02-23 02:02:57 -08:00
|
|
|
Arg::with_name("websocket-url")
|
2022-09-02 07:26:44 -07:00
|
|
|
.long("ws")
|
|
|
|
.value_name("URL")
|
|
|
|
.takes_value(true)
|
|
|
|
.global(true)
|
|
|
|
.validator(is_url)
|
|
|
|
.help("WebSocket URL for the solana cluster"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("entrypoint")
|
|
|
|
.short("n")
|
|
|
|
.long("entrypoint")
|
|
|
|
.value_name("HOST:PORT")
|
|
|
|
.takes_value(true)
|
|
|
|
.help(
|
|
|
|
"Rendezvous with the cluster at this entry point; defaults to 127.0.0.1:8001",
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("identity")
|
|
|
|
.short("i")
|
|
|
|
.long("identity")
|
2023-02-23 02:02:57 -08:00
|
|
|
.value_name("FILEPATH")
|
2022-09-02 07:26:44 -07:00
|
|
|
.takes_value(true)
|
2023-02-24 06:12:14 -08:00
|
|
|
.help("Identity used in the QUIC connection. Identity with a lot of stake has a \
|
|
|
|
better chance to send transaction to the leader"),
|
2022-09-02 07:26:44 -07:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("duration")
|
|
|
|
.short("d")
|
|
|
|
.long("duration")
|
|
|
|
.value_name("SECS")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Seconds to run benchmark, then exit; default is forever"),
|
|
|
|
)
|
|
|
|
.arg(
|
2023-02-23 02:02:57 -08:00
|
|
|
Arg::with_name("quotes-per-second")
|
2022-09-02 07:26:44 -07:00
|
|
|
.short("q")
|
2023-02-23 02:02:57 -08:00
|
|
|
.long("quotes-per-second")
|
2022-09-02 07:26:44 -07:00
|
|
|
.value_name("QPS")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Number of quotes per second"),
|
|
|
|
)
|
|
|
|
.arg(
|
2023-02-23 02:02:57 -08:00
|
|
|
Arg::with_name("account-keys")
|
2022-09-02 07:26:44 -07:00
|
|
|
.short("a")
|
|
|
|
.long("accounts")
|
|
|
|
.value_name("FILENAME")
|
|
|
|
.required(true)
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Read account keys from JSON file generated with mango-client-v3"),
|
|
|
|
)
|
|
|
|
.arg(
|
2023-02-23 02:02:57 -08:00
|
|
|
Arg::with_name("mango-keys")
|
2022-09-02 07:26:44 -07:00
|
|
|
.short("m")
|
|
|
|
.long("mango")
|
|
|
|
.value_name("FILENAME")
|
|
|
|
.required(true)
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Read mango keys from JSON file generated with mango-client-v3"),
|
|
|
|
)
|
|
|
|
.arg(
|
2023-02-23 02:02:57 -08:00
|
|
|
Arg::with_name("transaction-save-file")
|
2022-11-02 07:39:26 -07:00
|
|
|
.short("tsf")
|
2023-02-23 02:02:57 -08:00
|
|
|
.long("transaction-save-file")
|
2022-11-02 07:39:26 -07:00
|
|
|
.value_name("FILENAME")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
|
|
|
.help("To save details of all transactions during a run"),
|
2022-09-02 07:26:44 -07:00
|
|
|
)
|
2022-09-14 06:48:33 -07:00
|
|
|
.arg(
|
2023-02-23 02:02:57 -08:00
|
|
|
Arg::with_name("block-data-save-file")
|
2022-11-02 07:39:26 -07:00
|
|
|
.short("bdsf")
|
2023-02-23 02:02:57 -08:00
|
|
|
.long("block-data-save-file")
|
2022-11-02 07:39:26 -07:00
|
|
|
.value_name("FILENAME")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
|
|
|
.help("To save details of all block containing mm transactions"),
|
2022-09-14 06:48:33 -07:00
|
|
|
)
|
2022-10-01 05:51:46 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("mango-cluster")
|
|
|
|
.short("c")
|
|
|
|
.long("mango-cluster")
|
|
|
|
.value_name("STR")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("Name of mango cluster from ids.json"),
|
|
|
|
)
|
2022-11-14 08:32:49 -08:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("batch-size")
|
|
|
|
.long("batch-size")
|
|
|
|
.value_name("UINT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
|
|
|
.help("If specified, transactions are send in batches of specified size"),
|
|
|
|
)
|
2023-02-21 02:04:02 -08:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("prioritization-fees")
|
|
|
|
.long("prioritization-fees")
|
|
|
|
.value_name("UINT")
|
|
|
|
.min_values(1)
|
2023-02-22 04:29:10 -08:00
|
|
|
.validator(is_valid_percentage)
|
2023-02-21 02:04:02 -08:00
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
2023-02-21 00:49:20 -08:00
|
|
|
.help("Takes percentage of transaction we want to add random prioritization fees to, prioritization fees are random number between 100-1000")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("keeper-authority")
|
|
|
|
.long("keeper-authority")
|
|
|
|
.short("ka")
|
2023-02-23 02:02:57 -08:00
|
|
|
.value_name("FILEPATH")
|
2023-02-21 00:49:20 -08:00
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
|
|
|
.help(
|
|
|
|
"If specified, authority keypair would be used to pay for keeper transactions",
|
|
|
|
),
|
2023-02-21 02:04:02 -08:00
|
|
|
)
|
2023-02-24 06:48:08 -08:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("markets-per-mm")
|
|
|
|
.long("markets-per-mm")
|
|
|
|
.value_name("UINT")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
|
|
|
.help("Number of markets a market maker will trade on at a time"),
|
|
|
|
)
|
2023-04-15 03:39:26 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("keeper-prioritization-fees")
|
|
|
|
.long("keeper-prioritization-fees")
|
|
|
|
.value_name("UINT")
|
|
|
|
.min_values(0)
|
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
|
|
|
.help("Prioritization fees set for all keeper instructions (1000 by default)")
|
|
|
|
)
|
2022-09-02 07:26:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Parses a clap `ArgMatches` structure into a `Config`
|
|
|
|
/// # Arguments
|
|
|
|
/// * `matches` - command line arguments parsed by clap
|
|
|
|
/// # Panics
|
|
|
|
/// Panics if there is trouble parsing any of the arguments
|
|
|
|
pub fn extract_args(matches: &ArgMatches) -> Config {
|
|
|
|
let mut args = Config::default();
|
|
|
|
|
2023-02-23 02:02:57 -08:00
|
|
|
let config = if let Some(config_file) = matches.value_of("config-file") {
|
2022-09-02 07:26:44 -07:00
|
|
|
solana_cli_config::Config::load(config_file).unwrap_or_default()
|
|
|
|
} else {
|
|
|
|
solana_cli_config::Config::default()
|
|
|
|
};
|
|
|
|
let (_, json_rpc_url) = ConfigInput::compute_json_rpc_url_setting(
|
2023-02-23 02:02:57 -08:00
|
|
|
matches.value_of("json-rpc-url").unwrap_or(""),
|
2022-09-02 07:26:44 -07:00
|
|
|
&config.json_rpc_url,
|
|
|
|
);
|
|
|
|
args.json_rpc_url = json_rpc_url;
|
|
|
|
|
|
|
|
let (_, websocket_url) = ConfigInput::compute_websocket_url_setting(
|
2023-02-23 02:02:57 -08:00
|
|
|
matches.value_of("websocket-url").unwrap_or(""),
|
2022-09-02 07:26:44 -07:00
|
|
|
&config.websocket_url,
|
2023-02-23 02:02:57 -08:00
|
|
|
matches.value_of("json-rpc-url").unwrap_or(""),
|
2022-09-02 07:26:44 -07:00
|
|
|
&config.json_rpc_url,
|
|
|
|
);
|
|
|
|
args.websocket_url = websocket_url;
|
|
|
|
|
|
|
|
let (_, id_path) = ConfigInput::compute_keypair_path_setting(
|
|
|
|
matches.value_of("identity").unwrap_or(""),
|
|
|
|
&config.keypair_path,
|
|
|
|
);
|
|
|
|
if let Ok(id) = read_keypair_file(id_path) {
|
|
|
|
args.id = id;
|
|
|
|
} else if matches.is_present("identity") {
|
|
|
|
panic!("could not parse identity path");
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(addr) = matches.value_of("entrypoint") {
|
|
|
|
args.entrypoint_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
|
|
|
|
eprintln!("failed to parse entrypoint address: {}", e);
|
|
|
|
exit(1)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(duration) = matches.value_of("duration") {
|
|
|
|
args.duration = Duration::new(
|
|
|
|
duration.to_string().parse().expect("can't parse duration"),
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-02-23 02:02:57 -08:00
|
|
|
if let Some(qps) = matches.value_of("quotes-per-second") {
|
|
|
|
args.quotes_per_second = qps.parse().expect("can't parse quotes-per-second");
|
2022-09-02 07:26:44 -07:00
|
|
|
}
|
|
|
|
|
2023-02-23 02:02:57 -08:00
|
|
|
args.account_keys = matches.value_of("account-keys").unwrap().to_string();
|
|
|
|
args.mango_keys = matches.value_of("mango-keys").unwrap().to_string();
|
|
|
|
args.transaction_save_file = match matches.value_of("transaction-save-file") {
|
2022-09-02 07:26:44 -07:00
|
|
|
Some(x) => x.to_string(),
|
|
|
|
None => String::new(),
|
|
|
|
};
|
2023-02-23 02:02:57 -08:00
|
|
|
args.block_data_save_file = match matches.value_of("block-data-save-file") {
|
2022-09-14 06:48:33 -07:00
|
|
|
Some(x) => x.to_string(),
|
|
|
|
None => String::new(),
|
|
|
|
};
|
2022-11-02 07:39:26 -07:00
|
|
|
|
2022-10-01 05:51:46 -07:00
|
|
|
args.mango_cluster = match matches.value_of("mango-cluster") {
|
|
|
|
Some(x) => x.to_string(),
|
|
|
|
None => "testnet.0".to_string(),
|
|
|
|
};
|
2022-11-14 08:32:49 -08:00
|
|
|
args.txs_batch_size = matches
|
|
|
|
.value_of("batch-size")
|
|
|
|
.map(|batch_size_str| batch_size_str.parse().expect("can't parse batch-size"));
|
2023-02-21 02:04:02 -08:00
|
|
|
|
|
|
|
args.priority_fees_proba = match matches.value_of("prioritization-fees") {
|
2023-02-23 02:02:57 -08:00
|
|
|
Some(x) => x
|
|
|
|
.parse()
|
|
|
|
.expect("Percentage of transactions having prioritization fees"),
|
2023-02-21 02:04:02 -08:00
|
|
|
None => 0,
|
|
|
|
};
|
2023-02-21 00:49:20 -08:00
|
|
|
let (_, kp_auth_path) = ConfigInput::compute_keypair_path_setting(
|
|
|
|
matches.value_of("keeper-authority").unwrap_or(""),
|
|
|
|
&config.keypair_path,
|
|
|
|
);
|
|
|
|
|
2023-02-23 02:02:57 -08:00
|
|
|
args.keeper_authority = read_keypair_file(kp_auth_path.clone()).ok();
|
2023-02-24 06:48:08 -08:00
|
|
|
|
|
|
|
args.number_of_markers_per_mm = match matches.value_of("markets-per-mm") {
|
|
|
|
Some(x) => x
|
|
|
|
.parse()
|
|
|
|
.expect("can't parse number of markets per market maker"),
|
|
|
|
None => 5,
|
|
|
|
};
|
2023-04-15 03:39:26 -07:00
|
|
|
|
|
|
|
args.keeper_prioritization = match matches.value_of("keeper-prioritization-fees") {
|
|
|
|
Some(x) => x.parse().expect("can't parse keeper prioritization fees"),
|
|
|
|
None => 1000,
|
|
|
|
};
|
2022-09-02 07:26:44 -07:00
|
|
|
args
|
|
|
|
}
|