1use {
2 crate::client_error,
3 serde::{Deserialize, Deserializer, Serialize, Serializer},
4 safecoin_account_decoder::{parse_token::UiTokenAmount, UiAccount},
5 solana_sdk::{
6 clock::{Epoch, Slot, UnixTimestamp},
7 fee_calculator::{FeeCalculator, FeeRateGovernor},
8 hash::Hash,
9 inflation::Inflation,
10 transaction::{Result, TransactionError},
11 },
12 safecoin_transaction_status::{
13 ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus, UiConfirmedBlock,
14 UiTransactionReturnData,
15 },
16 std::{collections::HashMap, fmt, net::SocketAddr, str::FromStr},
17 thiserror::Error,
18};
19
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(untagged)]
25pub enum OptionalContext<T> {
26 Context(Response<T>),
27 NoContext(T),
28}
29
30impl<T> OptionalContext<T> {
31 pub fn parse_value(self) -> T {
32 match self {
33 Self::Context(response) => response.value,
34 Self::NoContext(value) => value,
35 }
36 }
37}
38
39pub type RpcResult<T> = client_error::Result<Response<T>>;
40
41#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub struct RpcResponseContext {
44 pub slot: Slot,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub api_version: Option<RpcApiVersion>,
47}
48
49#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct RpcApiVersion(semver::Version);
51
52impl std::ops::Deref for RpcApiVersion {
53 type Target = semver::Version;
54 fn deref(&self) -> &Self::Target {
55 &self.0
56 }
57}
58
59impl Default for RpcApiVersion {
60 fn default() -> Self {
61 Self(safecoin_version::Version::default().as_semver_version())
62 }
63}
64
65impl Serialize for RpcApiVersion {
66 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
67 where
68 S: Serializer,
69 {
70 serializer.serialize_str(&self.to_string())
71 }
72}
73
74impl<'de> Deserialize<'de> for RpcApiVersion {
75 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
76 where
77 D: Deserializer<'de>,
78 {
79 let s: String = Deserialize::deserialize(deserializer)?;
80 Ok(RpcApiVersion(
81 semver::Version::from_str(&s).map_err(serde::de::Error::custom)?,
82 ))
83 }
84}
85
86impl RpcResponseContext {
87 pub fn new(slot: Slot) -> Self {
88 Self {
89 slot,
90 api_version: Some(RpcApiVersion::default()),
91 }
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
96pub struct Response<T> {
97 pub context: RpcResponseContext,
98 pub value: T,
99}
100
101#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct RpcBlockCommitment<T> {
104 pub commitment: Option<T>,
105 pub total_stake: u64,
106}
107
108#[derive(Serialize, Deserialize, Clone, Debug)]
109#[serde(rename_all = "camelCase")]
110pub struct RpcBlockhashFeeCalculator {
111 pub blockhash: String,
112 pub fee_calculator: FeeCalculator,
113}
114
115#[derive(Serialize, Deserialize, Clone, Debug)]
116#[serde(rename_all = "camelCase")]
117pub struct RpcBlockhash {
118 pub blockhash: String,
119 pub last_valid_block_height: u64,
120}
121
122#[derive(Serialize, Deserialize, Clone, Debug)]
123#[serde(rename_all = "camelCase")]
124pub struct RpcFees {
125 pub blockhash: String,
126 pub fee_calculator: FeeCalculator,
127 pub last_valid_slot: Slot,
128 pub last_valid_block_height: u64,
129}
130
131#[derive(Serialize, Deserialize, Clone, Debug)]
132#[serde(rename_all = "camelCase")]
133pub struct DeprecatedRpcFees {
134 pub blockhash: String,
135 pub fee_calculator: FeeCalculator,
136 pub last_valid_slot: Slot,
137}
138
139#[derive(Serialize, Deserialize, Clone, Debug)]
140#[serde(rename_all = "camelCase")]
141pub struct Fees {
142 pub blockhash: Hash,
143 pub fee_calculator: FeeCalculator,
144 pub last_valid_block_height: u64,
145}
146
147#[derive(Serialize, Deserialize, Clone, Debug)]
148#[serde(rename_all = "camelCase")]
149pub struct RpcFeeCalculator {
150 pub fee_calculator: FeeCalculator,
151}
152
153#[derive(Serialize, Deserialize, Clone, Debug)]
154#[serde(rename_all = "camelCase")]
155pub struct RpcFeeRateGovernor {
156 pub fee_rate_governor: FeeRateGovernor,
157}
158
159#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
160#[serde(rename_all = "camelCase")]
161pub struct RpcInflationGovernor {
162 pub initial: f64,
163 pub terminal: f64,
164 pub taper: f64,
165 pub foundation: f64,
166 pub foundation_term: f64,
167}
168
169impl From<Inflation> for RpcInflationGovernor {
170 fn from(inflation: Inflation) -> Self {
171 Self {
172 initial: inflation.initial,
173 terminal: inflation.terminal,
174 taper: inflation.taper,
175 foundation: inflation.foundation,
176 foundation_term: inflation.foundation_term,
177 }
178 }
179}
180
181#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
182#[serde(rename_all = "camelCase")]
183pub struct RpcInflationRate {
184 pub total: f64,
185 pub validator: f64,
186 pub foundation: f64,
187 pub epoch: Epoch,
188}
189
190#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
191#[serde(rename_all = "camelCase")]
192pub struct RpcKeyedAccount {
193 pub pubkey: String,
194 pub account: UiAccount,
195}
196
197#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
198pub struct SlotInfo {
199 pub slot: Slot,
200 pub parent: Slot,
201 pub root: Slot,
202}
203
204#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
205#[serde(rename_all = "camelCase")]
206pub struct SlotTransactionStats {
207 pub num_transaction_entries: u64,
208 pub num_successful_transactions: u64,
209 pub num_failed_transactions: u64,
210 pub max_transactions_per_entry: u64,
211}
212
213#[derive(Serialize, Deserialize, Debug)]
214#[serde(rename_all = "camelCase", tag = "type")]
215pub enum SlotUpdate {
216 FirstShredReceived {
217 slot: Slot,
218 timestamp: u64,
219 },
220 Completed {
221 slot: Slot,
222 timestamp: u64,
223 },
224 CreatedBank {
225 slot: Slot,
226 parent: Slot,
227 timestamp: u64,
228 },
229 Frozen {
230 slot: Slot,
231 timestamp: u64,
232 stats: SlotTransactionStats,
233 },
234 Dead {
235 slot: Slot,
236 timestamp: u64,
237 err: String,
238 },
239 OptimisticConfirmation {
240 slot: Slot,
241 timestamp: u64,
242 },
243 Root {
244 slot: Slot,
245 timestamp: u64,
246 },
247}
248
249impl SlotUpdate {
250 pub fn slot(&self) -> Slot {
251 match self {
252 Self::FirstShredReceived { slot, .. } => *slot,
253 Self::Completed { slot, .. } => *slot,
254 Self::CreatedBank { slot, .. } => *slot,
255 Self::Frozen { slot, .. } => *slot,
256 Self::Dead { slot, .. } => *slot,
257 Self::OptimisticConfirmation { slot, .. } => *slot,
258 Self::Root { slot, .. } => *slot,
259 }
260 }
261}
262
263#[derive(Serialize, Deserialize, Clone, Debug)]
264#[serde(rename_all = "camelCase", untagged)]
265pub enum RpcSignatureResult {
266 ProcessedSignature(ProcessedSignatureResult),
267 ReceivedSignature(ReceivedSignatureResult),
268}
269
270#[derive(Serialize, Deserialize, Clone, Debug)]
271#[serde(rename_all = "camelCase")]
272pub struct RpcLogsResponse {
273 pub signature: String, pub err: Option<TransactionError>,
275 pub logs: Vec<String>,
276}
277
278#[derive(Serialize, Deserialize, Clone, Debug)]
279#[serde(rename_all = "camelCase")]
280pub struct ProcessedSignatureResult {
281 pub err: Option<TransactionError>,
282}
283
284#[derive(Serialize, Deserialize, Clone, Debug)]
285#[serde(rename_all = "camelCase")]
286pub enum ReceivedSignatureResult {
287 ReceivedSignature,
288}
289
290#[derive(Serialize, Deserialize, Clone, Debug)]
291#[serde(rename_all = "camelCase")]
292pub struct RpcContactInfo {
293 pub pubkey: String,
295 pub gossip: Option<SocketAddr>,
297 pub tpu: Option<SocketAddr>,
299 pub rpc: Option<SocketAddr>,
301 pub version: Option<String>,
303 pub feature_set: Option<u32>,
305 pub shred_version: Option<u16>,
307}
308
309pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
311
312#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
313#[serde(rename_all = "camelCase")]
314pub struct RpcBlockProductionRange {
315 pub first_slot: Slot,
316 pub last_slot: Slot,
317}
318
319#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
320#[serde(rename_all = "camelCase")]
321pub struct RpcBlockProduction {
322 pub by_identity: HashMap<String, (usize, usize)>,
324 pub range: RpcBlockProductionRange,
325}
326
327#[derive(Serialize, Deserialize, Clone)]
328#[serde(rename_all = "kebab-case")]
329pub struct RpcVersionInfo {
330 pub solana_core: String,
332 pub feature_set: Option<u32>,
334}
335
336impl fmt::Debug for RpcVersionInfo {
337 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338 write!(f, "{}", self.solana_core)
339 }
340}
341
342impl fmt::Display for RpcVersionInfo {
343 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344 if let Some(version) = self.solana_core.split_whitespace().next() {
345 write!(f, "{}", version)
347 } else {
348 write!(f, "{}", self.solana_core)
349 }
350 }
351}
352
353#[derive(Serialize, Deserialize, Clone, Debug)]
354#[serde(rename_all = "kebab-case")]
355pub struct RpcIdentity {
356 pub identity: String,
358}
359
360#[derive(Serialize, Deserialize, Clone, Debug)]
361#[serde(rename_all = "camelCase")]
362pub struct RpcVote {
363 pub vote_pubkey: String,
365 pub slots: Vec<Slot>,
366 pub hash: String,
367 pub timestamp: Option<UnixTimestamp>,
368 pub signature: String,
369}
370
371#[derive(Serialize, Deserialize, Clone, Debug)]
372#[serde(rename_all = "camelCase")]
373pub struct RpcVoteAccountStatus {
374 pub current: Vec<RpcVoteAccountInfo>,
375 pub delinquent: Vec<RpcVoteAccountInfo>,
376}
377
378#[derive(Serialize, Deserialize, Clone, Debug)]
379#[serde(rename_all = "camelCase")]
380pub struct RpcVoteAccountInfo {
381 pub vote_pubkey: String,
383
384 pub node_pubkey: String,
386
387 pub activated_stake: u64,
389
390 pub commission: u8,
392
393 pub epoch_vote_account: bool,
395
396 pub epoch_credits: Vec<(Epoch, u64, u64)>,
399
400 pub last_vote: u64,
402
403 pub root_slot: Slot,
405}
406
407#[derive(Serialize, Deserialize, Clone, Debug)]
408#[serde(rename_all = "camelCase")]
409pub struct RpcSignatureConfirmation {
410 pub confirmations: usize,
411 pub status: Result<()>,
412}
413
414#[derive(Serialize, Deserialize, Clone, Debug)]
415#[serde(rename_all = "camelCase")]
416pub struct RpcSimulateTransactionResult {
417 pub err: Option<TransactionError>,
418 pub logs: Option<Vec<String>>,
419 pub accounts: Option<Vec<Option<UiAccount>>>,
420 pub units_consumed: Option<u64>,
421 pub return_data: Option<UiTransactionReturnData>,
422}
423
424#[derive(Serialize, Deserialize, Clone, Debug)]
425#[serde(rename_all = "camelCase")]
426pub struct RpcStorageTurn {
427 pub blockhash: String,
428 pub slot: Slot,
429}
430
431#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
432#[serde(rename_all = "camelCase")]
433pub struct RpcAccountBalance {
434 pub address: String,
435 pub lamports: u64,
436}
437
438#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
439#[serde(rename_all = "camelCase")]
440pub struct RpcSupply {
441 pub total: u64,
442 pub circulating: u64,
443 pub non_circulating: u64,
444 pub non_circulating_accounts: Vec<String>,
445}
446
447#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
448#[serde(rename_all = "camelCase")]
449pub enum StakeActivationState {
450 Activating,
451 Active,
452 Deactivating,
453 Inactive,
454}
455
456#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
457#[serde(rename_all = "camelCase")]
458pub struct RpcStakeActivation {
459 pub state: StakeActivationState,
460 pub active: u64,
461 pub inactive: u64,
462}
463
464#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
465#[serde(rename_all = "camelCase")]
466pub struct RpcTokenAccountBalance {
467 pub address: String,
468 #[serde(flatten)]
469 pub amount: UiTokenAmount,
470}
471
472#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
473#[serde(rename_all = "camelCase")]
474pub struct RpcConfirmedTransactionStatusWithSignature {
475 pub signature: String,
476 pub slot: Slot,
477 pub err: Option<TransactionError>,
478 pub memo: Option<String>,
479 pub block_time: Option<UnixTimestamp>,
480 pub confirmation_status: Option<TransactionConfirmationStatus>,
481}
482
483#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
484#[serde(rename_all = "camelCase")]
485pub struct RpcPerfSample {
486 pub slot: Slot,
487 pub num_transactions: u64,
488 pub num_slots: u64,
489 pub sample_period_secs: u16,
490}
491
492#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
493#[serde(rename_all = "camelCase")]
494pub struct RpcInflationReward {
495 pub epoch: Epoch,
496 pub effective_slot: Slot,
497 pub amount: u64, pub post_balance: u64, pub commission: Option<u8>, }
501
502#[derive(Clone, Deserialize, Serialize, Debug, Error, Eq, PartialEq)]
503pub enum RpcBlockUpdateError {
504 #[error("block store error")]
505 BlockStoreError,
506
507 #[error("unsupported transaction version ({0})")]
508 UnsupportedTransactionVersion(u8),
509}
510
511#[derive(Serialize, Deserialize, Debug)]
512#[serde(rename_all = "camelCase")]
513pub struct RpcBlockUpdate {
514 pub slot: Slot,
515 pub block: Option<UiConfirmedBlock>,
516 pub err: Option<RpcBlockUpdateError>,
517}
518
519impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionStatusWithSignature {
520 fn from(value: ConfirmedTransactionStatusWithSignature) -> Self {
521 let ConfirmedTransactionStatusWithSignature {
522 signature,
523 slot,
524 err,
525 memo,
526 block_time,
527 } = value;
528 Self {
529 signature: signature.to_string(),
530 slot,
531 err,
532 memo,
533 block_time,
534 confirmation_status: None,
535 }
536 }
537}
538
539#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
540pub struct RpcSnapshotSlotInfo {
541 pub full: Slot,
542 pub incremental: Option<Slot>,
543}
544
545#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
546#[serde(rename_all = "camelCase")]
547pub struct RpcPrioritizationFee {
548 pub slot: Slot,
549 pub prioritization_fee: u64,
550}