1use crate::{account::KeyedAccount, output::pretty_lamports_to_sol};
2use console::style;
3use serde::Serialize;
4use solana_sdk::{bpf_loader_upgradeable::UpgradeableLoaderState, pubkey::Pubkey};
5use std::fmt;
6
7pub struct ProgramFieldVisibility {
8 program_account: bool,
9 programdata_account: bool,
10}
11
12impl ProgramFieldVisibility {
13 pub fn new_all_enabled() -> Self {
14 Self {
15 program_account: true,
16 programdata_account: true,
17 }
18 }
19
20 pub fn new_all_disabled() -> Self {
21 Self {
22 program_account: false,
23 programdata_account: false,
24 }
25 }
26
27 pub fn program_account(&self) -> bool {
28 self.program_account
29 }
30
31 pub fn enable_program_account(&mut self) -> &mut Self {
32 self.program_account = true;
33 self
34 }
35
36 pub fn disable_program_account(&mut self) -> &mut Self {
37 self.program_account = false;
38 self
39 }
40
41 pub fn programdata_account(&self) -> bool {
42 self.programdata_account
43 }
44
45 pub fn enable_programdata_account(&mut self) -> &mut Self {
46 self.programdata_account = true;
47 self
48 }
49
50 pub fn disable_programdata_account(&mut self) -> &mut Self {
51 self.programdata_account = false;
52 self
53 }
54}
55
56#[derive(Serialize)]
57pub struct ProgramDataDeserialized {
58 pub slot: u64,
59 pub upgrade_authority_address: String,
60 pub raw_program_data: String,
61}
62
63#[derive(Serialize)]
64pub struct ProgramDeserialized {
65 pub programdata_address: String,
66}
67
68#[derive(Serialize)]
69pub struct DisplayProgramDataAccount {
70 pub lamports: u64,
71 pub data: ProgramDataDeserialized,
72 pub owner: String,
73 pub executable: bool,
74 pub rent_epoch: u64,
75}
76
77#[derive(Serialize)]
78pub struct DisplayProgramAccount {
79 pub lamports: u64,
80 pub data: ProgramDeserialized,
81 pub owner: String,
82 pub executable: bool,
83 pub rent_epoch: u64,
84}
85
86#[derive(Serialize)]
87pub struct DisplayUpgradeableProgram {
88 pub program_id: String,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub program_account: Option<DisplayProgramAccount>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub programdata_account: Option<DisplayProgramDataAccount>,
93}
94
95impl DisplayUpgradeableProgram {
96 pub fn from(
97 program_account: &KeyedAccount,
98 programdata_account: &KeyedAccount,
99 slot: u64,
100 upgrade_authority_address: &Option<Pubkey>,
101 visibility: &ProgramFieldVisibility,
102 ) -> Self {
103 Self {
104 program_id: program_account.pubkey.to_string(),
105 program_account: if visibility.program_account {
106 Some(DisplayProgramAccount {
107 lamports: program_account.account.lamports,
108 data: ProgramDeserialized {
109 programdata_address: programdata_account.pubkey.to_string(),
110 },
111 owner: program_account.account.owner.to_string(),
112 executable: program_account.account.executable,
113 rent_epoch: program_account.account.rent_epoch,
114 })
115 } else {
116 None
117 },
118 programdata_account: if visibility.programdata_account {
119 Some(DisplayProgramDataAccount {
120 lamports: programdata_account.account.lamports,
121 data: ProgramDataDeserialized {
122 slot,
123 upgrade_authority_address: upgrade_authority_address
124 .map(|pubkey| pubkey.to_string())
125 .unwrap_or_else(|| "none".to_string()),
126 raw_program_data: base64::encode(
127 &programdata_account.account.data
128 [UpgradeableLoaderState::size_of_programdata_metadata()..],
129 ),
130 },
131 owner: programdata_account.account.owner.to_string(),
132 executable: programdata_account.account.executable,
133 rent_epoch: programdata_account.account.rent_epoch,
134 })
135 } else {
136 None
137 },
138 }
139 }
140}
141
142impl fmt::Display for DisplayUpgradeableProgram {
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 writeln!(
145 f,
146 "========================================================"
147 )?;
148 writeln!(f, "{} {}", style("Program Id:").bold(), self.program_id)?;
149 writeln!(
150 f,
151 "========================================================"
152 )?;
153
154 if let Some(program_account) = &self.program_account {
155 writeln!(f)?;
156
157 writeln!(f, "{}", style("--> Program Account").bold(),)?;
158
159 writeln!(f)?;
160
161 writeln!(
162 f,
163 "{} {} (◎ {})",
164 style("Lamports:").bold(),
165 program_account.lamports,
166 pretty_lamports_to_sol(program_account.lamports)
167 )?;
168 writeln!(
169 f,
170 "{} [Deserialized and interpreted below]",
171 style("Data:").bold()
172 )?;
173 writeln!(f, "{} {}", style("Owner").bold(), program_account.owner)?;
174 writeln!(
175 f,
176 "{} {}",
177 style("Executable:").bold(),
178 program_account.executable
179 )?;
180 writeln!(
181 f,
182 "{} {}",
183 style("Rent Epoch:").bold(),
184 program_account.rent_epoch
185 )?;
186
187 writeln!(f)?;
188
189 writeln!(f, "{}", style("Deserialized:").bold())?;
190 write!(f, " - ")?;
191 write!(
192 f,
193 "{} {}",
194 style("ProgramData Address:").bold(),
195 program_account.data.programdata_address
196 )?;
197
198 if self.programdata_account.is_some() {
199 writeln!(f)?;
200 }
201 }
202
203 if let Some(programdata_account) = &self.programdata_account {
204 writeln!(f)?;
205
206 writeln!(f, "{}", style("--> ProgramData Account").bold())?;
207
208 writeln!(f)?;
209
210 writeln!(
211 f,
212 "{} {} (◎ {})",
213 style("Lamports:").bold(),
214 programdata_account.lamports,
215 pretty_lamports_to_sol(programdata_account.lamports)
216 )?;
217 writeln!(
218 f,
219 "{} [Deserialized and interpreted below]",
220 style("Data:").bold()
221 )?;
222 writeln!(f, "{} {}", style("Owner").bold(), programdata_account.owner)?;
223 writeln!(
224 f,
225 "{} {}",
226 style("Executable:").bold(),
227 programdata_account.executable
228 )?;
229 writeln!(
230 f,
231 "{} {}",
232 style("Rent Epoch:").bold(),
233 programdata_account.rent_epoch
234 )?;
235
236 writeln!(f)?;
237
238 writeln!(f, "{}", style("Deserialized:").bold())?;
239 write!(f, " - ")?;
240 writeln!(
241 f,
242 "{} {}",
243 style("Last Deployed Slot:").bold(),
244 programdata_account.data.slot
245 )?;
246 write!(f, " - ")?;
247 write!(
248 f,
249 "{} {}",
250 style("Upgrade Authority:").bold(),
251 programdata_account.data.upgrade_authority_address
252 )?;
253 }
254
255 Ok(())
256 }
257}