gemachain_client/
rpc_response.rs

1use {
2    crate::client_error,
3    gemachain_account_decoder::{parse_token::UiTokenAmount, UiAccount},
4    gemachain_sdk::{
5        clock::{Epoch, Slot, UnixTimestamp},
6        fee_calculator::{FeeCalculator, FeeRateGovernor},
7        hash::Hash,
8        inflation::Inflation,
9        transaction::{Result, TransactionError},
10    },
11    gemachain_transaction_status::{
12        ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus,
13    },
14    std::{collections::HashMap, fmt, net::SocketAddr},
15};
16
17pub type RpcResult<T> = client_error::Result<Response<T>>;
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20pub struct RpcResponseContext {
21    pub slot: u64,
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub struct Response<T> {
26    pub context: RpcResponseContext,
27    pub value: T,
28}
29
30#[derive(Debug, PartialEq, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct RpcBlockCommitment<T> {
33    pub commitment: Option<T>,
34    pub total_stake: u64,
35}
36
37#[derive(Serialize, Deserialize, Clone, Debug)]
38#[serde(rename_all = "camelCase")]
39pub struct RpcBlockhashFeeCalculator {
40    pub blockhash: String,
41    pub fee_calculator: FeeCalculator,
42}
43
44#[derive(Serialize, Deserialize, Clone, Debug)]
45#[serde(rename_all = "camelCase")]
46pub struct RpcBlockhash {
47    pub blockhash: String,
48    pub last_valid_block_height: u64,
49}
50
51#[derive(Serialize, Deserialize, Clone, Debug)]
52#[serde(rename_all = "camelCase")]
53pub struct RpcFees {
54    pub blockhash: String,
55    pub fee_calculator: FeeCalculator,
56    pub last_valid_slot: Slot,
57    pub last_valid_block_height: u64,
58}
59
60#[derive(Serialize, Deserialize, Clone, Debug)]
61#[serde(rename_all = "camelCase")]
62pub struct DeprecatedRpcFees {
63    pub blockhash: String,
64    pub fee_calculator: FeeCalculator,
65    pub last_valid_slot: Slot,
66}
67
68#[derive(Serialize, Deserialize, Clone, Debug)]
69#[serde(rename_all = "camelCase")]
70pub struct Fees {
71    pub blockhash: Hash,
72    pub fee_calculator: FeeCalculator,
73    pub last_valid_block_height: u64,
74}
75
76#[derive(Serialize, Deserialize, Clone, Debug)]
77#[serde(rename_all = "camelCase")]
78pub struct RpcFeeCalculator {
79    pub fee_calculator: FeeCalculator,
80}
81
82#[derive(Serialize, Deserialize, Clone, Debug)]
83#[serde(rename_all = "camelCase")]
84pub struct RpcFeeRateGovernor {
85    pub fee_rate_governor: FeeRateGovernor,
86}
87
88#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
89#[serde(rename_all = "camelCase")]
90pub struct RpcInflationGovernor {
91    pub initial: f64,
92    pub terminal: f64,
93    pub taper: f64,
94    pub foundation: f64,
95    pub foundation_term: f64,
96}
97
98impl From<Inflation> for RpcInflationGovernor {
99    fn from(inflation: Inflation) -> Self {
100        Self {
101            initial: inflation.initial,
102            terminal: inflation.terminal,
103            taper: inflation.taper,
104            foundation: inflation.foundation,
105            foundation_term: inflation.foundation_term,
106        }
107    }
108}
109
110#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
111#[serde(rename_all = "camelCase")]
112pub struct RpcInflationRate {
113    pub total: f64,
114    pub validator: f64,
115    pub foundation: f64,
116    pub epoch: Epoch,
117}
118
119#[derive(Serialize, Deserialize, Clone, Debug)]
120#[serde(rename_all = "camelCase")]
121pub struct RpcKeyedAccount {
122    pub pubkey: String,
123    pub account: UiAccount,
124}
125
126#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
127pub struct SlotInfo {
128    pub slot: Slot,
129    pub parent: Slot,
130    pub root: Slot,
131}
132
133#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
134#[serde(rename_all = "camelCase")]
135pub struct SlotTransactionStats {
136    pub num_transaction_entries: u64,
137    pub num_successful_transactions: u64,
138    pub num_failed_transactions: u64,
139    pub max_transactions_per_entry: u64,
140}
141
142#[derive(Serialize, Deserialize, Debug)]
143#[serde(rename_all = "camelCase", tag = "type")]
144pub enum SlotUpdate {
145    FirstShredReceived {
146        slot: Slot,
147        timestamp: u64,
148    },
149    Completed {
150        slot: Slot,
151        timestamp: u64,
152    },
153    CreatedBank {
154        slot: Slot,
155        parent: Slot,
156        timestamp: u64,
157    },
158    Frozen {
159        slot: Slot,
160        timestamp: u64,
161        stats: SlotTransactionStats,
162    },
163    Dead {
164        slot: Slot,
165        timestamp: u64,
166        err: String,
167    },
168    OptimisticConfirmation {
169        slot: Slot,
170        timestamp: u64,
171    },
172    Root {
173        slot: Slot,
174        timestamp: u64,
175    },
176}
177
178impl SlotUpdate {
179    pub fn slot(&self) -> Slot {
180        match self {
181            Self::FirstShredReceived { slot, .. } => *slot,
182            Self::Completed { slot, .. } => *slot,
183            Self::CreatedBank { slot, .. } => *slot,
184            Self::Frozen { slot, .. } => *slot,
185            Self::Dead { slot, .. } => *slot,
186            Self::OptimisticConfirmation { slot, .. } => *slot,
187            Self::Root { slot, .. } => *slot,
188        }
189    }
190}
191
192#[derive(Serialize, Deserialize, Clone, Debug)]
193#[serde(rename_all = "camelCase", untagged)]
194pub enum RpcSignatureResult {
195    ProcessedSignature(ProcessedSignatureResult),
196    ReceivedSignature(ReceivedSignatureResult),
197}
198
199#[derive(Serialize, Deserialize, Clone, Debug)]
200#[serde(rename_all = "camelCase")]
201pub struct RpcLogsResponse {
202    pub signature: String, // Signature as base58 string
203    pub err: Option<TransactionError>,
204    pub logs: Vec<String>,
205}
206
207#[derive(Serialize, Deserialize, Clone, Debug)]
208#[serde(rename_all = "camelCase")]
209pub struct ProcessedSignatureResult {
210    pub err: Option<TransactionError>,
211}
212
213#[derive(Serialize, Deserialize, Clone, Debug)]
214#[serde(rename_all = "camelCase")]
215pub enum ReceivedSignatureResult {
216    ReceivedSignature,
217}
218
219#[derive(Serialize, Deserialize, Clone, Debug)]
220#[serde(rename_all = "camelCase")]
221pub struct RpcContactInfo {
222    /// Pubkey of the node as a base-58 string
223    pub pubkey: String,
224    /// Gossip port
225    pub gossip: Option<SocketAddr>,
226    /// Tpu port
227    pub tpu: Option<SocketAddr>,
228    /// JSON RPC port
229    pub rpc: Option<SocketAddr>,
230    /// Software version
231    pub version: Option<String>,
232    /// First 4 bytes of the FeatureSet identifier
233    pub feature_set: Option<u32>,
234    /// Shred version
235    pub shred_version: Option<u16>,
236}
237
238/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
239pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
240
241#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
242#[serde(rename_all = "camelCase")]
243pub struct RpcBlockProductionRange {
244    pub first_slot: Slot,
245    pub last_slot: Slot,
246}
247
248#[derive(Serialize, Deserialize, Clone)]
249#[serde(rename_all = "camelCase")]
250pub struct RpcBlockProduction {
251    /// Map of leader base58 identity pubkeys to a tuple of `(number of leader slots, number of blocks produced)`
252    pub by_identity: HashMap<String, (usize, usize)>,
253    pub range: RpcBlockProductionRange,
254}
255
256#[derive(Serialize, Deserialize, Clone)]
257#[serde(rename_all = "kebab-case")]
258pub struct RpcVersionInfo {
259    /// The current version of gemachain-core
260    pub gemachain_core: String,
261    /// first 4 bytes of the FeatureSet identifier
262    pub feature_set: Option<u32>,
263}
264
265impl fmt::Debug for RpcVersionInfo {
266    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267        write!(f, "{}", self.gemachain_core)
268    }
269}
270
271impl fmt::Display for RpcVersionInfo {
272    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273        if let Some(version) = self.gemachain_core.split_whitespace().next() {
274            // Display just the semver if possible
275            write!(f, "{}", version)
276        } else {
277            write!(f, "{}", self.gemachain_core)
278        }
279    }
280}
281
282#[derive(Serialize, Deserialize, Clone, Debug)]
283#[serde(rename_all = "kebab-case")]
284pub struct RpcIdentity {
285    /// The current node identity pubkey
286    pub identity: String,
287}
288
289#[derive(Serialize, Deserialize, Clone, Debug)]
290#[serde(rename_all = "camelCase")]
291pub struct RpcVoteAccountStatus {
292    pub current: Vec<RpcVoteAccountInfo>,
293    pub delinquent: Vec<RpcVoteAccountInfo>,
294}
295
296#[derive(Serialize, Deserialize, Clone, Debug)]
297#[serde(rename_all = "camelCase")]
298pub struct RpcVoteAccountInfo {
299    /// Vote account address, as base-58 encoded string
300    pub vote_pubkey: String,
301
302    /// The validator identity, as base-58 encoded string
303    pub node_pubkey: String,
304
305    /// The current stake, in carats, delegated to this vote account
306    pub activated_stake: u64,
307
308    /// An 8-bit integer used as a fraction (commission/MAX_U8) for rewards payout
309    pub commission: u8,
310
311    /// Whether this account is staked for the current epoch
312    pub epoch_vote_account: bool,
313
314    /// History of how many credits earned by the end of each epoch
315    ///   each tuple is (Epoch, credits, prev_credits)
316    pub epoch_credits: Vec<(Epoch, u64, u64)>,
317
318    /// Most recent slot voted on by this vote account (0 if no votes exist)
319    pub last_vote: u64,
320
321    /// Current root slot for this vote account (0 if not root slot exists)
322    pub root_slot: Slot,
323}
324
325#[derive(Serialize, Deserialize, Clone, Debug)]
326#[serde(rename_all = "camelCase")]
327pub struct RpcSignatureConfirmation {
328    pub confirmations: usize,
329    pub status: Result<()>,
330}
331
332#[derive(Serialize, Deserialize, Clone, Debug)]
333#[serde(rename_all = "camelCase")]
334pub struct RpcSimulateTransactionResult {
335    pub err: Option<TransactionError>,
336    pub logs: Option<Vec<String>>,
337    pub accounts: Option<Vec<Option<UiAccount>>>,
338    pub units_consumed: Option<u64>,
339}
340
341#[derive(Serialize, Deserialize, Clone, Debug)]
342#[serde(rename_all = "camelCase")]
343pub struct RpcStorageTurn {
344    pub blockhash: String,
345    pub slot: Slot,
346}
347
348#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
349#[serde(rename_all = "camelCase")]
350pub struct RpcAccountBalance {
351    pub address: String,
352    pub carats: u64,
353}
354
355#[derive(Serialize, Deserialize, Clone, Debug)]
356#[serde(rename_all = "camelCase")]
357pub struct RpcSupply {
358    pub total: u64,
359    pub circulating: u64,
360    pub non_circulating: u64,
361    pub non_circulating_accounts: Vec<String>,
362}
363
364#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
365#[serde(rename_all = "camelCase")]
366pub enum StakeActivationState {
367    Activating,
368    Active,
369    Deactivating,
370    Inactive,
371}
372
373#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
374#[serde(rename_all = "camelCase")]
375pub struct RpcStakeActivation {
376    pub state: StakeActivationState,
377    pub active: u64,
378    pub inactive: u64,
379}
380
381#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
382#[serde(rename_all = "camelCase")]
383pub struct RpcTokenAccountBalance {
384    pub address: String,
385    #[serde(flatten)]
386    pub amount: UiTokenAmount,
387}
388
389#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
390#[serde(rename_all = "camelCase")]
391pub struct RpcConfirmedTransactionStatusWithSignature {
392    pub signature: String,
393    pub slot: Slot,
394    pub err: Option<TransactionError>,
395    pub memo: Option<String>,
396    pub block_time: Option<UnixTimestamp>,
397    pub confirmation_status: Option<TransactionConfirmationStatus>,
398}
399
400#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
401#[serde(rename_all = "camelCase")]
402pub struct RpcPerfSample {
403    pub slot: Slot,
404    pub num_transactions: u64,
405    pub num_slots: u64,
406    pub sample_period_secs: u16,
407}
408
409#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
410#[serde(rename_all = "camelCase")]
411pub struct RpcInflationReward {
412    pub epoch: Epoch,
413    pub effective_slot: Slot,
414    pub amount: u64,            // carats
415    pub post_balance: u64,      // carats
416    pub commission: Option<u8>, // Vote account commission when the reward was credited
417}
418
419impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionStatusWithSignature {
420    fn from(value: ConfirmedTransactionStatusWithSignature) -> Self {
421        let ConfirmedTransactionStatusWithSignature {
422            signature,
423            slot,
424            err,
425            memo,
426            block_time,
427        } = value;
428        Self {
429            signature: signature.to_string(),
430            slot,
431            err,
432            memo,
433            block_time,
434            confirmation_status: None,
435        }
436    }
437}
438
439#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
440pub struct RpcSnapshotSlotInfo {
441    pub full: Slot,
442    pub incremental: Option<Slot>,
443}