|solana-gossip spy| no longer requires an entrypoint (#6999)
This commit is contained in:
parent
70322d1ff8
commit
c3926e6af0
|
@ -324,7 +324,7 @@ while [[ $iteration -le $iterations ]]; do
|
||||||
set -x
|
set -x
|
||||||
client_keypair=/tmp/client-id.json-$$
|
client_keypair=/tmp/client-id.json-$$
|
||||||
$solana_keygen new -f -o $client_keypair || exit $?
|
$solana_keygen new -f -o $client_keypair || exit $?
|
||||||
$solana_gossip spy --num-nodes-exactly $numNodes || exit $?
|
$solana_gossip spy -n 127.0.0.1:8001 --num-nodes-exactly $numNodes || exit $?
|
||||||
rm -rf $client_keypair
|
rm -rf $client_keypair
|
||||||
) || flag_error
|
) || flag_error
|
||||||
|
|
||||||
|
|
|
@ -68,26 +68,36 @@ impl GossipService {
|
||||||
|
|
||||||
/// Discover Nodes and Archivers in a cluster
|
/// Discover Nodes and Archivers in a cluster
|
||||||
pub fn discover_cluster(
|
pub fn discover_cluster(
|
||||||
entry_point: &SocketAddr,
|
entrypoint: &SocketAddr,
|
||||||
num_nodes: usize,
|
num_nodes: usize,
|
||||||
) -> std::io::Result<(Vec<ContactInfo>, Vec<ContactInfo>)> {
|
) -> std::io::Result<(Vec<ContactInfo>, Vec<ContactInfo>)> {
|
||||||
discover(entry_point, Some(num_nodes), Some(30), None, None, None)
|
discover(
|
||||||
|
Some(entrypoint),
|
||||||
|
Some(num_nodes),
|
||||||
|
Some(30),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discover(
|
pub fn discover(
|
||||||
entry_point: &SocketAddr,
|
entrypoint: Option<&SocketAddr>,
|
||||||
num_nodes: Option<usize>,
|
num_nodes: Option<usize>,
|
||||||
timeout: Option<u64>,
|
timeout: Option<u64>,
|
||||||
find_node_by_pubkey: Option<Pubkey>,
|
find_node_by_pubkey: Option<Pubkey>,
|
||||||
find_node_by_gossip_addr: Option<SocketAddr>,
|
find_node_by_gossip_addr: Option<&SocketAddr>,
|
||||||
my_gossip_addr: Option<&SocketAddr>,
|
my_gossip_addr: Option<&SocketAddr>,
|
||||||
) -> std::io::Result<(Vec<ContactInfo>, Vec<ContactInfo>)> {
|
) -> std::io::Result<(Vec<ContactInfo>, Vec<ContactInfo>)> {
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let (gossip_service, ip_echo, spy_ref) = make_gossip_node(entry_point, &exit, my_gossip_addr);
|
let (gossip_service, ip_echo, spy_ref) = make_gossip_node(entrypoint, &exit, my_gossip_addr);
|
||||||
|
|
||||||
let id = spy_ref.read().unwrap().keypair.pubkey();
|
let id = spy_ref.read().unwrap().keypair.pubkey();
|
||||||
info!("Gossip entry point: {:?}", entry_point);
|
info!("Entrypoint: {:?}", entrypoint);
|
||||||
info!("Spy node id: {:?}", id);
|
info!("Node Id: {:?}", id);
|
||||||
|
if let Some(my_gossip_addr) = my_gossip_addr {
|
||||||
|
info!("Gossip Address: {:?}", my_gossip_addr);
|
||||||
|
}
|
||||||
|
|
||||||
let _ip_echo_server = ip_echo.map(solana_net_utils::ip_echo_server);
|
let _ip_echo_server = ip_echo.map(solana_net_utils::ip_echo_server);
|
||||||
|
|
||||||
|
@ -169,7 +179,7 @@ fn spy(
|
||||||
num_nodes: Option<usize>,
|
num_nodes: Option<usize>,
|
||||||
timeout: Option<u64>,
|
timeout: Option<u64>,
|
||||||
find_node_by_pubkey: Option<Pubkey>,
|
find_node_by_pubkey: Option<Pubkey>,
|
||||||
find_node_by_gossip_addr: Option<SocketAddr>,
|
find_node_by_gossip_addr: Option<&SocketAddr>,
|
||||||
) -> (bool, u64, Vec<ContactInfo>, Vec<ContactInfo>) {
|
) -> (bool, u64, Vec<ContactInfo>, Vec<ContactInfo>) {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let mut met_criteria = false;
|
let mut met_criteria = false;
|
||||||
|
@ -198,7 +208,7 @@ fn spy(
|
||||||
if tvu_peers
|
if tvu_peers
|
||||||
.iter()
|
.iter()
|
||||||
.chain(archivers.iter())
|
.chain(archivers.iter())
|
||||||
.any(|x| x.gossip == gossip_addr)
|
.any(|x| x.gossip == *gossip_addr)
|
||||||
{
|
{
|
||||||
met_criteria = true;
|
met_criteria = true;
|
||||||
break;
|
break;
|
||||||
|
@ -235,7 +245,7 @@ fn spy(
|
||||||
if tvu_peers
|
if tvu_peers
|
||||||
.iter()
|
.iter()
|
||||||
.chain(archivers.iter())
|
.chain(archivers.iter())
|
||||||
.any(|x| x.gossip == gossip_addr)
|
.any(|x| x.gossip == *gossip_addr)
|
||||||
{
|
{
|
||||||
met_criteria = true;
|
met_criteria = true;
|
||||||
break;
|
break;
|
||||||
|
@ -259,7 +269,7 @@ fn spy(
|
||||||
/// Makes a spy or gossip node based on whether or not a gossip_addr was passed in
|
/// Makes a spy or gossip node based on whether or not a gossip_addr was passed in
|
||||||
/// Pass in a gossip addr to fully participate in gossip instead of relying on just pulls
|
/// Pass in a gossip addr to fully participate in gossip instead of relying on just pulls
|
||||||
fn make_gossip_node(
|
fn make_gossip_node(
|
||||||
entry_point: &SocketAddr,
|
entrypoint: Option<&SocketAddr>,
|
||||||
exit: &Arc<AtomicBool>,
|
exit: &Arc<AtomicBool>,
|
||||||
gossip_addr: Option<&SocketAddr>,
|
gossip_addr: Option<&SocketAddr>,
|
||||||
) -> (GossipService, Option<TcpListener>, Arc<RwLock<ClusterInfo>>) {
|
) -> (GossipService, Option<TcpListener>, Arc<RwLock<ClusterInfo>>) {
|
||||||
|
@ -270,7 +280,9 @@ fn make_gossip_node(
|
||||||
ClusterInfo::spy_node(&keypair.pubkey())
|
ClusterInfo::spy_node(&keypair.pubkey())
|
||||||
};
|
};
|
||||||
let mut cluster_info = ClusterInfo::new(node, keypair);
|
let mut cluster_info = ClusterInfo::new(node, keypair);
|
||||||
cluster_info.set_entrypoint(ContactInfo::new_gossip_entry_point(entry_point));
|
if let Some(entrypoint) = entrypoint {
|
||||||
|
cluster_info.set_entrypoint(ContactInfo::new_gossip_entry_point(entrypoint));
|
||||||
|
}
|
||||||
let cluster_info = Arc::new(RwLock::new(cluster_info));
|
let cluster_info = Arc::new(RwLock::new(cluster_info));
|
||||||
let gossip_service =
|
let gossip_service =
|
||||||
GossipService::new(&cluster_info.clone(), None, None, gossip_socket, &exit);
|
GossipService::new(&cluster_info.clone(), None, None, gossip_socket, &exit);
|
||||||
|
@ -350,14 +362,15 @@ mod tests {
|
||||||
|
|
||||||
// Find specific node by gossip address
|
// Find specific node by gossip address
|
||||||
let (met_criteria, _, _, _) =
|
let (met_criteria, _, _, _) =
|
||||||
spy(spy_ref.clone(), None, None, None, Some(peer0_info.gossip));
|
spy(spy_ref.clone(), None, None, None, Some(&peer0_info.gossip));
|
||||||
assert_eq!(met_criteria, true);
|
assert_eq!(met_criteria, true);
|
||||||
|
|
||||||
let (met_criteria, _, _, _) = spy(
|
let (met_criteria, _, _, _) = spy(
|
||||||
spy_ref.clone(),
|
spy_ref.clone(),
|
||||||
None,
|
None,
|
||||||
Some(0),
|
Some(0),
|
||||||
None,
|
None,
|
||||||
Some("1.1.1.1:1234".parse().unwrap()),
|
Some(&"1.1.1.1:1234".parse().unwrap()),
|
||||||
);
|
);
|
||||||
assert_eq!(met_criteria, false);
|
assert_eq!(met_criteria, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
//! A command-line executable for monitoring a cluster's gossip plane.
|
//! A command-line executable for monitoring a cluster's gossip plane.
|
||||||
|
|
||||||
use clap::{crate_description, crate_name, value_t_or_exit, App, AppSettings, Arg, SubCommand};
|
use clap::{
|
||||||
|
crate_description, crate_name, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand,
|
||||||
|
};
|
||||||
use solana_clap_utils::input_validators::is_pubkey;
|
use solana_clap_utils::input_validators::is_pubkey;
|
||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::rpc_client::RpcClient;
|
||||||
use solana_core::{contact_info::ContactInfo, gossip_service::discover};
|
use solana_core::{contact_info::ContactInfo, gossip_service::discover, socketaddr};
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
@ -12,26 +14,23 @@ use std::process::exit;
|
||||||
fn main() -> Result<(), Box<dyn error::Error>> {
|
fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
solana_logger::setup_with_filter("solana=info");
|
solana_logger::setup_with_filter("solana=info");
|
||||||
|
|
||||||
let mut entrypoint_addr = SocketAddr::from(([127, 0, 0, 1], 8001));
|
|
||||||
let entrypoint_string = entrypoint_addr.to_string();
|
|
||||||
let matches = App::new(crate_name!())
|
let matches = App::new(crate_name!())
|
||||||
.about(crate_description!())
|
.about(crate_description!())
|
||||||
.version(solana_clap_utils::version!())
|
.version(solana_clap_utils::version!())
|
||||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("get-rpc-url")
|
||||||
|
.about("Get an RPC URL for the cluster")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("entrypoint")
|
Arg::with_name("entrypoint")
|
||||||
.short("n")
|
.short("n")
|
||||||
.long("entrypoint")
|
.long("entrypoint")
|
||||||
.value_name("HOST:PORT")
|
.value_name("HOST:PORT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.default_value(&entrypoint_string)
|
.required(true)
|
||||||
.validator(solana_net_utils::is_host_port)
|
.validator(solana_net_utils::is_host_port)
|
||||||
.global(true)
|
|
||||||
.help("Rendezvous with the cluster at this entry point"),
|
.help("Rendezvous with the cluster at this entry point"),
|
||||||
)
|
)
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("get-rpc-url")
|
|
||||||
.about("Get an RPC URL for the cluster")
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("all")
|
Arg::with_name("all")
|
||||||
.long("all")
|
.long("all")
|
||||||
|
@ -52,12 +51,21 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
SubCommand::with_name("spy")
|
SubCommand::with_name("spy")
|
||||||
.about("Monitor the gossip entrypoint")
|
.about("Monitor the gossip entrypoint")
|
||||||
.setting(AppSettings::DisableVersion)
|
.setting(AppSettings::DisableVersion)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("entrypoint")
|
||||||
|
.short("n")
|
||||||
|
.long("entrypoint")
|
||||||
|
.value_name("HOST:PORT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required_unless("gossip_port")
|
||||||
|
.validator(solana_net_utils::is_host_port)
|
||||||
|
.help("Rendezvous with the cluster at this entry point"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("gossip_port")
|
clap::Arg::with_name("gossip_port")
|
||||||
.long("gossip-port")
|
.long("gossip-port")
|
||||||
.value_name("PORT")
|
.value_name("HOST:PORT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.default_value("0")
|
|
||||||
.help("Gossip port number for the node"),
|
.help("Gossip port number for the node"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -98,6 +106,16 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
SubCommand::with_name("stop")
|
SubCommand::with_name("stop")
|
||||||
.about("Send stop request to a node")
|
.about("Send stop request to a node")
|
||||||
.setting(AppSettings::DisableVersion)
|
.setting(AppSettings::DisableVersion)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("entrypoint")
|
||||||
|
.short("n")
|
||||||
|
.long("entrypoint")
|
||||||
|
.value_name("HOST:PORT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(solana_net_utils::is_host_port)
|
||||||
|
.help("Rendezvous with the cluster at this entry point"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("node_pubkey")
|
Arg::with_name("node_pubkey")
|
||||||
.index(1)
|
.index(1)
|
||||||
|
@ -109,11 +127,13 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
if let Some(addr) = matches.value_of("entrypoint") {
|
fn parse_entrypoint(matches: &ArgMatches) -> Option<SocketAddr> {
|
||||||
entrypoint_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
|
matches.value_of("entrypoint").map(|entrypoint| {
|
||||||
|
solana_net_utils::parse_host_port(entrypoint).unwrap_or_else(|e| {
|
||||||
eprintln!("failed to parse entrypoint address: {}", e);
|
eprintln!("failed to parse entrypoint address: {}", e);
|
||||||
exit(1);
|
exit(1);
|
||||||
});
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
|
@ -132,16 +152,30 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
.value_of("node_pubkey")
|
.value_of("node_pubkey")
|
||||||
.map(|pubkey_str| pubkey_str.parse::<Pubkey>().unwrap());
|
.map(|pubkey_str| pubkey_str.parse::<Pubkey>().unwrap());
|
||||||
|
|
||||||
let gossip_addr = SocketAddr::new(
|
let mut gossip_addr = solana_net_utils::parse_port_or_addr(
|
||||||
solana_net_utils::get_public_ip_addr(&entrypoint_addr).unwrap_or_else(|err| {
|
matches.value_of("gossip_port"),
|
||||||
eprintln!("failed to contact {}: {}", entrypoint_addr, err);
|
socketaddr!(
|
||||||
exit(1);
|
[127, 0, 0, 1],
|
||||||
}),
|
solana_net_utils::find_available_port_in_range((0, 1))
|
||||||
value_t_or_exit!(matches, "gossip_port", u16),
|
.expect("unable to find an available gossip port")
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let entrypoint_addr = parse_entrypoint(&matches);
|
||||||
|
if let Some(entrypoint_addr) = entrypoint_addr {
|
||||||
|
gossip_addr.set_ip(
|
||||||
|
solana_net_utils::get_public_ip_addr(&entrypoint_addr).unwrap_or_else(|err| {
|
||||||
|
eprintln!(
|
||||||
|
"Failed to contact cluster entrypoint {}: {}",
|
||||||
|
entrypoint_addr, err
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let (nodes, _archivers) = discover(
|
let (nodes, _archivers) = discover(
|
||||||
&entrypoint_addr,
|
entrypoint_addr.as_ref(),
|
||||||
num_nodes,
|
num_nodes,
|
||||||
timeout,
|
timeout,
|
||||||
pubkey,
|
pubkey,
|
||||||
|
@ -182,20 +216,21 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("get-rpc-url", Some(matches)) => {
|
("get-rpc-url", Some(matches)) => {
|
||||||
|
let entrypoint_addr = parse_entrypoint(&matches);
|
||||||
let timeout = value_t_or_exit!(matches, "timeout", u64);
|
let timeout = value_t_or_exit!(matches, "timeout", u64);
|
||||||
let (nodes, _archivers) = discover(
|
let (nodes, _archivers) = discover(
|
||||||
&entrypoint_addr,
|
entrypoint_addr.as_ref(),
|
||||||
Some(1),
|
Some(1),
|
||||||
Some(timeout),
|
Some(timeout),
|
||||||
None,
|
None,
|
||||||
Some(entrypoint_addr),
|
entrypoint_addr.as_ref(),
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let rpc_addrs: Vec<_> = nodes
|
let rpc_addrs: Vec<_> = nodes
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|contact_info| {
|
.filter_map(|contact_info| {
|
||||||
if (matches.is_present("all") || contact_info.gossip == entrypoint_addr)
|
if (matches.is_present("all") || Some(contact_info.gossip) == entrypoint_addr)
|
||||||
&& ContactInfo::is_valid_address(&contact_info.rpc)
|
&& ContactInfo::is_valid_address(&contact_info.rpc)
|
||||||
{
|
{
|
||||||
return Some(contact_info.rpc);
|
return Some(contact_info.rpc);
|
||||||
|
@ -214,13 +249,20 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("stop", Some(matches)) => {
|
("stop", Some(matches)) => {
|
||||||
|
let entrypoint_addr = parse_entrypoint(&matches);
|
||||||
let pubkey = matches
|
let pubkey = matches
|
||||||
.value_of("node_pubkey")
|
.value_of("node_pubkey")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse::<Pubkey>()
|
.parse::<Pubkey>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (nodes, _archivers) =
|
let (nodes, _archivers) = discover(
|
||||||
discover(&entrypoint_addr, None, None, Some(pubkey), None, None)?;
|
entrypoint_addr.as_ref(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Some(pubkey),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
let node = nodes.iter().find(|x| x.id == pubkey).unwrap();
|
let node = nodes.iter().find(|x| x.id == pubkey).unwrap();
|
||||||
|
|
||||||
if !ContactInfo::is_valid_address(&node.rpc) {
|
if !ContactInfo::is_valid_address(&node.rpc) {
|
||||||
|
|
|
@ -172,11 +172,11 @@ fn create_rpc_client(
|
||||||
entrypoint: &ContactInfo,
|
entrypoint: &ContactInfo,
|
||||||
) -> Result<(std::net::SocketAddr, RpcClient), String> {
|
) -> Result<(std::net::SocketAddr, RpcClient), String> {
|
||||||
let (nodes, _archivers) = discover(
|
let (nodes, _archivers) = discover(
|
||||||
&entrypoint.gossip,
|
Some(&entrypoint.gossip),
|
||||||
Some(1),
|
Some(1),
|
||||||
Some(60),
|
Some(60),
|
||||||
None,
|
None,
|
||||||
Some(entrypoint.gossip),
|
Some(&entrypoint.gossip),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.to_string())?;
|
.map_err(|err| err.to_string())?;
|
||||||
|
|
Loading…
Reference in New Issue