trident_explorer/
program.rs

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}