Request/reqwest improvements
- Use json macro to simplify request builds - Add proxy option for reqwest to use TLS - Add rpc port options for configured nodes
This commit is contained in:
parent
ad4fef4f09
commit
e87cac06da
|
@ -54,8 +54,18 @@ pub fn parse_args(matches: &ArgMatches) -> Result<WalletConfig, Box<error::Error
|
||||||
let mut drone_addr = leader.contact_info.tpu;
|
let mut drone_addr = leader.contact_info.tpu;
|
||||||
drone_addr.set_port(DRONE_PORT);
|
drone_addr.set_port(DRONE_PORT);
|
||||||
|
|
||||||
let mut rpc_addr = leader.contact_info.tpu;
|
let rpc_addr = if let Some(proxy) = matches.value_of("proxy") {
|
||||||
rpc_addr.set_port(RPC_PORT);
|
proxy.to_string()
|
||||||
|
} else {
|
||||||
|
let rpc_port = if let Some(port) = matches.value_of("rpc-port") {
|
||||||
|
port.to_string().parse().expect("integer")
|
||||||
|
} else {
|
||||||
|
RPC_PORT
|
||||||
|
};
|
||||||
|
let mut rpc_addr = leader.contact_info.tpu;
|
||||||
|
rpc_addr.set_port(rpc_port);
|
||||||
|
format!("http://{}", rpc_addr.to_string())
|
||||||
|
};
|
||||||
|
|
||||||
let command = parse_command(id.pubkey(), &matches)?;
|
let command = parse_command(id.pubkey(), &matches)?;
|
||||||
|
|
||||||
|
@ -63,7 +73,7 @@ pub fn parse_args(matches: &ArgMatches) -> Result<WalletConfig, Box<error::Error
|
||||||
leader,
|
leader,
|
||||||
id,
|
id,
|
||||||
drone_addr, // TODO: Add an option for this.
|
drone_addr, // TODO: Add an option for this.
|
||||||
rpc_addr, // TODO: Add an option for this.
|
rpc_addr,
|
||||||
command,
|
command,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -92,6 +102,19 @@ fn main() -> Result<(), Box<error::Error>> {
|
||||||
.value_name("SECS")
|
.value_name("SECS")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("Max seconds to wait to get necessary gossip from the network"),
|
.help("Max seconds to wait to get necessary gossip from the network"),
|
||||||
|
).arg(
|
||||||
|
Arg::with_name("rpc-port")
|
||||||
|
.long("port")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("NUM")
|
||||||
|
.help("Optional rpc-port configuration to connect to non-default nodes")
|
||||||
|
).arg(
|
||||||
|
Arg::with_name("proxy")
|
||||||
|
.long("proxy")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("URL")
|
||||||
|
.help("Address of TLS proxy")
|
||||||
|
.conflicts_with("rpc-port")
|
||||||
).subcommand(
|
).subcommand(
|
||||||
SubCommand::with_name("airdrop")
|
SubCommand::with_name("airdrop")
|
||||||
.about("Request a batch of tokens")
|
.about("Request a batch of tokens")
|
||||||
|
|
|
@ -94,6 +94,7 @@ extern crate ring;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
#[macro_use]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate sha2;
|
extern crate sha2;
|
||||||
extern crate socket2;
|
extern crate socket2;
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub struct WalletConfig {
|
||||||
pub leader: NodeInfo,
|
pub leader: NodeInfo,
|
||||||
pub id: Keypair,
|
pub id: Keypair,
|
||||||
pub drone_addr: SocketAddr,
|
pub drone_addr: SocketAddr,
|
||||||
pub rpc_addr: SocketAddr,
|
pub rpc_addr: String,
|
||||||
pub command: WalletCommand,
|
pub command: WalletCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ impl Default for WalletConfig {
|
||||||
leader: NodeInfo::new_with_socketaddr(&default_addr),
|
leader: NodeInfo::new_with_socketaddr(&default_addr),
|
||||||
id: Keypair::new(),
|
id: Keypair::new(),
|
||||||
drone_addr: default_addr,
|
drone_addr: default_addr,
|
||||||
rpc_addr: default_addr,
|
rpc_addr: default_addr.to_string(),
|
||||||
command: WalletCommand::Balance,
|
command: WalletCommand::Balance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,17 +135,21 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
||||||
// Get address of this client
|
// Get address of this client
|
||||||
WalletCommand::Address => Ok(format!("{}", config.id.pubkey())),
|
WalletCommand::Address => Ok(format!("{}", config.id.pubkey())),
|
||||||
// Request an airdrop from Solana Drone;
|
// Request an airdrop from Solana Drone;
|
||||||
// Request amount is set in request_airdrop function
|
|
||||||
WalletCommand::AirDrop(tokens) => {
|
WalletCommand::AirDrop(tokens) => {
|
||||||
println!(
|
println!(
|
||||||
"Requesting airdrop of {:?} tokens from {}",
|
"Requesting airdrop of {:?} tokens from {}",
|
||||||
tokens, config.drone_addr
|
tokens, config.drone_addr
|
||||||
);
|
);
|
||||||
let params = format!("[\"{}\"]", config.id.pubkey());
|
let params = json!(format!("{}", config.id.pubkey()));
|
||||||
let previous_balance = WalletRpcRequest::GetBalance
|
let previous_balance = match WalletRpcRequest::GetBalance
|
||||||
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
||||||
.as_i64()
|
.as_i64()
|
||||||
.unwrap_or(0);
|
{
|
||||||
|
Some(tokens) => tokens,
|
||||||
|
None => Err(WalletError::RpcRequestError(
|
||||||
|
"Received result of an unexpected type".to_string(),
|
||||||
|
))?,
|
||||||
|
};
|
||||||
request_airdrop(&config.drone_addr, &config.id.pubkey(), tokens as u64)?;
|
request_airdrop(&config.drone_addr, &config.id.pubkey(), tokens as u64)?;
|
||||||
|
|
||||||
// TODO: return airdrop Result from Drone instead of polling the
|
// TODO: return airdrop Result from Drone instead of polling the
|
||||||
|
@ -153,7 +157,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
||||||
let mut current_balance = previous_balance;
|
let mut current_balance = previous_balance;
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
sleep(Duration::from_millis(500));
|
sleep(Duration::from_millis(500));
|
||||||
let params = format!("[\"{}\"]", config.id.pubkey());
|
let params = json!(format!("{}", config.id.pubkey()));
|
||||||
current_balance = WalletRpcRequest::GetBalance
|
current_balance = WalletRpcRequest::GetBalance
|
||||||
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
||||||
.as_i64()
|
.as_i64()
|
||||||
|
@ -171,7 +175,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
||||||
}
|
}
|
||||||
WalletCommand::Balance => {
|
WalletCommand::Balance => {
|
||||||
println!("Balance requested...");
|
println!("Balance requested...");
|
||||||
let params = format!("[\"{}\"]", config.id.pubkey());
|
let params = json!(format!("{}", config.id.pubkey()));
|
||||||
let balance = WalletRpcRequest::GetBalance
|
let balance = WalletRpcRequest::GetBalance
|
||||||
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
||||||
.as_i64();
|
.as_i64();
|
||||||
|
@ -185,7 +189,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
||||||
}
|
}
|
||||||
// Confirm the last client transaction by signature
|
// Confirm the last client transaction by signature
|
||||||
WalletCommand::Confirm(signature) => {
|
WalletCommand::Confirm(signature) => {
|
||||||
let params = format!("[\"{}\"]", signature);
|
let params = json!(format!("{}", signature));
|
||||||
let confirmation = WalletRpcRequest::ConfirmTransaction
|
let confirmation = WalletRpcRequest::ConfirmTransaction
|
||||||
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
.make_rpc_request(&config.rpc_addr, 1, Some(params))?
|
||||||
.as_bool();
|
.as_bool();
|
||||||
|
@ -202,7 +206,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
||||||
))?,
|
))?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If client has positive balance, spend tokens in {balance} number of transactions
|
// If client has positive balance, pay tokens to another address
|
||||||
WalletCommand::Pay(tokens, to) => {
|
WalletCommand::Pay(tokens, to) => {
|
||||||
let result = WalletRpcRequest::GetLastId.make_rpc_request(&config.rpc_addr, 1, None)?;
|
let result = WalletRpcRequest::GetLastId.make_rpc_request(&config.rpc_addr, 1, None)?;
|
||||||
if result.as_str().is_none() {
|
if result.as_str().is_none() {
|
||||||
|
@ -218,11 +222,11 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
||||||
|
|
||||||
let tx = Transaction::new(&config.id, to, tokens, last_id);
|
let tx = Transaction::new(&config.id, to, tokens, last_id);
|
||||||
let serialized = serialize(&tx).unwrap();
|
let serialized = serialize(&tx).unwrap();
|
||||||
let params = format!("[{}]", serde_json::to_string(&serialized)?);
|
let params = json!(serialized);
|
||||||
let signature = WalletRpcRequest::SendTransaction.make_rpc_request(
|
let signature = WalletRpcRequest::SendTransaction.make_rpc_request(
|
||||||
&config.rpc_addr,
|
&config.rpc_addr,
|
||||||
2,
|
2,
|
||||||
Some(params.to_string()),
|
Some(params),
|
||||||
)?;
|
)?;
|
||||||
if signature.as_str().is_none() {
|
if signature.as_str().is_none() {
|
||||||
Err(WalletError::RpcRequestError(
|
Err(WalletError::RpcRequestError(
|
||||||
|
@ -307,11 +311,10 @@ pub enum WalletRpcRequest {
|
||||||
impl WalletRpcRequest {
|
impl WalletRpcRequest {
|
||||||
fn make_rpc_request(
|
fn make_rpc_request(
|
||||||
&self,
|
&self,
|
||||||
rpc_addr: &SocketAddr,
|
rpc_addr: &String,
|
||||||
id: u64,
|
id: u64,
|
||||||
params: Option<String>,
|
params: Option<Value>,
|
||||||
) -> Result<Value, Box<error::Error>> {
|
) -> Result<Value, Box<error::Error>> {
|
||||||
let rpc_string = format!("http://{}", rpc_addr.to_string());
|
|
||||||
let jsonrpc = "2.0";
|
let jsonrpc = "2.0";
|
||||||
let method = match self {
|
let method = match self {
|
||||||
WalletRpcRequest::ConfirmTransaction => "confirmTransaction",
|
WalletRpcRequest::ConfirmTransaction => "confirmTransaction",
|
||||||
|
@ -324,18 +327,18 @@ impl WalletRpcRequest {
|
||||||
WalletRpcRequest::SendTransaction => "sendTransaction",
|
WalletRpcRequest::SendTransaction => "sendTransaction",
|
||||||
};
|
};
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let mut request: String = format!(
|
let mut request = json!({
|
||||||
"{{\"jsonrpc\":\"{}\",\"id\":{},\"method\":\"{}\"",
|
"jsonrpc": jsonrpc,
|
||||||
jsonrpc, id, method
|
"id": id,
|
||||||
);
|
"method": method,
|
||||||
|
});
|
||||||
if let Some(param_string) = params {
|
if let Some(param_string) = params {
|
||||||
request.push_str(&format!(",\"params\":{}", param_string));
|
request["params"] = json!(vec![param_string]);
|
||||||
}
|
}
|
||||||
request.push_str(&"}".to_string());
|
|
||||||
let mut response = client
|
let mut response = client
|
||||||
.post(&rpc_string)
|
.post(rpc_addr)
|
||||||
.header(CONTENT_TYPE, "application/json")
|
.header(CONTENT_TYPE, "application/json")
|
||||||
.body(request)
|
.body(request.to_string())
|
||||||
.send()?;
|
.send()?;
|
||||||
let json: Value = serde_json::from_str(&response.text()?)?;
|
let json: Value = serde_json::from_str(&response.text()?)?;
|
||||||
if json["error"].is_object() {
|
if json["error"].is_object() {
|
||||||
|
@ -499,7 +502,7 @@ mod tests {
|
||||||
|
|
||||||
let mut rpc_addr = leader_data.contact_info.ncp;
|
let mut rpc_addr = leader_data.contact_info.ncp;
|
||||||
rpc_addr.set_port(rpc_port);
|
rpc_addr.set_port(rpc_port);
|
||||||
config.rpc_addr = rpc_addr;
|
config.rpc_addr = format!("http://{}", rpc_addr.to_string());
|
||||||
|
|
||||||
let tokens = 50;
|
let tokens = 50;
|
||||||
config.command = WalletCommand::AirDrop(tokens);
|
config.command = WalletCommand::AirDrop(tokens);
|
||||||
|
@ -569,12 +572,13 @@ mod tests {
|
||||||
run_local_drone(alice.keypair(), leader_data.contact_info.ncp, sender);
|
run_local_drone(alice.keypair(), leader_data.contact_info.ncp, sender);
|
||||||
let drone_addr = receiver.recv().unwrap();
|
let drone_addr = receiver.recv().unwrap();
|
||||||
|
|
||||||
let mut rpc_addr = leader_data.contact_info.ncp;
|
let mut addr = leader_data.contact_info.ncp;
|
||||||
rpc_addr.set_port(rpc_port);
|
addr.set_port(rpc_port);
|
||||||
|
let rpc_addr = format!("http://{}", addr.to_string());
|
||||||
|
|
||||||
let signature = request_airdrop(&drone_addr, &bob_pubkey, 50);
|
let signature = request_airdrop(&drone_addr, &bob_pubkey, 50);
|
||||||
assert!(signature.is_ok());
|
assert!(signature.is_ok());
|
||||||
let params = format!("[\"{}\"]", signature.unwrap());
|
let params = json!(format!("{}", signature.unwrap()));
|
||||||
let confirmation = WalletRpcRequest::ConfirmTransaction
|
let confirmation = WalletRpcRequest::ConfirmTransaction
|
||||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
Loading…
Reference in New Issue