| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | use bincode::serialize;
 | 
					
						
							| 
									
										
										
										
											2021-02-02 19:53:08 -07:00
										 |  |  | use jsonrpc_core::futures::StreamExt;
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | use jsonrpc_core_client::transports::ws;
 | 
					
						
							| 
									
										
										
										
											2019-01-29 17:03:32 -08:00
										 |  |  | use log::*;
 | 
					
						
							| 
									
										
										
										
											2019-09-24 14:10:59 -06:00
										 |  |  | use reqwest::{self, header::CONTENT_TYPE};
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | use serde_json::{json, Value};
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | use solana_account_decoder::UiAccount;
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  | use solana_client::{
 | 
					
						
							| 
									
										
										
										
											2021-08-09 12:45:00 -05:00
										 |  |  |     client_error::{ClientErrorKind, Result as ClientResult},
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     rpc_client::RpcClient,
 | 
					
						
							| 
									
										
										
										
											2021-04-20 16:19:54 +08:00
										 |  |  |     rpc_config::{RpcAccountInfoConfig, RpcSignatureSubscribeConfig},
 | 
					
						
							| 
									
										
										
										
											2021-08-09 12:45:00 -05:00
										 |  |  |     rpc_request::RpcError,
 | 
					
						
							| 
									
										
										
										
											2021-03-12 21:44:06 +08:00
										 |  |  |     rpc_response::{Response, RpcSignatureResult, SlotUpdate},
 | 
					
						
							| 
									
										
										
										
											2021-04-23 09:35:12 +08:00
										 |  |  |     tpu_client::{TpuClient, TpuClientConfig},
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  | };
 | 
					
						
							| 
									
										
										
										
											2021-05-19 00:54:28 -06:00
										 |  |  | use solana_core::test_validator::TestValidator;
 | 
					
						
							|  |  |  | use solana_rpc::rpc_pubsub::gen_client::Client as PubsubClient;
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  | use solana_sdk::{
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  |     commitment_config::CommitmentConfig,
 | 
					
						
							|  |  |  |     hash::Hash,
 | 
					
						
							| 
									
										
										
										
											2021-03-12 21:44:06 +08:00
										 |  |  |     pubkey::Pubkey,
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  |     signature::{Keypair, Signer},
 | 
					
						
							|  |  |  |     system_transaction,
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:23:14 -07:00
										 |  |  |     transaction::Transaction,
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  | };
 | 
					
						
							| 
									
										
										
										
											2021-07-23 15:25:03 +00:00
										 |  |  | use solana_streamer::socket::SocketAddrSpace;
 | 
					
						
							| 
									
										
										
										
											2021-04-12 20:33:40 -06:00
										 |  |  | use solana_transaction_status::TransactionStatus;
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | use std::{
 | 
					
						
							|  |  |  |     collections::HashSet,
 | 
					
						
							|  |  |  |     net::UdpSocket,
 | 
					
						
							| 
									
										
										
										
											2021-03-12 21:44:06 +08:00
										 |  |  |     sync::{mpsc::channel, Arc},
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |     thread::sleep,
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |     time::{Duration, Instant},
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | };
 | 
					
						
							| 
									
										
										
										
											2021-07-26 12:32:17 -06:00
										 |  |  | use tokio::runtime::Runtime;
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  | macro_rules! json_req {
 | 
					
						
							|  |  |  |     ($method: expr, $params: expr) => {{
 | 
					
						
							|  |  |  |         json!({
 | 
					
						
							|  |  |  |            "jsonrpc": "2.0",
 | 
					
						
							|  |  |  |            "id": 1,
 | 
					
						
							|  |  |  |            "method": $method,
 | 
					
						
							|  |  |  |            "params": $params,
 | 
					
						
							|  |  |  |         })
 | 
					
						
							|  |  |  |     }}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  | fn post_rpc(request: Value, rpc_url: &str) -> Value {
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  |     let client = reqwest::blocking::Client::new();
 | 
					
						
							|  |  |  |     let response = client
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |         .post(rpc_url)
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  |         .header(CONTENT_TYPE, "application/json")
 | 
					
						
							|  |  |  |         .body(request.to_string())
 | 
					
						
							|  |  |  |         .send()
 | 
					
						
							|  |  |  |         .unwrap();
 | 
					
						
							|  |  |  |     serde_json::from_str(&response.text().unwrap()).unwrap()
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | #[test]
 | 
					
						
							|  |  |  | fn test_rpc_send_tx() {
 | 
					
						
							| 
									
										
										
										
											2019-01-29 17:03:32 -08:00
										 |  |  |     solana_logger::setup();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  |     let alice = Keypair::new();
 | 
					
						
							| 
									
										
										
										
											2021-07-23 15:25:03 +00:00
										 |  |  |     let test_validator =
 | 
					
						
							|  |  |  |         TestValidator::with_no_fees(alice.pubkey(), None, SocketAddrSpace::Unspecified);
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let rpc_url = test_validator.rpc_url();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |     let bob_pubkey = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  |     let req = json_req!("getRecentBlockhash", json!([]));
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let json = post_rpc(req, &rpc_url);
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-15 00:25:45 -07:00
										 |  |  |     let blockhash: Hash = json["result"]["value"]["blockhash"]
 | 
					
						
							| 
									
										
										
										
											2019-11-12 14:49:41 -05:00
										 |  |  |         .as_str()
 | 
					
						
							|  |  |  |         .unwrap()
 | 
					
						
							|  |  |  |         .parse()
 | 
					
						
							|  |  |  |         .unwrap();
 | 
					
						
							| 
									
										
										
										
											2019-01-29 17:03:32 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-02 10:25:16 -08:00
										 |  |  |     info!("blockhash: {:?}", blockhash);
 | 
					
						
							| 
									
										
										
										
											2019-05-20 10:03:19 -07:00
										 |  |  |     let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
 | 
					
						
							| 
									
										
										
										
											2020-01-21 22:16:07 -07:00
										 |  |  |     let serialized_encoded_tx = bs58::encode(serialize(&tx).unwrap()).into_string();
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  |     let req = json_req!("sendTransaction", json!([serialized_encoded_tx]));
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let json: Value = post_rpc(req, &rpc_url);
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  |     let signature = &json["result"];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let mut confirmed_tx = false;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-12 20:33:40 -06:00
										 |  |  |     let request = json_req!("getSignatureStatuses", [[signature]]);
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-06 14:30:56 -07:00
										 |  |  |     for _ in 0..solana_sdk::clock::DEFAULT_TICKS_PER_SLOT {
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |         let json = post_rpc(request.clone(), &rpc_url);
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-12 20:33:40 -06:00
										 |  |  |         let result: Option<TransactionStatus> =
 | 
					
						
							|  |  |  |             serde_json::from_value(json["result"]["value"][0].clone()).unwrap();
 | 
					
						
							|  |  |  |         if let Some(result) = result.as_ref() {
 | 
					
						
							|  |  |  |             if result.err.is_none() {
 | 
					
						
							|  |  |  |                 confirmed_tx = true;
 | 
					
						
							|  |  |  |                 break;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 17:03:32 -08:00
										 |  |  |         sleep(Duration::from_millis(500));
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-19 09:31:47 -05:00
										 |  |  |     assert!(confirmed_tx);
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-08 22:40:13 -07:00
										 |  |  |     use solana_account_decoder::UiAccountEncoding;
 | 
					
						
							|  |  |  |     use solana_client::rpc_config::RpcAccountInfoConfig;
 | 
					
						
							|  |  |  |     let config = RpcAccountInfoConfig {
 | 
					
						
							| 
									
										
										
										
											2020-08-15 22:06:39 -07:00
										 |  |  |         encoding: Some(UiAccountEncoding::Base64),
 | 
					
						
							| 
									
										
										
										
											2020-08-08 22:40:13 -07:00
										 |  |  |         commitment: None,
 | 
					
						
							| 
									
										
										
										
											2020-08-10 16:35:29 -06:00
										 |  |  |         data_slice: None,
 | 
					
						
							| 
									
										
										
										
											2020-08-08 22:40:13 -07:00
										 |  |  |     };
 | 
					
						
							|  |  |  |     let req = json_req!(
 | 
					
						
							|  |  |  |         "getAccountInfo",
 | 
					
						
							|  |  |  |         json!([bs58::encode(bob_pubkey).into_string(), config])
 | 
					
						
							|  |  |  |     );
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let json: Value = post_rpc(req, &rpc_url);
 | 
					
						
							| 
									
										
										
										
											2020-08-08 22:40:13 -07:00
										 |  |  |     info!("{:?}", json["result"]["value"]);
 | 
					
						
							| 
									
										
										
										
											2019-01-21 10:48:40 -08:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2019-11-14 11:41:26 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #[test]
 | 
					
						
							|  |  |  | fn test_rpc_invalid_requests() {
 | 
					
						
							|  |  |  |     solana_logger::setup();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  |     let alice = Keypair::new();
 | 
					
						
							| 
									
										
										
										
											2021-07-23 15:25:03 +00:00
										 |  |  |     let test_validator =
 | 
					
						
							|  |  |  |         TestValidator::with_no_fees(alice.pubkey(), None, SocketAddrSpace::Unspecified);
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let rpc_url = test_validator.rpc_url();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |     let bob_pubkey = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-11-14 11:41:26 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // test invalid get_balance request
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  |     let req = json_req!("getBalance", json!(["invalid9999"]));
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let json = post_rpc(req, &rpc_url);
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 11:41:26 -05:00
										 |  |  |     let the_error = json["error"]["message"].as_str().unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-07-03 01:46:29 -06:00
										 |  |  |     assert_eq!(the_error, "Invalid param: Invalid");
 | 
					
						
							| 
									
										
										
										
											2019-11-14 11:41:26 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // test invalid get_account_info request
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  |     let req = json_req!("getAccountInfo", json!(["invalid9999"]));
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let json = post_rpc(req, &rpc_url);
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 11:41:26 -05:00
										 |  |  |     let the_error = json["error"]["message"].as_str().unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-07-03 01:46:29 -06:00
										 |  |  |     assert_eq!(the_error, "Invalid param: Invalid");
 | 
					
						
							| 
									
										
										
										
											2019-11-14 11:41:26 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // test invalid get_account_info request
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  |     let req = json_req!("getAccountInfo", json!([bob_pubkey.to_string()]));
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let json = post_rpc(req, &rpc_url);
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:05:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 11:41:26 -05:00
										 |  |  |     let the_value = &json["result"]["value"];
 | 
					
						
							|  |  |  |     assert!(the_value.is_null());
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-12 21:44:06 +08:00
										 |  |  | #[test]
 | 
					
						
							|  |  |  | fn test_rpc_slot_updates() {
 | 
					
						
							|  |  |  |     solana_logger::setup();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-23 15:25:03 +00:00
										 |  |  |     let test_validator =
 | 
					
						
							|  |  |  |         TestValidator::with_no_fees(Pubkey::new_unique(), None, SocketAddrSpace::Unspecified);
 | 
					
						
							| 
									
										
										
										
											2021-03-12 21:44:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Create the pub sub runtime
 | 
					
						
							|  |  |  |     let rt = Runtime::new().unwrap();
 | 
					
						
							|  |  |  |     let rpc_pubsub_url = test_validator.rpc_pubsub_url();
 | 
					
						
							|  |  |  |     let (update_sender, update_receiver) = channel::<Arc<SlotUpdate>>();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Subscribe to slot updates
 | 
					
						
							|  |  |  |     rt.spawn(async move {
 | 
					
						
							|  |  |  |         let connect = ws::try_connect::<PubsubClient>(&rpc_pubsub_url).unwrap();
 | 
					
						
							|  |  |  |         let client = connect.await.unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 12:32:17 -06:00
										 |  |  |         tokio::spawn(async move {
 | 
					
						
							| 
									
										
										
										
											2021-03-12 21:44:06 +08:00
										 |  |  |             let mut update_sub = client.slots_updates_subscribe().unwrap();
 | 
					
						
							|  |  |  |             loop {
 | 
					
						
							|  |  |  |                 let response = update_sub.next().await.unwrap();
 | 
					
						
							|  |  |  |                 update_sender.send(response.unwrap()).unwrap();
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         });
 | 
					
						
							|  |  |  |     });
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let first_update = update_receiver
 | 
					
						
							|  |  |  |         .recv_timeout(Duration::from_secs(2))
 | 
					
						
							|  |  |  |         .unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Verify that updates are received in order for an upcoming slot
 | 
					
						
							|  |  |  |     let verify_slot = first_update.slot() + 2;
 | 
					
						
							|  |  |  |     let mut expected_update_index = 0;
 | 
					
						
							|  |  |  |     let expected_updates = vec![
 | 
					
						
							|  |  |  |         "CreatedBank",
 | 
					
						
							|  |  |  |         "Completed",
 | 
					
						
							|  |  |  |         "Frozen",
 | 
					
						
							|  |  |  |         "OptimisticConfirmation",
 | 
					
						
							|  |  |  |         "Root",
 | 
					
						
							|  |  |  |     ];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let test_start = Instant::now();
 | 
					
						
							|  |  |  |     loop {
 | 
					
						
							|  |  |  |         assert!(test_start.elapsed() < Duration::from_secs(30));
 | 
					
						
							|  |  |  |         let update = update_receiver
 | 
					
						
							|  |  |  |             .recv_timeout(Duration::from_secs(2))
 | 
					
						
							|  |  |  |             .unwrap();
 | 
					
						
							|  |  |  |         if update.slot() == verify_slot {
 | 
					
						
							|  |  |  |             let update_name = match *update {
 | 
					
						
							|  |  |  |                 SlotUpdate::CreatedBank { .. } => "CreatedBank",
 | 
					
						
							|  |  |  |                 SlotUpdate::Completed { .. } => "Completed",
 | 
					
						
							|  |  |  |                 SlotUpdate::Frozen { .. } => "Frozen",
 | 
					
						
							|  |  |  |                 SlotUpdate::OptimisticConfirmation { .. } => "OptimisticConfirmation",
 | 
					
						
							|  |  |  |                 SlotUpdate::Root { .. } => "Root",
 | 
					
						
							|  |  |  |                 _ => continue,
 | 
					
						
							|  |  |  |             };
 | 
					
						
							|  |  |  |             assert_eq!(update_name, expected_updates[expected_update_index]);
 | 
					
						
							|  |  |  |             expected_update_index += 1;
 | 
					
						
							|  |  |  |             if expected_update_index == expected_updates.len() {
 | 
					
						
							|  |  |  |                 break;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | #[test]
 | 
					
						
							|  |  |  | fn test_rpc_subscriptions() {
 | 
					
						
							|  |  |  |     solana_logger::setup();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  |     let alice = Keypair::new();
 | 
					
						
							| 
									
										
										
										
											2021-07-23 15:25:03 +00:00
										 |  |  |     let test_validator =
 | 
					
						
							|  |  |  |         TestValidator::with_no_fees(alice.pubkey(), None, SocketAddrSpace::Unspecified);
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     transactions_socket.connect(test_validator.tpu()).unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  |     let rpc_client = RpcClient::new(test_validator.rpc_url());
 | 
					
						
							| 
									
										
										
										
											2021-08-13 09:08:20 -07:00
										 |  |  |     let recent_blockhash = rpc_client.get_latest_blockhash().unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |     // Create transaction signatures to subscribe to
 | 
					
						
							|  |  |  |     let transactions: Vec<Transaction> = (0..1000)
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:23:14 -07:00
										 |  |  |         .map(|_| {
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |             system_transaction::transfer(
 | 
					
						
							|  |  |  |                 &alice,
 | 
					
						
							|  |  |  |                 &solana_sdk::pubkey::new_rand(),
 | 
					
						
							|  |  |  |                 1,
 | 
					
						
							| 
									
										
										
										
											2020-12-08 23:18:27 -08:00
										 |  |  |                 recent_blockhash,
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |             )
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:23:14 -07:00
										 |  |  |         })
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |         .collect();
 | 
					
						
							|  |  |  |     let mut signature_set: HashSet<String> = transactions
 | 
					
						
							|  |  |  |         .iter()
 | 
					
						
							|  |  |  |         .map(|tx| tx.signatures[0].to_string())
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |         .collect();
 | 
					
						
							| 
									
										
										
										
											2020-05-07 00:23:06 -06:00
										 |  |  |     let account_set: HashSet<String> = transactions
 | 
					
						
							|  |  |  |         .iter()
 | 
					
						
							|  |  |  |         .map(|tx| tx.message.account_keys[1].to_string())
 | 
					
						
							|  |  |  |         .collect();
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |     // Track when subscriptions are ready
 | 
					
						
							|  |  |  |     let (ready_sender, ready_receiver) = channel::<()>();
 | 
					
						
							| 
									
										
										
										
											2020-05-07 00:23:06 -06:00
										 |  |  |     // Track account notifications are received
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |     let (account_sender, account_receiver) = channel::<Response<UiAccount>>();
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |     // Track when status notifications are received
 | 
					
						
							| 
									
										
										
										
											2020-04-04 16:13:26 -07:00
										 |  |  |     let (status_sender, status_receiver) = channel::<(String, Response<RpcSignatureResult>)>();
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |     // Create the pub sub runtime
 | 
					
						
							| 
									
										
										
										
											2021-02-02 19:53:08 -07:00
										 |  |  |     let rt = Runtime::new().unwrap();
 | 
					
						
							|  |  |  |     let rpc_pubsub_url = test_validator.rpc_pubsub_url();
 | 
					
						
							|  |  |  |     let signature_set_clone = signature_set.clone();
 | 
					
						
							|  |  |  |     rt.spawn(async move {
 | 
					
						
							|  |  |  |         let connect = ws::try_connect::<PubsubClient>(&rpc_pubsub_url).unwrap();
 | 
					
						
							|  |  |  |         let client = connect.await.unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Subscribe to signature notifications
 | 
					
						
							|  |  |  |         for sig in signature_set_clone {
 | 
					
						
							|  |  |  |             let status_sender = status_sender.clone();
 | 
					
						
							|  |  |  |             let mut sig_sub = client
 | 
					
						
							| 
									
										
										
										
											2021-04-20 16:19:54 +08:00
										 |  |  |                 .signature_subscribe(
 | 
					
						
							|  |  |  |                     sig.clone(),
 | 
					
						
							|  |  |  |                     Some(RpcSignatureSubscribeConfig {
 | 
					
						
							|  |  |  |                         commitment: Some(CommitmentConfig::confirmed()),
 | 
					
						
							|  |  |  |                         ..RpcSignatureSubscribeConfig::default()
 | 
					
						
							|  |  |  |                     }),
 | 
					
						
							|  |  |  |                 )
 | 
					
						
							| 
									
										
										
										
											2021-02-02 19:53:08 -07:00
										 |  |  |                 .unwrap_or_else(|err| panic!("sig sub err: {:#?}", err));
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 12:32:17 -06:00
										 |  |  |             tokio::spawn(async move {
 | 
					
						
							| 
									
										
										
										
											2021-02-02 19:53:08 -07:00
										 |  |  |                 let response = sig_sub.next().await.unwrap();
 | 
					
						
							|  |  |  |                 status_sender
 | 
					
						
							|  |  |  |                     .send((sig.clone(), response.unwrap()))
 | 
					
						
							|  |  |  |                     .unwrap();
 | 
					
						
							|  |  |  |             });
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Subscribe to account notifications
 | 
					
						
							|  |  |  |         for pubkey in account_set {
 | 
					
						
							|  |  |  |             let account_sender = account_sender.clone();
 | 
					
						
							|  |  |  |             let mut client_sub = client
 | 
					
						
							| 
									
										
										
										
											2021-04-20 16:19:54 +08:00
										 |  |  |                 .account_subscribe(
 | 
					
						
							|  |  |  |                     pubkey,
 | 
					
						
							|  |  |  |                     Some(RpcAccountInfoConfig {
 | 
					
						
							|  |  |  |                         commitment: Some(CommitmentConfig::confirmed()),
 | 
					
						
							|  |  |  |                         ..RpcAccountInfoConfig::default()
 | 
					
						
							|  |  |  |                     }),
 | 
					
						
							|  |  |  |                 )
 | 
					
						
							| 
									
										
										
										
											2021-02-02 19:53:08 -07:00
										 |  |  |                 .unwrap_or_else(|err| panic!("acct sub err: {:#?}", err));
 | 
					
						
							| 
									
										
										
										
											2021-07-26 12:32:17 -06:00
										 |  |  |             tokio::spawn(async move {
 | 
					
						
							| 
									
										
										
										
											2021-02-02 19:53:08 -07:00
										 |  |  |                 let response = client_sub.next().await.unwrap();
 | 
					
						
							|  |  |  |                 account_sender.send(response.unwrap()).unwrap();
 | 
					
						
							|  |  |  |             });
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Signal ready after the next slot notification
 | 
					
						
							|  |  |  |         let mut slot_sub = client
 | 
					
						
							|  |  |  |             .slot_subscribe()
 | 
					
						
							|  |  |  |             .unwrap_or_else(|err| panic!("sig sub err: {:#?}", err));
 | 
					
						
							| 
									
										
										
										
											2021-07-26 12:32:17 -06:00
										 |  |  |         tokio::spawn(async move {
 | 
					
						
							| 
									
										
										
										
											2021-02-02 19:53:08 -07:00
										 |  |  |             let _response = slot_sub.next().await.unwrap();
 | 
					
						
							|  |  |  |             ready_sender.send(()).unwrap();
 | 
					
						
							|  |  |  |         });
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |     });
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |     // Wait for signature subscriptions
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |     ready_receiver.recv_timeout(Duration::from_secs(2)).unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:00:47 -08:00
										 |  |  |     let rpc_client = RpcClient::new(test_validator.rpc_url());
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |     let mut mint_balance = rpc_client
 | 
					
						
							| 
									
										
										
										
											2021-01-26 12:23:07 -07:00
										 |  |  |         .get_balance_with_commitment(&alice.pubkey(), CommitmentConfig::processed())
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |         .unwrap()
 | 
					
						
							|  |  |  |         .value;
 | 
					
						
							|  |  |  |     assert!(mint_balance >= transactions.len() as u64);
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Send all transactions to tpu socket for processing
 | 
					
						
							|  |  |  |     transactions.iter().for_each(|tx| {
 | 
					
						
							|  |  |  |         transactions_socket
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |             .send(&bincode::serialize(&tx).unwrap())
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |             .unwrap();
 | 
					
						
							|  |  |  |     });
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Track mint balance to know when transactions have completed
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |     let now = Instant::now();
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |     let expected_mint_balance = mint_balance - transactions.len() as u64;
 | 
					
						
							|  |  |  |     while mint_balance != expected_mint_balance && now.elapsed() < Duration::from_secs(5) {
 | 
					
						
							|  |  |  |         mint_balance = rpc_client
 | 
					
						
							| 
									
										
										
										
											2021-01-26 12:23:07 -07:00
										 |  |  |             .get_balance_with_commitment(&alice.pubkey(), CommitmentConfig::processed())
 | 
					
						
							| 
									
										
										
										
											2020-03-29 01:58:51 +08:00
										 |  |  |             .unwrap()
 | 
					
						
							|  |  |  |             .value;
 | 
					
						
							|  |  |  |         sleep(Duration::from_millis(100));
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |     // Wait for all signature subscriptions
 | 
					
						
							| 
									
										
										
										
											2020-05-12 21:05:05 -06:00
										 |  |  |     let deadline = Instant::now() + Duration::from_secs(7);
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |     while !signature_set.is_empty() {
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |         let timeout = deadline.saturating_duration_since(Instant::now());
 | 
					
						
							|  |  |  |         match status_receiver.recv_timeout(timeout) {
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |             Ok((sig, result)) => {
 | 
					
						
							| 
									
										
										
										
											2020-09-03 18:14:45 -06:00
										 |  |  |                 if let RpcSignatureResult::ProcessedSignature(result) = result.value {
 | 
					
						
							| 
									
										
										
										
											2020-09-01 22:06:06 -07:00
										 |  |  |                     assert!(result.err.is_none());
 | 
					
						
							|  |  |  |                     assert!(signature_set.remove(&sig));
 | 
					
						
							|  |  |  |                 } else {
 | 
					
						
							|  |  |  |                     panic!("Unexpected result");
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |             }
 | 
					
						
							|  |  |  |             Err(_err) => {
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |                 panic!(
 | 
					
						
							| 
									
										
										
										
											2020-03-24 08:00:34 +08:00
										 |  |  |                     "recv_timeout, {}/{} signatures remaining",
 | 
					
						
							|  |  |  |                     signature_set.len(),
 | 
					
						
							|  |  |  |                     transactions.len()
 | 
					
						
							|  |  |  |                 );
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 00:23:06 -06:00
										 |  |  |     let deadline = Instant::now() + Duration::from_secs(5);
 | 
					
						
							|  |  |  |     let mut account_notifications = transactions.len();
 | 
					
						
							|  |  |  |     while account_notifications > 0 {
 | 
					
						
							|  |  |  |         let timeout = deadline.saturating_duration_since(Instant::now());
 | 
					
						
							|  |  |  |         match account_receiver.recv_timeout(timeout) {
 | 
					
						
							|  |  |  |             Ok(result) => {
 | 
					
						
							|  |  |  |                 assert_eq!(result.value.lamports, 1);
 | 
					
						
							|  |  |  |                 account_notifications -= 1;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             Err(_err) => {
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |                 panic!(
 | 
					
						
							| 
									
										
										
										
											2020-05-07 00:23:06 -06:00
										 |  |  |                     "recv_timeout, {}/{} accounts remaining",
 | 
					
						
							|  |  |  |                     account_notifications,
 | 
					
						
							|  |  |  |                     transactions.len()
 | 
					
						
							|  |  |  |                 );
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-02-26 12:23:54 +08:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2021-04-23 09:35:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #[test]
 | 
					
						
							|  |  |  | fn test_tpu_send_transaction() {
 | 
					
						
							|  |  |  |     let mint_keypair = Keypair::new();
 | 
					
						
							|  |  |  |     let mint_pubkey = mint_keypair.pubkey();
 | 
					
						
							| 
									
										
										
										
											2021-07-23 15:25:03 +00:00
										 |  |  |     let test_validator =
 | 
					
						
							|  |  |  |         TestValidator::with_no_fees(mint_pubkey, None, SocketAddrSpace::Unspecified);
 | 
					
						
							| 
									
										
										
										
											2021-04-23 09:35:12 +08:00
										 |  |  |     let rpc_client = Arc::new(RpcClient::new_with_commitment(
 | 
					
						
							|  |  |  |         test_validator.rpc_url(),
 | 
					
						
							|  |  |  |         CommitmentConfig::processed(),
 | 
					
						
							|  |  |  |     ));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let tpu_client = TpuClient::new(
 | 
					
						
							|  |  |  |         rpc_client.clone(),
 | 
					
						
							|  |  |  |         &test_validator.rpc_pubsub_url(),
 | 
					
						
							|  |  |  |         TpuClientConfig::default(),
 | 
					
						
							|  |  |  |     )
 | 
					
						
							|  |  |  |     .unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-13 09:08:20 -07:00
										 |  |  |     let recent_blockhash = rpc_client.get_latest_blockhash().unwrap();
 | 
					
						
							| 
									
										
										
										
											2021-04-23 09:35:12 +08:00
										 |  |  |     let tx =
 | 
					
						
							|  |  |  |         system_transaction::transfer(&mint_keypair, &Pubkey::new_unique(), 42, recent_blockhash);
 | 
					
						
							|  |  |  |     assert!(tpu_client.send_transaction(&tx));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let timeout = Duration::from_secs(5);
 | 
					
						
							|  |  |  |     let now = Instant::now();
 | 
					
						
							|  |  |  |     let signatures = vec![tx.signatures[0]];
 | 
					
						
							|  |  |  |     loop {
 | 
					
						
							|  |  |  |         assert!(now.elapsed() < timeout);
 | 
					
						
							|  |  |  |         let statuses = rpc_client.get_signature_statuses(&signatures).unwrap();
 | 
					
						
							|  |  |  |         if statuses.value.get(0).is_some() {
 | 
					
						
							|  |  |  |             return;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2021-08-09 12:45:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #[test]
 | 
					
						
							|  |  |  | fn deserialize_rpc_error() -> ClientResult<()> {
 | 
					
						
							|  |  |  |     solana_logger::setup();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let alice = Keypair::new();
 | 
					
						
							|  |  |  |     let validator = TestValidator::with_no_fees(alice.pubkey(), None, SocketAddrSpace::Unspecified);
 | 
					
						
							|  |  |  |     let rpc_client = RpcClient::new(validator.rpc_url());
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let bob = Keypair::new();
 | 
					
						
							|  |  |  |     let lamports = 50;
 | 
					
						
							| 
									
										
										
										
											2021-08-13 09:08:20 -07:00
										 |  |  |     let blockhash = rpc_client.get_latest_blockhash()?;
 | 
					
						
							|  |  |  |     let mut tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, blockhash);
 | 
					
						
							| 
									
										
										
										
											2021-08-09 12:45:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // This will cause an error
 | 
					
						
							|  |  |  |     tx.signatures.clear();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let err = rpc_client.send_transaction(&tx);
 | 
					
						
							|  |  |  |     let err = err.unwrap_err();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     match err.kind {
 | 
					
						
							|  |  |  |         ClientErrorKind::RpcError(RpcError::RpcRequestError { .. }) => {
 | 
					
						
							|  |  |  |             // This is what used to happen
 | 
					
						
							|  |  |  |             panic!()
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         ClientErrorKind::RpcError(RpcError::RpcResponseError { .. }) => Ok(()),
 | 
					
						
							|  |  |  |         _ => {
 | 
					
						
							|  |  |  |             panic!()
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 |