lang: rest of accounts docs reference (#1231)
This commit is contained in:
parent
4d4cba5add
commit
3ddad6cbb6
|
@ -56,7 +56,7 @@ mod id;
|
||||||
/// To facilitate this, all fields in an account must be constrained to be
|
/// To facilitate this, all fields in an account must be constrained to be
|
||||||
/// "plain old data", i.e., they must implement
|
/// "plain old data", i.e., they must implement
|
||||||
/// [`Pod`](../bytemuck/trait.Pod.html). Please review the
|
/// [`Pod`](../bytemuck/trait.Pod.html). Please review the
|
||||||
/// [`safety`](file:///home/armaniferrante/Documents/code/src/github.com/project-serum/anchor/target/doc/bytemuck/trait.Pod.html#safety)
|
/// [`safety`](../bytemuck/trait.Pod.html#safety)
|
||||||
/// section before using.
|
/// section before using.
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn account(
|
pub fn account(
|
||||||
|
|
|
@ -13,6 +13,13 @@ use std::ops::{Deref, DerefMut};
|
||||||
/// Wrapper around [`AccountInfo`](crate::solana_program::account_info::AccountInfo)
|
/// Wrapper around [`AccountInfo`](crate::solana_program::account_info::AccountInfo)
|
||||||
/// that verifies program ownership and deserializes underlying data into a Rust type.
|
/// that verifies program ownership and deserializes underlying data into a Rust type.
|
||||||
///
|
///
|
||||||
|
/// # Table of Contents
|
||||||
|
/// - [Basic Functionality](#basic-functionality)
|
||||||
|
/// - [Using Account with non-anchor types](#using-account-with-non-anchor-types)
|
||||||
|
/// - [Out of the box wrapper types](#out-of-the-box-wrapper-types)
|
||||||
|
///
|
||||||
|
/// # Basic Functionality
|
||||||
|
///
|
||||||
/// Account checks that `Account.info.owner == T::owner()`.
|
/// Account checks that `Account.info.owner == T::owner()`.
|
||||||
/// This means that the data type that Accounts wraps around (`=T`) needs to
|
/// This means that the data type that Accounts wraps around (`=T`) needs to
|
||||||
/// implement the [Owner trait](crate::Owner).
|
/// implement the [Owner trait](crate::Owner).
|
||||||
|
@ -79,7 +86,7 @@ use std::ops::{Deref, DerefMut};
|
||||||
/// functions `#[account]` generates. See the example below for the code you have
|
/// functions `#[account]` generates. See the example below for the code you have
|
||||||
/// to write.
|
/// to write.
|
||||||
///
|
///
|
||||||
/// The mint wrapper type Anchor provides out of the box for the token program ([source](https://github.com/project-serum/anchor/blob/master/spl/src/token.rs))
|
/// The mint wrapper type that Anchor provides out of the box for the token program ([source](https://github.com/project-serum/anchor/blob/master/spl/src/token.rs))
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// #[derive(Clone)]
|
/// #[derive(Clone)]
|
||||||
/// pub struct Mint(spl_token::state::Mint);
|
/// pub struct Mint(spl_token::state::Mint);
|
||||||
|
@ -121,6 +128,96 @@ use std::ops::{Deref, DerefMut};
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Out of the box wrapper types
|
||||||
|
///
|
||||||
|
/// ### Accessing BPFUpgradeableLoader Data
|
||||||
|
///
|
||||||
|
/// Anchor provides wrapper types to access data stored in programs owned by the BPFUpgradeableLoader
|
||||||
|
/// such as the upgrade authority. If you're interested in the data of a program account, you can use
|
||||||
|
/// ```ignore
|
||||||
|
/// Account<'info, BpfUpgradeableLoaderState>
|
||||||
|
/// ```
|
||||||
|
/// and then match on its contents inside your instruction function.
|
||||||
|
///
|
||||||
|
/// Alternatively, you can use
|
||||||
|
/// ```ignore
|
||||||
|
/// Account<'info, ProgramData>
|
||||||
|
/// ```
|
||||||
|
/// to let anchor do the matching for you and return the ProgramData variant of BpfUpgradeableLoaderState.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// use anchor_lang::prelude::*;
|
||||||
|
/// use crate::program::MyProgram;
|
||||||
|
///
|
||||||
|
/// declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");
|
||||||
|
///
|
||||||
|
/// #[program]
|
||||||
|
/// pub mod my_program {
|
||||||
|
/// use super::*;
|
||||||
|
///
|
||||||
|
/// pub fn set_initial_admin(
|
||||||
|
/// ctx: Context<SetInitialAdmin>,
|
||||||
|
/// admin_key: Pubkey
|
||||||
|
/// ) -> ProgramResult {
|
||||||
|
/// ctx.accounts.admin_settings.admin_key = admin_key;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// pub fn set_admin(...){...}
|
||||||
|
///
|
||||||
|
/// pub fn set_settings(...){...}
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[account]
|
||||||
|
/// #[derive(Default, Debug)]
|
||||||
|
/// pub struct AdminSettings {
|
||||||
|
/// admin_key: Pubkey
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// pub struct SetInitialAdmin<'info> {
|
||||||
|
/// #[account(init, payer = authority, seeds = [b"admin"], bump)]
|
||||||
|
/// pub admin_settings: Account<'info, AdminSettings>,
|
||||||
|
/// #[account(mut)]
|
||||||
|
/// pub authority: Signer<'info>,
|
||||||
|
/// #[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>,
|
||||||
|
/// pub system_program: Program<'info, System>,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This example solves a problem you may face if your program has admin settings: How do you set the
|
||||||
|
/// admin key for restricted functionality after deployment? Setting the admin key itself should
|
||||||
|
/// be a restricted action but how do you restrict it without having set an admin key?
|
||||||
|
/// You're stuck in a loop.
|
||||||
|
/// One solution is to use the upgrade authority of the program as the initial
|
||||||
|
/// (or permanent) admin key.
|
||||||
|
///
|
||||||
|
/// ### SPL Types
|
||||||
|
///
|
||||||
|
/// Anchor provides wrapper types to access accounts owned by the token program. Use
|
||||||
|
/// ```ignore
|
||||||
|
/// use anchor_spl::token::TokenAccount;
|
||||||
|
///
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// pub struct Example {
|
||||||
|
/// pub my_acc: Account<'info, TokenAccount>
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// to access token accounts and
|
||||||
|
/// ```ignore
|
||||||
|
/// use anchor_spl::token::Mint;
|
||||||
|
///
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// pub struct Example {
|
||||||
|
/// pub my_acc: Account<'info, Mint>
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// to access mint accounts.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Account<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> {
|
pub struct Account<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> {
|
||||||
account: T,
|
account: T,
|
||||||
|
@ -186,6 +283,22 @@ impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> Account<'a, T
|
||||||
self.account
|
self.account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the inner account.
|
||||||
|
///
|
||||||
|
/// Instead of this:
|
||||||
|
/// ```ignore
|
||||||
|
/// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> ProgramResult {
|
||||||
|
/// (*ctx.accounts.user_to_create).name = new_user.name;
|
||||||
|
/// (*ctx.accounts.user_to_create).age = new_user.age;
|
||||||
|
/// (*ctx.accounts.user_to_create).address = new_user.address;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// You can do this:
|
||||||
|
/// ```ignore
|
||||||
|
/// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> ProgramResult {
|
||||||
|
/// ctx.accounts.user_to_create.set_inner(new_user);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn set_inner(&mut self, inner: T) {
|
pub fn set_inner(&mut self, inner: T) {
|
||||||
self.account = inner;
|
self.account = inner;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
//! AccountInfo can be used as a type but
|
||||||
|
//! [Unchecked Account](crate::accounts::unchecked_account::UncheckedAccount)
|
||||||
|
//! should be used instead.
|
||||||
|
|
||||||
use crate::error::ErrorCode;
|
use crate::error::ErrorCode;
|
||||||
use crate::{Accounts, AccountsExit, Key, ToAccountInfo, ToAccountInfos, ToAccountMetas};
|
use crate::{Accounts, AccountsExit, Key, ToAccountInfo, ToAccountInfos, ToAccountMetas};
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
//! Box<T> type to save stack space.
|
||||||
|
//!
|
||||||
|
//! Sometimes accounts are too large for the stack,
|
||||||
|
//! leading to stack violations.
|
||||||
|
//!
|
||||||
|
//! Boxing the account can help.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//! ```ignore
|
||||||
|
//! #[derive(Accounts)]
|
||||||
|
//! pub struct Example {
|
||||||
|
//! pub my_acc: Box<Account<'info, MyData>>
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
use crate::{Accounts, AccountsClose, AccountsExit, ToAccountInfos, ToAccountMetas};
|
use crate::{Accounts, AccountsClose, AccountsExit, ToAccountInfos, ToAccountMetas};
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
use solana_program::entrypoint::ProgramResult;
|
use solana_program::entrypoint::ProgramResult;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Type facilitating on demand zero copy deserialization.
|
||||||
|
|
||||||
use crate::error::ErrorCode;
|
use crate::error::ErrorCode;
|
||||||
use crate::{
|
use crate::{
|
||||||
Accounts, AccountsClose, AccountsExit, Key, Owner, ToAccountInfo, ToAccountInfos,
|
Accounts, AccountsClose, AccountsExit, Key, Owner, ToAccountInfo, ToAccountInfos,
|
||||||
|
@ -15,17 +17,81 @@ use std::io::Write;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
/// Account AccountLoader facilitating on demand zero copy deserialization.
|
/// Type facilitating on demand zero copy deserialization.
|
||||||
|
///
|
||||||
/// Note that using accounts in this way is distinctly different from using,
|
/// Note that using accounts in this way is distinctly different from using,
|
||||||
/// for example, the [`Account`](./struct.Account.html). Namely,
|
/// for example, the [`Account`](./struct.Account.html). Namely,
|
||||||
/// one must call `load`, `load_mut`, or `load_init`, before reading or writing
|
/// one must call
|
||||||
/// to the account. For more details on zero-copy-deserialization, see the
|
/// - `load_init` after initializing an account (this will ignore the missing
|
||||||
/// [`account`](./attr.account.html) attribute.
|
/// account discriminator that gets added only after the user's instruction code)
|
||||||
|
/// - `load` when the account is not mutable
|
||||||
|
/// - `load_mut` when the account is mutable
|
||||||
///
|
///
|
||||||
/// When using it's important to be mindful of any calls to `load` so as not to
|
/// For more details on zero-copy-deserialization, see the
|
||||||
/// induce a `RefCell` panic, especially when sharing accounts across CPI
|
/// [`account`](./attr.account.html) attribute.
|
||||||
/// boundaries. When in doubt, one should make sure all refs resulting from a
|
/// <p style=";padding:0.75em;border: 1px solid #ee6868">
|
||||||
/// call to `load` are dropped before CPI.
|
/// <strong>⚠️ </strong> When using this type it's important to be mindful
|
||||||
|
/// of any calls to the <code>load</code> functions so as not to
|
||||||
|
/// induce a <code>RefCell</code> panic, especially when sharing accounts across CPI
|
||||||
|
/// boundaries. When in doubt, one should make sure all refs resulting from
|
||||||
|
/// a call to a <code>load</code> function are dropped before CPI.
|
||||||
|
/// This can be done explicitly by calling <code>drop(my_var)</code> or implicitly
|
||||||
|
/// by wrapping the code using the <code>Ref</code> in braces <code>{..}</code> or
|
||||||
|
/// moving it into its own function.
|
||||||
|
/// </p>
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// use anchor_lang::prelude::*;
|
||||||
|
///
|
||||||
|
/// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||||
|
///
|
||||||
|
/// #[program]
|
||||||
|
/// pub mod bar {
|
||||||
|
/// use super::*;
|
||||||
|
///
|
||||||
|
/// pub fn create_bar(ctx: Context<CreateBar>, data: u64) -> ProgramResult {
|
||||||
|
/// let bar = &mut ctx.accounts.bar.load_init()?;
|
||||||
|
/// bar.authority = ctx.accounts.authority.key();
|
||||||
|
/// bar.data = data;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// pub fn update_bar(ctx: Context<UpdateBar>, data: u64) -> ProgramResult {
|
||||||
|
/// (*ctx.accounts.bar.load_mut()?).data = data;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[account(zero_copy)]
|
||||||
|
/// #[derive(Default)]
|
||||||
|
/// pub struct Bar {
|
||||||
|
/// authority: Pubkey,
|
||||||
|
/// data: u64
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// pub struct CreateBar<'info> {
|
||||||
|
/// #[account(
|
||||||
|
/// init,
|
||||||
|
/// payer = authority
|
||||||
|
/// )]
|
||||||
|
/// bar: AccountLoader<'info, Bar>,
|
||||||
|
/// #[account(mut)]
|
||||||
|
/// authority: Signer<'info>,
|
||||||
|
/// system_program: AccountInfo<'info>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// pub struct UpdateBar<'info> {
|
||||||
|
/// #[account(
|
||||||
|
/// mut,
|
||||||
|
/// has_one = authority,
|
||||||
|
/// )]
|
||||||
|
/// pub bar: AccountLoader<'info, Bar>,
|
||||||
|
/// pub authority: Signer<'info>,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AccountLoader<'info, T: ZeroCopy + Owner> {
|
pub struct AccountLoader<'info, T: ZeroCopy + Owner> {
|
||||||
acc_info: AccountInfo<'info>,
|
acc_info: AccountInfo<'info>,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Type validating that the account is the given Program
|
||||||
|
|
||||||
use crate::error::ErrorCode;
|
use crate::error::ErrorCode;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
|
@ -9,7 +11,52 @@ use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
/// Account container that checks ownership on deserialization.
|
/// Type validating that the account is the given Program
|
||||||
|
///
|
||||||
|
/// The type has a `programdata_address` property that will be set
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// Checks:
|
||||||
|
///
|
||||||
|
/// - `Account.info.key == Program`
|
||||||
|
/// - `Account.info.executable == true`
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
///
|
||||||
|
/// #[program]
|
||||||
|
/// mod my_program {
|
||||||
|
/// fn set_admin_settings(...){...}
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[account]
|
||||||
|
/// #[derive(Default)]
|
||||||
|
/// pub struct AdminSettings {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// 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()))]
|
||||||
|
/// pub program: Program<'info, MyProgram>,
|
||||||
|
/// #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
|
||||||
|
/// pub program_data: Account<'info, ProgramData>,
|
||||||
|
/// pub authority: Signer<'info>,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// The given program has a function with which the upgrade authority can set admin settings.
|
||||||
|
///
|
||||||
|
/// The required constraints are as follows:
|
||||||
|
///
|
||||||
|
/// - `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()`
|
||||||
|
/// 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.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Program<'info, T: Id + Clone> {
|
pub struct Program<'info, T: Id + Clone> {
|
||||||
info: AccountInfo<'info>,
|
info: AccountInfo<'info>,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//! Type validating that the account signed the transaction
|
||||||
use crate::error::ErrorCode;
|
use crate::error::ErrorCode;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
|
@ -10,6 +11,30 @@ use std::ops::Deref;
|
||||||
/// Type validating that the account signed the transaction. No other ownership
|
/// Type validating that the account signed the transaction. No other ownership
|
||||||
/// or type checks are done. If this is used, one should not try to access the
|
/// or type checks are done. If this is used, one should not try to access the
|
||||||
/// underlying account data.
|
/// underlying account data.
|
||||||
|
///
|
||||||
|
/// Checks:
|
||||||
|
///
|
||||||
|
/// - `Signer.info.is_signer == true`
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// #[account]
|
||||||
|
/// #[derive(Default)]
|
||||||
|
/// pub struct MyData {
|
||||||
|
/// pub data: u64
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// pub struct Example<'info> {
|
||||||
|
/// #[account(init, payer = payer)]
|
||||||
|
/// pub my_acc: Account<'info, MyData>,
|
||||||
|
/// #[account(mut)]
|
||||||
|
/// pub payer: Signer<'info>,
|
||||||
|
/// pub system_program: Program<'info, System>
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// When creating an account with `init`, the `payer` needs to sign the transaction.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Signer<'info> {
|
pub struct Signer<'info> {
|
||||||
info: AccountInfo<'info>,
|
info: AccountInfo<'info>,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Type validating that the account is owned by the system program
|
||||||
|
|
||||||
use crate::error::ErrorCode;
|
use crate::error::ErrorCode;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
|
@ -8,6 +10,11 @@ use solana_program::pubkey::Pubkey;
|
||||||
use solana_program::system_program;
|
use solana_program::system_program;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
/// Type validating that the account is owned by the system program
|
||||||
|
///
|
||||||
|
/// Checks:
|
||||||
|
///
|
||||||
|
/// - `SystemAccount.info.owner == SystemProgram`
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SystemAccount<'info> {
|
pub struct SystemAccount<'info> {
|
||||||
info: AccountInfo<'info>,
|
info: AccountInfo<'info>,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Type validating that the account is a sysvar and deserializing it
|
||||||
|
|
||||||
use crate::error::ErrorCode;
|
use crate::error::ErrorCode;
|
||||||
use crate::{Accounts, AccountsExit, Key, ToAccountInfo, ToAccountInfos, ToAccountMetas};
|
use crate::{Accounts, AccountsExit, Key, ToAccountInfo, ToAccountInfos, ToAccountMetas};
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
|
@ -8,7 +10,27 @@ use solana_program::pubkey::Pubkey;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
/// Container for sysvars.
|
/// Type validating that the account is a sysvar and deserializing it.
|
||||||
|
///
|
||||||
|
/// If possible, sysvars should not be used via accounts
|
||||||
|
/// but by using the [`get`](https://docs.rs/solana-program/latest/solana_program/sysvar/trait.Sysvar.html#method.get)
|
||||||
|
/// function on the desired sysvar. This is because using `get`
|
||||||
|
/// does not run the risk of Anchor having a bug in its `Sysvar` type
|
||||||
|
/// and using `get` also decreases tx size, making space for other
|
||||||
|
/// accounts that cannot be requested via syscall.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// // OK - via account in the account validation struct
|
||||||
|
/// #[derive(Accounts)]
|
||||||
|
/// pub struct Example<'info> {
|
||||||
|
/// pub clock: Sysvar<'info, Clock>
|
||||||
|
/// }
|
||||||
|
/// // BETTER - via syscall in the instruction function
|
||||||
|
/// fn better(ctx: Context<Better>) -> ProgramResult {
|
||||||
|
/// let clock = Clock::get()?;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub struct Sysvar<'info, T: solana_program::sysvar::Sysvar> {
|
pub struct Sysvar<'info, T: solana_program::sysvar::Sysvar> {
|
||||||
info: AccountInfo<'info>,
|
info: AccountInfo<'info>,
|
||||||
account: T,
|
account: T,
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
//! Explicit wrapper for AccountInfo types to emphasize
|
||||||
|
//! that no checks are performed
|
||||||
|
|
||||||
use crate::error::ErrorCode;
|
use crate::error::ErrorCode;
|
||||||
use crate::{Accounts, AccountsExit, Key, ToAccountInfo, ToAccountInfos, ToAccountMetas};
|
use crate::{Accounts, AccountsExit, Key, ToAccountInfo, ToAccountInfos, ToAccountMetas};
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
|
@ -7,7 +10,8 @@ use solana_program::program_error::ProgramError;
|
||||||
use solana_program::pubkey::Pubkey;
|
use solana_program::pubkey::Pubkey;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
/// Explicit wrapper for AccountInfo types.
|
/// Explicit wrapper for AccountInfo types to emphasize
|
||||||
|
/// that no checks are performed
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UncheckedAccount<'info>(AccountInfo<'info>);
|
pub struct UncheckedAccount<'info>(AccountInfo<'info>);
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,6 @@ use anchor_lang::prelude::*;
|
||||||
|
|
||||||
declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");
|
declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");
|
||||||
|
|
||||||
// TODO: Once anchor can deserialize data of programs (=programdata_address) automatically, add another test to this file.
|
|
||||||
// Instead of using UpgradeableLoaderState, it should use Program<'info, MY_PROGRAM>
|
|
||||||
|
|
||||||
#[program]
|
#[program]
|
||||||
pub mod bpf_upgradeable_state {
|
pub mod bpf_upgradeable_state {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -48,8 +45,10 @@ pub enum CustomError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(admin_data: u64)]
|
|
||||||
pub struct SetAdminSettings<'info> {
|
pub struct SetAdminSettings<'info> {
|
||||||
|
// In a real program, this should be a PDA,
|
||||||
|
// so the authority cannot create multiple settings accounts.
|
||||||
|
// Not done here for easier testing
|
||||||
#[account(init, payer = authority)]
|
#[account(init, payer = authority)]
|
||||||
pub settings: Account<'info, Settings>,
|
pub settings: Account<'info, Settings>,
|
||||||
#[account(mut)]
|
#[account(mut)]
|
||||||
|
@ -62,8 +61,10 @@ pub struct SetAdminSettings<'info> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(admin_data: u64)]
|
|
||||||
pub struct SetAdminSettingsUseProgramState<'info> {
|
pub struct SetAdminSettingsUseProgramState<'info> {
|
||||||
|
// In a real program, this should be a PDA,
|
||||||
|
// so the authority cannot create multiple settings accounts.
|
||||||
|
// Not done here for easier testing
|
||||||
#[account(init, payer = authority)]
|
#[account(init, payer = authority)]
|
||||||
pub settings: Account<'info, Settings>,
|
pub settings: Account<'info, Settings>,
|
||||||
#[account(mut)]
|
#[account(mut)]
|
||||||
|
|
Loading…
Reference in New Issue