Add port and gossip options to solana-test-validator (#16696)

This commit is contained in:
Tyera Eulberg 2021-04-20 20:40:52 -06:00 committed by GitHub
parent 9852572eb9
commit 0924c2d070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 198 additions and 22 deletions

View File

@ -3358,6 +3358,7 @@ impl Node {
},
}
}
fn get_gossip_port(
gossip_addr: &SocketAddr,
port_range: PortRange,
@ -3378,6 +3379,60 @@ impl Node {
bind_in_range(bind_ip_addr, port_range).expect("Failed to bind")
}
pub fn new_single_bind(
pubkey: &Pubkey,
gossip_addr: &SocketAddr,
port_range: PortRange,
bind_ip_addr: IpAddr,
) -> Self {
let (gossip_port, (gossip, ip_echo)) =
Self::get_gossip_port(gossip_addr, port_range, bind_ip_addr);
let (tvu_port, tvu) = Self::bind(bind_ip_addr, port_range);
let (tvu_forwards_port, tvu_forwards) = Self::bind(bind_ip_addr, port_range);
let (tpu_port, tpu) = Self::bind(bind_ip_addr, port_range);
let (tpu_forwards_port, tpu_forwards) = Self::bind(bind_ip_addr, port_range);
let (_, retransmit_socket) = Self::bind(bind_ip_addr, port_range);
let (repair_port, repair) = Self::bind(bind_ip_addr, port_range);
let (serve_repair_port, serve_repair) = Self::bind(bind_ip_addr, port_range);
let (_, broadcast) = Self::bind(bind_ip_addr, port_range);
let rpc_port = find_available_port_in_range(bind_ip_addr, port_range).unwrap();
let rpc_pubsub_port = find_available_port_in_range(bind_ip_addr, port_range).unwrap();
let info = ContactInfo {
id: *pubkey,
gossip: SocketAddr::new(gossip_addr.ip(), gossip_port),
tvu: SocketAddr::new(gossip_addr.ip(), tvu_port),
tvu_forwards: SocketAddr::new(gossip_addr.ip(), tvu_forwards_port),
repair: SocketAddr::new(gossip_addr.ip(), repair_port),
tpu: SocketAddr::new(gossip_addr.ip(), tpu_port),
tpu_forwards: SocketAddr::new(gossip_addr.ip(), tpu_forwards_port),
unused: socketaddr_any!(),
rpc: SocketAddr::new(gossip_addr.ip(), rpc_port),
rpc_pubsub: SocketAddr::new(gossip_addr.ip(), rpc_pubsub_port),
serve_repair: SocketAddr::new(gossip_addr.ip(), serve_repair_port),
wallclock: timestamp(),
shred_version: 0,
};
trace!("new ContactInfo: {:?}", info);
Node {
info,
sockets: Sockets {
gossip,
ip_echo: Some(ip_echo),
tvu: vec![tvu],
tvu_forwards: vec![tvu_forwards],
tpu: vec![tpu],
tpu_forwards: vec![tpu_forwards],
broadcast: vec![broadcast],
repair,
retransmit_sockets: vec![retransmit_socket],
serve_repair,
},
}
}
pub fn new_with_external_ip(
pubkey: &Pubkey,
gossip_addr: &SocketAddr,

View File

@ -7,6 +7,7 @@ use {
},
solana_client::rpc_client::RpcClient,
solana_ledger::{blockstore::create_new_ledger, create_new_tmp_ledger},
solana_net_utils::PortRange,
solana_runtime::{
bank_forks::{ArchiveFormat, SnapshotConfig, SnapshotVersion},
genesis_utils::create_genesis_config_with_leader_ex,
@ -42,6 +43,29 @@ pub struct ProgramInfo {
pub program_path: PathBuf,
}
#[derive(Debug)]
pub struct TestValidatorNodeConfig {
gossip_addr: SocketAddr,
port_range: PortRange,
bind_ip_addr: IpAddr,
}
impl Default for TestValidatorNodeConfig {
fn default() -> Self {
const MIN_PORT_RANGE: u16 = 1024;
const MAX_PORT_RANGE: u16 = 65535;
let bind_ip_addr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
let port_range = (MIN_PORT_RANGE, MAX_PORT_RANGE);
Self {
gossip_addr: socketaddr!("127.0.0.1:0"),
port_range,
bind_ip_addr,
}
}
}
#[derive(Default)]
pub struct TestValidatorGenesis {
fee_rate_governor: FeeRateGovernor,
@ -54,6 +78,7 @@ pub struct TestValidatorGenesis {
accounts: HashMap<Pubkey, AccountSharedData>,
programs: Vec<ProgramInfo>,
epoch_schedule: Option<EpochSchedule>,
node_config: TestValidatorNodeConfig,
pub validator_exit: Arc<RwLock<ValidatorExit>>,
pub start_progress: Arc<RwLock<ValidatorStartProgress>>,
pub authorized_voter_keypairs: Arc<RwLock<Vec<Arc<Keypair>>>>,
@ -110,6 +135,26 @@ impl TestValidatorGenesis {
self
}
pub fn gossip_host(&mut self, gossip_host: IpAddr) -> &mut Self {
self.node_config.gossip_addr.set_ip(gossip_host);
self
}
pub fn gossip_port(&mut self, gossip_port: u16) -> &mut Self {
self.node_config.gossip_addr.set_port(gossip_port);
self
}
pub fn port_range(&mut self, port_range: PortRange) -> &mut Self {
self.node_config.port_range = port_range;
self
}
pub fn bind_ip_addr(&mut self, bind_ip_addr: IpAddr) -> &mut Self {
self.node_config.bind_ip_addr = bind_ip_addr;
self
}
/// Add an account to the test environment
pub fn add_account(&mut self, address: Pubkey, account: AccountSharedData) -> &mut Self {
self.accounts.insert(address, account);
@ -398,7 +443,12 @@ impl TestValidator {
.unwrap(),
)?;
let mut node = Node::new_localhost_with_pubkey(&validator_identity.pubkey());
let mut node = Node::new_single_bind(
&validator_identity.pubkey(),
&config.node_config.gossip_addr,
config.node_config.port_range,
config.node_config.bind_ip_addr,
);
if let Some((rpc, rpc_pubsub)) = config.rpc_ports {
node.info.rpc = SocketAddr::new(node.info.gossip.ip(), rpc);
node.info.rpc_pubsub = SocketAddr::new(node.info.gossip.ip(), rpc_pubsub);

View File

@ -179,6 +179,44 @@ fn main() {
If the ledger already exists then this parameter is silently ignored",
),
)
.arg(
Arg::with_name("gossip_port")
.long("gossip-port")
.value_name("PORT")
.takes_value(true)
.help("Gossip port number for the validator"),
)
.arg(
Arg::with_name("gossip_host")
.long("gossip-host")
.value_name("HOST")
.takes_value(true)
.validator(solana_net_utils::is_host)
.help(
"Gossip DNS name or IP address for the validator to advertise in gossip \
[default: 127.0.0.1]",
),
)
.arg(
Arg::with_name("dynamic_port_range")
.long("dynamic-port-range")
.value_name("MIN_PORT-MAX_PORT")
.takes_value(true)
.validator(solana_validator::port_range_validator)
.help(
"Range to use for dynamically assigned ports \
[default: 1024-65535]",
),
)
.arg(
Arg::with_name("bind_address")
.long("bind-address")
.value_name("HOST")
.takes_value(true)
.validator(solana_net_utils::is_host)
.default_value("0.0.0.0")
.help("IP address to bind the validator ports [default: 0.0.0.0]"),
)
.arg(
Arg::with_name("clone_account")
.long("clone")
@ -240,6 +278,25 @@ fn main() {
let rpc_port = value_t_or_exit!(matches, "rpc_port", u16);
let faucet_port = value_t_or_exit!(matches, "faucet_port", u16);
let slots_per_epoch = value_t!(matches, "slots_per_epoch", Slot).ok();
let gossip_host = matches.value_of("gossip_host").map(|gossip_host| {
solana_net_utils::parse_host(gossip_host).unwrap_or_else(|err| {
eprintln!("Failed to parse --gossip-host: {}", err);
exit(1);
})
});
let gossip_port = value_t!(matches, "gossip_port", u16).ok();
let dynamic_port_range = matches.value_of("dynamic_port_range").map(|port_range| {
solana_net_utils::parse_port_range(port_range).unwrap_or_else(|| {
eprintln!("Failed to parse --dynamic-port-range");
exit(1);
})
});
let bind_address = matches.value_of("bind_address").map(|bind_address| {
solana_net_utils::parse_host(bind_address).unwrap_or_else(|err| {
eprintln!("Failed to parse --bind-address: {}", err);
exit(1);
})
});
let faucet_addr = Some(SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
@ -467,6 +524,22 @@ fn main() {
));
}
if let Some(gossip_host) = gossip_host {
genesis.gossip_host(gossip_host);
}
if let Some(gossip_port) = gossip_port {
genesis.gossip_port(gossip_port);
}
if let Some(dynamic_port_range) = dynamic_port_range {
genesis.port_range(dynamic_port_range);
}
if let Some(bind_address) = bind_address {
genesis.bind_ip_addr(bind_address);
}
match genesis.start_with_mint_address(mint_address) {
Ok(test_validator) => {
if let Some(dashboard) = dashboard {

View File

@ -1,5 +1,5 @@
#![allow(clippy::integer_arithmetic)]
pub use solana_core::test_validator;
pub use solana_core::{cluster_info::MINIMUM_VALIDATOR_PORT_RANGE_WIDTH, test_validator};
use {
console::style,
indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle},
@ -75,6 +75,22 @@ pub fn port_validator(port: String) -> Result<(), String> {
.map_err(|e| format!("{:?}", e))
}
pub fn port_range_validator(port_range: String) -> Result<(), String> {
if let Some((start, end)) = solana_net_utils::parse_port_range(&port_range) {
if end - start < MINIMUM_VALIDATOR_PORT_RANGE_WIDTH {
Err(format!(
"Port range is too small. Try --dynamic-port-range {}-{}",
start,
start + MINIMUM_VALIDATOR_PORT_RANGE_WIDTH
))
} else {
Ok(())
}
} else {
Err("Invalid port range".to_string())
}
}
/// Creates a new process bar for processing that will take an unknown amount of time
pub fn new_spinner_progress_bar() -> ProgressBar {
let progress_bar = ProgressBar::new(42);

View File

@ -21,9 +21,7 @@ use {
DEFAULT_MAX_LEDGER_SHREDS, DEFAULT_MIN_MAX_LEDGER_SHREDS,
},
solana_core::{
cluster_info::{
ClusterInfo, Node, MINIMUM_VALIDATOR_PORT_RANGE_WIDTH, VALIDATOR_PORT_RANGE,
},
cluster_info::{ClusterInfo, Node, VALIDATOR_PORT_RANGE},
contact_info::ContactInfo,
gossip_service::GossipService,
poh_service,
@ -296,22 +294,6 @@ fn wait_for_restart_window(
Ok(())
}
fn port_range_validator(port_range: String) -> Result<(), String> {
if let Some((start, end)) = solana_net_utils::parse_port_range(&port_range) {
if end - start < MINIMUM_VALIDATOR_PORT_RANGE_WIDTH {
Err(format!(
"Port range is too small. Try --dynamic-port-range {}-{}",
start,
start + MINIMUM_VALIDATOR_PORT_RANGE_WIDTH
))
} else {
Ok(())
}
} else {
Err("Invalid port range".to_string())
}
}
fn hash_validator(hash: String) -> Result<(), String> {
Hash::from_str(&hash)
.map(|_| ())
@ -1298,7 +1280,7 @@ pub fn main() {
.value_name("MIN_PORT-MAX_PORT")
.takes_value(true)
.default_value(default_dynamic_port_range)
.validator(port_range_validator)
.validator(solana_validator::port_range_validator)
.help("Range to use for dynamically assigned ports"),
)
.arg(