gemachain_account_decoder/
parse_bpf_loader.rs1use crate::{
2 parse_account_data::{ParsableAccount, ParseAccountError},
3 UiAccountData, UiAccountEncoding,
4};
5use bincode::{deserialize, serialized_size};
6use gemachain_sdk::{bpf_loader_upgradeable::UpgradeableLoaderState, pubkey::Pubkey};
7
8pub fn parse_bpf_upgradeable_loader(
9 data: &[u8],
10) -> Result<BpfUpgradeableLoaderAccountType, ParseAccountError> {
11 let account_state: UpgradeableLoaderState = deserialize(data).map_err(|_| {
12 ParseAccountError::AccountNotParsable(ParsableAccount::BpfUpgradeableLoader)
13 })?;
14 let parsed_account = match account_state {
15 UpgradeableLoaderState::Uninitialized => BpfUpgradeableLoaderAccountType::Uninitialized,
16 UpgradeableLoaderState::Buffer { authority_address } => {
17 let offset = if authority_address.is_some() {
18 UpgradeableLoaderState::buffer_data_offset().unwrap()
19 } else {
20 UpgradeableLoaderState::buffer_data_offset().unwrap()
23 - serialized_size(&Pubkey::default()).unwrap() as usize
24 };
25 BpfUpgradeableLoaderAccountType::Buffer(UiBuffer {
26 authority: authority_address.map(|pubkey| pubkey.to_string()),
27 data: UiAccountData::Binary(
28 base64::encode(&data[offset as usize..]),
29 UiAccountEncoding::Base64,
30 ),
31 })
32 }
33 UpgradeableLoaderState::Program {
34 programdata_address,
35 } => BpfUpgradeableLoaderAccountType::Program(UiProgram {
36 program_data: programdata_address.to_string(),
37 }),
38 UpgradeableLoaderState::ProgramData {
39 slot,
40 upgrade_authority_address,
41 } => {
42 let offset = if upgrade_authority_address.is_some() {
43 UpgradeableLoaderState::programdata_data_offset().unwrap()
44 } else {
45 UpgradeableLoaderState::programdata_data_offset().unwrap()
46 - serialized_size(&Pubkey::default()).unwrap() as usize
47 };
48 BpfUpgradeableLoaderAccountType::ProgramData(UiProgramData {
49 slot,
50 authority: upgrade_authority_address.map(|pubkey| pubkey.to_string()),
51 data: UiAccountData::Binary(
52 base64::encode(&data[offset as usize..]),
53 UiAccountEncoding::Base64,
54 ),
55 })
56 }
57 };
58 Ok(parsed_account)
59}
60
61#[derive(Debug, Serialize, Deserialize, PartialEq)]
62#[serde(rename_all = "camelCase", tag = "type", content = "info")]
63pub enum BpfUpgradeableLoaderAccountType {
64 Uninitialized,
65 Buffer(UiBuffer),
66 Program(UiProgram),
67 ProgramData(UiProgramData),
68}
69
70#[derive(Debug, Serialize, Deserialize, PartialEq)]
71#[serde(rename_all = "camelCase")]
72pub struct UiBuffer {
73 pub authority: Option<String>,
74 pub data: UiAccountData,
75}
76
77#[derive(Debug, Serialize, Deserialize, PartialEq)]
78#[serde(rename_all = "camelCase")]
79pub struct UiProgram {
80 pub program_data: String,
81}
82
83#[derive(Debug, Serialize, Deserialize, PartialEq)]
84#[serde(rename_all = "camelCase")]
85pub struct UiProgramData {
86 pub slot: u64,
87 pub authority: Option<String>,
88 pub data: UiAccountData,
89}
90
91#[cfg(test)]
92mod test {
93 use super::*;
94 use bincode::serialize;
95 use gemachain_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}