request.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. use {
  2. crate::response::RpcSimulateTransactionResult,
  3. serde_json::{json, Value},
  4. solana_clock::Slot,
  5. solana_pubkey::Pubkey,
  6. std::fmt,
  7. thiserror::Error,
  8. };
  9. #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
  10. pub enum RpcRequest {
  11. Custom { method: &'static str },
  12. DeregisterNode,
  13. GetAccountInfo,
  14. GetBalance,
  15. GetBlock,
  16. GetBlockHeight,
  17. GetBlockProduction,
  18. GetBlocks,
  19. GetBlocksWithLimit,
  20. GetBlockTime,
  21. GetClusterNodes,
  22. GetEpochInfo,
  23. GetEpochSchedule,
  24. GetFeeForMessage,
  25. GetFirstAvailableBlock,
  26. GetGenesisHash,
  27. GetHealth,
  28. GetIdentity,
  29. GetInflationGovernor,
  30. GetInflationRate,
  31. GetInflationReward,
  32. GetLargestAccounts,
  33. GetLatestBlockhash,
  34. GetLeaderSchedule,
  35. GetMaxRetransmitSlot,
  36. GetMaxShredInsertSlot,
  37. GetMinimumBalanceForRentExemption,
  38. GetMultipleAccounts,
  39. GetProgramAccounts,
  40. GetRecentPerformanceSamples,
  41. GetRecentPrioritizationFees,
  42. GetHighestSnapshotSlot,
  43. GetSignaturesForAddress,
  44. GetSignatureStatuses,
  45. GetSlot,
  46. GetSlotLeader,
  47. GetSlotLeaders,
  48. GetStorageTurn,
  49. GetStorageTurnRate,
  50. GetSlotsPerSegment,
  51. GetStakeMinimumDelegation,
  52. GetStoragePubkeysForSlot,
  53. GetSupply,
  54. GetTokenAccountBalance,
  55. GetTokenAccountsByDelegate,
  56. GetTokenAccountsByOwner,
  57. GetTokenLargestAccounts,
  58. GetTokenSupply,
  59. GetTransaction,
  60. GetTransactionCount,
  61. GetVersion,
  62. GetVoteAccounts,
  63. IsBlockhashValid,
  64. MinimumLedgerSlot,
  65. RegisterNode,
  66. RequestAirdrop,
  67. SendTransaction,
  68. SimulateTransaction,
  69. SignVote,
  70. }
  71. #[allow(deprecated)]
  72. impl fmt::Display for RpcRequest {
  73. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  74. let method = match self {
  75. RpcRequest::Custom { method } => method,
  76. RpcRequest::DeregisterNode => "deregisterNode",
  77. RpcRequest::GetAccountInfo => "getAccountInfo",
  78. RpcRequest::GetBalance => "getBalance",
  79. RpcRequest::GetBlock => "getBlock",
  80. RpcRequest::GetBlockHeight => "getBlockHeight",
  81. RpcRequest::GetBlockProduction => "getBlockProduction",
  82. RpcRequest::GetBlocks => "getBlocks",
  83. RpcRequest::GetBlocksWithLimit => "getBlocksWithLimit",
  84. RpcRequest::GetBlockTime => "getBlockTime",
  85. RpcRequest::GetClusterNodes => "getClusterNodes",
  86. RpcRequest::GetEpochInfo => "getEpochInfo",
  87. RpcRequest::GetEpochSchedule => "getEpochSchedule",
  88. RpcRequest::GetFeeForMessage => "getFeeForMessage",
  89. RpcRequest::GetFirstAvailableBlock => "getFirstAvailableBlock",
  90. RpcRequest::GetGenesisHash => "getGenesisHash",
  91. RpcRequest::GetHealth => "getHealth",
  92. RpcRequest::GetIdentity => "getIdentity",
  93. RpcRequest::GetInflationGovernor => "getInflationGovernor",
  94. RpcRequest::GetInflationRate => "getInflationRate",
  95. RpcRequest::GetInflationReward => "getInflationReward",
  96. RpcRequest::GetLargestAccounts => "getLargestAccounts",
  97. RpcRequest::GetLatestBlockhash => "getLatestBlockhash",
  98. RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
  99. RpcRequest::GetMaxRetransmitSlot => "getMaxRetransmitSlot",
  100. RpcRequest::GetMaxShredInsertSlot => "getMaxShredInsertSlot",
  101. RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
  102. RpcRequest::GetMultipleAccounts => "getMultipleAccounts",
  103. RpcRequest::GetProgramAccounts => "getProgramAccounts",
  104. RpcRequest::GetRecentPerformanceSamples => "getRecentPerformanceSamples",
  105. RpcRequest::GetRecentPrioritizationFees => "getRecentPrioritizationFees",
  106. RpcRequest::GetHighestSnapshotSlot => "getHighestSnapshotSlot",
  107. RpcRequest::GetSignaturesForAddress => "getSignaturesForAddress",
  108. RpcRequest::GetSignatureStatuses => "getSignatureStatuses",
  109. RpcRequest::GetSlot => "getSlot",
  110. RpcRequest::GetSlotLeader => "getSlotLeader",
  111. RpcRequest::GetSlotLeaders => "getSlotLeaders",
  112. RpcRequest::GetStakeMinimumDelegation => "getStakeMinimumDelegation",
  113. RpcRequest::GetStorageTurn => "getStorageTurn",
  114. RpcRequest::GetStorageTurnRate => "getStorageTurnRate",
  115. RpcRequest::GetSlotsPerSegment => "getSlotsPerSegment",
  116. RpcRequest::GetStoragePubkeysForSlot => "getStoragePubkeysForSlot",
  117. RpcRequest::GetSupply => "getSupply",
  118. RpcRequest::GetTokenAccountBalance => "getTokenAccountBalance",
  119. RpcRequest::GetTokenAccountsByDelegate => "getTokenAccountsByDelegate",
  120. RpcRequest::GetTokenAccountsByOwner => "getTokenAccountsByOwner",
  121. RpcRequest::GetTokenSupply => "getTokenSupply",
  122. RpcRequest::GetTokenLargestAccounts => "getTokenLargestAccounts",
  123. RpcRequest::GetTransaction => "getTransaction",
  124. RpcRequest::GetTransactionCount => "getTransactionCount",
  125. RpcRequest::GetVersion => "getVersion",
  126. RpcRequest::GetVoteAccounts => "getVoteAccounts",
  127. RpcRequest::IsBlockhashValid => "isBlockhashValid",
  128. RpcRequest::MinimumLedgerSlot => "minimumLedgerSlot",
  129. RpcRequest::RegisterNode => "registerNode",
  130. RpcRequest::RequestAirdrop => "requestAirdrop",
  131. RpcRequest::SendTransaction => "sendTransaction",
  132. RpcRequest::SimulateTransaction => "simulateTransaction",
  133. RpcRequest::SignVote => "signVote",
  134. };
  135. write!(f, "{method}")
  136. }
  137. }
  138. // Changing any of these? Update the JSON RPC docs!
  139. pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256;
  140. pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000;
  141. pub const MAX_GET_CONFIRMED_BLOCKS_RANGE: u64 = 500_000;
  142. pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT: usize = 1_000;
  143. pub const MAX_MULTIPLE_ACCOUNTS: usize = 100;
  144. pub const NUM_LARGEST_ACCOUNTS: usize = 20;
  145. pub const MAX_GET_PROGRAM_ACCOUNT_FILTERS: usize = 4;
  146. pub const MAX_GET_SLOT_LEADERS: usize = 5000;
  147. // Limit the length of the `epoch_credits` array for each validator in a `get_vote_accounts`
  148. // response
  149. pub const MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY: usize = 5;
  150. // Validators that are this number of slots behind are considered delinquent
  151. pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;
  152. impl RpcRequest {
  153. pub fn build_request_json(self, id: u64, params: Value) -> Value {
  154. let jsonrpc = "2.0";
  155. json!({
  156. "jsonrpc": jsonrpc,
  157. "id": id,
  158. "method": format!("{self}"),
  159. "params": params,
  160. })
  161. }
  162. }
  163. #[derive(Debug)]
  164. pub enum RpcResponseErrorData {
  165. Empty,
  166. SendTransactionPreflightFailure(RpcSimulateTransactionResult),
  167. NodeUnhealthy { num_slots_behind: Option<Slot> },
  168. }
  169. impl fmt::Display for RpcResponseErrorData {
  170. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  171. match self {
  172. RpcResponseErrorData::SendTransactionPreflightFailure(
  173. RpcSimulateTransactionResult {
  174. logs: Some(logs), ..
  175. },
  176. ) => {
  177. if logs.is_empty() {
  178. Ok(())
  179. } else {
  180. writeln!(f, "{} log messages:", logs.len())?;
  181. for log in logs {
  182. writeln!(f, " {log}")?;
  183. }
  184. Ok(())
  185. }
  186. }
  187. _ => Ok(()),
  188. }
  189. }
  190. }
  191. #[derive(Debug, Error)]
  192. pub enum RpcError {
  193. #[error("RPC request error: {0}")]
  194. RpcRequestError(String),
  195. #[error("RPC response error {code}: {message}; {data}")]
  196. RpcResponseError {
  197. code: i64,
  198. message: String,
  199. data: RpcResponseErrorData,
  200. },
  201. #[error("parse error: expected {0}")]
  202. ParseError(String), /* "expected" */
  203. // Anything in a `ForUser` needs to die. The caller should be
  204. // deciding what to tell their user
  205. #[error("{0}")]
  206. ForUser(String), /* "direct-to-user message" */
  207. }
  208. #[derive(Serialize, Deserialize)]
  209. pub enum TokenAccountsFilter {
  210. Mint(Pubkey),
  211. ProgramId(Pubkey),
  212. }
  213. #[cfg(test)]
  214. mod tests {
  215. use {
  216. super::*,
  217. crate::config::RpcTokenAccountsFilter,
  218. solana_commitment_config::{CommitmentConfig, CommitmentLevel},
  219. };
  220. #[test]
  221. fn test_build_request_json() {
  222. let test_request = RpcRequest::GetAccountInfo;
  223. let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
  224. let request = test_request.build_request_json(1, json!([addr]));
  225. assert_eq!(request["method"], "getAccountInfo");
  226. assert_eq!(request["params"], json!([addr]));
  227. let test_request = RpcRequest::GetBalance;
  228. let request = test_request.build_request_json(1, json!([addr]));
  229. assert_eq!(request["method"], "getBalance");
  230. let test_request = RpcRequest::GetEpochInfo;
  231. let request = test_request.build_request_json(1, Value::Null);
  232. assert_eq!(request["method"], "getEpochInfo");
  233. let test_request = RpcRequest::GetLatestBlockhash;
  234. let request = test_request.build_request_json(1, Value::Null);
  235. assert_eq!(request["method"], "getLatestBlockhash");
  236. let test_request = RpcRequest::GetSlot;
  237. let request = test_request.build_request_json(1, Value::Null);
  238. assert_eq!(request["method"], "getSlot");
  239. let test_request = RpcRequest::GetTransactionCount;
  240. let request = test_request.build_request_json(1, Value::Null);
  241. assert_eq!(request["method"], "getTransactionCount");
  242. let test_request = RpcRequest::RequestAirdrop;
  243. let request = test_request.build_request_json(1, Value::Null);
  244. assert_eq!(request["method"], "requestAirdrop");
  245. let test_request = RpcRequest::SendTransaction;
  246. let request = test_request.build_request_json(1, Value::Null);
  247. assert_eq!(request["method"], "sendTransaction");
  248. let test_request = RpcRequest::GetTokenLargestAccounts;
  249. let request = test_request.build_request_json(1, Value::Null);
  250. assert_eq!(request["method"], "getTokenLargestAccounts");
  251. }
  252. #[test]
  253. fn test_build_request_json_config_options() {
  254. let commitment_config = CommitmentConfig {
  255. commitment: CommitmentLevel::Finalized,
  256. };
  257. let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
  258. // Test request with CommitmentConfig and no params
  259. let test_request = RpcRequest::GetLatestBlockhash;
  260. let request = test_request.build_request_json(1, json!([commitment_config]));
  261. assert_eq!(request["params"], json!([commitment_config.clone()]));
  262. // Test request with CommitmentConfig and params
  263. let test_request = RpcRequest::GetBalance;
  264. let request = test_request.build_request_json(1, json!([addr, commitment_config]));
  265. assert_eq!(request["params"], json!([addr, commitment_config]));
  266. // Test request with CommitmentConfig and params
  267. let test_request = RpcRequest::GetTokenAccountsByOwner;
  268. let mint = solana_pubkey::new_rand();
  269. let token_account_filter = RpcTokenAccountsFilter::Mint(mint.to_string());
  270. let request = test_request
  271. .build_request_json(1, json!([addr, token_account_filter, commitment_config]));
  272. assert_eq!(
  273. request["params"],
  274. json!([addr, token_account_filter, commitment_config])
  275. );
  276. }
  277. }