lang: deserialize programdata address on demand/lazily (#1723)
This commit is contained in:
parent
248ef79006
commit
778e328753
|
@ -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
|
||||
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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)
|
||||
|
@ -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>,
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>,
|
||||
|
|
Loading…
Reference in New Issue