From 6ff2a0a75e4b54e6844e8a3b282ea5ab158416c1 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 1 Apr 2019 17:11:42 -0600 Subject: [PATCH] Rework discover to handle additional parameters, and be unit-testable --- bench-tps/src/bench.rs | 4 +- book/src/cluster-test-framework.md | 6 +- core/src/cluster_tests.rs | 8 +- core/src/gossip_service.rs | 149 +++++++++++++++++++++++------ core/src/local_cluster.rs | 6 +- core/src/replicator.rs | 2 +- core/tests/local_cluster.rs | 4 +- core/tests/replicator.rs | 6 +- tests/thin_client.rs | 10 +- 9 files changed, 145 insertions(+), 50 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 0c93472b0..7d93196a7 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -5,7 +5,7 @@ use rayon::prelude::*; use solana::cluster_info::FULLNODE_PORT_RANGE; use solana::contact_info::ContactInfo; use solana::gen_keys::GenKeys; -use solana::gossip_service::discover; +use solana::gossip_service::discover_nodes; use solana_client::thin_client::create_client; use solana_client::thin_client::ThinClient; use solana_drone::drone::request_airdrop_transaction; @@ -55,7 +55,7 @@ pub fn do_bench_tps(config: Config) { converge_only, } = config; - let nodes = discover(&network, num_nodes).unwrap_or_else(|err| { + let nodes = discover_nodes(&network, num_nodes).unwrap_or_else(|err| { eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err); exit(1); }); diff --git a/book/src/cluster-test-framework.md b/book/src/cluster-test-framework.md index 1cb9fad3c..36e903813 100644 --- a/book/src/cluster-test-framework.md +++ b/book/src/cluster-test-framework.md @@ -51,10 +51,10 @@ At test start, the cluster has already been established and is fully connected. The test can discover most of the available nodes over a few second. ```rust,ignore -use crate::gossip_service::discover; +use crate::gossip_service::discover_nodes; // Discover the cluster over a few seconds. -let cluster_nodes = discover(&entry_point_info, num_nodes); +let cluster_nodes = discover_nodes(&entry_point_info, num_nodes); ``` ## Cluster Configuration @@ -99,7 +99,7 @@ pub fn test_large_invalid_gossip_nodes( funding_keypair: &Keypair, num_nodes: usize, ) { - let cluster = discover(&entry_point_info, num_nodes); + let cluster = discover_nodes(&entry_point_info, num_nodes); // Poison the cluster. let client = create_client(entry_point_info.client_facing_addr(), FULLNODE_PORT_RANGE); diff --git a/core/src/cluster_tests.rs b/core/src/cluster_tests.rs index 577bc563e..54b530441 100644 --- a/core/src/cluster_tests.rs +++ b/core/src/cluster_tests.rs @@ -6,7 +6,7 @@ use crate::blocktree::Blocktree; use crate::cluster_info::FULLNODE_PORT_RANGE; use crate::contact_info::ContactInfo; use crate::entry::{Entry, EntrySlice}; -use crate::gossip_service::discover; +use crate::gossip_service::discover_nodes; use crate::locktower::VOTE_THRESHOLD_DEPTH; use crate::poh_service::PohServiceConfig; use solana_client::thin_client::create_client; @@ -28,7 +28,7 @@ pub fn spend_and_verify_all_nodes( funding_keypair: &Keypair, nodes: usize, ) { - let cluster_nodes = discover(&entry_point_info.gossip, nodes).unwrap(); + let cluster_nodes = discover_nodes(&entry_point_info.gossip, nodes).unwrap(); assert!(cluster_nodes.len() >= nodes); for ingress_node in &cluster_nodes { let random_keypair = Keypair::new(); @@ -77,7 +77,7 @@ pub fn send_many_transactions(node: &ContactInfo, funding_keypair: &Keypair, num } pub fn fullnode_exit(entry_point_info: &ContactInfo, nodes: usize) { - let cluster_nodes = discover(&entry_point_info.gossip, nodes).unwrap(); + let cluster_nodes = discover_nodes(&entry_point_info.gossip, nodes).unwrap(); assert!(cluster_nodes.len() >= nodes); for node in &cluster_nodes { let client = create_client(node.client_facing_addr(), FULLNODE_PORT_RANGE); @@ -148,7 +148,7 @@ pub fn kill_entry_and_spend_and_verify_rest( nodes: usize, ) { solana_logger::setup(); - let cluster_nodes = discover(&entry_point_info.gossip, nodes).unwrap(); + let cluster_nodes = discover_nodes(&entry_point_info.gossip, nodes).unwrap(); assert!(cluster_nodes.len() >= nodes); let client = create_client(entry_point_info.client_facing_addr(), FULLNODE_PORT_RANGE); info!("sleeping for 2 leader fortnights"); diff --git a/core/src/gossip_service.rs b/core/src/gossip_service.rs index 18e2335d2..9b219a185 100644 --- a/core/src/gossip_service.rs +++ b/core/src/gossip_service.rs @@ -6,6 +6,7 @@ use crate::cluster_info::ClusterInfo; use crate::contact_info::ContactInfo; use crate::service::Service; use crate::streamer; +use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::{Keypair, KeypairUtil}; use std::net::SocketAddr; use std::net::UdpSocket; @@ -51,31 +52,95 @@ impl GossipService { } } -pub fn discover(gossip_addr: &SocketAddr, num_nodes: usize) -> std::io::Result> { +pub fn discover_nodes( + gossip_addr: &SocketAddr, + num_nodes: usize, +) -> std::io::Result> { + discover(gossip_addr, Some(num_nodes), Some(30), None) +} + +pub fn discover( + gossip_addr: &SocketAddr, + num_nodes: Option, + timeout: Option, + find_node: Option, +) -> std::io::Result> { let exit = Arc::new(AtomicBool::new(false)); let (gossip_service, spy_ref) = make_spy_node(gossip_addr, &exit); let id = spy_ref.read().unwrap().keypair.pubkey(); trace!( - "discover: spy_node {} looking for at least {} nodes", + "discover: spy_node {} looking for at least {:?} nodes", id, num_nodes ); - // Wait for the cluster to converge - let now = Instant::now(); - let mut i = 0; - while now.elapsed() < Duration::from_secs(30) { - let tvu_peers = spy_ref.read().unwrap().tvu_peers(); - if tvu_peers.len() >= num_nodes { - info!( - "discover success in {}s...\n{}", - now.elapsed().as_secs(), - spy_ref.read().unwrap().contact_info_trace() - ); + let (met_criteria, secs, tvu_peers) = spy(spy_ref.clone(), num_nodes, timeout, find_node); - exit.store(true, Ordering::Relaxed); - gossip_service.join().unwrap(); - return Ok(tvu_peers); + exit.store(true, Ordering::Relaxed); + gossip_service.join().unwrap(); + + if met_criteria { + info!( + "discover success in {}s...\n{}", + secs, + spy_ref.read().unwrap().contact_info_trace() + ); + return Ok(tvu_peers); + } + + if !tvu_peers.is_empty() { + info!( + "discover failed to match criteria by timeout...\n{}", + spy_ref.read().unwrap().contact_info_trace() + ); + return Ok(tvu_peers); + } + + info!( + "discover failed...\n{}", + spy_ref.read().unwrap().contact_info_trace() + ); + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Failed to converge", + )) +} + +fn spy( + spy_ref: Arc>, + num_nodes: Option, + timeout: Option, + find_node: Option, +) -> (bool, u64, Vec) { + let now = Instant::now(); + let mut met_criteria = false; + let mut tvu_peers: Vec = Vec::new(); + let mut i = 0; + loop { + if let Some(secs) = timeout { + if now.elapsed() >= Duration::from_secs(secs) { + break; + } + } + tvu_peers = spy_ref.read().unwrap().tvu_peers(); + if let Some(num) = num_nodes { + if tvu_peers.len() >= num { + if let Some(pubkey) = find_node { + if tvu_peers.iter().any(|x| x.id == pubkey) { + met_criteria = true; + break; + } + } else { + met_criteria = true; + break; + } + } + } + if let Some(pubkey) = find_node { + if num_nodes.is_none() && tvu_peers.iter().any(|x| x.id == pubkey) { + met_criteria = true; + break; + } } if i % 20 == 0 { info!( @@ -88,17 +153,7 @@ pub fn discover(gossip_addr: &SocketAddr, num_nodes: usize) -> std::io::Result= 2); let leader_id = cluster.entry_point_info.id; diff --git a/core/tests/replicator.rs b/core/tests/replicator.rs index 2b0706784..3fe819ad1 100644 --- a/core/tests/replicator.rs +++ b/core/tests/replicator.rs @@ -9,7 +9,7 @@ use solana::blocktree::{create_new_tmp_ledger, Blocktree}; use solana::cluster_info::{ClusterInfo, Node, FULLNODE_PORT_RANGE}; use solana::contact_info::ContactInfo; use solana::fullnode::FullnodeConfig; -use solana::gossip_service::discover; +use solana::gossip_service::discover_nodes; use solana::local_cluster::LocalCluster; use solana::replicator::Replicator; use solana::replicator::ReplicatorRequest; @@ -116,7 +116,7 @@ fn run_replicator_startup_basic(num_nodes: usize, num_replicators: usize) { DEFAULT_SLOTS_PER_EPOCH, ); - let cluster_nodes = discover( + let cluster_nodes = discover_nodes( &cluster.entry_point_info.gossip, num_nodes + num_replicators, ) @@ -230,7 +230,7 @@ fn test_account_setup() { DEFAULT_SLOTS_PER_EPOCH, ); - let _ = discover( + let _ = discover_nodes( &cluster.entry_point_info.gossip, num_nodes + num_replicators, ) diff --git a/tests/thin_client.rs b/tests/thin_client.rs index a88466a9b..f1e746f41 100644 --- a/tests/thin_client.rs +++ b/tests/thin_client.rs @@ -2,7 +2,7 @@ use bincode::{deserialize, serialize}; use log::*; use solana::cluster_info::FULLNODE_PORT_RANGE; use solana::fullnode::new_fullnode_for_tests; -use solana::gossip_service::discover; +use solana::gossip_service::discover_nodes; use solana_client::thin_client::create_client; use solana_client::thin_client::ThinClient; use solana_logger; @@ -41,7 +41,7 @@ fn test_thin_client_basic() { solana_logger::setup(); let (server, leader_data, alice, ledger_path) = new_fullnode_for_tests(); let bob_pubkey = Pubkey::new_rand(); - discover(&leader_data.gossip, 1).unwrap(); + discover_nodes(&leader_data.gossip, 1).unwrap(); let client = create_client(leader_data.client_facing_addr(), FULLNODE_PORT_RANGE); @@ -70,7 +70,7 @@ fn test_bad_sig() { solana_logger::setup(); let (server, leader_data, alice, ledger_path) = new_fullnode_for_tests(); let bob_pubkey = Pubkey::new_rand(); - discover(&leader_data.gossip, 1).unwrap(); + discover_nodes(&leader_data.gossip, 1).unwrap(); let client = create_client(leader_data.client_facing_addr(), FULLNODE_PORT_RANGE); @@ -101,7 +101,7 @@ fn test_bad_sig() { fn test_register_vote_account() { solana_logger::setup(); let (server, leader_data, alice, ledger_path) = new_fullnode_for_tests(); - discover(&leader_data.gossip, 1).unwrap(); + discover_nodes(&leader_data.gossip, 1).unwrap(); let client = create_client(leader_data.client_facing_addr(), FULLNODE_PORT_RANGE); @@ -178,7 +178,7 @@ fn test_zero_balance_after_nonzero() { solana_logger::setup(); let (server, leader_data, alice, ledger_path) = new_fullnode_for_tests(); let bob_keypair = Keypair::new(); - discover(&leader_data.gossip, 1).unwrap(); + discover_nodes(&leader_data.gossip, 1).unwrap(); let client = create_client(leader_data.client_facing_addr(), FULLNODE_PORT_RANGE); let blockhash = client.get_recent_blockhash().unwrap();