| @@ -16,7 +16,7 @@ use solana_drone::drone::request_airdrop_transaction; | |||||||
| use solana_drone::drone_mock::request_airdrop_transaction; | use solana_drone::drone_mock::request_airdrop_transaction; | ||||||
| use solana_sdk::{ | use solana_sdk::{ | ||||||
|     account_utils::State, |     account_utils::State, | ||||||
|     bpf_loader, |     bpf_loader, clock, | ||||||
|     fee_calculator::FeeCalculator, |     fee_calculator::FeeCalculator, | ||||||
|     hash::Hash, |     hash::Hash, | ||||||
|     instruction::InstructionError, |     instruction::InstructionError, | ||||||
| @@ -97,6 +97,7 @@ pub enum WalletCommand { | |||||||
|     ShowStorageAccount(Pubkey), |     ShowStorageAccount(Pubkey), | ||||||
|     Deploy(String), |     Deploy(String), | ||||||
|     GetSlot, |     GetSlot, | ||||||
|  |     GetEpochInfo, | ||||||
|     GetTransactionCount, |     GetTransactionCount, | ||||||
|     GetVersion, |     GetVersion, | ||||||
|     Pay { |     Pay { | ||||||
| @@ -343,6 +344,7 @@ pub fn parse_command( | |||||||
|                 .to_string(), |                 .to_string(), | ||||||
|         )), |         )), | ||||||
|         ("get-slot", Some(_matches)) => Ok(WalletCommand::GetSlot), |         ("get-slot", Some(_matches)) => Ok(WalletCommand::GetSlot), | ||||||
|  |         ("get-epoch-info", Some(_matches)) => Ok(WalletCommand::GetEpochInfo), | ||||||
|         ("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount), |         ("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount), | ||||||
|         ("pay", Some(pay_matches)) => { |         ("pay", Some(pay_matches)) => { | ||||||
|             let lamports = parse_amount_lamports( |             let lamports = parse_amount_lamports( | ||||||
| @@ -1077,6 +1079,35 @@ fn process_get_slot(rpc_client: &RpcClient) -> ProcessResult { | |||||||
|     Ok(slot.to_string()) |     Ok(slot.to_string()) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fn process_get_epoch_info(rpc_client: &RpcClient) -> ProcessResult { | ||||||
|  |     let epoch_info = rpc_client.get_epoch_info()?; | ||||||
|  |     println!(); | ||||||
|  |     println_name_value("Current epoch:", &epoch_info.epoch.to_string()); | ||||||
|  |     println_name_value("Current slot:", &epoch_info.absolute_slot.to_string()); | ||||||
|  |     println_name_value( | ||||||
|  |         "Total slots in current epoch:", | ||||||
|  |         &epoch_info.slots_in_epoch.to_string(), | ||||||
|  |     ); | ||||||
|  |     let remaining_slots_in_epoch = epoch_info.slots_in_epoch - epoch_info.slot_index; | ||||||
|  |     println_name_value( | ||||||
|  |         "Remaining slots in current epoch:", | ||||||
|  |         &remaining_slots_in_epoch.to_string(), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     let remaining_time_in_epoch = Duration::from_secs( | ||||||
|  |         remaining_slots_in_epoch * clock::DEFAULT_TICKS_PER_SLOT / clock::DEFAULT_TICKS_PER_SECOND, | ||||||
|  |     ); | ||||||
|  |     println_name_value( | ||||||
|  |         "Time remaining in current epoch:", | ||||||
|  |         &format!( | ||||||
|  |             "{} minutes, {} seconds", | ||||||
|  |             remaining_time_in_epoch.as_secs() / 60, | ||||||
|  |             remaining_time_in_epoch.as_secs() % 60 | ||||||
|  |         ), | ||||||
|  |     ); | ||||||
|  |     Ok("".to_string()) | ||||||
|  | } | ||||||
|  |  | ||||||
| fn process_get_transaction_count(rpc_client: &RpcClient) -> ProcessResult { | fn process_get_transaction_count(rpc_client: &RpcClient) -> ProcessResult { | ||||||
|     let transaction_count = rpc_client.get_transaction_count()?; |     let transaction_count = rpc_client.get_transaction_count()?; | ||||||
|     Ok(transaction_count.to_string()) |     Ok(transaction_count.to_string()) | ||||||
| @@ -1459,6 +1490,7 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         WalletCommand::GetSlot => process_get_slot(&rpc_client), |         WalletCommand::GetSlot => process_get_slot(&rpc_client), | ||||||
|  |         WalletCommand::GetEpochInfo => process_get_epoch_info(&rpc_client), | ||||||
|         WalletCommand::GetTransactionCount => process_get_transaction_count(&rpc_client), |         WalletCommand::GetTransactionCount => process_get_transaction_count(&rpc_client), | ||||||
|  |  | ||||||
|         // If client has positive balance, pay lamports to another address |         // If client has positive balance, pay lamports to another address | ||||||
| @@ -2156,6 +2188,10 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, ' | |||||||
|             SubCommand::with_name("get-slot") |             SubCommand::with_name("get-slot") | ||||||
|                 .about("Get current slot"), |                 .about("Get current slot"), | ||||||
|         ) |         ) | ||||||
|  |         .subcommand( | ||||||
|  |             SubCommand::with_name("get-epoch-info") | ||||||
|  |                 .about("Get information about the current epoch"), | ||||||
|  |         ) | ||||||
|         .subcommand( |         .subcommand( | ||||||
|             SubCommand::with_name("get-transaction-count") |             SubCommand::with_name("get-transaction-count") | ||||||
|                 .about("Get current transaction count"), |                 .about("Get current transaction count"), | ||||||
|   | |||||||
| @@ -1,3 +1,6 @@ | |||||||
|  | #[macro_use] | ||||||
|  | extern crate serde_derive; | ||||||
|  |  | ||||||
| pub mod client_error; | pub mod client_error; | ||||||
| mod generic_rpc_client_request; | mod generic_rpc_client_request; | ||||||
| pub mod mock_rpc_client_request; | pub mod mock_rpc_client_request; | ||||||
|   | |||||||
| @@ -2,23 +2,26 @@ use crate::client_error::ClientError; | |||||||
| use crate::generic_rpc_client_request::GenericRpcClientRequest; | use crate::generic_rpc_client_request::GenericRpcClientRequest; | ||||||
| use crate::mock_rpc_client_request::MockRpcClientRequest; | use crate::mock_rpc_client_request::MockRpcClientRequest; | ||||||
| use crate::rpc_client_request::RpcClientRequest; | use crate::rpc_client_request::RpcClientRequest; | ||||||
| use crate::rpc_request::RpcRequest; | use crate::rpc_request::{RpcEpochInfo, RpcRequest}; | ||||||
| use bincode::serialize; | use bincode::serialize; | ||||||
| use log::*; | use log::*; | ||||||
| use serde_json::{json, Value}; | use serde_json::{json, Value}; | ||||||
| use solana_sdk::account::Account; | use solana_sdk::{ | ||||||
| use solana_sdk::clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT}; |     account::Account, | ||||||
| use solana_sdk::fee_calculator::FeeCalculator; |     clock::{Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT}, | ||||||
| use solana_sdk::hash::Hash; |     fee_calculator::FeeCalculator, | ||||||
| use solana_sdk::inflation::Inflation; |     hash::Hash, | ||||||
| use solana_sdk::pubkey::Pubkey; |     inflation::Inflation, | ||||||
| use solana_sdk::signature::{KeypairUtil, Signature}; |     pubkey::Pubkey, | ||||||
| use solana_sdk::transaction::{self, Transaction, TransactionError}; |     signature::{KeypairUtil, Signature}, | ||||||
| use std::error; |     transaction::{self, Transaction, TransactionError}, | ||||||
| use std::io; | }; | ||||||
| use std::net::SocketAddr; | use std::{ | ||||||
| use std::thread::sleep; |     error, io, | ||||||
| use std::time::{Duration, Instant}; |     net::SocketAddr, | ||||||
|  |     thread::sleep, | ||||||
|  |     time::{Duration, Instant}, | ||||||
|  | }; | ||||||
|  |  | ||||||
| pub struct RpcClient { | pub struct RpcClient { | ||||||
|     client: Box<dyn GenericRpcClientRequest + Send + Sync>, |     client: Box<dyn GenericRpcClientRequest + Send + Sync>, | ||||||
| @@ -76,7 +79,7 @@ impl RpcClient { | |||||||
|         Ok(result) |         Ok(result) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn get_slot(&self) -> io::Result<u64> { |     pub fn get_slot(&self) -> io::Result<Slot> { | ||||||
|         let response = self |         let response = self | ||||||
|             .client |             .client | ||||||
|             .send(&RpcRequest::GetSlot, None, 0) |             .send(&RpcRequest::GetSlot, None, 0) | ||||||
| @@ -95,6 +98,25 @@ impl RpcClient { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn get_epoch_info(&self) -> io::Result<RpcEpochInfo> { | ||||||
|  |         let response = self | ||||||
|  |             .client | ||||||
|  |             .send(&RpcRequest::GetEpochInfo, None, 0) | ||||||
|  |             .map_err(|err| { | ||||||
|  |                 io::Error::new( | ||||||
|  |                     io::ErrorKind::Other, | ||||||
|  |                     format!("GetEpochInfo request failure: {:?}", err), | ||||||
|  |                 ) | ||||||
|  |             })?; | ||||||
|  |  | ||||||
|  |         serde_json::from_value(response).map_err(|err| { | ||||||
|  |             io::Error::new( | ||||||
|  |                 io::ErrorKind::Other, | ||||||
|  |                 format!("GetEpochInfo parse failure: {}", err), | ||||||
|  |             ) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn get_inflation(&self) -> io::Result<Inflation> { |     pub fn get_inflation(&self) -> io::Result<Inflation> { | ||||||
|         let response = self |         let response = self | ||||||
|             .client |             .client | ||||||
|   | |||||||
| @@ -1,6 +1,22 @@ | |||||||
| use serde_json::{json, Value}; | use serde_json::{json, Value}; | ||||||
| use std::{error, fmt}; | use std::{error, fmt}; | ||||||
|  |  | ||||||
|  | #[derive(Serialize, Deserialize, Clone, Debug)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct RpcEpochInfo { | ||||||
|  |     /// The current epoch | ||||||
|  |     pub epoch: u64, | ||||||
|  |  | ||||||
|  |     /// The current slot, relative to the start of the current epoch | ||||||
|  |     pub slot_index: u64, | ||||||
|  |  | ||||||
|  |     /// The number of slots in this epoch | ||||||
|  |     pub slots_in_epoch: u64, | ||||||
|  |  | ||||||
|  |     /// The absolute current slot | ||||||
|  |     pub absolute_slot: u64, | ||||||
|  | } | ||||||
|  |  | ||||||
| #[derive(Debug, PartialEq)] | #[derive(Debug, PartialEq)] | ||||||
| pub enum RpcRequest { | pub enum RpcRequest { | ||||||
|     ConfirmTransaction, |     ConfirmTransaction, | ||||||
| @@ -9,6 +25,7 @@ pub enum RpcRequest { | |||||||
|     GetAccountInfo, |     GetAccountInfo, | ||||||
|     GetBalance, |     GetBalance, | ||||||
|     GetClusterNodes, |     GetClusterNodes, | ||||||
|  |     GetEpochInfo, | ||||||
|     GetGenesisBlockhash, |     GetGenesisBlockhash, | ||||||
|     GetInflation, |     GetInflation, | ||||||
|     GetNumBlocksSinceSignatureConfirmation, |     GetNumBlocksSinceSignatureConfirmation, | ||||||
| @@ -40,6 +57,7 @@ impl RpcRequest { | |||||||
|             RpcRequest::GetAccountInfo => "getAccountInfo", |             RpcRequest::GetAccountInfo => "getAccountInfo", | ||||||
|             RpcRequest::GetBalance => "getBalance", |             RpcRequest::GetBalance => "getBalance", | ||||||
|             RpcRequest::GetClusterNodes => "getClusterNodes", |             RpcRequest::GetClusterNodes => "getClusterNodes", | ||||||
|  |             RpcRequest::GetEpochInfo => "getEpochInfo", | ||||||
|             RpcRequest::GetGenesisBlockhash => "getGenesisBlockhash", |             RpcRequest::GetGenesisBlockhash => "getGenesisBlockhash", | ||||||
|             RpcRequest::GetInflation => "getInflation", |             RpcRequest::GetInflation => "getInflation", | ||||||
|             RpcRequest::GetNumBlocksSinceSignatureConfirmation => { |             RpcRequest::GetNumBlocksSinceSignatureConfirmation => { | ||||||
| @@ -112,6 +130,10 @@ mod tests { | |||||||
|         let request = test_request.build_request_json(1, Some(addr)); |         let request = test_request.build_request_json(1, Some(addr)); | ||||||
|         assert_eq!(request["method"], "getBalance"); |         assert_eq!(request["method"], "getBalance"); | ||||||
|  |  | ||||||
|  |         let test_request = RpcRequest::GetEpochInfo; | ||||||
|  |         let request = test_request.build_request_json(1, None); | ||||||
|  |         assert_eq!(request["method"], "getEpochInfo"); | ||||||
|  |  | ||||||
|         let test_request = RpcRequest::GetInflation; |         let test_request = RpcRequest::GetInflation; | ||||||
|         let request = test_request.build_request_json(1, None); |         let request = test_request.build_request_json(1, None); | ||||||
|         assert_eq!(request["method"], "getInflation"); |         assert_eq!(request["method"], "getInflation"); | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ use crate::version::VERSION; | |||||||
| use bincode::{deserialize, serialize}; | use bincode::{deserialize, serialize}; | ||||||
| use jsonrpc_core::{Error, Metadata, Result}; | use jsonrpc_core::{Error, Metadata, Result}; | ||||||
| use jsonrpc_derive::rpc; | use jsonrpc_derive::rpc; | ||||||
|  | use solana_client::rpc_request::RpcEpochInfo; | ||||||
| use solana_drone::drone::request_airdrop_transaction; | use solana_drone::drone::request_airdrop_transaction; | ||||||
| use solana_runtime::bank::Bank; | use solana_runtime::bank::Bank; | ||||||
| use solana_sdk::account::Account; | use solana_sdk::account::Account; | ||||||
| @@ -267,22 +268,6 @@ pub struct RpcVoteAccountInfo { | |||||||
|     pub last_vote: u64, |     pub last_vote: u64, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Clone, Debug)] |  | ||||||
| #[serde(rename_all = "camelCase")] |  | ||||||
| pub struct RpcEpochInfo { |  | ||||||
|     /// The current epoch |  | ||||||
|     pub epoch: u64, |  | ||||||
|  |  | ||||||
|     /// The current slot, relative to the start of the current epoch |  | ||||||
|     pub slot_index: u64, |  | ||||||
|  |  | ||||||
|     /// The number of slots in this epoch |  | ||||||
|     pub slots_in_epoch: u64, |  | ||||||
|  |  | ||||||
|     /// The absolute current slot |  | ||||||
|     pub absolute_slot: u64, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Clone, Debug)] | #[derive(Serialize, Deserialize, Clone, Debug)] | ||||||
| #[serde(rename_all = "kebab-case")] | #[serde(rename_all = "kebab-case")] | ||||||
| pub struct RpcVersionInfo { | pub struct RpcVersionInfo { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user