wallet: add --url, remove --host/--rpc-host/--rpc-port/-rpc-tls (#4153)

Also by default the wallet now talks to testnet.solana.com instead of
localhost
This commit is contained in:
Michael Vines 2019-05-06 07:38:26 -07:00 committed by GitHub
parent 71f9b44687
commit 9b50583641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 103 additions and 141 deletions

1
Cargo.lock generated
View File

@ -2775,6 +2775,7 @@ dependencies = [
"solana-sdk 0.15.0",
"solana-vote-api 0.15.0",
"solana-vote-signer 0.15.0",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

View File

@ -104,8 +104,8 @@ $ export PATH=$PWD/bin:$PATH
Sanity check that you are able to interact with the cluster by receiving a small
airdrop of lamports from the testnet drone:
```bash
$ solana-wallet -n testnet.solana.com airdrop 123
$ solana-wallet -n testnet.solana.com balance
$ solana-wallet airdrop 123
$ solana-wallet balance
```
Also try running following command to join the gossip network and view all the other nodes in the cluster:

View File

@ -7,7 +7,7 @@ restartInterval=never
rollingRestart=false
maybeNoLeaderRotation=
extraNodes=0
walletRpcEndpoint=
walletRpcPort=
usage() {
exitcode=0
@ -61,7 +61,7 @@ while getopts "ch?i:k:brxR" opt; do
extraNodes=$((extraNodes + 1))
;;
r)
walletRpcEndpoint="--rpc-port 18899"
walletRpcPort=":18899"
;;
R)
rollingRestart=true
@ -362,8 +362,7 @@ while [[ $iteration -le $iterations ]]; do
}
(
set -x
# shellcheck disable=SC2086 # Don't want to double quote $walletRpcEndpoint
timeout 60s scripts/wallet-sanity.sh $walletRpcEndpoint
timeout 60s scripts/wallet-sanity.sh --url http://127.0.0.1"$walletRpcPort"
) || flag_error_if_no_leader_rotation
iteration=$((iteration + 1))

View File

@ -10,15 +10,23 @@ mod config;
mod defaults;
mod update_manifest;
fn url_validator(url: String) -> Result<(), String> {
match url::Url::parse(&url) {
Ok(_) => Ok(()),
// Return an error if a url cannot be parsed.
fn is_url(string: String) -> Result<(), String> {
match url::Url::parse(&string) {
Ok(url) => {
if url.has_host() {
Ok(())
} else {
Err("no host provided".to_string())
}
}
Err(err) => Err(format!("{:?}", err)),
}
}
fn pubkey_validator(pubkey: String) -> Result<(), String> {
match pubkey.parse::<Pubkey>() {
// Return an error if a pubkey cannot be parsed.
fn is_pubkey(string: String) -> Result<(), String> {
match string.parse::<Pubkey>() {
Ok(_) => Ok(()),
Err(err) => Err(format!("{:?}", err)),
}
@ -67,7 +75,7 @@ fn main() -> Result<(), String> {
.value_name("URL")
.takes_value(true)
.default_value(defaults::JSON_RPC_URL)
.validator(url_validator)
.validator(is_url)
.help("JSON RPC URL for the solana cluster"),
)
.arg(
@ -82,7 +90,7 @@ fn main() -> Result<(), String> {
.value_name("PUBKEY")
.takes_value(true)
.required(true)
.validator(pubkey_validator)
.validator(is_pubkey)
.help("Public key of the update manifest");
match defaults::update_manifest_pubkey(build_env::TARGET) {
@ -128,14 +136,14 @@ fn main() -> Result<(), String> {
.value_name("URL")
.takes_value(true)
.default_value(defaults::JSON_RPC_URL)
.validator(url_validator)
.validator(is_url)
.help("JSON RPC URL for the solana cluster"),
)
.arg(
Arg::with_name("download_url")
.index(1)
.required(true)
.validator(url_validator)
.validator(is_url)
.help("URL to the solana release archive"),
)
.arg(

View File

@ -72,7 +72,7 @@ rsync_url() { # adds the 'rsync://` prefix to URLs that need it
airdrop() {
declare keypair_file=$1
declare host=$2
declare entrypoint_ip=$2
declare amount=$3
declare address
@ -83,7 +83,7 @@ airdrop() {
# node restart, costing it lamports
declare retries=5
while ! $solana_wallet --keypair "$keypair_file" --host "$host" airdrop "$amount"; do
while ! $solana_wallet --keypair "$keypair_file" --url "http://$entrypoint_ip:8899" airdrop "$amount"; do
# TODO: Consider moving this retry logic into `solana-wallet airdrop`
# itself, currently it does not retry on "Connection refused" errors.
@ -100,7 +100,7 @@ airdrop() {
}
setup_vote_account() {
declare drone_address=$1
declare entrypoint_ip=$1
declare node_id_path=$2
declare vote_id_path=$3
declare stake=$4
@ -114,16 +114,17 @@ setup_vote_account() {
if [[ -f "$vote_id_path".configured ]]; then
echo "Vote account has already been configured"
else
airdrop "$node_id_path" "$drone_address" "$stake" || return $?
airdrop "$node_id_path" "$entrypoint_ip" "$stake" || return $?
# Fund the vote account from the node, with the node as the node_id
$solana_wallet --keypair "$node_id_path" --host "$drone_address" \
$solana_wallet --keypair "$node_id_path" --url "http://$entrypoint_ip:8899" \
create-vote-account "$vote_id" "$node_id" $((stake - 1)) || return $?
touch "$vote_id_path".configured
fi
$solana_wallet --keypair "$node_id_path" --host "$drone_address" show-vote-account "$vote_id"
$solana_wallet --keypair "$node_id_path" --url "http://$entrypoint_ip:8899" \
show-vote-account "$vote_id"
return 0
}

View File

@ -31,6 +31,6 @@ loadConfigFile
PATH="$HOME"/.cargo/bin:"$PATH"
set -x
solana-wallet airdrop 42
solana-wallet --url http://127.0.0.1:8899 airdrop 42
solana-install deploy "$updateDownloadUrl" update_manifest_keypair.json \
--url http://localhost:8899
--url http://127.0.0.1:8899

View File

@ -117,7 +117,7 @@ echo "--- RPC API: getTransactionCount"
echo "--- $entrypointIp: wallet sanity"
(
set -x
scripts/wallet-sanity.sh --host "$entrypointIp"
scripts/wallet-sanity.sh --url http://"$entrypointIp":8899
)
echo "--- $entrypointIp: verify ledger"

View File

@ -9,8 +9,8 @@ cd "$(dirname "$0")"/..
# shellcheck source=multinode-demo/common.sh
source multinode-demo/common.sh
if [[ -z $1 ]]; then # no network argument, use default
entrypoint=()
if [[ -z $1 ]]; then # no network argument, use localhost by default
entrypoint=(--url http://127.0.0.1:8899)
else
entrypoint=("$@")
fi

View File

@ -25,6 +25,7 @@ solana-netutil = { path = "../netutil", version = "0.15.0" }
solana-sdk = { path = "../sdk", version = "0.15.0" }
solana-vote-api = { path = "../programs/vote_api", version = "0.15.0" }
solana-vote-signer = { path = "../vote-signer", version = "0.15.0" }
url = "1.7.2"
[dev-dependencies]
solana-budget-program = { path = "../programs/budget_program", version = "0.15.0" }

View File

@ -7,12 +7,7 @@ use solana_wallet::wallet::{parse_command, process_command, WalletConfig, Wallet
use std::error;
pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn error::Error>> {
let host = solana_netutil::parse_host(matches.value_of("host").unwrap()).or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid host: {:?}",
err
)))
})?;
let json_rpc_url = matches.value_of("json_rpc_url").unwrap().to_string();
let drone_host = if let Some(drone_host) = matches.value_of("drone_host") {
Some(solana_netutil::parse_host(drone_host).or_else(|err| {
@ -25,17 +20,6 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn erro
None
};
let rpc_host = if let Some(rpc_host) = matches.value_of("rpc_host") {
Some(solana_netutil::parse_host(rpc_host).or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid rpc host: {:?}",
err
)))
})?)
} else {
None
};
let drone_port = matches
.value_of("drone_port")
.unwrap()
@ -47,17 +31,6 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn erro
)))
})?;
let rpc_port = matches
.value_of("rpc_port")
.unwrap()
.parse()
.or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid rpc port: {:?}",
err
)))
})?;
let mut path = dirs::home_dir().expect("home directory");
let id_path = if matches.is_present("keypair") {
matches.value_of("keypair").unwrap()
@ -80,18 +53,29 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn erro
let command = parse_command(&keypair.pubkey(), &matches)?;
Ok(WalletConfig {
keypair,
command,
drone_host,
drone_port,
host,
json_rpc_url,
keypair,
rpc_client: None,
rpc_host,
rpc_port,
rpc_tls: matches.is_present("rpc_tls"),
})
}
// Return an error if a url cannot be parsed.
fn is_url(string: String) -> Result<(), String> {
match url::Url::parse(&string) {
Ok(url) => {
if url.has_host() {
Ok(())
} else {
Err("no host provided".to_string())
}
}
Err(err) => Err(format!("{:?}", err)),
}
}
// Return an error if a pubkey cannot be parsed.
fn is_pubkey(string: String) -> Result<(), String> {
match string.parse::<Pubkey>() {
@ -103,54 +87,29 @@ fn is_pubkey(string: String) -> Result<(), String> {
fn main() -> Result<(), Box<dyn error::Error>> {
solana_logger::setup();
let (default_host, default_rpc_port, default_drone_port) = {
let defaults = WalletConfig::default();
(
defaults.host.to_string(),
defaults.rpc_port.to_string(),
defaults.drone_port.to_string(),
)
};
let default = WalletConfig::default();
let default_drone_port = format!("{}", default.drone_port);
let matches = App::new(crate_name!())
.about(crate_description!())
.version(crate_version!())
.setting(AppSettings::ArgRequiredElseHelp)
.setting(AppSettings::SubcommandRequiredElseHelp)
.arg(
Arg::with_name("host")
.short("n")
.long("host")
.value_name("IP ADDRESS")
Arg::with_name("json_rpc_url")
.short("u")
.long("url")
.value_name("URL")
.takes_value(true)
.default_value(&default_host)
.help("Host to use for both RPC and drone"),
)
.arg(
Arg::with_name("rpc_host")
.long("rpc-host")
.value_name("IP ADDRESS")
.takes_value(true)
.help("RPC host to use [default: same as --host]"),
)
.arg(
Arg::with_name("rpc_port")
.long("rpc-port")
.value_name("PORT")
.takes_value(true)
.default_value(&default_rpc_port)
.help("RPC port to use"),
)
.arg(
Arg::with_name("rpc_tps")
.long("rpc-tls")
.help("Enable TLS for the RPC endpoint"),
.default_value(&default.json_rpc_url)
.validator(is_url)
.help("JSON RPC URL for the solana cluster"),
)
.arg(
Arg::with_name("drone_host")
.long("drone-host")
.value_name("IP ADDRESS")
.value_name("HOST")
.takes_value(true)
.help("Drone host to use [default: same as --host]"),
.help("Drone host to use [default: same as the --url host]"),
)
.arg(
Arg::with_name("drone_port")

View File

@ -9,7 +9,7 @@ use solana_budget_api;
use solana_budget_api::budget_instruction;
use solana_budget_api::budget_state::BudgetError;
use solana_client::client_error::ClientError;
use solana_client::rpc_client::{get_rpc_request_str, RpcClient};
use solana_client::rpc_client::RpcClient;
#[cfg(not(test))]
use solana_drone::drone::request_airdrop_transaction;
use solana_drone::drone::DRONE_PORT;
@ -21,7 +21,6 @@ use solana_sdk::instruction::InstructionError;
use solana_sdk::instruction_processor_utils::DecodeError;
use solana_sdk::loader_instruction;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::rpc_port::DEFAULT_RPC_PORT;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
use solana_sdk::system_instruction::SystemError;
use solana_sdk::system_transaction;
@ -29,7 +28,7 @@ use solana_sdk::transaction::{Transaction, TransactionError};
use solana_vote_api::vote_instruction;
use std::fs::File;
use std::io::Read;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::{IpAddr, SocketAddr};
use std::{error, fmt, mem};
const USERDATA_CHUNK_SIZE: usize = 256;
@ -88,15 +87,12 @@ impl error::Error for WalletError {
}
pub struct WalletConfig {
pub keypair: Keypair,
pub command: WalletCommand,
pub drone_host: Option<IpAddr>,
pub drone_port: u16,
pub host: IpAddr,
pub json_rpc_url: String,
pub keypair: Keypair,
pub rpc_client: Option<RpcClient>,
pub rpc_host: Option<IpAddr>,
pub rpc_port: u16,
pub rpc_tls: bool,
}
impl Default for WalletConfig {
@ -105,25 +101,27 @@ impl Default for WalletConfig {
command: WalletCommand::Balance(Pubkey::default()),
drone_host: None,
drone_port: DRONE_PORT,
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
json_rpc_url: "http://testnet.solana.com:8899".to_string(),
keypair: Keypair::new(),
rpc_client: None,
rpc_host: None,
rpc_port: DEFAULT_RPC_PORT,
rpc_tls: false,
}
}
}
impl WalletConfig {
pub fn drone_addr(&self) -> SocketAddr {
SocketAddr::new(self.drone_host.unwrap_or(self.host), self.drone_port)
}
pub fn rpc_addr(&self) -> String {
get_rpc_request_str(
SocketAddr::new(self.rpc_host.unwrap_or(self.host), self.rpc_port),
self.rpc_tls,
SocketAddr::new(
self.drone_host.unwrap_or_else(|| {
let drone_host = url::Url::parse(&self.json_rpc_url)
.unwrap()
.host()
.unwrap()
.to_string();
solana_netutil::parse_host(&drone_host).unwrap_or_else(|err| {
panic!("Unable to resolve {}: {}", drone_host, err);
})
}),
self.drone_port,
)
}
}
@ -645,8 +643,7 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
let mut _rpc_client;
let rpc_client = if config.rpc_client.is_none() {
let rpc_addr = config.rpc_addr();
_rpc_client = RpcClient::new(rpc_addr);
_rpc_client = RpcClient::new(config.json_rpc_url.to_string());
&_rpc_client
} else {
// Primarily for testing
@ -823,31 +820,23 @@ mod tests {
#[test]
fn test_wallet_config_drone_addr() {
let mut config = WalletConfig::default();
config.json_rpc_url = "http://127.0.0.1:8899".to_string();
let rpc_host = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
assert_eq!(
config.drone_addr(),
SocketAddr::new(config.host, config.drone_port)
SocketAddr::new(rpc_host, config.drone_port)
);
config.drone_port = 1234;
assert_eq!(config.drone_addr(), SocketAddr::new(config.host, 1234));
assert_eq!(config.drone_addr(), SocketAddr::new(rpc_host, 1234));
config.drone_host = Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)));
config.drone_host = Some(rpc_host);
assert_eq!(
config.drone_addr(),
SocketAddr::new(config.drone_host.unwrap(), 1234)
);
}
#[test]
fn test_wallet_config_rpc_addr() {
let mut config = WalletConfig::default();
assert_eq!(config.rpc_addr(), "http://127.0.0.1:8899");
config.rpc_port = 1234;
assert_eq!(config.rpc_addr(), "http://127.0.0.1:1234");
config.rpc_host = Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)));
assert_eq!(config.rpc_addr(), "http://127.0.0.2:1234");
}
#[test]
fn test_wallet_parse_command() {
let test_commands = App::new("test")

View File

@ -30,7 +30,7 @@ fn test_wallet_deploy_program() {
let mut config = WalletConfig::default();
config.drone_port = drone_addr.port();
config.rpc_port = leader_data.rpc.port();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.command = WalletCommand::Airdrop(50);
process_command(&config).unwrap();

View File

@ -31,11 +31,12 @@ fn test_wallet_timestamp_tx() {
let mut config_payer = WalletConfig::default();
config_payer.drone_port = drone_addr.port();
config_payer.rpc_port = leader_data.rpc.port();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let mut config_witness = WalletConfig::default();
config_witness.drone_port = drone_addr.port();
config_witness.rpc_port = leader_data.rpc.port();
config_witness.drone_port = config_payer.drone_port;
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
assert_ne!(
config_payer.keypair.pubkey(),
@ -95,11 +96,12 @@ fn test_wallet_witness_tx() {
let mut config_payer = WalletConfig::default();
config_payer.drone_port = drone_addr.port();
config_payer.rpc_port = leader_data.rpc.port();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let mut config_witness = WalletConfig::default();
config_witness.drone_port = drone_addr.port();
config_witness.rpc_port = leader_data.rpc.port();
config_witness.drone_port = config_payer.drone_port;
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
assert_ne!(
config_payer.keypair.pubkey(),
@ -156,11 +158,12 @@ fn test_wallet_cancel_tx() {
let mut config_payer = WalletConfig::default();
config_payer.drone_port = drone_addr.port();
config_payer.rpc_port = leader_data.rpc.port();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let mut config_witness = WalletConfig::default();
config_witness.drone_port = drone_addr.port();
config_witness.rpc_port = leader_data.rpc.port();
config_witness.drone_port = config_payer.drone_port;
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
assert_ne!(
config_payer.keypair.pubkey(),

View File

@ -15,7 +15,8 @@ fn test_wallet_request_airdrop() {
let mut bob_config = WalletConfig::default();
bob_config.drone_port = drone_addr.port();
bob_config.rpc_port = leader_data.rpc.port();
bob_config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
bob_config.command = WalletCommand::Airdrop(50);
let sig_response = process_command(&bob_config);