Cli: add cluster-date subcommand, and make block-time slot optional (#9878)

* Add CliBlockTime struct

* Add cli cluster-date subcommand

* Make slot param optional; also jsonify

* Make prints prettier
This commit is contained in:
Tyera Eulberg
2020-05-05 09:42:03 -06:00
committed by GitHub
parent 16af67d5e1
commit b2672fd623
3 changed files with 82 additions and 19 deletions

View File

@ -179,6 +179,7 @@ pub enum CliCommand {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
follow: bool, follow: bool,
}, },
ClusterDate,
ClusterVersion, ClusterVersion,
CreateAddressWithSeed { CreateAddressWithSeed {
from_pubkey: Option<Pubkey>, from_pubkey: Option<Pubkey>,
@ -187,7 +188,7 @@ pub enum CliCommand {
}, },
Fees, Fees,
GetBlockTime { GetBlockTime {
slot: Slot, slot: Option<Slot>,
}, },
GetEpochInfo { GetEpochInfo {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
@ -587,6 +588,10 @@ pub fn parse_command(
let response = match matches.subcommand() { let response = match matches.subcommand() {
// Cluster Query Commands // Cluster Query Commands
("catchup", Some(matches)) => parse_catchup(matches, wallet_manager), ("catchup", Some(matches)) => parse_catchup(matches, wallet_manager),
("cluster-date", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::ClusterDate,
signers: vec![],
}),
("cluster-version", Some(_matches)) => Ok(CliCommandInfo { ("cluster-version", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::ClusterVersion, command: CliCommand::ClusterVersion,
signers: vec![], signers: vec![],
@ -1685,6 +1690,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*commitment_config, *commitment_config,
*follow, *follow,
), ),
CliCommand::ClusterDate => process_cluster_date(&rpc_client, config),
CliCommand::ClusterVersion => process_cluster_version(&rpc_client), CliCommand::ClusterVersion => process_cluster_version(&rpc_client),
CliCommand::CreateAddressWithSeed { CliCommand::CreateAddressWithSeed {
from_pubkey, from_pubkey,
@ -1692,7 +1698,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
program_id, program_id,
} => process_create_address_with_seed(config, from_pubkey.as_ref(), &seed, &program_id), } => process_create_address_with_seed(config, from_pubkey.as_ref(), &seed, &program_id),
CliCommand::Fees => process_fees(&rpc_client), CliCommand::Fees => process_fees(&rpc_client),
CliCommand::GetBlockTime { slot } => process_get_block_time(&rpc_client, *slot), CliCommand::GetBlockTime { slot } => process_get_block_time(&rpc_client, config, *slot),
CliCommand::GetGenesisHash => process_get_genesis_hash(&rpc_client), CliCommand::GetGenesisHash => process_get_genesis_hash(&rpc_client),
CliCommand::GetEpochInfo { commitment_config } => { CliCommand::GetEpochInfo { commitment_config } => {
process_get_epoch_info(&rpc_client, config, *commitment_config) process_get_epoch_info(&rpc_client, config, *commitment_config)

View File

@ -839,3 +839,26 @@ impl From<&Lockout> for CliLockout {
} }
} }
} }
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliBlockTime {
pub slot: Slot,
pub timestamp: UnixTimestamp,
}
impl fmt::Display for CliBlockTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Block:", &self.slot.to_string())?;
writeln_name_value(
f,
"Date:",
&format!(
"{} (UnixTimestamp: {})",
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(self.timestamp, 0), Utc)
.to_rfc3339_opts(SecondsFormat::Secs, true),
self.timestamp
),
)
}
}

View File

@ -1,12 +1,8 @@
use crate::{ use crate::{
cli::{check_account_for_fee, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult}, cli::{check_account_for_fee, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
cli_output::{ cli_output::*,
CliBlockProduction, CliBlockProductionEntry, CliEpochInfo, CliKeyedStakeState,
CliSlotStatus, CliStakeVec, CliValidator, CliValidators,
},
display::println_name_value, display::println_name_value,
}; };
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand}; use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use console::{style, Emoji}; use console::{style, Emoji};
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
@ -24,7 +20,7 @@ use solana_client::{
use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{ use solana_sdk::{
account_utils::StateMut, account_utils::StateMut,
clock::{self, Slot}, clock::{self, Clock, Slot},
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
epoch_schedule::Epoch, epoch_schedule::Epoch,
hash::Hash, hash::Hash,
@ -33,6 +29,7 @@ use solana_sdk::{
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
system_instruction, system_instruction,
sysvar::{self, Sysvar},
transaction::Transaction, transaction::Transaction,
}; };
use std::{ use std::{
@ -81,6 +78,10 @@ impl ClusterQuerySubCommands for App<'_, '_> {
) )
.arg(commitment_arg()), .arg(commitment_arg()),
) )
.subcommand(
SubCommand::with_name("cluster-date")
.about("Get current cluster date, computed from genesis creation time and network time")
)
.subcommand( .subcommand(
SubCommand::with_name("cluster-version") SubCommand::with_name("cluster-version")
.about("Get the version of the cluster entrypoint"), .about("Get the version of the cluster entrypoint"),
@ -94,7 +95,6 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.index(1) .index(1)
.takes_value(true) .takes_value(true)
.value_name("SLOT") .value_name("SLOT")
.required(true)
.help("Slot number of the block to query") .help("Slot number of the block to query")
) )
) )
@ -310,7 +310,7 @@ pub fn parse_cluster_ping(
} }
pub fn parse_get_block_time(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> { pub fn parse_get_block_time(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let slot = value_t_or_exit!(matches, "slot", u64); let slot = value_of(matches, "slot");
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::GetBlockTime { slot }, command: CliCommand::GetBlockTime { slot },
signers: vec![], signers: vec![],
@ -518,6 +518,24 @@ pub fn process_catchup(
} }
} }
pub fn process_cluster_date(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
let result = rpc_client
.get_account_with_commitment(&sysvar::clock::id(), CommitmentConfig::default())?;
if let Some(clock_account) = result.value {
let clock: Clock = Sysvar::from_account(&clock_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string())
})?;
let block_time = CliBlockTime {
slot: result.context.slot,
timestamp: clock.unix_timestamp,
};
config.output_format.formatted_print(&block_time);
Ok("".to_string())
} else {
Err(format!("AccountNotFound: pubkey={}", sysvar::clock::id()).into())
}
}
pub fn process_cluster_version(rpc_client: &RpcClient) -> ProcessResult { pub fn process_cluster_version(rpc_client: &RpcClient) -> ProcessResult {
let remote_version = rpc_client.get_version()?; let remote_version = rpc_client.get_version()?;
Ok(remote_version.solana_core) Ok(remote_version.solana_core)
@ -567,15 +585,20 @@ pub fn process_leader_schedule(rpc_client: &RpcClient) -> ProcessResult {
Ok("".to_string()) Ok("".to_string())
} }
pub fn process_get_block_time(rpc_client: &RpcClient, slot: Slot) -> ProcessResult { pub fn process_get_block_time(
rpc_client: &RpcClient,
config: &CliConfig,
slot: Option<Slot>,
) -> ProcessResult {
let slot = if let Some(slot) = slot {
slot
} else {
rpc_client.get_slot()?
};
let timestamp = rpc_client.get_block_time(slot)?; let timestamp = rpc_client.get_block_time(slot)?;
let result = format!( let block_time = CliBlockTime { slot, timestamp };
"{} (UnixTimestamp: {})", config.output_format.formatted_print(&block_time);
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(timestamp, 0), Utc) Ok("".to_string())
.to_rfc3339_opts(SecondsFormat::Secs, true),
timestamp
);
Ok(result)
} }
pub fn process_get_epoch_info( pub fn process_get_epoch_info(
@ -1196,6 +1219,17 @@ mod tests {
let (default_keypair_file, mut tmp_file) = make_tmp_file(); let (default_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap(); write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
let test_cluster_version = test_commands
.clone()
.get_matches_from(vec!["test", "cluster-date"]);
assert_eq!(
parse_command(&test_cluster_version, &default_keypair_file, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::ClusterDate,
signers: vec![],
}
);
let test_cluster_version = test_commands let test_cluster_version = test_commands
.clone() .clone()
.get_matches_from(vec!["test", "cluster-version"]); .get_matches_from(vec!["test", "cluster-version"]);
@ -1224,7 +1258,7 @@ mod tests {
assert_eq!( assert_eq!(
parse_command(&test_get_block_time, &default_keypair_file, &mut None).unwrap(), parse_command(&test_get_block_time, &default_keypair_file, &mut None).unwrap(),
CliCommandInfo { CliCommandInfo {
command: CliCommand::GetBlockTime { slot }, command: CliCommand::GetBlockTime { slot: Some(slot) },
signers: vec![], signers: vec![],
} }
); );