safecoin_account_decoder/
parse_bpf_loader.rs1use {
2 crate::{
3 parse_account_data::{ParsableAccount, ParseAccountError},
4 UiAccountData, UiAccountEncoding,
5 },
6 bincode::{deserialize, serialized_size},
7 solana_sdk::{bpf_loader_upgradeable::UpgradeableLoaderState, pubkey::Pubkey},
8};
9
10pub fn parse_bpf_upgradeable_loader(
11 data: &[u8],
12) -> Result<BpfUpgradeableLoaderAccountType, ParseAccountError> {
13 let account_state: UpgradeableLoaderState = deserialize(data).map_err(|_| {
14 ParseAccountError::AccountNotParsable(ParsableAccount::BpfUpgradeableLoader)
15 })?;
16 let parsed_account = match account_state {
17 UpgradeableLoaderState::Uninitialized => BpfUpgradeableLoaderAccountType::Uninitialized,
18 UpgradeableLoaderState::Buffer { authority_address } => {
19 let offset = if authority_address.is_some() {
20 UpgradeableLoaderState::size_of_buffer_metadata()
21 } else {
22 UpgradeableLoaderState::size_of_buffer_metadata()
25 - serialized_size(&Pubkey::default()).unwrap() as usize
26 };
27 BpfUpgradeableLoaderAccountType::Buffer(UiBuffer {
28 authority: authority_address.map(|pubkey| pubkey.to_string()),
29 data: UiAccountData::Binary(
30 base64::encode(&data[offset as usize..]),
31 UiAccountEncoding::Base64,
32 ),
33 })
34 }
35 UpgradeableLoaderState::Program {
36 programdata_address,
37 } => BpfUpgradeableLoaderAccountType::Program(UiProgram {
38 program_data: programdata_address.to_string(),
39 }),
40 UpgradeableLoaderState::ProgramData {
41 slot,
42 upgrade_authority_address,
43 } => {
44 let offset = if upgrade_authority_address.is_some() {
45 UpgradeableLoaderState::size_of_programdata_metadata()
46 } else {
47 UpgradeableLoaderState::size_of_programdata_metadata()
48 - serialized_size(&Pubkey::default()).unwrap() as usize
49 };
50 BpfUpgradeableLoaderAccountType::ProgramData(UiProgramData {
51 slot,
52 authority: upgrade_authority_address.map(|pubkey| pubkey.to_string()),
53 data: UiAccountData::Binary(
54 base64::encode(&data[offset as usize..]),
55 UiAccountEncoding::Base64,
56 ),
57 })
58 }
59 };
60 Ok(parsed_account)
61}
62
63#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
64#[serde(rename_all = "camelCase", tag = "type", content = "info")]
65pub enum BpfUpgradeableLoaderAccountType {
66 Uninitialized,
67 Buffer(UiBuffer),
68 Program(UiProgram),
69 ProgramData(UiProgramData),
70}
71
72#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
73#[serde(rename_all = "camelCase")]
74pub struct UiBuffer {
75 pub authority: Option<String>,
76 pub data: UiAccountData,
77}
78
79#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
80#[serde(rename_all = "camelCase")]
81pub struct UiProgram {
82 pub program_data: String,
83}
84
85#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
86#[serde(rename_all = "camelCase")]
87pub struct UiProgramData {
88 pub slot: u64,
89 pub authority: Option<String>,
90 pub data: UiAccountData,
91}
92
93#[cfg(test)]
94mod test {
95 use {super::*, bincode::serialize, solana_sdk::pubkey::Pubkey};
96
97 #[test]
98 fn test_parse_bpf_upgradeable_loader_accounts() {
99 let bpf_loader_state = UpgradeableLoaderState::Uninitialized;
100 let account_data = serialize(&bpf_loader_state).unwrap();
101 assert_eq!(
102 parse_bpf_upgradeable_loader(&account_data).unwrap(),
103 BpfUpgradeableLoaderAccountType::Uninitialized
104 );
105
106 let program = vec![7u8; 64]; let authority = Pubkey::new_unique();
109 let bpf_loader_state = UpgradeableLoaderState::Buffer {
110 authority_address: Some(authority),
111 };
112 let mut account_data = serialize(&bpf_loader_state).unwrap();
113 account_data.extend_from_slice(&program);
114 assert_eq!(
115 parse_bpf_upgradeable_loader(&account_data).unwrap(),
116 BpfUpgradeableLoaderAccountType::Buffer(UiBuffer {
117 authority: Some(authority.to_string()),
118 data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
119 })
120 );
121
122 let bpf_loader_state = UpgradeableLoaderState::Buffer {
125 authority_address: None,
126 };
127 let mut account_data = serialize(&bpf_loader_state).unwrap();
128 account_data.extend_from_slice(&program);
129 assert_eq!(
130 parse_bpf_upgradeable_loader(&account_data).unwrap(),
131 BpfUpgradeableLoaderAccountType::Buffer(UiBuffer {
132 authority: None,
133 data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
134 })
135 );
136
137 let programdata_address = Pubkey::new_unique();
138 let bpf_loader_state = UpgradeableLoaderState::Program {
139 programdata_address,
140 };
141 let account_data = serialize(&bpf_loader_state).unwrap();
142 assert_eq!(
143 parse_bpf_upgradeable_loader(&account_data).unwrap(),
144 BpfUpgradeableLoaderAccountType::Program(UiProgram {
145 program_data: programdata_address.to_string(),
146 })
147 );
148
149 let authority = Pubkey::new_unique();
150 let slot = 42;
151 let bpf_loader_state = UpgradeableLoaderState::ProgramData {
152 slot,
153 upgrade_authority_address: Some(authority),
154 };
155 let mut account_data = serialize(&bpf_loader_state).unwrap();
156 account_data.extend_from_slice(&program);
157 assert_eq!(
158 parse_bpf_upgradeable_loader(&account_data).unwrap(),
159 BpfUpgradeableLoaderAccountType::ProgramData(UiProgramData {
160 slot,
161 authority: Some(authority.to_string()),
162 data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
163 })
164 );
165
166 let bpf_loader_state = UpgradeableLoaderState::ProgramData {
167 slot,
168 upgrade_authority_address: None,
169 };
170 let mut account_data = serialize(&bpf_loader_state).unwrap();
171 account_data.extend_from_slice(&program);
172 assert_eq!(
173 parse_bpf_upgradeable_loader(&account_data).unwrap(),
174 BpfUpgradeableLoaderAccountType::ProgramData(UiProgramData {
175 slot,
176 authority: None,
177 data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
178 })
179 );
180 }
181}