Overhaul wallet rpc/drone command-line arguments
This commit is contained in:
		@@ -168,21 +168,23 @@ $ solana-wallet send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
 | 
				
			|||||||
### Usage
 | 
					### Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```manpage
 | 
					```manpage
 | 
				
			||||||
solana-wallet 0.11.0
 | 
					solana-wallet 0.12.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
USAGE:
 | 
					USAGE:
 | 
				
			||||||
    solana-wallet [OPTIONS] [SUBCOMMAND]
 | 
					    solana-wallet [FLAGS] [OPTIONS] [SUBCOMMAND]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS:
 | 
					FLAGS:
 | 
				
			||||||
    -h, --help       Prints help information
 | 
					    -h, --help       Prints help information
 | 
				
			||||||
 | 
					        --rpc-tls    Enable TLS for the RPC endpoint
 | 
				
			||||||
    -V, --version    Prints version information
 | 
					    -V, --version    Prints version information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OPTIONS:
 | 
					OPTIONS:
 | 
				
			||||||
 | 
					        --drone-host <IP ADDRESS>    Drone host to use [default: same as --host]
 | 
				
			||||||
 | 
					        --drone-port <PORT>          Drone port to use [default: 9900]
 | 
				
			||||||
 | 
					    -n, --host <IP ADDRESS>          Host to use for both RPC and drone [default: 127.0.0.1]
 | 
				
			||||||
    -k, --keypair <PATH>             /path/to/id.json
 | 
					    -k, --keypair <PATH>             /path/to/id.json
 | 
				
			||||||
    -n, --network <HOST:PORT>    Rendezvous with the network at this gossip entry point; defaults to 127.0.0.1:8001
 | 
					        --rpc-host <IP ADDRESS>      RPC host to use [default: same as --host]
 | 
				
			||||||
        --proxy <URL>            Address of TLS proxy
 | 
					        --rpc-port <PORT>            RPC port to use [default: 8899]
 | 
				
			||||||
        --port <NUM>             Optional rpc-port configuration to connect to non-default nodes
 | 
					 | 
				
			||||||
        --timeout <SECS>         Max seconds to wait to get necessary gossip from the network
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
SUBCOMMANDS:
 | 
					SUBCOMMANDS:
 | 
				
			||||||
    address                  Get your public key
 | 
					    address                  Get your public key
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -194,7 +194,7 @@ $solana_wallet --keypair "$fullnode_id_path" address
 | 
				
			|||||||
# - one token to keep the node identity public key valid.
 | 
					# - one token to keep the node identity public key valid.
 | 
				
			||||||
retries=5
 | 
					retries=5
 | 
				
			||||||
while true; do
 | 
					while true; do
 | 
				
			||||||
  if $solana_wallet --keypair "$fullnode_id_path" --network "$leader_address" airdrop 3; then
 | 
					  if $solana_wallet --keypair "$fullnode_id_path" --host "${leader_address%:*}" airdrop 3; then
 | 
				
			||||||
    break
 | 
					    break
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -123,7 +123,7 @@ echo "--- RPC API: getTransactionCount"
 | 
				
			|||||||
echo "--- $entrypointIp: wallet sanity"
 | 
					echo "--- $entrypointIp: wallet sanity"
 | 
				
			||||||
(
 | 
					(
 | 
				
			||||||
  set -x
 | 
					  set -x
 | 
				
			||||||
  scripts/wallet-sanity.sh "$entrypointIp":8001
 | 
					  scripts/wallet-sanity.sh --host "$entrypointIp"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo "--- $entrypointIp: verify ledger"
 | 
					echo "--- $entrypointIp: verify ledger"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ source multinode-demo/common.sh
 | 
				
			|||||||
if [[ -z $1 ]]; then # no network argument, use default
 | 
					if [[ -z $1 ]]; then # no network argument, use default
 | 
				
			||||||
  entrypoint=()
 | 
					  entrypoint=()
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
  entrypoint=(-n "$1")
 | 
					  entrypoint=("$@")
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Tokens transferred to this address are lost forever...
 | 
					# Tokens transferred to this address are lost forever...
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -507,7 +507,7 @@ mod tests {
 | 
				
			|||||||
        let thread = rpc_service.thread_hdl.thread();
 | 
					        let thread = rpc_service.thread_hdl.thread();
 | 
				
			||||||
        assert_eq!(thread.name().unwrap(), "solana-jsonrpc");
 | 
					        assert_eq!(thread.name().unwrap(), "solana-jsonrpc");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let rpc_string = get_rpc_request_str(rpc_addr);
 | 
					        let rpc_string = get_rpc_request_str(rpc_addr, false);
 | 
				
			||||||
        let client = reqwest::Client::new();
 | 
					        let client = reqwest::Client::new();
 | 
				
			||||||
        let request = json!({
 | 
					        let request = json!({
 | 
				
			||||||
           "jsonrpc": "2.0",
 | 
					           "jsonrpc": "2.0",
 | 
				
			||||||
@@ -755,7 +755,7 @@ mod tests {
 | 
				
			|||||||
           "params": json!([serial_tx])
 | 
					           "params": json!([serial_tx])
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        let rpc_addr = leader_data.rpc;
 | 
					        let rpc_addr = leader_data.rpc;
 | 
				
			||||||
        let rpc_string = get_rpc_request_str(rpc_addr);
 | 
					        let rpc_string = get_rpc_request_str(rpc_addr, false);
 | 
				
			||||||
        let mut response = client
 | 
					        let mut response = client
 | 
				
			||||||
            .post(&rpc_string)
 | 
					            .post(&rpc_string)
 | 
				
			||||||
            .header(CONTENT_TYPE, "application/json")
 | 
					            .header(CONTENT_TYPE, "application/json")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ impl RpcClient {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn new_with_timeout(addr: SocketAddr, timeout: Duration) -> Self {
 | 
					    pub fn new_with_timeout(addr: SocketAddr, timeout: Duration) -> Self {
 | 
				
			||||||
        let addr = get_rpc_request_str(addr);
 | 
					        let addr = get_rpc_request_str(addr, false);
 | 
				
			||||||
        let client = reqwest::Client::builder()
 | 
					        let client = reqwest::Client::builder()
 | 
				
			||||||
            .timeout(timeout)
 | 
					            .timeout(timeout)
 | 
				
			||||||
            .build()
 | 
					            .build()
 | 
				
			||||||
@@ -30,7 +30,7 @@ impl RpcClient {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn new_from_socket(addr: SocketAddr) -> Self {
 | 
					    pub fn new_from_socket(addr: SocketAddr) -> Self {
 | 
				
			||||||
        Self::new(get_rpc_request_str(addr))
 | 
					        Self::new(get_rpc_request_str(addr, false))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn retry_make_rpc_request(
 | 
					    pub fn retry_make_rpc_request(
 | 
				
			||||||
@@ -77,9 +77,13 @@ impl RpcClient {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get_rpc_request_str(rpc_addr: SocketAddr) -> String {
 | 
					pub fn get_rpc_request_str(rpc_addr: SocketAddr, tls: bool) -> String {
 | 
				
			||||||
 | 
					    if tls {
 | 
				
			||||||
 | 
					        format!("https://{}", rpc_addr)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
        format!("http://{}", rpc_addr)
 | 
					        format!("http://{}", rpc_addr)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait RpcRequestHandler {
 | 
					pub trait RpcRequestHandler {
 | 
				
			||||||
    fn make_rpc_request(
 | 
					    fn make_rpc_request(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,46 @@
 | 
				
			|||||||
use clap::{crate_version, App, Arg, ArgMatches, SubCommand};
 | 
					use clap::{crate_version, App, Arg, ArgMatches, SubCommand};
 | 
				
			||||||
use solana::socketaddr;
 | 
					 | 
				
			||||||
use solana_sdk::signature::{gen_keypair_file, read_keypair, KeypairUtil};
 | 
					use solana_sdk::signature::{gen_keypair_file, read_keypair, KeypairUtil};
 | 
				
			||||||
use solana_wallet::wallet::{parse_command, process_command, WalletConfig, WalletError};
 | 
					use solana_wallet::wallet::{parse_command, process_command, WalletConfig, WalletError};
 | 
				
			||||||
use std::error;
 | 
					use std::error;
 | 
				
			||||||
use std::net::SocketAddr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 network = if let Some(addr) = matches.value_of("network") {
 | 
					    let host = matches
 | 
				
			||||||
        addr.parse().or_else(|_| {
 | 
					        .value_of("host")
 | 
				
			||||||
            Err(WalletError::BadParameter(
 | 
					        .unwrap()
 | 
				
			||||||
                "Invalid network location".to_string(),
 | 
					        .parse()
 | 
				
			||||||
            ))
 | 
					        .or_else(|_| Err(WalletError::BadParameter("Invalid host".to_string())))?;
 | 
				
			||||||
        })?
 | 
					
 | 
				
			||||||
 | 
					    let drone_host = if let Some(drone_host) = matches.value_of("drone_host") {
 | 
				
			||||||
 | 
					        Some(
 | 
				
			||||||
 | 
					            drone_host
 | 
				
			||||||
 | 
					                .parse()
 | 
				
			||||||
 | 
					                .or_else(|_| Err(WalletError::BadParameter("Invalid drone host".to_string())))?,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        socketaddr!("127.0.0.1:8001")
 | 
					        None
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let proxy = matches.value_of("proxy").map(|proxy| proxy.to_string());
 | 
					    let rpc_host = if let Some(rpc_host) = matches.value_of("rpc_host") {
 | 
				
			||||||
 | 
					        Some(
 | 
				
			||||||
 | 
					            rpc_host
 | 
				
			||||||
 | 
					                .parse()
 | 
				
			||||||
 | 
					                .or_else(|_| Err(WalletError::BadParameter("Invalid rpc host".to_string())))?,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        None
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let drone_port = matches
 | 
				
			||||||
 | 
					        .value_of("drone_port")
 | 
				
			||||||
 | 
					        .unwrap()
 | 
				
			||||||
 | 
					        .parse()
 | 
				
			||||||
 | 
					        .or_else(|_| Err(WalletError::BadParameter("Invalid drone port".to_string())))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let rpc_port = matches
 | 
				
			||||||
 | 
					        .value_of("rpc_port")
 | 
				
			||||||
 | 
					        .unwrap()
 | 
				
			||||||
 | 
					        .parse()
 | 
				
			||||||
 | 
					        .or_else(|_| Err(WalletError::BadParameter("Invalid rpc port".to_string())))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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") {
 | 
				
			||||||
@@ -42,40 +66,83 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn erro
 | 
				
			|||||||
    Ok(WalletConfig {
 | 
					    Ok(WalletConfig {
 | 
				
			||||||
        id,
 | 
					        id,
 | 
				
			||||||
        command,
 | 
					        command,
 | 
				
			||||||
        network,
 | 
					        drone_host,
 | 
				
			||||||
        proxy,
 | 
					        drone_port,
 | 
				
			||||||
        drone_port: None,
 | 
					        host,
 | 
				
			||||||
        rpc_client: None,
 | 
					        rpc_client: None,
 | 
				
			||||||
        rpc_port: None,
 | 
					        rpc_host,
 | 
				
			||||||
 | 
					        rpc_port,
 | 
				
			||||||
 | 
					        rpc_tls: matches.is_present("rpc_tls"),
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() -> Result<(), Box<dyn error::Error>> {
 | 
					fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			||||||
    solana_logger::setup();
 | 
					    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 matches = App::new("solana-wallet")
 | 
					    let matches = App::new("solana-wallet")
 | 
				
			||||||
        .version(crate_version!())
 | 
					        .version(crate_version!())
 | 
				
			||||||
        .arg(
 | 
					        .arg(
 | 
				
			||||||
            Arg::with_name("network")
 | 
					            Arg::with_name("host")
 | 
				
			||||||
                .short("n")
 | 
					                .short("n")
 | 
				
			||||||
                .long("network")
 | 
					                .long("host")
 | 
				
			||||||
                .value_name("HOST:PORT")
 | 
					                .value_name("IP ADDRESS")
 | 
				
			||||||
                .takes_value(true)
 | 
					                .takes_value(true)
 | 
				
			||||||
                .help("Rendezvous with the network at this gossip entry point; defaults to 127.0.0.1:8001"),
 | 
					                .default_value(&default_host)
 | 
				
			||||||
        ).arg(
 | 
					                .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"),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .arg(
 | 
				
			||||||
 | 
					            Arg::with_name("drone_host")
 | 
				
			||||||
 | 
					                .long("drone-host")
 | 
				
			||||||
 | 
					                .value_name("IP ADDRESS")
 | 
				
			||||||
 | 
					                .takes_value(true)
 | 
				
			||||||
 | 
					                .help("Drone host to use [default: same as --host]"),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .arg(
 | 
				
			||||||
 | 
					            Arg::with_name("drone_port")
 | 
				
			||||||
 | 
					                .long("drone-port")
 | 
				
			||||||
 | 
					                .value_name("PORT")
 | 
				
			||||||
 | 
					                .takes_value(true)
 | 
				
			||||||
 | 
					                .default_value(&default_drone_port)
 | 
				
			||||||
 | 
					                .help("Drone port to use"),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .arg(
 | 
				
			||||||
            Arg::with_name("keypair")
 | 
					            Arg::with_name("keypair")
 | 
				
			||||||
                .short("k")
 | 
					                .short("k")
 | 
				
			||||||
                .long("keypair")
 | 
					                .long("keypair")
 | 
				
			||||||
                .value_name("PATH")
 | 
					                .value_name("PATH")
 | 
				
			||||||
                .takes_value(true)
 | 
					                .takes_value(true)
 | 
				
			||||||
                .help("/path/to/id.json"),
 | 
					                .help("/path/to/id.json"),
 | 
				
			||||||
        ).arg(
 | 
					        )
 | 
				
			||||||
            Arg::with_name("proxy")
 | 
					        .subcommand(SubCommand::with_name("address").about("Get your public key"))
 | 
				
			||||||
                .long("proxy")
 | 
					 | 
				
			||||||
                .takes_value(true)
 | 
					 | 
				
			||||||
                .value_name("URL")
 | 
					 | 
				
			||||||
                .help("Address of TLS proxy")
 | 
					 | 
				
			||||||
                .conflicts_with("rpc-port")
 | 
					 | 
				
			||||||
        ).subcommand(SubCommand::with_name("address").about("Get your public key"))
 | 
					 | 
				
			||||||
        .subcommand(
 | 
					        .subcommand(
 | 
				
			||||||
            SubCommand::with_name("airdrop")
 | 
					            SubCommand::with_name("airdrop")
 | 
				
			||||||
                .about("Request a batch of tokens")
 | 
					                .about("Request a batch of tokens")
 | 
				
			||||||
@@ -87,7 +154,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The number of tokens to request"),
 | 
					                        .help("The number of tokens to request"),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
        ).subcommand(SubCommand::with_name("balance").about("Get your balance"))
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(SubCommand::with_name("balance").about("Get your balance"))
 | 
				
			||||||
        .subcommand(
 | 
					        .subcommand(
 | 
				
			||||||
            SubCommand::with_name("cancel")
 | 
					            SubCommand::with_name("cancel")
 | 
				
			||||||
                .about("Cancel a transfer")
 | 
					                .about("Cancel a transfer")
 | 
				
			||||||
@@ -99,7 +167,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The process id of the transfer to cancel"),
 | 
					                        .help("The process id of the transfer to cancel"),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
        ).subcommand(
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(
 | 
				
			||||||
            SubCommand::with_name("confirm")
 | 
					            SubCommand::with_name("confirm")
 | 
				
			||||||
                .about("Confirm transaction by signature")
 | 
					                .about("Confirm transaction by signature")
 | 
				
			||||||
                .arg(
 | 
					                .arg(
 | 
				
			||||||
@@ -110,7 +179,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The transaction signature to confirm"),
 | 
					                        .help("The transaction signature to confirm"),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
        ).subcommand(
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(
 | 
				
			||||||
            SubCommand::with_name("deploy")
 | 
					            SubCommand::with_name("deploy")
 | 
				
			||||||
                .about("Deploy a program")
 | 
					                .about("Deploy a program")
 | 
				
			||||||
                .arg(
 | 
					                .arg(
 | 
				
			||||||
@@ -120,12 +190,12 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("/path/to/program.o"),
 | 
					                        .help("/path/to/program.o"),
 | 
				
			||||||
 | 
					                ), // TODO: Add "loader" argument; current default is bpf_loader
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
                // TODO: Add "loader" argument; current default is bpf_loader
 | 
					        .subcommand(
 | 
				
			||||||
        ).subcommand(
 | 
					            SubCommand::with_name("get-transaction-count").about("Get current transaction count"),
 | 
				
			||||||
            SubCommand::with_name("get-transaction-count")
 | 
					        )
 | 
				
			||||||
                .about("Get current transaction count")
 | 
					        .subcommand(
 | 
				
			||||||
        ).subcommand(
 | 
					 | 
				
			||||||
            SubCommand::with_name("pay")
 | 
					            SubCommand::with_name("pay")
 | 
				
			||||||
                .about("Send a payment")
 | 
					                .about("Send a payment")
 | 
				
			||||||
                .arg(
 | 
					                .arg(
 | 
				
			||||||
@@ -135,27 +205,31 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The pubkey of recipient"),
 | 
					                        .help("The pubkey of recipient"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("tokens")
 | 
					                    Arg::with_name("tokens")
 | 
				
			||||||
                        .index(2)
 | 
					                        .index(2)
 | 
				
			||||||
                        .value_name("NUM")
 | 
					                        .value_name("NUM")
 | 
				
			||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The number of tokens to send"),
 | 
					                        .help("The number of tokens to send"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("timestamp")
 | 
					                    Arg::with_name("timestamp")
 | 
				
			||||||
                        .long("after")
 | 
					                        .long("after")
 | 
				
			||||||
                        .value_name("DATETIME")
 | 
					                        .value_name("DATETIME")
 | 
				
			||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .help("A timestamp after which transaction will execute"),
 | 
					                        .help("A timestamp after which transaction will execute"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("timestamp-pubkey")
 | 
					                    Arg::with_name("timestamp-pubkey")
 | 
				
			||||||
                        .long("require-timestamp-from")
 | 
					                        .long("require-timestamp-from")
 | 
				
			||||||
                        .value_name("PUBKEY")
 | 
					                        .value_name("PUBKEY")
 | 
				
			||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .requires("timestamp")
 | 
					                        .requires("timestamp")
 | 
				
			||||||
                        .help("Require timestamp from this third party"),
 | 
					                        .help("Require timestamp from this third party"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("witness")
 | 
					                    Arg::with_name("witness")
 | 
				
			||||||
                        .long("require-signature-from")
 | 
					                        .long("require-signature-from")
 | 
				
			||||||
                        .value_name("PUBKEY")
 | 
					                        .value_name("PUBKEY")
 | 
				
			||||||
@@ -163,12 +237,14 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .multiple(true)
 | 
					                        .multiple(true)
 | 
				
			||||||
                        .use_delimiter(true)
 | 
					                        .use_delimiter(true)
 | 
				
			||||||
                        .help("Any third party signatures required to unlock the tokens"),
 | 
					                        .help("Any third party signatures required to unlock the tokens"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("cancelable")
 | 
					                    Arg::with_name("cancelable")
 | 
				
			||||||
                        .long("cancelable")
 | 
					                        .long("cancelable")
 | 
				
			||||||
                        .takes_value(false),
 | 
					                        .takes_value(false),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
        ).subcommand(
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(
 | 
				
			||||||
            SubCommand::with_name("send-signature")
 | 
					            SubCommand::with_name("send-signature")
 | 
				
			||||||
                .about("Send a signature to authorize a transfer")
 | 
					                .about("Send a signature to authorize a transfer")
 | 
				
			||||||
                .arg(
 | 
					                .arg(
 | 
				
			||||||
@@ -178,15 +254,17 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The pubkey of recipient"),
 | 
					                        .help("The pubkey of recipient"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("process-id")
 | 
					                    Arg::with_name("process-id")
 | 
				
			||||||
                        .index(2)
 | 
					                        .index(2)
 | 
				
			||||||
                        .value_name("PROCESS_ID")
 | 
					                        .value_name("PROCESS_ID")
 | 
				
			||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The process id of the transfer to authorize")
 | 
					                        .help("The process id of the transfer to authorize"),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        ).subcommand(
 | 
					        .subcommand(
 | 
				
			||||||
            SubCommand::with_name("send-timestamp")
 | 
					            SubCommand::with_name("send-timestamp")
 | 
				
			||||||
                .about("Send a timestamp to unlock a transfer")
 | 
					                .about("Send a timestamp to unlock a transfer")
 | 
				
			||||||
                .arg(
 | 
					                .arg(
 | 
				
			||||||
@@ -196,21 +274,24 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 | 
				
			|||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The pubkey of recipient"),
 | 
					                        .help("The pubkey of recipient"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("process-id")
 | 
					                    Arg::with_name("process-id")
 | 
				
			||||||
                        .index(2)
 | 
					                        .index(2)
 | 
				
			||||||
                        .value_name("PROCESS_ID")
 | 
					                        .value_name("PROCESS_ID")
 | 
				
			||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .required(true)
 | 
					                        .required(true)
 | 
				
			||||||
                        .help("The process id of the transfer to unlock")
 | 
					                        .help("The process id of the transfer to unlock"),
 | 
				
			||||||
                ).arg(
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
                    Arg::with_name("datetime")
 | 
					                    Arg::with_name("datetime")
 | 
				
			||||||
                        .long("date")
 | 
					                        .long("date")
 | 
				
			||||||
                        .value_name("DATETIME")
 | 
					                        .value_name("DATETIME")
 | 
				
			||||||
                        .takes_value(true)
 | 
					                        .takes_value(true)
 | 
				
			||||||
                        .help("Optional arbitrary timestamp to apply")
 | 
					                        .help("Optional arbitrary timestamp to apply"),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        ).get_matches();
 | 
					        .get_matches();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let config = parse_args(&matches)?;
 | 
					    let config = parse_args(&matches)?;
 | 
				
			||||||
    let result = process_command(&config)?;
 | 
					    let result = process_command(&config)?;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ use solana::rpc_mock::{request_airdrop_transaction, MockRpcClient as RpcClient};
 | 
				
			|||||||
#[cfg(not(test))]
 | 
					#[cfg(not(test))]
 | 
				
			||||||
use solana::rpc_request::RpcClient;
 | 
					use solana::rpc_request::RpcClient;
 | 
				
			||||||
use solana::rpc_request::{get_rpc_request_str, RpcRequest};
 | 
					use solana::rpc_request::{get_rpc_request_str, RpcRequest};
 | 
				
			||||||
use solana::socketaddr;
 | 
					 | 
				
			||||||
#[cfg(not(test))]
 | 
					#[cfg(not(test))]
 | 
				
			||||||
use solana_drone::drone::request_airdrop_transaction;
 | 
					use solana_drone::drone::request_airdrop_transaction;
 | 
				
			||||||
use solana_drone::drone::DRONE_PORT;
 | 
					use solana_drone::drone::DRONE_PORT;
 | 
				
			||||||
@@ -25,7 +24,7 @@ use solana_sdk::system_transaction::SystemTransaction;
 | 
				
			|||||||
use solana_sdk::transaction::Transaction;
 | 
					use solana_sdk::transaction::Transaction;
 | 
				
			||||||
use std::fs::File;
 | 
					use std::fs::File;
 | 
				
			||||||
use std::io::Read;
 | 
					use std::io::Read;
 | 
				
			||||||
use std::net::{Ipv4Addr, SocketAddr};
 | 
					use std::net::{IpAddr, Ipv4Addr, SocketAddr};
 | 
				
			||||||
use std::str::FromStr;
 | 
					use std::str::FromStr;
 | 
				
			||||||
use std::thread::sleep;
 | 
					use std::thread::sleep;
 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
@@ -85,41 +84,41 @@ impl error::Error for WalletError {
 | 
				
			|||||||
pub struct WalletConfig {
 | 
					pub struct WalletConfig {
 | 
				
			||||||
    pub id: Keypair,
 | 
					    pub id: Keypair,
 | 
				
			||||||
    pub command: WalletCommand,
 | 
					    pub command: WalletCommand,
 | 
				
			||||||
    pub network: SocketAddr,
 | 
					    pub drone_host: Option<IpAddr>,
 | 
				
			||||||
    pub proxy: Option<String>,
 | 
					    pub drone_port: u16,
 | 
				
			||||||
    pub drone_port: Option<u16>,
 | 
					    pub host: IpAddr,
 | 
				
			||||||
    pub rpc_client: Option<RpcClient>,
 | 
					    pub rpc_client: Option<RpcClient>,
 | 
				
			||||||
    pub rpc_port: Option<u16>,
 | 
					    pub rpc_host: Option<IpAddr>,
 | 
				
			||||||
 | 
					    pub rpc_port: u16,
 | 
				
			||||||
 | 
					    pub rpc_tls: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for WalletConfig {
 | 
					impl Default for WalletConfig {
 | 
				
			||||||
    fn default() -> WalletConfig {
 | 
					    fn default() -> WalletConfig {
 | 
				
			||||||
        let default_addr = socketaddr!(0, 8000);
 | 
					 | 
				
			||||||
        WalletConfig {
 | 
					        WalletConfig {
 | 
				
			||||||
            id: Keypair::new(),
 | 
					 | 
				
			||||||
            command: WalletCommand::Balance,
 | 
					            command: WalletCommand::Balance,
 | 
				
			||||||
            network: default_addr,
 | 
					            drone_host: None,
 | 
				
			||||||
            proxy: None,
 | 
					            drone_port: DRONE_PORT,
 | 
				
			||||||
            drone_port: None,
 | 
					            host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
 | 
				
			||||||
 | 
					            id: Keypair::new(),
 | 
				
			||||||
            rpc_client: None,
 | 
					            rpc_client: None,
 | 
				
			||||||
            rpc_port: None,
 | 
					            rpc_host: None,
 | 
				
			||||||
 | 
					            rpc_port: RPC_PORT,
 | 
				
			||||||
 | 
					            rpc_tls: false,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl WalletConfig {
 | 
					impl WalletConfig {
 | 
				
			||||||
    pub fn drone_addr(&self) -> SocketAddr {
 | 
					    pub fn drone_addr(&self) -> SocketAddr {
 | 
				
			||||||
        // Assume drone is running on the provided network entrypoint
 | 
					        SocketAddr::new(self.drone_host.unwrap_or(self.host), self.drone_port)
 | 
				
			||||||
        let mut drone_addr = self.network;
 | 
					 | 
				
			||||||
        drone_addr.set_port(self.drone_port.unwrap_or(DRONE_PORT));
 | 
					 | 
				
			||||||
        drone_addr
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn rpc_addr(&self) -> String {
 | 
					    pub fn rpc_addr(&self) -> String {
 | 
				
			||||||
        let mut rpc_addr = self.network;
 | 
					        get_rpc_request_str(
 | 
				
			||||||
        rpc_addr.set_port(self.rpc_port.unwrap_or(RPC_PORT));
 | 
					            SocketAddr::new(self.rpc_host.unwrap_or(self.host), self.rpc_port),
 | 
				
			||||||
        let rpc_addr_str = get_rpc_request_str(rpc_addr);
 | 
					            self.rpc_tls,
 | 
				
			||||||
        self.proxy.clone().unwrap_or(rpc_addr_str)
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -794,6 +793,7 @@ mod tests {
 | 
				
			|||||||
    use clap::{App, Arg, SubCommand};
 | 
					    use clap::{App, Arg, SubCommand};
 | 
				
			||||||
    use serde_json::Value;
 | 
					    use serde_json::Value;
 | 
				
			||||||
    use solana::rpc_mock::{PUBKEY, SIGNATURE};
 | 
					    use solana::rpc_mock::{PUBKEY, SIGNATURE};
 | 
				
			||||||
 | 
					    use solana::socketaddr;
 | 
				
			||||||
    use solana_sdk::signature::{gen_keypair_file, read_keypair, read_pkcs8, Keypair, KeypairUtil};
 | 
					    use solana_sdk::signature::{gen_keypair_file, read_keypair, read_pkcs8, Keypair, KeypairUtil};
 | 
				
			||||||
    use std::fs;
 | 
					    use std::fs;
 | 
				
			||||||
    use std::net::{Ipv4Addr, SocketAddr};
 | 
					    use std::net::{Ipv4Addr, SocketAddr};
 | 
				
			||||||
@@ -802,15 +802,29 @@ mod tests {
 | 
				
			|||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_wallet_config_drone_addr() {
 | 
					    fn test_wallet_config_drone_addr() {
 | 
				
			||||||
        let mut config = WalletConfig::default();
 | 
					        let mut config = WalletConfig::default();
 | 
				
			||||||
        assert_eq!(config.drone_addr(), socketaddr!(0, DRONE_PORT));
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            config.drone_addr(),
 | 
				
			||||||
 | 
					            SocketAddr::new(config.host, config.drone_port)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        config.drone_port = Some(1234);
 | 
					        config.drone_port = 1234;
 | 
				
			||||||
        assert_eq!(config.drone_addr(), socketaddr!(0, 1234));
 | 
					        assert_eq!(config.drone_addr(), SocketAddr::new(config.host, 1234));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(config.rpc_addr(), "http://0.0.0.0:8899");
 | 
					        config.drone_host = Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)));
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            config.drone_addr(),
 | 
				
			||||||
 | 
					            SocketAddr::new(config.drone_host.unwrap(), 1234)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        config.rpc_port = Some(1234);
 | 
					    #[test]
 | 
				
			||||||
        assert_eq!(config.rpc_addr(), "http://0.0.0.0:1234");
 | 
					    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]
 | 
					    #[test]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,14 +72,12 @@ fn test_wallet_timestamp_tx() {
 | 
				
			|||||||
    let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
 | 
					    let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut config_payer = WalletConfig::default();
 | 
					    let mut config_payer = WalletConfig::default();
 | 
				
			||||||
    config_payer.network = leader_data.gossip;
 | 
					    config_payer.drone_port = drone_addr.port();
 | 
				
			||||||
    config_payer.drone_port = Some(drone_addr.port());
 | 
					    config_payer.rpc_port = leader_data.rpc.port();
 | 
				
			||||||
    config_payer.rpc_port = Some(leader_data.rpc.port());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut config_witness = WalletConfig::default();
 | 
					    let mut config_witness = WalletConfig::default();
 | 
				
			||||||
    config_witness.network = leader_data.gossip;
 | 
					    config_witness.drone_port = drone_addr.port();
 | 
				
			||||||
    config_witness.drone_port = Some(drone_addr.port());
 | 
					    config_witness.rpc_port = leader_data.rpc.port();
 | 
				
			||||||
    config_witness.rpc_port = Some(leader_data.rpc.port());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
 | 
					    assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -173,14 +171,12 @@ fn test_wallet_witness_tx() {
 | 
				
			|||||||
    let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
 | 
					    let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut config_payer = WalletConfig::default();
 | 
					    let mut config_payer = WalletConfig::default();
 | 
				
			||||||
    config_payer.network = leader_data.gossip;
 | 
					    config_payer.drone_port = drone_addr.port();
 | 
				
			||||||
    config_payer.drone_port = Some(drone_addr.port());
 | 
					    config_payer.rpc_port = leader_data.rpc.port();
 | 
				
			||||||
    config_payer.rpc_port = Some(leader_data.rpc.port());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut config_witness = WalletConfig::default();
 | 
					    let mut config_witness = WalletConfig::default();
 | 
				
			||||||
    config_witness.network = leader_data.gossip;
 | 
					    config_witness.drone_port = drone_addr.port();
 | 
				
			||||||
    config_witness.drone_port = Some(drone_addr.port());
 | 
					    config_witness.rpc_port = leader_data.rpc.port();
 | 
				
			||||||
    config_witness.rpc_port = Some(leader_data.rpc.port());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
 | 
					    assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -270,14 +266,12 @@ fn test_wallet_cancel_tx() {
 | 
				
			|||||||
    let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
 | 
					    let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut config_payer = WalletConfig::default();
 | 
					    let mut config_payer = WalletConfig::default();
 | 
				
			||||||
    config_payer.network = leader_data.gossip;
 | 
					    config_payer.drone_port = drone_addr.port();
 | 
				
			||||||
    config_payer.drone_port = Some(drone_addr.port());
 | 
					    config_payer.rpc_port = leader_data.rpc.port();
 | 
				
			||||||
    config_payer.rpc_port = Some(leader_data.rpc.port());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut config_witness = WalletConfig::default();
 | 
					    let mut config_witness = WalletConfig::default();
 | 
				
			||||||
    config_witness.network = leader_data.gossip;
 | 
					    config_witness.drone_port = drone_addr.port();
 | 
				
			||||||
    config_witness.drone_port = Some(drone_addr.port());
 | 
					    config_witness.rpc_port = leader_data.rpc.port();
 | 
				
			||||||
    config_witness.rpc_port = Some(leader_data.rpc.port());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
 | 
					    assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,9 +56,8 @@ fn test_wallet_request_airdrop() {
 | 
				
			|||||||
    let drone_addr = receiver.recv().unwrap();
 | 
					    let drone_addr = receiver.recv().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut bob_config = WalletConfig::default();
 | 
					    let mut bob_config = WalletConfig::default();
 | 
				
			||||||
    bob_config.network = leader_data.gossip;
 | 
					    bob_config.drone_port = drone_addr.port();
 | 
				
			||||||
    bob_config.drone_port = Some(drone_addr.port());
 | 
					    bob_config.rpc_port = leader_data.rpc.port();
 | 
				
			||||||
    bob_config.rpc_port = Some(leader_data.rpc.port());
 | 
					 | 
				
			||||||
    bob_config.command = WalletCommand::Airdrop(50);
 | 
					    bob_config.command = WalletCommand::Airdrop(50);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let sig_response = process_command(&bob_config);
 | 
					    let sig_response = process_command(&bob_config);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user