Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache calculated bump seeds in context #1367

Merged
merged 16 commits into from
Jan 27, 2022
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ incremented for features.
### Features

* lang: Add `seeds::program` constraint for specifying which program_id to use when deriving PDAs.([#1197](https://github.com/project-serum/anchor/pull/1197))
* ts: Remove error logging in the event parser when log websocket encounters a program error. ([#1313](https://github.com/project-serum/anchor/pull/1313))
* lang: `Context` now has a new `bumps: BTree<String, u8>` argument, mapping account name to bump seed "found" by the accounts context. This allows one to access bump seeds without having to pass them in from the client or recalculate them in the handler ([#1367](calculated )).
* ts: Remove error logging in the event parser when log websocket encounters a program error ([#1313](https://github.com/project-serum/anchor/pull/1313)).
* ts: Add new `methods` namespace to the program client, introducing a more ergonomic builder API ([#1324](https://github.com/project-serum/anchor/pull/1324)).

### Breaking

* lang: rename `loader_account` module to `account_loader` module ([#1279](https://github.com/project-serum/anchor/pull/1279))
* lang: The `Accounts` trait's `try_accounts` method now has an additional `bumps: &mut BTreeMap<String, u8>` argument, which accumulates bump seeds ([#1367](https://github.com/project-serum/anchor/pull/1367)).
* ts: `Coder` is now an interface and the existing class has been renamed to `BorshCoder`. This change allows the generation of Anchor clients for non anchor programs ([#1259](https://github.com/project-serum/anchor/pull/1259/files)).

## [0.20.1] - 2022-01-09
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use solana_program::entrypoint::ProgramResult;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::fmt;
use std::ops::{Deref, DerefMut};

Expand Down Expand Up @@ -314,6 +315,7 @@ where
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/account_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;

impl<'info> Accounts<'info> for AccountInfo<'info> {
fn try_accounts(
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/account_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::cell::{Ref, RefMut};
use std::collections::BTreeMap;
use std::fmt;
use std::io::Write;
use std::marker::PhantomData;
Expand Down Expand Up @@ -211,6 +212,7 @@ impl<'info, T: ZeroCopy + Owner> Accounts<'info> for AccountLoader<'info, T> {
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
4 changes: 3 additions & 1 deletion lang/src/accounts/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ use solana_program::entrypoint::ProgramResult;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::ops::Deref;

impl<'info, T: Accounts<'info>> Accounts<'info> for Box<T> {
fn try_accounts(
program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
ix_data: &[u8],
bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
T::try_accounts(program_id, accounts, ix_data).map(Box::new)
T::try_accounts(program_id, accounts, ix_data, bumps).map(Box::new)
}
}

Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/cpi_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use solana_program::entrypoint::ProgramResult;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

/// Container for any account *not* owned by the current program.
Expand Down Expand Up @@ -53,6 +54,7 @@ where
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/cpi_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

/// Boxed container for the program state singleton, used when the state
Expand Down Expand Up @@ -70,6 +71,7 @@ where
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::cell::{Ref, RefMut};
use std::collections::BTreeMap;
use std::fmt;
use std::io::Write;
use std::marker::PhantomData;
Expand Down Expand Up @@ -150,6 +151,7 @@ impl<'info, T: ZeroCopy> Accounts<'info> for Loader<'info, T> {
program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use solana_program::bpf_loader_upgradeable::{self, UpgradeableLoaderState};
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
Expand Down Expand Up @@ -135,6 +136,7 @@ where
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/program_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use solana_program::entrypoint::ProgramResult;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

/// Boxed container for a deserialized `account`. Use this to reference any
Expand Down Expand Up @@ -83,6 +84,7 @@ where
program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::ops::Deref;

/// Type validating that the account signed the transaction. No other ownership
Expand Down Expand Up @@ -60,6 +61,7 @@ impl<'info> Accounts<'info> for Signer<'info> {
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use solana_program::entrypoint::ProgramResult;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

pub const PROGRAM_STATE_SEED: &str = "unversioned";
Expand Down Expand Up @@ -75,6 +76,7 @@ where
program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/system_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use solana_program::system_program;
use std::collections::BTreeMap;
use std::ops::Deref;

/// Type validating that the account is owned by the system program
Expand Down Expand Up @@ -39,6 +40,7 @@ impl<'info> Accounts<'info> for SystemAccount<'info> {
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/sysvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::fmt;
use std::ops::{Deref, DerefMut};

Expand Down Expand Up @@ -69,6 +70,7 @@ impl<'info, T: solana_program::sysvar::Sysvar> Accounts<'info> for Sysvar<'info,
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
2 changes: 2 additions & 0 deletions lang/src/accounts/unchecked_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::ops::Deref;

/// Explicit wrapper for AccountInfo types to emphasize
Expand All @@ -25,6 +26,7 @@ impl<'info> Accounts<'info> for UncheckedAccount<'info> {
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
Expand Down
8 changes: 8 additions & 0 deletions lang/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{Accounts, ToAccountInfos, ToAccountMetas};
use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::fmt;

/// Provides non-argument inputs to the program.
Expand All @@ -29,6 +30,10 @@ pub struct Context<'a, 'b, 'c, 'info, T> {
/// Remaining accounts given but not deserialized or validated.
/// Be very careful when using this directly.
pub remaining_accounts: &'c [AccountInfo<'info>],
/// Bump seeds found during constraint validation. This is provided as a
/// convenience so that handlers don't have to recalculate bump seeds or
/// pass them in as arguments.
pub bumps: BTreeMap<String, u8>,
}

impl<'a, 'b, 'c, 'info, T: fmt::Debug> fmt::Debug for Context<'a, 'b, 'c, 'info, T> {
Expand All @@ -37,6 +42,7 @@ impl<'a, 'b, 'c, 'info, T: fmt::Debug> fmt::Debug for Context<'a, 'b, 'c, 'info,
.field("program_id", &self.program_id)
.field("accounts", &self.accounts)
.field("remaining_accounts", &self.remaining_accounts)
.field("bumps", &self.bumps)
.finish()
}
}
Expand All @@ -46,11 +52,13 @@ impl<'a, 'b, 'c, 'info, T: Accounts<'info>> Context<'a, 'b, 'c, 'info, T> {
program_id: &'a Pubkey,
accounts: &'b mut T,
remaining_accounts: &'c [AccountInfo<'info>],
bumps: BTreeMap<String, u8>,
) -> Self {
Self {
program_id,
accounts,
remaining_accounts,
bumps,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use solana_program::entrypoint::ProgramResult;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;
use std::io::Write;

mod account_meta;
Expand Down Expand Up @@ -80,6 +81,7 @@ pub trait Accounts<'info>: ToAccountMetas + ToAccountInfos<'info> + Sized {
program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
ix_data: &[u8],
bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError>;
}

Expand Down
13 changes: 8 additions & 5 deletions lang/src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeMap;

impl<'info, T: ToAccountInfos<'info>> ToAccountInfos<'info> for Vec<T> {
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
Expand All @@ -25,9 +26,10 @@ impl<'info, T: Accounts<'info>> Accounts<'info> for Vec<T> {
program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
ix_data: &[u8],
bumps: &mut BTreeMap<String, u8>,
) -> Result<Self, ProgramError> {
let mut vec: Vec<T> = Vec::new();
T::try_accounts(program_id, accounts, ix_data).map(|item| vec.push(item))?;
T::try_accounts(program_id, accounts, ix_data, bumps).map(|item| vec.push(item))?;
Ok(vec)
}
}
Expand Down Expand Up @@ -76,9 +78,10 @@ mod tests {
false,
Epoch::default(),
);

let mut bumps = std::collections::BTreeMap::new();
let mut accounts = &[account1, account2][..];
let parsed_accounts = Vec::<Test>::try_accounts(&program_id, &mut accounts, &[]).unwrap();
let parsed_accounts =
Vec::<Test>::try_accounts(&program_id, &mut accounts, &[], &mut bumps).unwrap();

assert_eq!(accounts.len(), parsed_accounts.len());
}
Expand All @@ -87,8 +90,8 @@ mod tests {
#[should_panic]
fn test_accounts_trait_for_vec_empty() {
let program_id = Pubkey::default();

let mut bumps = std::collections::BTreeMap::new();
let mut accounts = &[][..];
Vec::<Test>::try_accounts(&program_id, &mut accounts, &[]).unwrap();
Vec::<Test>::try_accounts(&program_id, &mut accounts, &[], &mut bumps).unwrap();
}
}
Loading