| 
									
										
										
										
											2021-02-16 14:48:20 -07:00
										 |  |  | #![allow(clippy::integer_arithmetic)]
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | #[macro_use]
 | 
					
						
							|  |  |  | extern crate lazy_static;
 | 
					
						
							|  |  |  | #[macro_use]
 | 
					
						
							|  |  |  | extern crate serde_derive;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub mod parse_account_data;
 | 
					
						
							| 
									
										
										
										
											2021-02-08 17:18:10 -07:00
										 |  |  | pub mod parse_bpf_loader;
 | 
					
						
							| 
									
										
										
										
											2020-08-09 01:50:45 -06:00
										 |  |  | pub mod parse_config;
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | pub mod parse_nonce;
 | 
					
						
							| 
									
										
										
										
											2020-08-09 01:50:45 -06:00
										 |  |  | pub mod parse_stake;
 | 
					
						
							|  |  |  | pub mod parse_sysvar;
 | 
					
						
							| 
									
										
										
										
											2020-07-24 17:45:21 -06:00
										 |  |  | pub mod parse_token;
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | pub mod parse_vote;
 | 
					
						
							| 
									
										
										
										
											2020-08-09 01:50:45 -06:00
										 |  |  | pub mod validator_info;
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  | use {
 | 
					
						
							|  |  |  |     crate::parse_account_data::{parse_account_data, AccountAdditionalData, ParsedAccount},
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |     solana_sdk::{
 | 
					
						
							| 
									
										
										
										
											2021-12-03 09:00:31 -08:00
										 |  |  |         account::{ReadableAccount, WritableAccount},
 | 
					
						
							|  |  |  |         clock::Epoch,
 | 
					
						
							|  |  |  |         fee_calculator::FeeCalculator,
 | 
					
						
							|  |  |  |         pubkey::Pubkey,
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |     },
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |     std::{
 | 
					
						
							|  |  |  |         io::{Read, Write},
 | 
					
						
							|  |  |  |         str::FromStr,
 | 
					
						
							|  |  |  |     },
 | 
					
						
							|  |  |  | };
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-07 11:37:39 -06:00
										 |  |  | pub type StringAmount = String;
 | 
					
						
							| 
									
										
										
										
											2021-03-02 22:51:41 -07:00
										 |  |  | pub type StringDecimals = String;
 | 
					
						
							| 
									
										
										
										
											2021-08-20 22:30:59 +02:00
										 |  |  | pub const MAX_BASE58_BYTES: usize = 128;
 | 
					
						
							| 
									
										
										
										
											2020-08-07 11:37:39 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | /// A duplicate representation of an Account for pretty JSON serialization
 | 
					
						
							|  |  |  | #[derive(Serialize, Deserialize, Clone, Debug)]
 | 
					
						
							|  |  |  | #[serde(rename_all = "camelCase")]
 | 
					
						
							|  |  |  | pub struct UiAccount {
 | 
					
						
							|  |  |  |     pub lamports: u64,
 | 
					
						
							|  |  |  |     pub data: UiAccountData,
 | 
					
						
							|  |  |  |     pub owner: String,
 | 
					
						
							|  |  |  |     pub executable: bool,
 | 
					
						
							|  |  |  |     pub rent_epoch: Epoch,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 | 
					
						
							|  |  |  | #[serde(rename_all = "camelCase", untagged)]
 | 
					
						
							|  |  |  | pub enum UiAccountData {
 | 
					
						
							| 
									
										
										
										
											2020-08-15 22:06:39 -07:00
										 |  |  |     LegacyBinary(String), // Legacy. Retained for RPC backwards compatibility
 | 
					
						
							| 
									
										
										
										
											2020-08-05 00:59:10 -06:00
										 |  |  |     Json(ParsedAccount),
 | 
					
						
							| 
									
										
										
										
											2020-08-15 17:56:09 -07:00
										 |  |  |     Binary(String, UiAccountEncoding),
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 22:40:14 +03:00
										 |  |  | #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | #[serde(rename_all = "camelCase")]
 | 
					
						
							|  |  |  | pub enum UiAccountEncoding {
 | 
					
						
							| 
									
										
										
										
											2020-08-15 22:06:39 -07:00
										 |  |  |     Binary, // Legacy. Retained for RPC backwards compatibility
 | 
					
						
							|  |  |  |     Base58,
 | 
					
						
							|  |  |  |     Base64,
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |     JsonParsed,
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |     #[serde(rename = "base64+zstd")]
 | 
					
						
							|  |  |  |     Base64Zstd,
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | impl UiAccount {
 | 
					
						
							| 
									
										
										
										
											2021-08-20 22:30:59 +02:00
										 |  |  |     fn encode_bs58<T: ReadableAccount>(
 | 
					
						
							|  |  |  |         account: &T,
 | 
					
						
							|  |  |  |         data_slice_config: Option<UiDataSliceConfig>,
 | 
					
						
							|  |  |  |     ) -> String {
 | 
					
						
							|  |  |  |         if account.data().len() <= MAX_BASE58_BYTES {
 | 
					
						
							|  |  |  |             bs58::encode(slice_data(account.data(), data_slice_config)).into_string()
 | 
					
						
							|  |  |  |         } else {
 | 
					
						
							|  |  |  |             "error: data too large for bs58 encoding".to_string()
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |     pub fn encode<T: ReadableAccount>(
 | 
					
						
							| 
									
										
										
										
											2020-08-09 01:50:45 -06:00
										 |  |  |         pubkey: &Pubkey,
 | 
					
						
							| 
									
										
										
										
											2021-05-25 16:44:18 -07:00
										 |  |  |         account: &T,
 | 
					
						
							| 
									
										
										
										
											2020-08-07 11:37:39 -06:00
										 |  |  |         encoding: UiAccountEncoding,
 | 
					
						
							|  |  |  |         additional_data: Option<AccountAdditionalData>,
 | 
					
						
							| 
									
										
										
										
											2020-08-10 16:35:29 -06:00
										 |  |  |         data_slice_config: Option<UiDataSliceConfig>,
 | 
					
						
							| 
									
										
										
										
											2020-08-07 11:37:39 -06:00
										 |  |  |     ) -> Self {
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |         let data = match encoding {
 | 
					
						
							| 
									
										
										
										
											2021-08-20 22:30:59 +02:00
										 |  |  |             UiAccountEncoding::Binary => {
 | 
					
						
							|  |  |  |                 let data = Self::encode_bs58(account, data_slice_config);
 | 
					
						
							|  |  |  |                 UiAccountData::LegacyBinary(data)
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             UiAccountEncoding::Base58 => {
 | 
					
						
							|  |  |  |                 let data = Self::encode_bs58(account, data_slice_config);
 | 
					
						
							|  |  |  |                 UiAccountData::Binary(data, encoding)
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-08-15 22:06:39 -07:00
										 |  |  |             UiAccountEncoding::Base64 => UiAccountData::Binary(
 | 
					
						
							| 
									
										
										
										
											2021-06-18 15:34:46 +02:00
										 |  |  |                 base64::encode(slice_data(account.data(), data_slice_config)),
 | 
					
						
							| 
									
										
										
										
											2020-08-15 17:56:09 -07:00
										 |  |  |                 encoding,
 | 
					
						
							|  |  |  |             ),
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |             UiAccountEncoding::Base64Zstd => {
 | 
					
						
							|  |  |  |                 let mut encoder = zstd::stream::write::Encoder::new(Vec::new(), 0).unwrap();
 | 
					
						
							|  |  |  |                 match encoder
 | 
					
						
							| 
									
										
										
										
											2021-06-18 15:34:46 +02:00
										 |  |  |                     .write_all(slice_data(account.data(), data_slice_config))
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |                     .and_then(|()| encoder.finish())
 | 
					
						
							|  |  |  |                 {
 | 
					
						
							|  |  |  |                     Ok(zstd_data) => UiAccountData::Binary(base64::encode(zstd_data), encoding),
 | 
					
						
							|  |  |  |                     Err(_) => UiAccountData::Binary(
 | 
					
						
							| 
									
										
										
										
											2021-06-18 15:34:46 +02:00
										 |  |  |                         base64::encode(slice_data(account.data(), data_slice_config)),
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |                         UiAccountEncoding::Base64,
 | 
					
						
							|  |  |  |                     ),
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |             UiAccountEncoding::JsonParsed => {
 | 
					
						
							| 
									
										
										
										
											2020-08-07 11:37:39 -06:00
										 |  |  |                 if let Ok(parsed_data) =
 | 
					
						
							| 
									
										
										
										
											2021-06-18 15:34:46 +02:00
										 |  |  |                     parse_account_data(pubkey, account.owner(), account.data(), additional_data)
 | 
					
						
							| 
									
										
										
										
											2020-08-07 11:37:39 -06:00
										 |  |  |                 {
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |                     UiAccountData::Json(parsed_data)
 | 
					
						
							|  |  |  |                 } else {
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |                     UiAccountData::Binary(
 | 
					
						
							|  |  |  |                         base64::encode(&account.data()),
 | 
					
						
							|  |  |  |                         UiAccountEncoding::Base64,
 | 
					
						
							|  |  |  |                     )
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         };
 | 
					
						
							|  |  |  |         UiAccount {
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |             lamports: account.lamports(),
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |             data,
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |             owner: account.owner().to_string(),
 | 
					
						
							|  |  |  |             executable: account.executable(),
 | 
					
						
							|  |  |  |             rent_epoch: account.rent_epoch(),
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |     pub fn decode<T: WritableAccount>(&self) -> Option<T> {
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |         let data = match &self.data {
 | 
					
						
							|  |  |  |             UiAccountData::Json(_) => None,
 | 
					
						
							| 
									
										
										
										
											2020-08-15 17:56:09 -07:00
										 |  |  |             UiAccountData::LegacyBinary(blob) => bs58::decode(blob).into_vec().ok(),
 | 
					
						
							|  |  |  |             UiAccountData::Binary(blob, encoding) => match encoding {
 | 
					
						
							| 
									
										
										
										
											2020-08-15 22:06:39 -07:00
										 |  |  |                 UiAccountEncoding::Base58 => bs58::decode(blob).into_vec().ok(),
 | 
					
						
							|  |  |  |                 UiAccountEncoding::Base64 => base64::decode(blob).ok(),
 | 
					
						
							| 
									
										
										
										
											2022-01-21 16:01:22 -08:00
										 |  |  |                 UiAccountEncoding::Base64Zstd => base64::decode(blob).ok().and_then(|zstd_data| {
 | 
					
						
							|  |  |  |                     let mut data = vec![];
 | 
					
						
							|  |  |  |                     zstd::stream::read::Decoder::new(zstd_data.as_slice())
 | 
					
						
							|  |  |  |                         .and_then(|mut reader| reader.read_to_end(&mut data))
 | 
					
						
							|  |  |  |                         .map(|_| data)
 | 
					
						
							|  |  |  |                         .ok()
 | 
					
						
							|  |  |  |                 }),
 | 
					
						
							| 
									
										
										
										
											2020-08-15 22:06:39 -07:00
										 |  |  |                 UiAccountEncoding::Binary | UiAccountEncoding::JsonParsed => None,
 | 
					
						
							| 
									
										
										
										
											2020-08-15 17:56:09 -07:00
										 |  |  |             },
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |         }?;
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |         Some(T::create(
 | 
					
						
							|  |  |  |             self.lamports,
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |             data,
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |             Pubkey::from_str(&self.owner).ok()?,
 | 
					
						
							|  |  |  |             self.executable,
 | 
					
						
							|  |  |  |             self.rent_epoch,
 | 
					
						
							|  |  |  |         ))
 | 
					
						
							| 
									
										
										
										
											2020-06-30 22:55:11 -06:00
										 |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-08-09 01:50:45 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
 | 
					
						
							|  |  |  | #[serde(rename_all = "camelCase")]
 | 
					
						
							|  |  |  | pub struct UiFeeCalculator {
 | 
					
						
							|  |  |  |     pub lamports_per_signature: StringAmount,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | impl From<FeeCalculator> for UiFeeCalculator {
 | 
					
						
							|  |  |  |     fn from(fee_calculator: FeeCalculator) -> Self {
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							|  |  |  |             lamports_per_signature: fee_calculator.lamports_per_signature.to_string(),
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | impl Default for UiFeeCalculator {
 | 
					
						
							|  |  |  |     fn default() -> Self {
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							|  |  |  |             lamports_per_signature: "0".to_string(),
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-08-10 16:35:29 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 22:40:14 +03:00
										 |  |  | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 | 
					
						
							| 
									
										
										
										
											2020-08-10 16:35:29 -06:00
										 |  |  | #[serde(rename_all = "camelCase")]
 | 
					
						
							|  |  |  | pub struct UiDataSliceConfig {
 | 
					
						
							|  |  |  |     pub offset: usize,
 | 
					
						
							|  |  |  |     pub length: usize,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | fn slice_data(data: &[u8], data_slice_config: Option<UiDataSliceConfig>) -> &[u8] {
 | 
					
						
							|  |  |  |     if let Some(UiDataSliceConfig { offset, length }) = data_slice_config {
 | 
					
						
							|  |  |  |         if offset >= data.len() {
 | 
					
						
							|  |  |  |             &[]
 | 
					
						
							|  |  |  |         } else if length > data.len() - offset {
 | 
					
						
							|  |  |  |             &data[offset..]
 | 
					
						
							|  |  |  |         } else {
 | 
					
						
							|  |  |  |             &data[offset..offset + length]
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     } else {
 | 
					
						
							|  |  |  |         data
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #[cfg(test)]
 | 
					
						
							|  |  |  | mod test {
 | 
					
						
							| 
									
										
										
										
											2021-12-03 09:00:31 -08:00
										 |  |  |     use {
 | 
					
						
							|  |  |  |         super::*,
 | 
					
						
							|  |  |  |         solana_sdk::account::{Account, AccountSharedData},
 | 
					
						
							|  |  |  |     };
 | 
					
						
							| 
									
										
										
										
											2020-08-10 16:35:29 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_slice_data() {
 | 
					
						
							|  |  |  |         let data = vec![1, 2, 3, 4, 5];
 | 
					
						
							|  |  |  |         let slice_config = Some(UiDataSliceConfig {
 | 
					
						
							|  |  |  |             offset: 0,
 | 
					
						
							|  |  |  |             length: 5,
 | 
					
						
							|  |  |  |         });
 | 
					
						
							|  |  |  |         assert_eq!(slice_data(&data, slice_config), &data[..]);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let slice_config = Some(UiDataSliceConfig {
 | 
					
						
							|  |  |  |             offset: 0,
 | 
					
						
							|  |  |  |             length: 10,
 | 
					
						
							|  |  |  |         });
 | 
					
						
							|  |  |  |         assert_eq!(slice_data(&data, slice_config), &data[..]);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let slice_config = Some(UiDataSliceConfig {
 | 
					
						
							|  |  |  |             offset: 1,
 | 
					
						
							|  |  |  |             length: 2,
 | 
					
						
							|  |  |  |         });
 | 
					
						
							|  |  |  |         assert_eq!(slice_data(&data, slice_config), &data[1..3]);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let slice_config = Some(UiDataSliceConfig {
 | 
					
						
							|  |  |  |             offset: 10,
 | 
					
						
							|  |  |  |             length: 2,
 | 
					
						
							|  |  |  |         });
 | 
					
						
							|  |  |  |         assert_eq!(slice_data(&data, slice_config), &[] as &[u8]);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_base64_zstd() {
 | 
					
						
							|  |  |  |         let encoded_account = UiAccount::encode(
 | 
					
						
							|  |  |  |             &Pubkey::default(),
 | 
					
						
							| 
									
										
										
										
											2021-05-25 16:44:18 -07:00
										 |  |  |             &AccountSharedData::from(Account {
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |                 data: vec![0; 1024],
 | 
					
						
							| 
									
										
										
										
											2021-03-11 18:09:04 -06:00
										 |  |  |                 ..Account::default()
 | 
					
						
							|  |  |  |             }),
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |             UiAccountEncoding::Base64Zstd,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert!(matches!(
 | 
					
						
							|  |  |  |             encoded_account.data,
 | 
					
						
							|  |  |  |             UiAccountData::Binary(_, UiAccountEncoding::Base64Zstd)
 | 
					
						
							|  |  |  |         ));
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |         let decoded_account = encoded_account.decode::<Account>().unwrap();
 | 
					
						
							| 
									
										
										
										
											2021-03-09 16:31:33 -06:00
										 |  |  |         assert_eq!(decoded_account.data(), &vec![0; 1024]);
 | 
					
						
							| 
									
										
										
										
											2021-03-09 15:06:07 -06:00
										 |  |  |         let decoded_account = encoded_account.decode::<AccountSharedData>().unwrap();
 | 
					
						
							| 
									
										
										
										
											2021-03-09 16:31:33 -06:00
										 |  |  |         assert_eq!(decoded_account.data(), &vec![0; 1024]);
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:52:01 -08:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-08-10 16:35:29 -06:00
										 |  |  | }
 |