diff --git a/cli-output/src/cli_output.rs b/cli-output/src/cli_output.rs index aad9e02b5b..e1884ec6d3 100644 --- a/cli-output/src/cli_output.rs +++ b/cli-output/src/cli_output.rs @@ -1621,10 +1621,34 @@ impl fmt::Display for CliProgramAuthority { } } +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CliProgram { + pub program_id: String, + pub owner: String, + pub data_len: usize, +} +impl QuietDisplay for CliProgram {} +impl VerboseDisplay for CliProgram {} +impl fmt::Display for CliProgram { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f)?; + writeln_name_value(f, "Program Id:", &self.program_id)?; + writeln_name_value(f, "Owner:", &self.owner)?; + writeln_name_value( + f, + "Data Length:", + &format!("{:?} ({:#x?}) bytes", self.data_len, self.data_len), + )?; + Ok(()) + } +} + #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CliUpgradeableProgram { pub program_id: String, + pub owner: String, pub programdata_address: String, pub authority: String, pub last_deploy_slot: u64, @@ -1636,6 +1660,7 @@ impl fmt::Display for CliUpgradeableProgram { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f)?; writeln_name_value(f, "Program Id:", &self.program_id)?; + writeln_name_value(f, "Owner:", &self.owner)?; writeln_name_value(f, "ProgramData Address:", &self.programdata_address)?; writeln_name_value(f, "Authority:", &self.authority)?; writeln_name_value( diff --git a/cli/src/program.rs b/cli/src/program.rs index 41ddf02f2e..b43da3c441 100644 --- a/cli/src/program.rs +++ b/cli/src/program.rs @@ -13,7 +13,7 @@ use log::*; use solana_bpf_loader_program::{bpf_verifier, BpfError, ThisInstructionMeter}; use solana_clap_utils::{self, input_parsers::*, input_validators::*, keypair::*}; use solana_cli_output::{ - display::new_spinner_progress_bar, CliProgramAccountType, CliProgramAuthority, + display::new_spinner_progress_bar, CliProgram, CliProgramAccountType, CliProgramAuthority, CliProgramBuffer, CliProgramId, CliUpgradeableBuffer, CliUpgradeableProgram, }; use solana_client::{ @@ -933,54 +933,69 @@ fn process_show( .get_account_with_commitment(&account_pubkey, config.commitment)? .value { - if let Ok(UpgradeableLoaderState::Program { - programdata_address, - }) = account.state() - { - if let Some(programdata_account) = rpc_client - .get_account_with_commitment(&programdata_address, config.commitment)? - .value + if account.owner == bpf_loader::id() || account.owner == bpf_loader_deprecated::id() { + Ok(config.output_format.formatted_string(&CliProgram { + program_id: account_pubkey.to_string(), + owner: account.owner.to_string(), + data_len: account.data.len(), + })) + } else if account.owner == bpf_loader_upgradeable::id() { + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = account.state() { - if let Ok(UpgradeableLoaderState::ProgramData { - upgrade_authority_address, - slot, - }) = programdata_account.state() + if let Some(programdata_account) = rpc_client + .get_account_with_commitment(&programdata_address, config.commitment)? + .value { - Ok(config - .output_format - .formatted_string(&CliUpgradeableProgram { - program_id: account_pubkey.to_string(), - programdata_address: programdata_address.to_string(), - authority: upgrade_authority_address - .map(|pubkey| pubkey.to_string()) - .unwrap_or_else(|| "none".to_string()), - last_deploy_slot: slot, - data_len: programdata_account.data.len() - - UpgradeableLoaderState::programdata_data_offset()?, - })) + if let Ok(UpgradeableLoaderState::ProgramData { + upgrade_authority_address, + slot, + }) = programdata_account.state() + { + Ok(config + .output_format + .formatted_string(&CliUpgradeableProgram { + program_id: account_pubkey.to_string(), + owner: account.owner.to_string(), + programdata_address: programdata_address.to_string(), + authority: upgrade_authority_address + .map(|pubkey| pubkey.to_string()) + .unwrap_or_else(|| "none".to_string()), + last_deploy_slot: slot, + data_len: programdata_account.data.len() + - UpgradeableLoaderState::programdata_data_offset()?, + })) + } else { + Err( + "Invalid associated ProgramData account found for the program" + .into(), + ) + } } else { - Err("Invalid associated ProgramData account found for the program".into()) - } - } else { - Err( + Err( "Failed to find associated ProgramData account for the provided program" .into(), ) + } + } else if let Ok(UpgradeableLoaderState::Buffer { authority_address }) = + account.state() + { + Ok(config + .output_format + .formatted_string(&CliUpgradeableBuffer { + address: account_pubkey.to_string(), + authority: authority_address + .map(|pubkey| pubkey.to_string()) + .unwrap_or_else(|| "none".to_string()), + data_len: account.data.len() + - UpgradeableLoaderState::buffer_data_offset()?, + })) + } else { + Err("Not a buffer or program account".into()) } - } else if let Ok(UpgradeableLoaderState::Buffer { authority_address }) = account.state() - { - Ok(config - .output_format - .formatted_string(&CliUpgradeableBuffer { - address: account_pubkey.to_string(), - authority: authority_address - .map(|pubkey| pubkey.to_string()) - .unwrap_or_else(|| "none".to_string()), - data_len: account.data.len() - - UpgradeableLoaderState::buffer_data_offset()?, - })) } else { - Err("Not a buffer or program account".into()) + Err("Accont is not a BPF program".into()) } } else { Err("Unable to find the account".into()) diff --git a/docs/src/cli/deploy-a-program.md b/docs/src/cli/deploy-a-program.md index 7cee809081..b18231cd00 100644 --- a/docs/src/cli/deploy-a-program.md +++ b/docs/src/cli/deploy-a-program.md @@ -69,6 +69,7 @@ An example output looks like: ```bash Program Id: 3KS2k14CmtnuVv2fvYcvdrNgC94Y11WETBpMUGgXyWZL +Owner: BPFLoaderUpgradeab1e11111111111111111111111 ProgramData Address: EHsACWBhgmw8iq5dmUZzTA1esRqcTognhKNHUkPi4q4g Authority: FwoGJNUaJN2zfVEex9BB11Dqb3NJKy3e9oY3KTh9XzCU Last Deployed In Slot: 63890568 @@ -77,6 +78,7 @@ Data Length: 5216 (0x1460) bytes - `Program Id` is the address that can be referenced in an instruction's `program_id` field when invoking a program. +- `Owner`: The loader this program was deployed with. - `ProgramData Address` is the account associated with the program account that holds the program's data (shared object). - `Authority` is the program's upgrade authority.