use { crate::client_error, serde::{Deserialize, Deserializer, Serialize, Serializer}, solana_account_decoder::{parse_token::UiTokenAmount, UiAccount}, solana_sdk::{ clock::{Epoch, Slot, UnixTimestamp}, fee_calculator::{FeeCalculator, FeeRateGovernor}, hash::Hash, inflation::Inflation, transaction::{Result, TransactionError}, transaction_context::TransactionReturnData, }, solana_transaction_status::{ ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus, UiConfirmedBlock, }, std::{collections::HashMap, fmt, net::SocketAddr, str::FromStr}, thiserror::Error, }; pub type RpcResult = client_error::Result>; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcResponseContext { pub slot: Slot, #[serde(skip_serializing_if = "Option::is_none")] pub api_version: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct RpcApiVersion(semver::Version); impl std::ops::Deref for RpcApiVersion { type Target = semver::Version; fn deref(&self) -> &Self::Target { &self.0 } } impl Default for RpcApiVersion { fn default() -> Self { Self(solana_version::Version::default().as_semver_version()) } } impl Serialize for RpcApiVersion { fn serialize(&self, serializer: S) -> std::result::Result where S: Serializer, { serializer.serialize_str(&self.to_string()) } } impl<'de> Deserialize<'de> for RpcApiVersion { fn deserialize(deserializer: D) -> std::result::Result where D: Deserializer<'de>, { let s: String = Deserialize::deserialize(deserializer)?; Ok(RpcApiVersion( semver::Version::from_str(&s).map_err(serde::de::Error::custom)?, )) } } impl RpcResponseContext { pub fn new(slot: Slot) -> Self { Self { slot, api_version: Some(RpcApiVersion::default()), } } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Response { pub context: RpcResponseContext, pub value: T, } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct RpcBlockCommitment { pub commitment: Option, pub total_stake: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcBlockhashFeeCalculator { pub blockhash: String, pub fee_calculator: FeeCalculator, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcBlockhash { pub blockhash: String, pub last_valid_block_height: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcFees { pub blockhash: String, pub fee_calculator: FeeCalculator, pub last_valid_slot: Slot, pub last_valid_block_height: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DeprecatedRpcFees { pub blockhash: String, pub fee_calculator: FeeCalculator, pub last_valid_slot: Slot, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Fees { pub blockhash: Hash, pub fee_calculator: FeeCalculator, pub last_valid_block_height: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcFeeCalculator { pub fee_calculator: FeeCalculator, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcFeeRateGovernor { pub fee_rate_governor: FeeRateGovernor, } #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] #[serde(rename_all = "camelCase")] pub struct RpcInflationGovernor { pub initial: f64, pub terminal: f64, pub taper: f64, pub foundation: f64, pub foundation_term: f64, } impl From for RpcInflationGovernor { fn from(inflation: Inflation) -> Self { Self { initial: inflation.initial, terminal: inflation.terminal, taper: inflation.taper, foundation: inflation.foundation, foundation_term: inflation.foundation_term, } } } #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] #[serde(rename_all = "camelCase")] pub struct RpcInflationRate { pub total: f64, pub validator: f64, pub foundation: f64, pub epoch: Epoch, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcKeyedAccount { pub pubkey: String, pub account: UiAccount, } #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] pub struct SlotInfo { pub slot: Slot, pub parent: Slot, pub root: Slot, } #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct SlotTransactionStats { pub num_transaction_entries: u64, pub num_successful_transactions: u64, pub num_failed_transactions: u64, pub max_transactions_per_entry: u64, } #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(rename_all = "camelCase", tag = "type")] pub enum SlotUpdate { FirstShredReceived { slot: Slot, timestamp: u64, }, Completed { slot: Slot, timestamp: u64, }, CreatedBank { slot: Slot, parent: Slot, timestamp: u64, }, Frozen { slot: Slot, timestamp: u64, stats: SlotTransactionStats, }, Dead { slot: Slot, timestamp: u64, err: String, }, OptimisticConfirmation { slot: Slot, timestamp: u64, }, Root { slot: Slot, timestamp: u64, }, } impl SlotUpdate { pub fn slot(&self) -> Slot { match self { Self::FirstShredReceived { slot, .. } => *slot, Self::Completed { slot, .. } => *slot, Self::CreatedBank { slot, .. } => *slot, Self::Frozen { slot, .. } => *slot, Self::Dead { slot, .. } => *slot, Self::OptimisticConfirmation { slot, .. } => *slot, Self::Root { slot, .. } => *slot, } } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase", untagged)] pub enum RpcSignatureResult { ProcessedSignature(ProcessedSignatureResult), ReceivedSignature(ReceivedSignatureResult), } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcLogsResponse { pub signature: String, // Signature as base58 string pub err: Option, pub logs: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct ProcessedSignatureResult { pub err: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub enum ReceivedSignatureResult { ReceivedSignature, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcContactInfo { /// Pubkey of the node as a base-58 string pub pubkey: String, /// Gossip port pub gossip: Option, /// Tpu port pub tpu: Option, /// JSON RPC port pub rpc: Option, /// Software version pub version: Option, /// First 4 bytes of the FeatureSet identifier pub feature_set: Option, /// Shred version pub shred_version: Option, } /// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot pub type RpcLeaderSchedule = HashMap>; #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcBlockProductionRange { pub first_slot: Slot, pub last_slot: Slot, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcBlockProduction { /// Map of leader base58 identity pubkeys to a tuple of `(number of leader slots, number of blocks produced)` pub by_identity: HashMap, pub range: RpcBlockProductionRange, } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub struct RpcVersionInfo { /// The current version of solana-core pub solana_core: String, /// first 4 bytes of the FeatureSet identifier pub feature_set: Option, } impl fmt::Debug for RpcVersionInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.solana_core) } } impl fmt::Display for RpcVersionInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(version) = self.solana_core.split_whitespace().next() { // Display just the semver if possible write!(f, "{}", version) } else { write!(f, "{}", self.solana_core) } } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub struct RpcIdentity { /// The current node identity pubkey pub identity: String, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcVote { /// Vote account address, as base-58 encoded string pub vote_pubkey: String, pub slots: Vec, pub hash: String, pub timestamp: Option, pub signature: String, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcVoteAccountStatus { pub current: Vec, pub delinquent: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcVoteAccountInfo { /// Vote account address, as base-58 encoded string pub vote_pubkey: String, /// The validator identity, as base-58 encoded string 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, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcSignatureConfirmation { pub confirmations: usize, pub status: Result<()>, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcSimulateTransactionResult { pub err: Option, pub logs: Option>, pub accounts: Option>>, pub units_consumed: Option, pub return_data: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcTransactionReturnData { pub program_id: String, pub data: (String, ReturnDataEncoding), } impl From for RpcTransactionReturnData { fn from(return_data: TransactionReturnData) -> Self { Self { program_id: return_data.program_id.to_string(), data: (base64::encode(return_data.data), ReturnDataEncoding::Base64), } } } #[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)] #[serde(rename_all = "camelCase")] pub enum ReturnDataEncoding { Base64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcStorageTurn { pub blockhash: String, pub slot: Slot, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcAccountBalance { pub address: String, pub lamports: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcSupply { pub total: u64, pub circulating: u64, pub non_circulating: u64, pub non_circulating_accounts: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub enum StakeActivationState { Activating, Active, Deactivating, Inactive, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct RpcStakeActivation { pub state: StakeActivationState, pub active: u64, pub inactive: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct RpcTokenAccountBalance { pub address: String, #[serde(flatten)] pub amount: UiTokenAmount, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcConfirmedTransactionStatusWithSignature { pub signature: String, pub slot: Slot, pub err: Option, pub memo: Option, pub block_time: Option, pub confirmation_status: Option, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcPerfSample { pub slot: Slot, pub num_transactions: u64, pub num_slots: u64, pub sample_period_secs: u16, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcInflationReward { pub epoch: Epoch, pub effective_slot: Slot, pub amount: u64, // lamports pub post_balance: u64, // lamports pub commission: Option, // Vote account commission when the reward was credited } #[derive(Clone, Deserialize, Serialize, Debug, Error, Eq, PartialEq)] pub enum RpcBlockUpdateError { #[error("block store error")] BlockStoreError, #[error("unsupported transaction version ({0})")] UnsupportedTransactionVersion(u8), } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[serde(rename_all = "camelCase")] pub struct RpcBlockUpdate { pub slot: Slot, pub block: Option, pub err: Option, } impl From for RpcConfirmedTransactionStatusWithSignature { fn from(value: ConfirmedTransactionStatusWithSignature) -> Self { let ConfirmedTransactionStatusWithSignature { signature, slot, err, memo, block_time, } = value; Self { signature: signature.to_string(), slot, err, memo, block_time, confirmation_status: None, } } } #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] pub struct RpcSnapshotSlotInfo { pub full: Slot, pub incremental: Option, }