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
This commit is contained in:
parent
7e60ee39d9
commit
5ab4975c44
|
@ -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 <VALIDATOR_INFO_ARGS>
|
||||
$ solana-validator-info publish ~/validator-keypair.json <VALIDATOR_NAME> <VALIDATOR_INFO_ARGS>
|
||||
```
|
||||
Available fields for VALIDATOR_INFO_ARGS:
|
||||
* Name (required)
|
||||
Optional fields for VALIDATOR_INFO_ARGS:
|
||||
* Website
|
||||
* Keybase ID
|
||||
* Details
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<dyn error::Error>> {
|
||||
fn parse_validator_info(
|
||||
pubkey: &Pubkey,
|
||||
account_data: &[u8],
|
||||
) -> Result<(Pubkey, String), Box<dyn error::Error>> {
|
||||
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<dyn error::Error>> {
|
||||
|
@ -173,8 +184,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
)
|
||||
.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<dyn error::Error>> {
|
|||
)
|
||||
.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<dyn error::Error>> {
|
|||
)
|
||||
.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<dyn error::Error>> {
|
|||
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::<Pubkey>().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::<Pubkey>().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]
|
||||
|
|
Loading…
Reference in New Issue