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:
		
				
					committed by
					
						 Tyera Eulberg
						Tyera Eulberg
					
				
			
			
				
	
			
			
			
						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; | ||||
|     drone_addr.set_port(DRONE_PORT); | ||||
|  | ||||
|     let mut rpc_addr = leader.contact_info.tpu; | ||||
|     rpc_addr.set_port(RPC_PORT); | ||||
|     let rpc_addr = if let Some(proxy) = matches.value_of("proxy") { | ||||
|         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)?; | ||||
|  | ||||
| @@ -63,7 +73,7 @@ pub fn parse_args(matches: &ArgMatches) -> Result<WalletConfig, Box<error::Error | ||||
|         leader, | ||||
|         id, | ||||
|         drone_addr, // TODO: Add an option for this. | ||||
|         rpc_addr,   // TODO: Add an option for this. | ||||
|         rpc_addr, | ||||
|         command, | ||||
|     }) | ||||
| } | ||||
| @@ -92,6 +102,19 @@ fn main() -> Result<(), Box<error::Error>> { | ||||
|                 .value_name("SECS") | ||||
|                 .takes_value(true) | ||||
|                 .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::with_name("airdrop") | ||||
|                 .about("Request a batch of tokens") | ||||
|   | ||||
| @@ -94,6 +94,7 @@ extern crate ring; | ||||
| extern crate serde; | ||||
| #[macro_use] | ||||
| extern crate serde_derive; | ||||
| #[macro_use] | ||||
| extern crate serde_json; | ||||
| extern crate sha2; | ||||
| extern crate socket2; | ||||
|   | ||||
| @@ -59,7 +59,7 @@ pub struct WalletConfig { | ||||
|     pub leader: NodeInfo, | ||||
|     pub id: Keypair, | ||||
|     pub drone_addr: SocketAddr, | ||||
|     pub rpc_addr: SocketAddr, | ||||
|     pub rpc_addr: String, | ||||
|     pub command: WalletCommand, | ||||
| } | ||||
|  | ||||
| @@ -70,7 +70,7 @@ impl Default for WalletConfig { | ||||
|             leader: NodeInfo::new_with_socketaddr(&default_addr), | ||||
|             id: Keypair::new(), | ||||
|             drone_addr: default_addr, | ||||
|             rpc_addr: default_addr, | ||||
|             rpc_addr: default_addr.to_string(), | ||||
|             command: WalletCommand::Balance, | ||||
|         } | ||||
|     } | ||||
| @@ -135,17 +135,21 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error | ||||
|         // Get address of this client | ||||
|         WalletCommand::Address => Ok(format!("{}", config.id.pubkey())), | ||||
|         // Request an airdrop from Solana Drone; | ||||
|         // Request amount is set in request_airdrop function | ||||
|         WalletCommand::AirDrop(tokens) => { | ||||
|             println!( | ||||
|                 "Requesting airdrop of {:?} tokens from {}", | ||||
|                 tokens, config.drone_addr | ||||
|             ); | ||||
|             let params = format!("[\"{}\"]", config.id.pubkey()); | ||||
|             let previous_balance = WalletRpcRequest::GetBalance | ||||
|             let params = json!(format!("{}", config.id.pubkey())); | ||||
|             let previous_balance = match WalletRpcRequest::GetBalance | ||||
|                 .make_rpc_request(&config.rpc_addr, 1, Some(params))? | ||||
|                 .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)?; | ||||
|  | ||||
|             // 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; | ||||
|             for _ in 0..20 { | ||||
|                 sleep(Duration::from_millis(500)); | ||||
|                 let params = format!("[\"{}\"]", config.id.pubkey()); | ||||
|                 let params = json!(format!("{}", config.id.pubkey())); | ||||
|                 current_balance = WalletRpcRequest::GetBalance | ||||
|                     .make_rpc_request(&config.rpc_addr, 1, Some(params))? | ||||
|                     .as_i64() | ||||
| @@ -171,7 +175,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error | ||||
|         } | ||||
|         WalletCommand::Balance => { | ||||
|             println!("Balance requested..."); | ||||
|             let params = format!("[\"{}\"]", config.id.pubkey()); | ||||
|             let params = json!(format!("{}", config.id.pubkey())); | ||||
|             let balance = WalletRpcRequest::GetBalance | ||||
|                 .make_rpc_request(&config.rpc_addr, 1, Some(params))? | ||||
|                 .as_i64(); | ||||
| @@ -185,7 +189,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error | ||||
|         } | ||||
|         // Confirm the last client transaction by signature | ||||
|         WalletCommand::Confirm(signature) => { | ||||
|             let params = format!("[\"{}\"]", signature); | ||||
|             let params = json!(format!("{}", signature)); | ||||
|             let confirmation = WalletRpcRequest::ConfirmTransaction | ||||
|                 .make_rpc_request(&config.rpc_addr, 1, Some(params))? | ||||
|                 .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) => { | ||||
|             let result = WalletRpcRequest::GetLastId.make_rpc_request(&config.rpc_addr, 1, 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 serialized = serialize(&tx).unwrap(); | ||||
|             let params = format!("[{}]", serde_json::to_string(&serialized)?); | ||||
|             let params = json!(serialized); | ||||
|             let signature = WalletRpcRequest::SendTransaction.make_rpc_request( | ||||
|                 &config.rpc_addr, | ||||
|                 2, | ||||
|                 Some(params.to_string()), | ||||
|                 Some(params), | ||||
|             )?; | ||||
|             if signature.as_str().is_none() { | ||||
|                 Err(WalletError::RpcRequestError( | ||||
| @@ -307,11 +311,10 @@ pub enum WalletRpcRequest { | ||||
| impl WalletRpcRequest { | ||||
|     fn make_rpc_request( | ||||
|         &self, | ||||
|         rpc_addr: &SocketAddr, | ||||
|         rpc_addr: &String, | ||||
|         id: u64, | ||||
|         params: Option<String>, | ||||
|         params: Option<Value>, | ||||
|     ) -> Result<Value, Box<error::Error>> { | ||||
|         let rpc_string = format!("http://{}", rpc_addr.to_string()); | ||||
|         let jsonrpc = "2.0"; | ||||
|         let method = match self { | ||||
|             WalletRpcRequest::ConfirmTransaction => "confirmTransaction", | ||||
| @@ -324,18 +327,18 @@ impl WalletRpcRequest { | ||||
|             WalletRpcRequest::SendTransaction => "sendTransaction", | ||||
|         }; | ||||
|         let client = reqwest::Client::new(); | ||||
|         let mut request: String = format!( | ||||
|             "{{\"jsonrpc\":\"{}\",\"id\":{},\"method\":\"{}\"", | ||||
|             jsonrpc, id, method | ||||
|         ); | ||||
|         let mut request = json!({ | ||||
|            "jsonrpc": jsonrpc, | ||||
|            "id": id, | ||||
|            "method": method, | ||||
|         }); | ||||
|         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 | ||||
|             .post(&rpc_string) | ||||
|             .post(rpc_addr) | ||||
|             .header(CONTENT_TYPE, "application/json") | ||||
|             .body(request) | ||||
|             .body(request.to_string()) | ||||
|             .send()?; | ||||
|         let json: Value = serde_json::from_str(&response.text()?)?; | ||||
|         if json["error"].is_object() { | ||||
| @@ -499,7 +502,7 @@ mod tests { | ||||
|  | ||||
|         let mut rpc_addr = leader_data.contact_info.ncp; | ||||
|         rpc_addr.set_port(rpc_port); | ||||
|         config.rpc_addr = rpc_addr; | ||||
|         config.rpc_addr = format!("http://{}", rpc_addr.to_string()); | ||||
|  | ||||
|         let tokens = 50; | ||||
|         config.command = WalletCommand::AirDrop(tokens); | ||||
| @@ -569,12 +572,13 @@ mod tests { | ||||
|         run_local_drone(alice.keypair(), leader_data.contact_info.ncp, sender); | ||||
|         let drone_addr = receiver.recv().unwrap(); | ||||
|  | ||||
|         let mut rpc_addr = leader_data.contact_info.ncp; | ||||
|         rpc_addr.set_port(rpc_port); | ||||
|         let mut addr = leader_data.contact_info.ncp; | ||||
|         addr.set_port(rpc_port); | ||||
|         let rpc_addr = format!("http://{}", addr.to_string()); | ||||
|  | ||||
|         let signature = request_airdrop(&drone_addr, &bob_pubkey, 50); | ||||
|         assert!(signature.is_ok()); | ||||
|         let params = format!("[\"{}\"]", signature.unwrap()); | ||||
|         let params = json!(format!("{}", signature.unwrap())); | ||||
|         let confirmation = WalletRpcRequest::ConfirmTransaction | ||||
|             .make_rpc_request(&rpc_addr, 1, Some(params)) | ||||
|             .unwrap() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user