diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 82000bc73..a4ecc937a 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -84,6 +84,7 @@ pub enum CliCommand { timeout: Duration, commitment_config: CommitmentConfig, }, + ShowGossip, ShowValidators { use_lamports_unit: bool, }, @@ -264,6 +265,10 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result parse_cluster_ping(matches), + ("show-gossip", Some(_matches)) => Ok(CliCommandInfo { + command: CliCommand::ShowGossip, + require_keypair: false, + }), ("show-validators", Some(matches)) => parse_show_validators(matches), // Program Deployment ("deploy", Some(matches)) => Ok(CliCommandInfo { @@ -871,6 +876,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { timeout, commitment_config, ), + CliCommand::ShowGossip => process_show_gossip(&rpc_client), CliCommand::ShowValidators { use_lamports_unit } => { process_show_validators(&rpc_client, *use_lamports_unit) } diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 4c442f68f..c3278234a 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -20,6 +20,7 @@ use solana_sdk::{ }; use std::{ collections::VecDeque, + net::SocketAddr, thread::sleep, time::{Duration, Instant}, }; @@ -101,6 +102,10 @@ impl ClusterQuerySubCommands for App<'_, '_> { ), ), ) + .subcommand( + SubCommand::with_name("show-gossip") + .about("Show the current gossip network nodes"), + ) .subcommand( SubCommand::with_name("show-validators") .about("Show information about the current validators") @@ -400,6 +405,42 @@ pub fn process_ping( Ok("".to_string()) } +pub fn process_show_gossip(rpc_client: &RpcClient) -> ProcessResult { + let cluster_nodes = rpc_client.get_cluster_nodes()?; + + fn format_port(addr: Option) -> String { + addr.map(|addr| addr.port().to_string()) + .unwrap_or_else(|| "none".to_string()) + } + + let s: Vec<_> = cluster_nodes + .iter() + .map(|node| { + format!( + "{:15} | {:44} | {:6} | {:5} | {:5}", + node.gossip + .map(|addr| addr.ip().to_string()) + .unwrap_or_else(|| "none".to_string()), + node.pubkey, + format_port(node.gossip), + format_port(node.tpu), + format_port(node.rpc), + ) + }) + .collect(); + + Ok(format!( + "IP Address | Node identifier \ + | Gossip | TPU | RPC\n\ + ----------------+----------------------------------------------+\ + --------+-------+-------\n\ + {}\n\ + Nodes: {}", + s.join("\n"), + s.len(), + )) +} + pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) -> ProcessResult { let vote_accounts = rpc_client.get_vote_accounts()?; let total_active_stake = vote_accounts