Add DNS resolution to cli tools
This commit is contained in:
parent
6859907df9
commit
0767c0c07f
|
@ -2200,6 +2200,7 @@ dependencies = [
|
||||||
"solana-drone 0.13.0",
|
"solana-drone 0.13.0",
|
||||||
"solana-logger 0.13.0",
|
"solana-logger 0.13.0",
|
||||||
"solana-metrics 0.13.0",
|
"solana-metrics 0.13.0",
|
||||||
|
"solana-netutil 0.13.0",
|
||||||
"solana-sdk 0.13.0",
|
"solana-sdk 0.13.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2388,6 +2389,7 @@ dependencies = [
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"solana 0.13.0",
|
"solana 0.13.0",
|
||||||
|
"solana-netutil 0.13.0",
|
||||||
"solana-sdk 0.13.0",
|
"solana-sdk 0.13.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2690,6 +2692,7 @@ dependencies = [
|
||||||
"solana-client 0.13.0",
|
"solana-client 0.13.0",
|
||||||
"solana-drone 0.13.0",
|
"solana-drone 0.13.0",
|
||||||
"solana-logger 0.13.0",
|
"solana-logger 0.13.0",
|
||||||
|
"solana-netutil 0.13.0",
|
||||||
"solana-sdk 0.13.0",
|
"solana-sdk 0.13.0",
|
||||||
"solana-vote-api 0.13.0",
|
"solana-vote-api 0.13.0",
|
||||||
"solana-vote-signer 0.13.0",
|
"solana-vote-signer 0.13.0",
|
||||||
|
|
|
@ -16,6 +16,7 @@ solana-client = { path = "../client", version = "0.13.0" }
|
||||||
solana-drone = { path = "../drone", version = "0.13.0" }
|
solana-drone = { path = "../drone", version = "0.13.0" }
|
||||||
solana-logger = { path = "../logger", version = "0.13.0" }
|
solana-logger = { path = "../logger", version = "0.13.0" }
|
||||||
solana-metrics = { path = "../metrics", version = "0.13.0" }
|
solana-metrics = { path = "../metrics", version = "0.13.0" }
|
||||||
|
solana-netutil = { path = "../netutil", version = "0.13.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "0.13.0" }
|
solana-sdk = { path = "../sdk", version = "0.13.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -117,14 +117,14 @@ pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
|
||||||
let mut args = Config::default();
|
let mut args = Config::default();
|
||||||
|
|
||||||
if let Some(addr) = matches.value_of("network") {
|
if let Some(addr) = matches.value_of("network") {
|
||||||
args.network_addr = addr.parse().unwrap_or_else(|e| {
|
args.network_addr = solana_netutil::parse_host_port(addr).unwrap_or_else(|e| {
|
||||||
eprintln!("failed to parse network: {}", e);
|
eprintln!("failed to parse network address: {}", e);
|
||||||
exit(1)
|
exit(1)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(addr) = matches.value_of("drone") {
|
if let Some(addr) = matches.value_of("drone") {
|
||||||
args.drone_addr = addr.parse().unwrap_or_else(|e| {
|
args.drone_addr = solana_netutil::parse_host_port(addr).unwrap_or_else(|e| {
|
||||||
eprintln!("failed to parse drone address: {}", e);
|
eprintln!("failed to parse drone address: {}", e);
|
||||||
exit(1)
|
exit(1)
|
||||||
});
|
});
|
||||||
|
|
|
@ -161,7 +161,7 @@ This will dump all the threads stack traces into gdb.txt
|
||||||
In this example the client connects to our public testnet. To run validators on the testnet you would need to open udp ports `8000-10000`.
|
In this example the client connects to our public testnet. To run validators on the testnet you would need to open udp ports `8000-10000`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./multinode-demo/client.sh --network $(dig +short testnet.solana.com):8001 --duration 60
|
$ ./multinode-demo/client.sh --network testnet.solana.com:8001 --duration 60
|
||||||
```
|
```
|
||||||
|
|
||||||
You can observe the effects of your client's transactions on our [dashboard](https://metrics.solana.com:3000/d/testnet/testnet-hud?orgId=2&from=now-30m&to=now&refresh=5s&var-testnet=testnet)
|
You can observe the effects of your client's transactions on our [dashboard](https://metrics.solana.com:3000/d/testnet/testnet-hud?orgId=2&from=now-30m&to=now&refresh=5s&var-testnet=testnet)
|
||||||
|
|
|
@ -26,14 +26,7 @@ Prebuilt binaries are available for Linux x86_64 (Ubuntu 18.04 recommended).
|
||||||
MacOS or WSL users may build from source.
|
MacOS or WSL users may build from source.
|
||||||
|
|
||||||
### Validator Setup
|
### Validator Setup
|
||||||
The shell commands in this section assume the following environment variables are
|
|
||||||
set:
|
|
||||||
```bash
|
|
||||||
$ export ip=$(dig +short beta.testnet.solana.com)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Obtaining The Software
|
#### Obtaining The Software
|
||||||
|
|
||||||
##### Bootstrap with `solana-install`
|
##### Bootstrap with `solana-install`
|
||||||
|
|
||||||
The `solana-install` tool can be used to easily install and upgrade the cluster
|
The `solana-install` tool can be used to easily install and upgrade the cluster
|
||||||
|
@ -82,8 +75,8 @@ just restarting itself before debugging further.
|
||||||
|
|
||||||
Receive an airdrop of lamports from the testnet drone:
|
Receive an airdrop of lamports from the testnet drone:
|
||||||
```bash
|
```bash
|
||||||
$ solana-wallet -n ${ip:?} airdrop 123
|
$ solana-wallet -n beta.testnet.solana.com airdrop 123
|
||||||
$ solana-wallet -n ${ip:?} balance
|
$ solana-wallet -n beta.testnet.solana.com balance
|
||||||
```
|
```
|
||||||
|
|
||||||
Fetch the current testnet transaction count over JSON RPC:
|
Fetch the current testnet transaction count over JSON RPC:
|
||||||
|
@ -95,7 +88,7 @@ Inspect the blockexplorer at http://beta.testnet.solana.com/ for activity.
|
||||||
|
|
||||||
Run the following command to join the gossip network and view all the other nodes in the cluster:
|
Run the following command to join the gossip network and view all the other nodes in the cluster:
|
||||||
```bash
|
```bash
|
||||||
$ RUST_LOG=info solana-gossip --network ${ip:?}:8001
|
$ solana-gossip --network beta.testnet.solana.com:8001
|
||||||
```
|
```
|
||||||
|
|
||||||
### Starting The Validator
|
### Starting The Validator
|
||||||
|
@ -103,24 +96,24 @@ The following command will start a new validator node.
|
||||||
|
|
||||||
If this is a `solana-install`-installation:
|
If this is a `solana-install`-installation:
|
||||||
```bash
|
```bash
|
||||||
$ fullnode-x.sh --public-address --poll-for-new-genesis-block ${ip:?}
|
$ fullnode-x.sh --public-address --poll-for-new-genesis-block beta.testnet.solana.com:8001
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, the `solana-install run` command can be used to run the validator
|
Alternatively, the `solana-install run` command can be used to run the validator
|
||||||
node while periodically checking for and applying software updates:
|
node while periodically checking for and applying software updates:
|
||||||
```bash
|
```bash
|
||||||
$ solana-install run fullnode-x.sh --public-address --poll-for-new-genesis-block ${ip:?}
|
$ solana-install run fullnode-x.sh --public-address --poll-for-new-genesis-block beta.testnet.solana.com:8001
|
||||||
```
|
```
|
||||||
|
|
||||||
When not using `solana-install`:
|
When not using `solana-install`:
|
||||||
```bash
|
```bash
|
||||||
$ USE_INSTALL=1 ./multinode-demo/fullnode-x.sh --public-address --poll-for-new-genesis-block ${ip:?}
|
$ USE_INSTALL=1 ./multinode-demo/fullnode-x.sh --public-address --poll-for-new-genesis-block beta.testnet.solana.com:8001
|
||||||
```
|
```
|
||||||
|
|
||||||
Then from another console, confirm the IP address if your node is now visible in
|
Then from another console, confirm the IP address if your node is now visible in
|
||||||
the gossip network by running:
|
the gossip network by running:
|
||||||
```bash
|
```bash
|
||||||
$ RUST_LOG=info solana-gossip --network ${ip:?}:8001
|
$ solana-gossip --network beta.testnet.solana.com:8001
|
||||||
```
|
```
|
||||||
|
|
||||||
Congratulations, you're now participating in the testnet cluster!
|
Congratulations, you're now participating in the testnet cluster!
|
||||||
|
|
|
@ -187,9 +187,9 @@ fn main() {
|
||||||
if matches.is_present("enable_rpc_exit") {
|
if matches.is_present("enable_rpc_exit") {
|
||||||
fullnode_config.rpc_config.enable_fullnode_exit = true;
|
fullnode_config.rpc_config.enable_fullnode_exit = true;
|
||||||
}
|
}
|
||||||
fullnode_config.rpc_config.drone_addr = matches
|
fullnode_config.rpc_config.drone_addr = matches.value_of("rpc_drone_address").map(|address| {
|
||||||
.value_of("rpc_drone_address")
|
solana_netutil::parse_host_port(address).expect("failed to parse drone address")
|
||||||
.map(|address| address.parse().expect("failed to parse drone address"));
|
});
|
||||||
|
|
||||||
let dynamic_port_range = parse_port_range(matches.value_of("dynamic_port_range").unwrap())
|
let dynamic_port_range = parse_port_range(matches.value_of("dynamic_port_range").unwrap())
|
||||||
.expect("invalid dynamic_port_range");
|
.expect("invalid dynamic_port_range");
|
||||||
|
@ -214,7 +214,8 @@ fn main() {
|
||||||
fullnode_config.account_paths = None;
|
fullnode_config.account_paths = None;
|
||||||
}
|
}
|
||||||
let cluster_entrypoint = matches.value_of("network").map(|network| {
|
let cluster_entrypoint = matches.value_of("network").map(|network| {
|
||||||
let gossip_addr = network.parse().expect("failed to parse network address");
|
let gossip_addr =
|
||||||
|
solana_netutil::parse_host_port(network).expect("failed to parse network address");
|
||||||
ContactInfo::new_gossip_entry_point(&gossip_addr)
|
ContactInfo::new_gossip_entry_point(&gossip_addr)
|
||||||
});
|
});
|
||||||
let (_signer_service, _signer_addr) = if let Some(signer_addr) = matches.value_of("signer") {
|
let (_signer_service, _signer_addr) = if let Some(signer_addr) = matches.value_of("signer") {
|
||||||
|
|
|
@ -12,6 +12,7 @@ homepage = "https://solana.com/"
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
env_logger = "0.6.1"
|
env_logger = "0.6.1"
|
||||||
solana = { path = "../core", version = "0.13.0" }
|
solana = { path = "../core", version = "0.13.0" }
|
||||||
|
solana-netutil = { path = "../netutil", version = "0.13.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "0.13.0" }
|
solana-sdk = { path = "../sdk", version = "0.13.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -67,8 +67,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
if let Some(addr) = matches.value_of("network") {
|
if let Some(addr) = matches.value_of("network") {
|
||||||
network_addr = addr.parse().unwrap_or_else(|e| {
|
network_addr = solana_netutil::parse_host_port(addr).unwrap_or_else(|e| {
|
||||||
eprintln!("failed to parse network: {}", e);
|
eprintln!("failed to parse network address: {}", e);
|
||||||
exit(1)
|
exit(1)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,19 +78,7 @@ find_leader() {
|
||||||
leader_address=127.0.0.1:8001 # Default to local leader
|
leader_address=127.0.0.1:8001 # Default to local leader
|
||||||
elif [[ -z $2 ]]; then
|
elif [[ -z $2 ]]; then
|
||||||
leader=$1
|
leader=$1
|
||||||
|
leader_address=$leader:8001
|
||||||
declare leader_ip
|
|
||||||
if [[ $leader =~ ^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$ ]]; then
|
|
||||||
leader_ip=$leader
|
|
||||||
else
|
|
||||||
leader_ip=$(dig +short "${leader%:*}" | head -n1)
|
|
||||||
|
|
||||||
if [[ -z $leader_ip ]]; then
|
|
||||||
usage "Error: unable to resolve IP address for $leader"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
leader_address=$leader_ip:8001
|
|
||||||
shift=1
|
shift=1
|
||||||
else
|
else
|
||||||
leader=$1
|
leader=$1
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rand::{thread_rng, Rng};
|
||||||
use reqwest;
|
use reqwest;
|
||||||
use socket2::{Domain, SockAddr, Socket, Type};
|
use socket2::{Domain, SockAddr, Socket, Type};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, UdpSocket};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, ToSocketAddrs, UdpSocket};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
/// A data type representing a public Udp socket
|
/// A data type representing a public Udp socket
|
||||||
|
@ -70,6 +70,31 @@ pub fn parse_port_range(port_range: &str) -> Option<PortRange> {
|
||||||
Some((start_port, end_port))
|
Some((start_port, end_port))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_host(host: &str) -> Result<IpAddr, String> {
|
||||||
|
let ips: Vec<_> = (host, 0)
|
||||||
|
.to_socket_addrs()
|
||||||
|
.map_err(|err| err.to_string())?
|
||||||
|
.map(|socket_address| socket_address.ip())
|
||||||
|
.collect();
|
||||||
|
if ips.is_empty() {
|
||||||
|
Err(format!("Unable to resolve host: {}", host))
|
||||||
|
} else {
|
||||||
|
Ok(ips[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_host_port(host_port: &str) -> Result<SocketAddr, String> {
|
||||||
|
let addrs: Vec<_> = host_port
|
||||||
|
.to_socket_addrs()
|
||||||
|
.map_err(|err| err.to_string())?
|
||||||
|
.collect();
|
||||||
|
if addrs.is_empty() {
|
||||||
|
Err(format!("Unable to resolve host: {}", host_port))
|
||||||
|
} else {
|
||||||
|
Ok(addrs[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn find_eth0ish_ip_addr(
|
fn find_eth0ish_ip_addr(
|
||||||
ifaces: &mut Vec<datalink::NetworkInterface>,
|
ifaces: &mut Vec<datalink::NetworkInterface>,
|
||||||
enable_ipv6: bool,
|
enable_ipv6: bool,
|
||||||
|
@ -334,6 +359,22 @@ mod tests {
|
||||||
assert_eq!(parse_port_range("2-1"), None);
|
assert_eq!(parse_port_range("2-1"), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_host() {
|
||||||
|
parse_host("localhost:1234").unwrap_err();
|
||||||
|
parse_host("localhost").unwrap();
|
||||||
|
parse_host("127.0.0.0:1234").unwrap_err();
|
||||||
|
parse_host("127.0.0.0").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_host_port() {
|
||||||
|
parse_host_port("localhost:1234").unwrap();
|
||||||
|
parse_host_port("localhost").unwrap_err();
|
||||||
|
parse_host_port("127.0.0.0:1234").unwrap();
|
||||||
|
parse_host_port("127.0.0.0").unwrap_err();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bind() {
|
fn test_bind() {
|
||||||
assert_eq!(bind_in_range((2000, 2001)).unwrap().0, 2000);
|
assert_eq!(bind_in_range((2000, 2001)).unwrap().0, 2000);
|
||||||
|
|
|
@ -78,7 +78,9 @@ fn main() {
|
||||||
|
|
||||||
let network_addr = matches
|
let network_addr = matches
|
||||||
.value_of("network")
|
.value_of("network")
|
||||||
.map(|network| network.parse().expect("failed to parse network address"))
|
.map(|network| {
|
||||||
|
solana_netutil::parse_host_port(network).expect("failed to parse network address")
|
||||||
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let leader_info = ContactInfo::new_gossip_entry_point(&network_addr);
|
let leader_info = ContactInfo::new_gossip_entry_point(&network_addr);
|
||||||
|
@ -94,6 +96,5 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
replicator.run();
|
replicator.run();
|
||||||
|
|
||||||
replicator.close();
|
replicator.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ solana-budget-api = { path = "../programs/budget_api", version = "0.13.0" }
|
||||||
solana-client = { path = "../client", version = "0.13.0" }
|
solana-client = { path = "../client", version = "0.13.0" }
|
||||||
solana-drone = { path = "../drone", version = "0.13.0" }
|
solana-drone = { path = "../drone", version = "0.13.0" }
|
||||||
solana-logger = { path = "../logger", version = "0.13.0" }
|
solana-logger = { path = "../logger", version = "0.13.0" }
|
||||||
|
solana-netutil = { path = "../netutil", version = "0.13.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "0.13.0" }
|
solana-sdk = { path = "../sdk", version = "0.13.0" }
|
||||||
solana-vote-api = { path = "../programs/vote_api", version = "0.13.0" }
|
solana-vote-api = { path = "../programs/vote_api", version = "0.13.0" }
|
||||||
solana-vote-signer = { path = "../vote-signer", version = "0.13.0" }
|
solana-vote-signer = { path = "../vote-signer", version = "0.13.0" }
|
||||||
|
|
|
@ -7,28 +7,31 @@ use solana_wallet::wallet::{parse_command, process_command, WalletConfig, Wallet
|
||||||
use std::error;
|
use std::error;
|
||||||
|
|
||||||
pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn error::Error>> {
|
pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn error::Error>> {
|
||||||
let host = matches
|
let host = solana_netutil::parse_host(matches.value_of("host").unwrap()).or_else(|err| {
|
||||||
.value_of("host")
|
Err(WalletError::BadParameter(format!(
|
||||||
.unwrap()
|
"Invalid host: {:?}",
|
||||||
.parse()
|
err
|
||||||
.or_else(|_| Err(WalletError::BadParameter("Invalid host".to_string())))?;
|
)))
|
||||||
|
})?;
|
||||||
|
|
||||||
let drone_host = if let Some(drone_host) = matches.value_of("drone_host") {
|
let drone_host = if let Some(drone_host) = matches.value_of("drone_host") {
|
||||||
Some(
|
Some(solana_netutil::parse_host(drone_host).or_else(|err| {
|
||||||
drone_host
|
Err(WalletError::BadParameter(format!(
|
||||||
.parse()
|
"Invalid drone host: {:?}",
|
||||||
.or_else(|_| Err(WalletError::BadParameter("Invalid drone host".to_string())))?,
|
err
|
||||||
)
|
)))
|
||||||
|
})?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let rpc_host = if let Some(rpc_host) = matches.value_of("rpc_host") {
|
let rpc_host = if let Some(rpc_host) = matches.value_of("rpc_host") {
|
||||||
Some(
|
Some(solana_netutil::parse_host(rpc_host).or_else(|err| {
|
||||||
rpc_host
|
Err(WalletError::BadParameter(format!(
|
||||||
.parse()
|
"Invalid rpc host: {:?}",
|
||||||
.or_else(|_| Err(WalletError::BadParameter("Invalid rpc host".to_string())))?,
|
err
|
||||||
)
|
)))
|
||||||
|
})?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -37,13 +40,23 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn erro
|
||||||
.value_of("drone_port")
|
.value_of("drone_port")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.or_else(|_| Err(WalletError::BadParameter("Invalid drone port".to_string())))?;
|
.or_else(|err| {
|
||||||
|
Err(WalletError::BadParameter(format!(
|
||||||
|
"Invalid drone port: {:?}",
|
||||||
|
err
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
|
||||||
let rpc_port = matches
|
let rpc_port = matches
|
||||||
.value_of("rpc_port")
|
.value_of("rpc_port")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.or_else(|_| Err(WalletError::BadParameter("Invalid rpc port".to_string())))?;
|
.or_else(|err| {
|
||||||
|
Err(WalletError::BadParameter(format!(
|
||||||
|
"Invalid rpc port: {:?}",
|
||||||
|
err
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut path = dirs::home_dir().expect("home directory");
|
let mut path = dirs::home_dir().expect("home directory");
|
||||||
let id_path = if matches.is_present("keypair") {
|
let id_path = if matches.is_present("keypair") {
|
||||||
|
|
Loading…
Reference in New Issue