|
@@ -1,6 +1,7 @@
|
|
|
use crate::error::ErrorCode;
|
|
|
use crate::*;
|
|
|
use solana_program::account_info::AccountInfo;
|
|
|
+use solana_program::bpf_loader_upgradeable::{self, UpgradeableLoaderState};
|
|
|
use solana_program::instruction::AccountMeta;
|
|
|
use solana_program::program_error::ProgramError;
|
|
|
use solana_program::pubkey::Pubkey;
|
|
@@ -12,6 +13,7 @@ use std::ops::Deref;
|
|
|
pub struct Program<'info, T: Id + AccountDeserialize + Clone> {
|
|
|
_account: T,
|
|
|
info: AccountInfo<'info>,
|
|
|
+ programdata_address: Option<Pubkey>,
|
|
|
}
|
|
|
|
|
|
impl<'info, T: Id + AccountDeserialize + Clone + fmt::Debug> fmt::Debug for Program<'info, T> {
|
|
@@ -19,13 +21,22 @@ impl<'info, T: Id + AccountDeserialize + Clone + fmt::Debug> fmt::Debug for Prog
|
|
|
f.debug_struct("Program")
|
|
|
.field("account", &self._account)
|
|
|
.field("info", &self.info)
|
|
|
+ .field("programdata_address", &self.programdata_address)
|
|
|
.finish()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl<'a, T: Id + AccountDeserialize + Clone> Program<'a, T> {
|
|
|
- fn new(info: AccountInfo<'a>, _account: T) -> Program<'a, T> {
|
|
|
- Self { info, _account }
|
|
|
+ fn new(
|
|
|
+ info: AccountInfo<'a>,
|
|
|
+ _account: T,
|
|
|
+ programdata_address: Option<Pubkey>,
|
|
|
+ ) -> Program<'a, T> {
|
|
|
+ Self {
|
|
|
+ info,
|
|
|
+ _account,
|
|
|
+ programdata_address,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Deserializes the given `info` into a `Program`.
|
|
@@ -37,9 +48,44 @@ impl<'a, T: Id + AccountDeserialize + Clone> Program<'a, T> {
|
|
|
if !info.executable {
|
|
|
return Err(ErrorCode::InvalidProgramExecutable.into());
|
|
|
}
|
|
|
+ let programdata_address = if *info.owner == bpf_loader_upgradeable::ID {
|
|
|
+ let mut data: &[u8] = &info.try_borrow_data()?;
|
|
|
+ let upgradable_loader_state =
|
|
|
+ UpgradeableLoaderState::try_deserialize_unchecked(&mut data)?;
|
|
|
+
|
|
|
+ match upgradable_loader_state {
|
|
|
+ UpgradeableLoaderState::Uninitialized
|
|
|
+ | UpgradeableLoaderState::Buffer {
|
|
|
+ authority_address: _,
|
|
|
+ }
|
|
|
+ | UpgradeableLoaderState::ProgramData {
|
|
|
+ slot: _,
|
|
|
+ upgrade_authority_address: _,
|
|
|
+ } => {
|
|
|
+ // Unreachable because check above already
|
|
|
+ // ensures that program is executable
|
|
|
+ // and therefore a program account.
|
|
|
+ unreachable!()
|
|
|
+ }
|
|
|
+ UpgradeableLoaderState::Program {
|
|
|
+ programdata_address,
|
|
|
+ } => Some(programdata_address),
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ None
|
|
|
+ };
|
|
|
+
|
|
|
// Programs have no data so use an empty slice.
|
|
|
let mut empty = &[][..];
|
|
|
- Ok(Program::new(info.clone(), T::try_deserialize(&mut empty)?))
|
|
|
+ Ok(Program::new(
|
|
|
+ info.clone(),
|
|
|
+ T::try_deserialize(&mut empty)?,
|
|
|
+ programdata_address,
|
|
|
+ ))
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn programdata_address(&self) -> Option<Pubkey> {
|
|
|
+ self.programdata_address
|
|
|
}
|
|
|
}
|
|
|
|