Skip to content

Commit

Permalink
lang: deserialize programdata address on demand/lazily (#1723)
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-schaaf committed Apr 8, 2022
1 parent 248ef79 commit 778e328
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -32,6 +32,7 @@ The minor version will be incremented upon a breaking change and the patch versi
* spl: Re-export the `spl_token` crate ([#1665](https://github.com/project-serum/anchor/pull/1665)).
* lang, cli, spl: Update solana toolchain to v1.9.13 ([#1653](https://github.com/project-serum/anchor/pull/1653)).
* lang: Use fallback function if ix data length smaller than `8` instead of panicking ([#1721](https://github.com/project-serum/anchor/pull/1721)).
* lang: `Program` type now deserializes `programdata_address` only on demand ([#1723](https://github.com/project-serum/anchor/pull/1723)).

## [0.23.0] - 2022-03-20

Expand Down
2 changes: 1 addition & 1 deletion lang/src/accounts/account.rs
Expand Up @@ -186,7 +186,7 @@ use std::ops::{Deref, DerefMut};
/// pub admin_settings: Account<'info, AdminSettings>,
/// #[account(mut)]
/// pub authority: Signer<'info>,
/// #[account(constraint = program.programdata_address() == Some(program_data.key()))]
/// #[account(constraint = program.programdata_address()? == Some(program_data.key()))]
/// pub program: Program<'info, MyProgram>,
/// #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
/// pub program_data: Account<'info, ProgramData>,
Expand Down
40 changes: 17 additions & 23 deletions lang/src/accounts/program.rs
Expand Up @@ -15,9 +15,9 @@ use std::ops::Deref;

/// Type validating that the account is the given Program
///
/// The type has a `programdata_address` property that will be set
/// The type has a `programdata_address` function that will return `Option::Some`
/// if the program is owned by the [`BPFUpgradeableLoader`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/index.html)
/// and will contain the `programdata_address` property of the `Program` variant of the [`UpgradeableLoaderState`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/enum.UpgradeableLoaderState.html) enum.
/// which will contain the `programdata_address` property of the `Program` variant of the [`UpgradeableLoaderState`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/enum.UpgradeableLoaderState.html) enum.
///
/// # Table of Contents
/// - [Basic Functionality](#basic-functionality)
Expand Down Expand Up @@ -47,7 +47,7 @@ use std::ops::Deref;
/// pub struct SetAdminSettings<'info> {
/// #[account(mut, seeds = [b"admin"], bump)]
/// pub admin_settings: Account<'info, AdminSettings>,
/// #[account(constraint = program.programdata_address() == Some(program_data.key()))]
/// #[account(constraint = program.programdata_address()? == Some(program_data.key()))]
/// pub program: Program<'info, MyProgram>,
/// #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
/// pub program_data: Account<'info, ProgramData>,
Expand All @@ -60,7 +60,7 @@ use std::ops::Deref;
///
/// - `program` is the account of the program itself.
/// Its constraint checks that `program_data` is the account that contains the program's upgrade authority.
/// Implicitly, this checks that `program` is a BPFUpgradeable program (`program.programdata_address()`
/// Implicitly, this checks that `program` is a BPFUpgradeable program (`program.programdata_address()?`
/// will be `None` if it's not).
/// - `program_data`'s constraint checks that its upgrade authority is the `authority` account.
/// - Finally, `authority` needs to sign the transaction.
Expand All @@ -77,24 +77,19 @@ use std::ops::Deref;
#[derive(Clone)]
pub struct Program<'info, T: Id + Clone> {
info: AccountInfo<'info>,
programdata_address: Option<Pubkey>,
_phantom: PhantomData<T>,
}

impl<'info, T: Id + Clone + fmt::Debug> fmt::Debug for Program<'info, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Program")
.field("info", &self.info)
.field("programdata_address", &self.programdata_address)
.finish()
f.debug_struct("Program").field("info", &self.info).finish()
}
}

impl<'a, T: Id + Clone> Program<'a, T> {
fn new(info: AccountInfo<'a>, programdata_address: Option<Pubkey>) -> Program<'a, T> {
fn new(info: AccountInfo<'a>) -> Program<'a, T> {
Self {
info,
programdata_address,
_phantom: PhantomData,
}
}
Expand All @@ -108,8 +103,13 @@ impl<'a, T: Id + 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()?;

Ok(Program::new(info.clone()))
}

pub fn programdata_address(&self) -> Result<Option<Pubkey>> {
if *self.info.owner == bpf_loader_upgradeable::ID {
let mut data: &[u8] = &self.info.try_borrow_data()?;
let upgradable_loader_state =
UpgradeableLoaderState::try_deserialize_unchecked(&mut data)?;

Expand All @@ -122,24 +122,18 @@ impl<'a, T: Id + Clone> Program<'a, T> {
slot: _,
upgrade_authority_address: _,
} => {
// Unreachable because check above already
// Unreachable because check in try_from
// ensures that program is executable
// and therefore a program account.
unreachable!()
}
UpgradeableLoaderState::Program {
programdata_address,
} => Some(programdata_address),
} => Ok(Some(programdata_address)),
}
} else {
None
};

Ok(Program::new(info.clone(), programdata_address))
}

pub fn programdata_address(&self) -> Option<Pubkey> {
self.programdata_address
Ok(None)
}
}
}

Expand Down
Expand Up @@ -72,7 +72,7 @@ pub struct SetAdminSettingsUseProgramState<'info> {
pub settings: Account<'info, Settings>,
#[account(mut)]
pub authority: Signer<'info>,
#[account(constraint = program.programdata_address() == Some(program_data.key()))]
#[account(constraint = program.programdata_address()? == Some(program_data.key()))]
pub program: Program<'info, crate::program::BpfUpgradeableState>,
#[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
pub program_data: Account<'info, ProgramData>,
Expand Down

0 comments on commit 778e328

Please sign in to comment.