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