Remove tuples from JSON RPC responses (#7806)
* Remove RpcConfirmedBlock tuple * Remove getRecentBlockhash tuple * Remove getProgramAccounts tuple * Remove tuple from get_signature_confirmation_status * Collect Rpc response types * Camel-case epoch schedule for rpc response * Remove getBlockCommitment tuple * Remove getStorageTurn tuple * Update json-rpc docs
This commit is contained in:
@ -8,4 +8,5 @@ pub mod perf_utils;
|
||||
pub mod rpc_client;
|
||||
pub mod rpc_client_request;
|
||||
pub mod rpc_request;
|
||||
pub mod rpc_response;
|
||||
pub mod thin_client;
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::rpc_request::{Response, RpcResponseContext};
|
||||
use crate::{
|
||||
client_error::ClientError, generic_rpc_client_request::GenericRpcClientRequest,
|
||||
client_error::ClientError,
|
||||
generic_rpc_client_request::GenericRpcClientRequest,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{Response, RpcResponseContext},
|
||||
};
|
||||
use serde_json::{Number, Value};
|
||||
use solana_sdk::{
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::rpc_request::{Response, RpcResponse};
|
||||
use crate::{
|
||||
client_error::ClientError,
|
||||
generic_rpc_client_request::GenericRpcClientRequest,
|
||||
mock_rpc_client_request::{MockRpcClientRequest, Mocks},
|
||||
rpc_client_request::RpcClientRequest,
|
||||
rpc_request::{
|
||||
RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule, RpcRequest,
|
||||
RpcVersionInfo, RpcVoteAccountStatus,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{
|
||||
Response, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo,
|
||||
RpcLeaderSchedule, RpcResponse, RpcVersionInfo, RpcVoteAccountStatus,
|
||||
},
|
||||
};
|
||||
use bincode::serialize;
|
||||
@ -753,8 +753,12 @@ impl RpcClient {
|
||||
|
||||
let Response {
|
||||
context,
|
||||
value: (blockhash_str, fee_calculator),
|
||||
} = serde_json::from_value::<Response<(String, FeeCalculator)>>(response).map_err(
|
||||
value:
|
||||
RpcBlockhashFeeCalculator {
|
||||
blockhash,
|
||||
fee_calculator,
|
||||
},
|
||||
} = serde_json::from_value::<Response<RpcBlockhashFeeCalculator>>(response).map_err(
|
||||
|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
@ -762,7 +766,7 @@ impl RpcClient {
|
||||
)
|
||||
},
|
||||
)?;
|
||||
let blockhash = blockhash_str.parse().map_err(|err| {
|
||||
let blockhash = blockhash.parse().map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetRecentBlockhash hash parse failure: {:?}", err),
|
||||
|
@ -1,197 +1,5 @@
|
||||
use bincode::serialize;
|
||||
use jsonrpc_core::Result as JsonResult;
|
||||
use serde_json::{json, Value};
|
||||
use solana_sdk::{
|
||||
clock::{Epoch, Slot},
|
||||
message::MessageHeader,
|
||||
transaction::{Result, Transaction},
|
||||
};
|
||||
use std::{collections::HashMap, error, fmt, io, net::SocketAddr};
|
||||
|
||||
pub type RpcResponseIn<T> = JsonResult<Response<T>>;
|
||||
pub type RpcResponse<T> = io::Result<Response<T>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RpcResponseContext {
|
||||
pub slot: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Response<T> {
|
||||
pub context: RpcResponseContext,
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedBlock {
|
||||
pub previous_blockhash: String,
|
||||
pub blockhash: String,
|
||||
pub parent_slot: Slot,
|
||||
pub transactions: Vec<(RpcEncodedTransaction, Option<RpcTransactionStatus>)>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum RpcTransactionEncoding {
|
||||
Binary,
|
||||
Json,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum RpcEncodedTransaction {
|
||||
Binary(String),
|
||||
Json(RpcTransaction),
|
||||
}
|
||||
|
||||
impl RpcEncodedTransaction {
|
||||
pub fn encode(transaction: Transaction, encoding: RpcTransactionEncoding) -> Self {
|
||||
if encoding == RpcTransactionEncoding::Json {
|
||||
RpcEncodedTransaction::Json(RpcTransaction {
|
||||
signatures: transaction
|
||||
.signatures
|
||||
.iter()
|
||||
.map(|sig| sig.to_string())
|
||||
.collect(),
|
||||
message: RpcMessage {
|
||||
header: transaction.message.header,
|
||||
account_keys: transaction
|
||||
.message
|
||||
.account_keys
|
||||
.iter()
|
||||
.map(|pubkey| pubkey.to_string())
|
||||
.collect(),
|
||||
recent_blockhash: transaction.message.recent_blockhash.to_string(),
|
||||
instructions: transaction
|
||||
.message
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|instruction| RpcCompiledInstruction {
|
||||
program_id_index: instruction.program_id_index,
|
||||
accounts: instruction.accounts.clone(),
|
||||
data: bs58::encode(instruction.data.clone()).into_string(),
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
RpcEncodedTransaction::Binary(
|
||||
bs58::encode(serialize(&transaction).unwrap()).into_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Transaction for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransaction {
|
||||
pub signatures: Vec<String>,
|
||||
pub message: RpcMessage,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcMessage {
|
||||
pub header: MessageHeader,
|
||||
pub account_keys: Vec<String>,
|
||||
pub recent_blockhash: String,
|
||||
pub instructions: Vec<RpcCompiledInstruction>,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcCompiledInstruction {
|
||||
pub program_id_index: u8,
|
||||
pub accounts: Vec<u8>,
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionStatus {
|
||||
pub status: Result<()>,
|
||||
pub fee: u64,
|
||||
pub pre_balances: Vec<u64>,
|
||||
pub post_balances: Vec<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct RpcContactInfo {
|
||||
/// Pubkey of the node as a base-58 string
|
||||
pub pubkey: String,
|
||||
/// Gossip port
|
||||
pub gossip: Option<SocketAddr>,
|
||||
/// Tpu port
|
||||
pub tpu: Option<SocketAddr>,
|
||||
/// JSON RPC port
|
||||
pub rpc: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
||||
pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcEpochInfo {
|
||||
/// The current epoch
|
||||
pub epoch: Epoch,
|
||||
|
||||
/// 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: Slot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct RpcVersionInfo {
|
||||
/// The current version of solana-core
|
||||
pub solana_core: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountStatus {
|
||||
pub current: Vec<RpcVoteAccountInfo>,
|
||||
pub delinquent: Vec<RpcVoteAccountInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountInfo {
|
||||
/// Vote account pubkey as base-58 encoded string
|
||||
pub vote_pubkey: String,
|
||||
|
||||
/// The pubkey of the node that votes using this account
|
||||
pub node_pubkey: String,
|
||||
|
||||
/// The current stake, in lamports, delegated to this vote account
|
||||
pub activated_stake: u64,
|
||||
|
||||
/// An 8-bit integer used as a fraction (commission/MAX_U8) for rewards payout
|
||||
pub commission: u8,
|
||||
|
||||
/// Whether this account is staked for the current epoch
|
||||
pub epoch_vote_account: bool,
|
||||
|
||||
/// History of how many credits earned by the end of each epoch
|
||||
/// each tuple is (Epoch, credits, prev_credits)
|
||||
pub epoch_credits: Vec<(Epoch, u64, u64)>,
|
||||
|
||||
/// Most recent slot voted on by this vote account (0 if no votes exist)
|
||||
pub last_vote: u64,
|
||||
|
||||
/// Current root slot for this vote account (0 if not root slot exists)
|
||||
pub root_slot: Slot,
|
||||
}
|
||||
use std::{error, fmt};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub enum RpcRequest {
|
||||
|
237
client/src/rpc_response.rs
Normal file
237
client/src/rpc_response.rs
Normal file
@ -0,0 +1,237 @@
|
||||
use bincode::serialize;
|
||||
use jsonrpc_core::Result as JsonResult;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
clock::{Epoch, Slot},
|
||||
fee_calculator::FeeCalculator,
|
||||
message::MessageHeader,
|
||||
transaction::{Result, Transaction},
|
||||
};
|
||||
use std::{collections::HashMap, io, net::SocketAddr};
|
||||
|
||||
pub type RpcResponseIn<T> = JsonResult<Response<T>>;
|
||||
pub type RpcResponse<T> = io::Result<Response<T>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RpcResponseContext {
|
||||
pub slot: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Response<T> {
|
||||
pub context: RpcResponseContext,
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcBlockCommitment<T> {
|
||||
pub commitment: Option<T>,
|
||||
pub total_stake: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedBlock {
|
||||
pub previous_blockhash: String,
|
||||
pub blockhash: String,
|
||||
pub parent_slot: Slot,
|
||||
pub transactions: Vec<RpcTransactionWithStatusMeta>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionWithStatusMeta {
|
||||
pub transaction: RpcEncodedTransaction,
|
||||
pub meta: Option<RpcTransactionStatus>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum RpcTransactionEncoding {
|
||||
Binary,
|
||||
Json,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum RpcEncodedTransaction {
|
||||
Binary(String),
|
||||
Json(RpcTransaction),
|
||||
}
|
||||
|
||||
impl RpcEncodedTransaction {
|
||||
pub fn encode(transaction: Transaction, encoding: RpcTransactionEncoding) -> Self {
|
||||
if encoding == RpcTransactionEncoding::Json {
|
||||
RpcEncodedTransaction::Json(RpcTransaction {
|
||||
signatures: transaction
|
||||
.signatures
|
||||
.iter()
|
||||
.map(|sig| sig.to_string())
|
||||
.collect(),
|
||||
message: RpcMessage {
|
||||
header: transaction.message.header,
|
||||
account_keys: transaction
|
||||
.message
|
||||
.account_keys
|
||||
.iter()
|
||||
.map(|pubkey| pubkey.to_string())
|
||||
.collect(),
|
||||
recent_blockhash: transaction.message.recent_blockhash.to_string(),
|
||||
instructions: transaction
|
||||
.message
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|instruction| RpcCompiledInstruction {
|
||||
program_id_index: instruction.program_id_index,
|
||||
accounts: instruction.accounts.clone(),
|
||||
data: bs58::encode(instruction.data.clone()).into_string(),
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
RpcEncodedTransaction::Binary(
|
||||
bs58::encode(serialize(&transaction).unwrap()).into_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Transaction for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransaction {
|
||||
pub signatures: Vec<String>,
|
||||
pub message: RpcMessage,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcMessage {
|
||||
pub header: MessageHeader,
|
||||
pub account_keys: Vec<String>,
|
||||
pub recent_blockhash: String,
|
||||
pub instructions: Vec<RpcCompiledInstruction>,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcCompiledInstruction {
|
||||
pub program_id_index: u8,
|
||||
pub accounts: Vec<u8>,
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionStatus {
|
||||
pub status: Result<()>,
|
||||
pub fee: u64,
|
||||
pub pre_balances: Vec<u64>,
|
||||
pub post_balances: Vec<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcBlockhashFeeCalculator {
|
||||
pub blockhash: String,
|
||||
pub fee_calculator: FeeCalculator,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcKeyedAccount {
|
||||
pub pubkey: String,
|
||||
pub account: Account,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct RpcContactInfo {
|
||||
/// Pubkey of the node as a base-58 string
|
||||
pub pubkey: String,
|
||||
/// Gossip port
|
||||
pub gossip: Option<SocketAddr>,
|
||||
/// Tpu port
|
||||
pub tpu: Option<SocketAddr>,
|
||||
/// JSON RPC port
|
||||
pub rpc: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
||||
pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcEpochInfo {
|
||||
/// The current epoch
|
||||
pub epoch: Epoch,
|
||||
|
||||
/// 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: Slot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct RpcVersionInfo {
|
||||
/// The current version of solana-core
|
||||
pub solana_core: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountStatus {
|
||||
pub current: Vec<RpcVoteAccountInfo>,
|
||||
pub delinquent: Vec<RpcVoteAccountInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountInfo {
|
||||
/// Vote account pubkey as base-58 encoded string
|
||||
pub vote_pubkey: String,
|
||||
|
||||
/// The pubkey of the node that votes using this account
|
||||
pub node_pubkey: String,
|
||||
|
||||
/// The current stake, in lamports, delegated to this vote account
|
||||
pub activated_stake: u64,
|
||||
|
||||
/// An 8-bit integer used as a fraction (commission/MAX_U8) for rewards payout
|
||||
pub commission: u8,
|
||||
|
||||
/// Whether this account is staked for the current epoch
|
||||
pub epoch_vote_account: bool,
|
||||
|
||||
/// History of how many credits earned by the end of each epoch
|
||||
/// each tuple is (Epoch, credits, prev_credits)
|
||||
pub epoch_credits: Vec<(Epoch, u64, u64)>,
|
||||
|
||||
/// Most recent slot voted on by this vote account (0 if no votes exist)
|
||||
pub last_vote: u64,
|
||||
|
||||
/// Current root slot for this vote account (0 if not root slot exists)
|
||||
pub root_slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSignatureConfirmation {
|
||||
pub confirmations: usize,
|
||||
pub status: Result<()>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcStorageTurn {
|
||||
pub blockhash: String,
|
||||
pub slot: Slot,
|
||||
}
|
@ -3,8 +3,7 @@
|
||||
//! messages to the network directly. The binary encoding of its messages are
|
||||
//! unstable and may change in future releases.
|
||||
|
||||
use crate::rpc_client::RpcClient;
|
||||
use crate::rpc_request::Response;
|
||||
use crate::{rpc_client::RpcClient, rpc_response::Response};
|
||||
use bincode::{serialize_into, serialized_size};
|
||||
use log::*;
|
||||
use solana_sdk::{
|
||||
|
Reference in New Issue
Block a user