diff --git a/cli-output/src/cli_output.rs b/cli-output/src/cli_output.rs index e1884ec6d3..af104d80a7 100644 --- a/cli-output/src/cli_output.rs +++ b/cli-output/src/cli_output.rs @@ -19,7 +19,7 @@ use { RpcVoteAccountInfo, }, solana_sdk::{ - clock::{self, Epoch, Slot, UnixTimestamp}, + clock::{Epoch, Slot, UnixTimestamp}, epoch_info::EpochInfo, hash::Hash, native_token::lamports_to_sol, @@ -231,12 +231,8 @@ pub struct CliSlotStatus { pub struct CliEpochInfo { #[serde(flatten)] pub epoch_info: EpochInfo, -} - -impl From for CliEpochInfo { - fn from(epoch_info: EpochInfo) -> Self { - Self { epoch_info } - } + #[serde(skip)] + pub average_slot_time_ms: u64, } impl QuietDisplay for CliEpochInfo {} @@ -286,16 +282,16 @@ impl fmt::Display for CliEpochInfo { "Epoch Completed Time:", &format!( "{}/{} ({} remaining)", - slot_to_human_time(self.epoch_info.slot_index), - slot_to_human_time(self.epoch_info.slots_in_epoch), - slot_to_human_time(remaining_slots_in_epoch) + slot_to_human_time(self.epoch_info.slot_index, self.average_slot_time_ms), + slot_to_human_time(self.epoch_info.slots_in_epoch, self.average_slot_time_ms), + slot_to_human_time(remaining_slots_in_epoch, self.average_slot_time_ms) ), ) } } -fn slot_to_human_time(slot: Slot) -> String { - humantime::format_duration(Duration::from_millis(slot * clock::DEFAULT_MS_PER_SLOT)).to_string() +fn slot_to_human_time(slot: Slot, slot_time_ms: u64) -> String { + humantime::format_duration(Duration::from_secs((slot * slot_time_ms) / 1000)).to_string() } #[derive(Serialize, Deserialize, Default)] diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 7c54b82688..d725769bbb 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -993,7 +993,20 @@ pub fn process_get_epoch(rpc_client: &RpcClient, _config: &CliConfig) -> Process } pub fn process_get_epoch_info(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult { - let epoch_info: CliEpochInfo = rpc_client.get_epoch_info()?.into(); + let epoch_info = rpc_client.get_epoch_info()?; + let average_slot_time_ms = rpc_client + .get_recent_performance_samples(Some(60)) + .map(|samples| { + let (slots, secs) = samples.iter().fold((0, 0), |(slots, secs), sample| { + (slots + sample.num_slots, secs + sample.sample_period_secs) + }); + (secs as u64 * 1000) / slots + }) + .unwrap_or(clock::DEFAULT_MS_PER_SLOT); + let epoch_info = CliEpochInfo { + epoch_info, + average_slot_time_ms, + }; Ok(config.output_format.formatted_string(&epoch_info)) } @@ -1008,8 +1021,8 @@ pub fn process_get_slot(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessR } pub fn process_get_block_height(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessResult { - let epoch_info: CliEpochInfo = rpc_client.get_epoch_info()?.into(); - Ok(epoch_info.epoch_info.block_height.to_string()) + let epoch_info = rpc_client.get_epoch_info()?; + Ok(epoch_info.block_height.to_string()) } pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result { diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 5d880fd168..2ba50e51c7 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -644,6 +644,13 @@ impl RpcClient { self.send(RpcRequest::GetEpochSchedule, Value::Null) } + pub fn get_recent_performance_samples( + &self, + limit: Option, + ) -> ClientResult> { + self.send(RpcRequest::GetRecentPerformanceSamples, json!([limit])) + } + pub fn get_identity(&self) -> ClientResult { let rpc_identity: RpcIdentity = self.send(RpcRequest::GetIdentity, Value::Null)?; diff --git a/client/src/rpc_request.rs b/client/src/rpc_request.rs index 9a8ec8ba43..5a73e427fb 100644 --- a/client/src/rpc_request.rs +++ b/client/src/rpc_request.rs @@ -34,6 +34,7 @@ pub enum RpcRequest { GetMultipleAccounts, GetProgramAccounts, GetRecentBlockhash, + GetRecentPerformanceSamples, GetSnapshotSlot, GetSignatureStatuses, GetSlot, @@ -90,6 +91,7 @@ impl fmt::Display for RpcRequest { RpcRequest::GetMultipleAccounts => "getMultipleAccounts", RpcRequest::GetProgramAccounts => "getProgramAccounts", RpcRequest::GetRecentBlockhash => "getRecentBlockhash", + RpcRequest::GetRecentPerformanceSamples => "getRecentPerformanceSamples", RpcRequest::GetSnapshotSlot => "getSnapshotSlot", RpcRequest::GetSignatureStatuses => "getSignatureStatuses", RpcRequest::GetSlot => "getSlot",