From 5ab4975c44336acbfbd8af8850f622fce58f180c Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Tue, 16 Jul 2019 09:22:55 -0600 Subject: [PATCH] Improve validator-info CLI (#5121) * Fix index OOB panic * Handle 'get' empty validator-info responses properly * Improve 'get' argument flow * Improve arg help text * Improve 'publish' argument flow * Update book doc --- book/src/testnet-participation.md | 5 +- client/src/rpc_client.rs | 1 - validator-info/src/validator_info.rs | 93 +++++++++++++++------------- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/book/src/testnet-participation.md b/book/src/testnet-participation.md index bf4f23e12..3adc0e0f2 100644 --- a/book/src/testnet-participation.md +++ b/book/src/testnet-participation.md @@ -248,10 +248,9 @@ to other users. Run the solana-validator-info CLI to populate a validator-info account: ```bash -$ solana-validator-info publish -k ~/validator-keypair.json +$ solana-validator-info publish ~/validator-keypair.json ``` -Available fields for VALIDATOR_INFO_ARGS: -* Name (required) +Optional fields for VALIDATOR_INFO_ARGS: * Website * Keybase ID * Details diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index d182b176c..67d47945a 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -293,7 +293,6 @@ impl RpcClient { format!("GetProgramAccounts parse failure: {:?}", err), ) })?; - println!("{:?}", accounts); let mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::new(); for (string, account) in accounts.into_iter() { diff --git a/validator-info/src/validator_info.rs b/validator-info/src/validator_info.rs index 5c4209ce0..fac54986d 100644 --- a/validator-info/src/validator_info.rs +++ b/validator-info/src/validator_info.rs @@ -7,6 +7,7 @@ use serde_derive::{Deserialize, Serialize}; use serde_json::{Map, Value}; use solana_client::rpc_client::RpcClient; use solana_config_api::{config_instruction, config_instruction::ConfigKeys, ConfigState}; +use solana_sdk::account::Account; use solana_sdk::message::Message; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil}; @@ -144,12 +145,22 @@ fn parse_args(matches: &ArgMatches<'_>) -> Value { Value::Object(map) } -fn parse_validator_info(account_data: &[u8]) -> Result<(Pubkey, String), Box> { +fn parse_validator_info( + pubkey: &Pubkey, + account_data: &[u8], +) -> Result<(Pubkey, String), Box> { let key_list: ConfigKeys = deserialize(&account_data)?; - let (validator_pubkey, _) = key_list.keys[1]; - let meta_length = ConfigKeys::serialized_size(key_list.keys); - let validator_info: String = deserialize(&account_data[meta_length..])?; - Ok((validator_pubkey, validator_info)) + if !key_list.keys.is_empty() { + let (validator_pubkey, _) = key_list.keys[1]; + let meta_length = ConfigKeys::serialized_size(key_list.keys); + let validator_info: String = deserialize(&account_data[meta_length..])?; + Ok((validator_pubkey, validator_info)) + } else { + Err(format!( + "account {} found, but could not be parsed as ValidatorInfo", + pubkey + ))? + } } fn main() -> Result<(), Box> { @@ -173,8 +184,7 @@ fn main() -> Result<(), Box> { ) .arg( Arg::with_name("validator_keypair") - .short("v") - .long("validator-keypair") + .index(1) .value_name("PATH") .takes_value(true) .required(true) @@ -191,8 +201,7 @@ fn main() -> Result<(), Box> { ) .arg( Arg::with_name("name") - .short("n") - .long("name") + .index(2) .value_name("STRING") .takes_value(true) .required(true) @@ -246,21 +255,11 @@ fn main() -> Result<(), Box> { ) .arg( Arg::with_name("info_pubkey") - .short("p") - .long("info-pubkey") + .index(1) .value_name("PUBKEY") .takes_value(true) - .required_unless("all") - .conflicts_with("all") .validator(is_pubkey) - .help("The pubkey of the Validator info account"), - ) - .arg( - Arg::with_name("all") - .short("a") - .long("all") - .required_unless("info_pubkey") - .help("Return all current Validator info"), + .help("The pubkey of the Validator info account; without this argument, returns all"), ), ) .get_matches(); @@ -361,32 +360,35 @@ fn main() -> Result<(), Box> { let json_rpc_url = matches.value_of("json_rpc_url").unwrap(); let rpc_client = RpcClient::new(json_rpc_url.to_string()); - if matches.is_present("all") { - let all_validator_info = - rpc_client.get_program_accounts(&solana_config_api::id())?; - for (info_pubkey, account) in all_validator_info.iter().filter(|(_, account)| { - let key_list: ConfigKeys = - deserialize(&account.data).map_err(|_| false).unwrap(); - key_list.keys.contains(&(id(), false)) - }) { + if matches.is_present("info_pubkey") { + if let Some(pubkey) = matches.value_of("info_pubkey") { + let info_pubkey = pubkey.parse::().unwrap(); + let validator_info_data = rpc_client.get_account_data(&info_pubkey)?; + let (validator_pubkey, validator_info) = + parse_validator_info(&info_pubkey, &validator_info_data)?; + println!("Validator pubkey: {:?}", validator_pubkey); + println!("Info: {}", validator_info); + } + } else { + let all_config = rpc_client.get_program_accounts(&solana_config_api::id())?; + let all_validator_info: Vec<&(Pubkey, Account)> = all_config + .iter() + .filter(|(_, account)| { + let key_list: ConfigKeys = + deserialize(&account.data).map_err(|_| false).unwrap(); + key_list.keys.contains(&(id(), false)) + }) + .collect(); + if all_validator_info.is_empty() { + println!("No validator info accounts found"); + } + for (info_pubkey, account) in all_validator_info.iter() { println!("Validator info from {:?}", info_pubkey); - let (validator_pubkey, validator_info) = parse_validator_info(&account.data)?; + let (validator_pubkey, validator_info) = + parse_validator_info(&info_pubkey, &account.data)?; println!(" Validator pubkey: {:?}", validator_pubkey); println!(" Info: {}", validator_info); } - } else { - let info_pubkey = if let Some(keypair) = matches.value_of("info_keypair") { - read_keypair(keypair)?.pubkey() - } else if let Some(pubkey) = matches.value_of("info_pubkey") { - pubkey.parse::().unwrap() - } else { - Pubkey::default() // unreachable - }; - let validator_info_data = rpc_client.get_account_data(&info_pubkey)?; - let (validator_pubkey, validator_info) = - parse_validator_info(&validator_info_data)?; - println!("Validator pubkey: {:?}", validator_pubkey); - println!("Info: {}", validator_info); } } _ => unreachable!(), @@ -475,7 +477,10 @@ mod tests { }; let data = serialize(&(config, validator_info)).unwrap(); - assert_eq!(parse_validator_info(&data).unwrap(), (pubkey, info_string)); + assert_eq!( + parse_validator_info(&Pubkey::default(), &data).unwrap(), + (pubkey, info_string) + ); } #[test]