@@ -16,7 +16,7 @@ use solana_drone::drone::request_airdrop_transaction;
 | 
			
		||||
use solana_drone::drone_mock::request_airdrop_transaction;
 | 
			
		||||
use solana_sdk::{
 | 
			
		||||
    account_utils::State,
 | 
			
		||||
    bpf_loader,
 | 
			
		||||
    bpf_loader, clock,
 | 
			
		||||
    fee_calculator::FeeCalculator,
 | 
			
		||||
    hash::Hash,
 | 
			
		||||
    instruction::InstructionError,
 | 
			
		||||
@@ -97,6 +97,7 @@ pub enum WalletCommand {
 | 
			
		||||
    ShowStorageAccount(Pubkey),
 | 
			
		||||
    Deploy(String),
 | 
			
		||||
    GetSlot,
 | 
			
		||||
    GetEpochInfo,
 | 
			
		||||
    GetTransactionCount,
 | 
			
		||||
    GetVersion,
 | 
			
		||||
    Pay {
 | 
			
		||||
@@ -343,6 +344,7 @@ pub fn parse_command(
 | 
			
		||||
                .to_string(),
 | 
			
		||||
        )),
 | 
			
		||||
        ("get-slot", Some(_matches)) => Ok(WalletCommand::GetSlot),
 | 
			
		||||
        ("get-epoch-info", Some(_matches)) => Ok(WalletCommand::GetEpochInfo),
 | 
			
		||||
        ("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount),
 | 
			
		||||
        ("pay", Some(pay_matches)) => {
 | 
			
		||||
            let lamports = parse_amount_lamports(
 | 
			
		||||
@@ -1077,6 +1079,35 @@ fn process_get_slot(rpc_client: &RpcClient) -> ProcessResult {
 | 
			
		||||
    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 {
 | 
			
		||||
    let transaction_count = rpc_client.get_transaction_count()?;
 | 
			
		||||
    Ok(transaction_count.to_string())
 | 
			
		||||
@@ -1459,6 +1490,7 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WalletCommand::GetSlot => process_get_slot(&rpc_client),
 | 
			
		||||
        WalletCommand::GetEpochInfo => process_get_epoch_info(&rpc_client),
 | 
			
		||||
        WalletCommand::GetTransactionCount => process_get_transaction_count(&rpc_client),
 | 
			
		||||
 | 
			
		||||
        // 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")
 | 
			
		||||
                .about("Get current slot"),
 | 
			
		||||
        )
 | 
			
		||||
        .subcommand(
 | 
			
		||||
            SubCommand::with_name("get-epoch-info")
 | 
			
		||||
                .about("Get information about the current epoch"),
 | 
			
		||||
        )
 | 
			
		||||
        .subcommand(
 | 
			
		||||
            SubCommand::with_name("get-transaction-count")
 | 
			
		||||
                .about("Get current transaction count"),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,6 @@
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate serde_derive;
 | 
			
		||||
 | 
			
		||||
pub mod client_error;
 | 
			
		||||
mod generic_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::mock_rpc_client_request::MockRpcClientRequest;
 | 
			
		||||
use crate::rpc_client_request::RpcClientRequest;
 | 
			
		||||
use crate::rpc_request::RpcRequest;
 | 
			
		||||
use crate::rpc_request::{RpcEpochInfo, RpcRequest};
 | 
			
		||||
use bincode::serialize;
 | 
			
		||||
use log::*;
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
use solana_sdk::account::Account;
 | 
			
		||||
use solana_sdk::clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT};
 | 
			
		||||
use solana_sdk::fee_calculator::FeeCalculator;
 | 
			
		||||
use solana_sdk::hash::Hash;
 | 
			
		||||
use solana_sdk::inflation::Inflation;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::signature::{KeypairUtil, Signature};
 | 
			
		||||
use solana_sdk::transaction::{self, Transaction, TransactionError};
 | 
			
		||||
use std::error;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::net::SocketAddr;
 | 
			
		||||
use std::thread::sleep;
 | 
			
		||||
use std::time::{Duration, Instant};
 | 
			
		||||
use solana_sdk::{
 | 
			
		||||
    account::Account,
 | 
			
		||||
    clock::{Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT},
 | 
			
		||||
    fee_calculator::FeeCalculator,
 | 
			
		||||
    hash::Hash,
 | 
			
		||||
    inflation::Inflation,
 | 
			
		||||
    pubkey::Pubkey,
 | 
			
		||||
    signature::{KeypairUtil, Signature},
 | 
			
		||||
    transaction::{self, Transaction, TransactionError},
 | 
			
		||||
};
 | 
			
		||||
use std::{
 | 
			
		||||
    error, io,
 | 
			
		||||
    net::SocketAddr,
 | 
			
		||||
    thread::sleep,
 | 
			
		||||
    time::{Duration, Instant},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub struct RpcClient {
 | 
			
		||||
    client: Box<dyn GenericRpcClientRequest + Send + Sync>,
 | 
			
		||||
@@ -76,7 +79,7 @@ impl RpcClient {
 | 
			
		||||
        Ok(result)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_slot(&self) -> io::Result<u64> {
 | 
			
		||||
    pub fn get_slot(&self) -> io::Result<Slot> {
 | 
			
		||||
        let response = self
 | 
			
		||||
            .client
 | 
			
		||||
            .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> {
 | 
			
		||||
        let response = self
 | 
			
		||||
            .client
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,22 @@
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
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)]
 | 
			
		||||
pub enum RpcRequest {
 | 
			
		||||
    ConfirmTransaction,
 | 
			
		||||
@@ -9,6 +25,7 @@ pub enum RpcRequest {
 | 
			
		||||
    GetAccountInfo,
 | 
			
		||||
    GetBalance,
 | 
			
		||||
    GetClusterNodes,
 | 
			
		||||
    GetEpochInfo,
 | 
			
		||||
    GetGenesisBlockhash,
 | 
			
		||||
    GetInflation,
 | 
			
		||||
    GetNumBlocksSinceSignatureConfirmation,
 | 
			
		||||
@@ -40,6 +57,7 @@ impl RpcRequest {
 | 
			
		||||
            RpcRequest::GetAccountInfo => "getAccountInfo",
 | 
			
		||||
            RpcRequest::GetBalance => "getBalance",
 | 
			
		||||
            RpcRequest::GetClusterNodes => "getClusterNodes",
 | 
			
		||||
            RpcRequest::GetEpochInfo => "getEpochInfo",
 | 
			
		||||
            RpcRequest::GetGenesisBlockhash => "getGenesisBlockhash",
 | 
			
		||||
            RpcRequest::GetInflation => "getInflation",
 | 
			
		||||
            RpcRequest::GetNumBlocksSinceSignatureConfirmation => {
 | 
			
		||||
@@ -112,6 +130,10 @@ mod tests {
 | 
			
		||||
        let request = test_request.build_request_json(1, Some(addr));
 | 
			
		||||
        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 request = test_request.build_request_json(1, None);
 | 
			
		||||
        assert_eq!(request["method"], "getInflation");
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ use crate::version::VERSION;
 | 
			
		||||
use bincode::{deserialize, serialize};
 | 
			
		||||
use jsonrpc_core::{Error, Metadata, Result};
 | 
			
		||||
use jsonrpc_derive::rpc;
 | 
			
		||||
use solana_client::rpc_request::RpcEpochInfo;
 | 
			
		||||
use solana_drone::drone::request_airdrop_transaction;
 | 
			
		||||
use solana_runtime::bank::Bank;
 | 
			
		||||
use solana_sdk::account::Account;
 | 
			
		||||
@@ -267,22 +268,6 @@ pub struct RpcVoteAccountInfo {
 | 
			
		||||
    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)]
 | 
			
		||||
#[serde(rename_all = "kebab-case")]
 | 
			
		||||
pub struct RpcVersionInfo {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user