1use {
2 crate::rpc_response::RpcSimulateTransactionResult,
3 serde_json::{json, Value},
4 solana_sdk::{clock::Slot, pubkey::Pubkey},
5 std::fmt,
6 thiserror::Error,
7};
8
9#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
10pub enum RpcRequest {
11 Custom {
12 method: &'static str,
13 },
14 DeregisterNode,
15 GetAccountInfo,
16 GetBalance,
17 GetBlock,
18 GetBlockHeight,
19 GetBlockProduction,
20 GetBlocks,
21 GetBlocksWithLimit,
22 GetBlockTime,
23 GetClusterNodes,
24 #[deprecated(since = "1.7.0", note = "Please use RpcRequest::GetBlock instead")]
25 GetConfirmedBlock,
26 #[deprecated(since = "1.7.0", note = "Please use RpcRequest::GetBlocks instead")]
27 GetConfirmedBlocks,
28 #[deprecated(
29 since = "1.7.0",
30 note = "Please use RpcRequest::GetBlocksWithLimit instead"
31 )]
32 GetConfirmedBlocksWithLimit,
33 #[deprecated(
34 since = "1.7.0",
35 note = "Please use RpcRequest::GetSignaturesForAddress instead"
36 )]
37 GetConfirmedSignaturesForAddress2,
38 #[deprecated(
39 since = "1.7.0",
40 note = "Please use RpcRequest::GetTransaction instead"
41 )]
42 GetConfirmedTransaction,
43 GetEpochInfo,
44 GetEpochSchedule,
45 #[deprecated(
46 since = "1.9.0",
47 note = "Please use RpcRequest::GetFeeForMessage instead"
48 )]
49 GetFeeCalculatorForBlockhash,
50 GetFeeForMessage,
51 #[deprecated(
52 since = "1.9.0",
53 note = "Please do not use, will no longer be available in the future"
54 )]
55 GetFeeRateGovernor,
56 #[deprecated(
57 since = "1.9.0",
58 note = "Please use RpcRequest::GetFeeForMessage instead"
59 )]
60 GetFees,
61 GetFirstAvailableBlock,
62 GetGenesisHash,
63 GetHealth,
64 GetIdentity,
65 GetInflationGovernor,
66 GetInflationRate,
67 GetInflationReward,
68 GetLargestAccounts,
69 GetLatestBlockhash,
70 GetLeaderSchedule,
71 GetMaxRetransmitSlot,
72 GetMaxShredInsertSlot,
73 GetMinimumBalanceForRentExemption,
74 GetMultipleAccounts,
75 GetProgramAccounts,
76 #[deprecated(
77 since = "1.9.0",
78 note = "Please use RpcRequest::GetLatestBlockhash instead"
79 )]
80 GetRecentBlockhash,
81 GetRecentPerformanceSamples,
82 GetRecentPrioritizationFees,
83 GetHighestSnapshotSlot,
84 #[deprecated(
85 since = "1.9.0",
86 note = "Please use RpcRequest::GetHighestSnapshotSlot instead"
87 )]
88 GetSnapshotSlot,
89 GetSignaturesForAddress,
90 GetSignatureStatuses,
91 GetSlot,
92 GetSlotLeader,
93 GetSlotLeaders,
94 GetStorageTurn,
95 GetStorageTurnRate,
96 GetSlotsPerSegment,
97 GetStakeActivation,
98 GetStakeMinimumDelegation,
99 GetStoragePubkeysForSlot,
100 GetSupply,
101 GetTokenAccountBalance,
102 GetTokenAccountsByDelegate,
103 GetTokenAccountsByOwner,
104 GetTokenSupply,
105 GetTransaction,
106 GetTransactionCount,
107 GetVersion,
108 GetVoteAccounts,
109 IsBlockhashValid,
110 MinimumLedgerSlot,
111 RegisterNode,
112 RequestAirdrop,
113 SendTransaction,
114 SimulateTransaction,
115 SignVote,
116}
117
118#[allow(deprecated)]
119impl fmt::Display for RpcRequest {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 let method = match self {
122 RpcRequest::Custom { method } => method,
123 RpcRequest::DeregisterNode => "deregisterNode",
124 RpcRequest::GetAccountInfo => "getAccountInfo",
125 RpcRequest::GetBalance => "getBalance",
126 RpcRequest::GetBlock => "getBlock",
127 RpcRequest::GetBlockHeight => "getBlockHeight",
128 RpcRequest::GetBlockProduction => "getBlockProduction",
129 RpcRequest::GetBlocks => "getBlocks",
130 RpcRequest::GetBlocksWithLimit => "getBlocksWithLimit",
131 RpcRequest::GetBlockTime => "getBlockTime",
132 RpcRequest::GetClusterNodes => "getClusterNodes",
133 RpcRequest::GetConfirmedBlock => "getConfirmedBlock",
134 RpcRequest::GetConfirmedBlocks => "getConfirmedBlocks",
135 RpcRequest::GetConfirmedBlocksWithLimit => "getConfirmedBlocksWithLimit",
136 RpcRequest::GetConfirmedSignaturesForAddress2 => "getConfirmedSignaturesForAddress2",
137 RpcRequest::GetConfirmedTransaction => "getConfirmedTransaction",
138 RpcRequest::GetEpochInfo => "getEpochInfo",
139 RpcRequest::GetEpochSchedule => "getEpochSchedule",
140 RpcRequest::GetFeeCalculatorForBlockhash => "getFeeCalculatorForBlockhash",
141 RpcRequest::GetFeeForMessage => "getFeeForMessage",
142 RpcRequest::GetFeeRateGovernor => "getFeeRateGovernor",
143 RpcRequest::GetFees => "getFees",
144 RpcRequest::GetFirstAvailableBlock => "getFirstAvailableBlock",
145 RpcRequest::GetGenesisHash => "getGenesisHash",
146 RpcRequest::GetHealth => "getHealth",
147 RpcRequest::GetIdentity => "getIdentity",
148 RpcRequest::GetInflationGovernor => "getInflationGovernor",
149 RpcRequest::GetInflationRate => "getInflationRate",
150 RpcRequest::GetInflationReward => "getInflationReward",
151 RpcRequest::GetLargestAccounts => "getLargestAccounts",
152 RpcRequest::GetLatestBlockhash => "getLatestBlockhash",
153 RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
154 RpcRequest::GetMaxRetransmitSlot => "getMaxRetransmitSlot",
155 RpcRequest::GetMaxShredInsertSlot => "getMaxShredInsertSlot",
156 RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
157 RpcRequest::GetMultipleAccounts => "getMultipleAccounts",
158 RpcRequest::GetProgramAccounts => "getProgramAccounts",
159 RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
160 RpcRequest::GetRecentPerformanceSamples => "getRecentPerformanceSamples",
161 RpcRequest::GetRecentPrioritizationFees => "getRecentPrioritizationFees",
162 RpcRequest::GetHighestSnapshotSlot => "getHighestSnapshotSlot",
163 RpcRequest::GetSnapshotSlot => "getSnapshotSlot",
164 RpcRequest::GetSignaturesForAddress => "getSignaturesForAddress",
165 RpcRequest::GetSignatureStatuses => "getSignatureStatuses",
166 RpcRequest::GetSlot => "getSlot",
167 RpcRequest::GetSlotLeader => "getSlotLeader",
168 RpcRequest::GetSlotLeaders => "getSlotLeaders",
169 RpcRequest::GetStakeActivation => "getStakeActivation",
170 RpcRequest::GetStakeMinimumDelegation => "getStakeMinimumDelegation",
171 RpcRequest::GetStorageTurn => "getStorageTurn",
172 RpcRequest::GetStorageTurnRate => "getStorageTurnRate",
173 RpcRequest::GetSlotsPerSegment => "getSlotsPerSegment",
174 RpcRequest::GetStoragePubkeysForSlot => "getStoragePubkeysForSlot",
175 RpcRequest::GetSupply => "getSupply",
176 RpcRequest::GetTokenAccountBalance => "getTokenAccountBalance",
177 RpcRequest::GetTokenAccountsByDelegate => "getTokenAccountsByDelegate",
178 RpcRequest::GetTokenAccountsByOwner => "getTokenAccountsByOwner",
179 RpcRequest::GetTokenSupply => "getTokenSupply",
180 RpcRequest::GetTransaction => "getTransaction",
181 RpcRequest::GetTransactionCount => "getTransactionCount",
182 RpcRequest::GetVersion => "getVersion",
183 RpcRequest::GetVoteAccounts => "getVoteAccounts",
184 RpcRequest::IsBlockhashValid => "isBlockhashValid",
185 RpcRequest::MinimumLedgerSlot => "minimumLedgerSlot",
186 RpcRequest::RegisterNode => "registerNode",
187 RpcRequest::RequestAirdrop => "requestAirdrop",
188 RpcRequest::SendTransaction => "sendTransaction",
189 RpcRequest::SimulateTransaction => "simulateTransaction",
190 RpcRequest::SignVote => "signVote",
191 };
192
193 write!(f, "{}", method)
194 }
195}
196
197pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256;
199pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000;
200pub const MAX_GET_CONFIRMED_BLOCKS_RANGE: u64 = 500_000;
201pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT: usize = 1_000;
202pub const MAX_MULTIPLE_ACCOUNTS: usize = 100;
203pub const NUM_LARGEST_ACCOUNTS: usize = 20;
204pub const MAX_GET_PROGRAM_ACCOUNT_FILTERS: usize = 4;
205pub const MAX_GET_SLOT_LEADERS: usize = 5000;
206
207pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;
209
210impl RpcRequest {
211 pub(crate) fn build_request_json(self, id: u64, params: Value) -> Value {
212 let jsonrpc = "2.0";
213 json!({
214 "jsonrpc": jsonrpc,
215 "id": id,
216 "method": format!("{}", self),
217 "params": params,
218 })
219 }
220}
221
222#[derive(Debug)]
223pub enum RpcResponseErrorData {
224 Empty,
225 SendTransactionPreflightFailure(RpcSimulateTransactionResult),
226 NodeUnhealthy { num_slots_behind: Option<Slot> },
227}
228
229impl fmt::Display for RpcResponseErrorData {
230 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231 match self {
232 RpcResponseErrorData::SendTransactionPreflightFailure(
233 RpcSimulateTransactionResult {
234 logs: Some(logs), ..
235 },
236 ) => {
237 if logs.is_empty() {
238 Ok(())
239 } else {
240 write!(f, "[{} log messages]", logs.len())
242 }
243 }
244 _ => Ok(()),
245 }
246 }
247}
248
249#[derive(Debug, Error)]
250pub enum RpcError {
251 #[error("RPC request error: {0}")]
252 RpcRequestError(String),
253 #[error("RPC response error {code}: {message} {data}")]
254 RpcResponseError {
255 code: i64,
256 message: String,
257 data: RpcResponseErrorData,
258 },
259 #[error("parse error: expected {0}")]
260 ParseError(String), #[error("{0}")]
264 ForUser(String), }
266
267#[derive(Serialize, Deserialize)]
268pub enum TokenAccountsFilter {
269 Mint(Pubkey),
270 ProgramId(Pubkey),
271}
272
273#[cfg(test)]
274mod tests {
275 use {
276 super::*,
277 crate::rpc_config::RpcTokenAccountsFilter,
278 solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel},
279 };
280
281 #[test]
282 fn test_build_request_json() {
283 let test_request = RpcRequest::GetAccountInfo;
284 let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
285 let request = test_request.build_request_json(1, json!([addr]));
286 assert_eq!(request["method"], "getAccountInfo");
287 assert_eq!(request["params"], json!([addr]));
288
289 let test_request = RpcRequest::GetBalance;
290 let request = test_request.build_request_json(1, json!([addr]));
291 assert_eq!(request["method"], "getBalance");
292
293 let test_request = RpcRequest::GetEpochInfo;
294 let request = test_request.build_request_json(1, Value::Null);
295 assert_eq!(request["method"], "getEpochInfo");
296
297 #[allow(deprecated)]
298 let test_request = RpcRequest::GetRecentBlockhash;
299 let request = test_request.build_request_json(1, Value::Null);
300 assert_eq!(request["method"], "getRecentBlockhash");
301
302 #[allow(deprecated)]
303 let test_request = RpcRequest::GetFeeCalculatorForBlockhash;
304 let request = test_request.build_request_json(1, json!([addr]));
305 assert_eq!(request["method"], "getFeeCalculatorForBlockhash");
306
307 #[allow(deprecated)]
308 let test_request = RpcRequest::GetFeeRateGovernor;
309 let request = test_request.build_request_json(1, Value::Null);
310 assert_eq!(request["method"], "getFeeRateGovernor");
311
312 let test_request = RpcRequest::GetSlot;
313 let request = test_request.build_request_json(1, Value::Null);
314 assert_eq!(request["method"], "getSlot");
315
316 let test_request = RpcRequest::GetTransactionCount;
317 let request = test_request.build_request_json(1, Value::Null);
318 assert_eq!(request["method"], "getTransactionCount");
319
320 let test_request = RpcRequest::RequestAirdrop;
321 let request = test_request.build_request_json(1, Value::Null);
322 assert_eq!(request["method"], "requestAirdrop");
323
324 let test_request = RpcRequest::SendTransaction;
325 let request = test_request.build_request_json(1, Value::Null);
326 assert_eq!(request["method"], "sendTransaction");
327 }
328
329 #[test]
330 fn test_build_request_json_config_options() {
331 let commitment_config = CommitmentConfig {
332 commitment: CommitmentLevel::Finalized,
333 };
334 let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
335
336 #[allow(deprecated)]
338 let test_request = RpcRequest::GetRecentBlockhash;
339 let request = test_request.build_request_json(1, json!([commitment_config]));
340 assert_eq!(request["params"], json!([commitment_config.clone()]));
341
342 let test_request = RpcRequest::GetBalance;
344 let request = test_request.build_request_json(1, json!([addr, commitment_config]));
345 assert_eq!(request["params"], json!([addr, commitment_config]));
346
347 let test_request = RpcRequest::GetTokenAccountsByOwner;
349 let mint = solana_sdk::pubkey::new_rand();
350 let token_account_filter = RpcTokenAccountsFilter::Mint(mint.to_string());
351 let request = test_request
352 .build_request_json(1, json!([addr, token_account_filter, commitment_config]));
353 assert_eq!(
354 request["params"],
355 json!([addr, token_account_filter, commitment_config])
356 );
357 }
358}