lang: improved Account reference (#1207)
This commit is contained in:
parent
1749a7bd53
commit
a7eccb6e82
|
@ -5,12 +5,16 @@ use syn::parse_macro_input;
|
|||
|
||||
mod id;
|
||||
|
||||
/// A data structure representing a Solana account, implementing various traits:
|
||||
/// An attribute for a data structure representing a Solana account.
|
||||
///
|
||||
/// `#[account]` generates trait implementations for the following traits:
|
||||
///
|
||||
/// - [`AccountSerialize`](./trait.AccountSerialize.html)
|
||||
/// - [`AccountDeserialize`](./trait.AccountDeserialize.html)
|
||||
/// - [`AnchorSerialize`](./trait.AnchorSerialize.html)
|
||||
/// - [`AnchorDeserialize`](./trait.AnchorDeserialize.html)
|
||||
/// - [`Owner`](./trait.Owner.html)
|
||||
/// - [`Discriminator`](./trait.Discriminator.html)
|
||||
///
|
||||
/// When implementing account serialization traits the first 8 bytes are
|
||||
/// reserved for a unique account discriminator, self described by the first 8
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Account container that checks ownership on deserialization.
|
||||
|
||||
use crate::error::ErrorCode;
|
||||
use crate::*;
|
||||
use solana_program::account_info::AccountInfo;
|
||||
|
@ -8,7 +10,115 @@ use solana_program::pubkey::Pubkey;
|
|||
use std::fmt;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// Account container that checks ownership on deserialization.
|
||||
/// Wrapper around [`AccountInfo`](crate::solana_program::account_info::AccountInfo)
|
||||
/// that verifies program ownership and deserializes underlying data into a Rust type.
|
||||
///
|
||||
/// Account checks that `Account.info.owner == T::owner()`.
|
||||
/// This means that the data type that Accounts wraps around (`=T`) needs to
|
||||
/// implement the [Owner trait](crate::Owner).
|
||||
/// The `#[account]` attribute implements the Owner trait for
|
||||
/// a struct using the `crate::ID` declared by [`declareId`](crate::declare_id)
|
||||
/// in the same program. It follows that Account can also be used
|
||||
/// with a `T` that comes from a different program.
|
||||
///
|
||||
/// Checks:
|
||||
///
|
||||
/// - `Account.info.owner == T::owner()`
|
||||
/// - `!(Account.info.owner == SystemProgram && Account.info.lamports() == 0)`
|
||||
///
|
||||
/// Example
|
||||
/// ```ignore
|
||||
/// use anchor_lang::prelude::*;
|
||||
/// use other_program::Auth;
|
||||
///
|
||||
/// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
///
|
||||
/// #[program]
|
||||
/// mod hello_anchor {
|
||||
/// use super::*;
|
||||
/// pub fn set_data(ctx: Context<SetData>, data: u64) -> ProgramResult {
|
||||
/// if (*ctx.accounts.auth_account).authorized {
|
||||
/// (*ctx.accounts.my_account).data = data;
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[account]
|
||||
/// #[derive(Default)]
|
||||
/// pub struct MyData {
|
||||
/// pub data: u64
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Accounts)]
|
||||
/// pub struct SetData<'info> {
|
||||
/// #[account(mut)]
|
||||
/// pub my_account: Account<'info, MyData> // checks that my_account.info.owner == Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
|
||||
/// pub auth_account: Account<'info, Auth> // checks that auth_account.info.owner == FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9
|
||||
/// }
|
||||
///
|
||||
/// // In a different program
|
||||
///
|
||||
/// ...
|
||||
/// declare_id!("FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9");
|
||||
/// #[account]
|
||||
/// #[derive(Default)]
|
||||
/// pub struct Auth {
|
||||
/// pub authorized: bool
|
||||
/// }
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Account can also be used with non-anchor programs. The data types from
|
||||
/// those programs are not annotated with `#[account]` so you have to
|
||||
/// - create a wrapper type around the structs you want to wrap with Account
|
||||
/// - implement the functions required by Account yourself
|
||||
/// instead of using `#[account]`. You only have to implement a fraction of the
|
||||
/// functions `#[account]` generates. See the example below for the code you have
|
||||
/// 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))
|
||||
/// ```ignore
|
||||
/// #[derive(Clone)]
|
||||
/// pub struct Mint(spl_token::state::Mint);
|
||||
///
|
||||
/// // This is necessary so we can use "anchor_spl::token::Mint::LEN"
|
||||
/// // because rust does not resolve "anchor_spl::token::Mint::LEN" to
|
||||
/// // "spl_token::state::Mint::LEN" automatically
|
||||
/// impl Mint {
|
||||
/// pub const LEN: usize = spl_token::state::Mint::LEN;
|
||||
/// }
|
||||
///
|
||||
/// // You don't have to implement the "try_deserialize" function
|
||||
/// // from this trait. It delegates to
|
||||
/// // "try_deserialize_unchecked" by default which is what we want here
|
||||
/// // because non-anchor accounts don't have a discriminator to check
|
||||
/// impl anchor_lang::AccountDeserialize for Mint {
|
||||
/// fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError> {
|
||||
/// spl_token::state::Mint::unpack(buf).map(Mint)
|
||||
/// }
|
||||
/// }
|
||||
/// // AccountSerialize defaults to a no-op which is what we want here
|
||||
/// // because it's a foreign program, so our program does not
|
||||
/// // have permission to write to the foreign program's accounts anyway
|
||||
/// impl anchor_lang::AccountSerialize for Mint {}
|
||||
///
|
||||
/// impl anchor_lang::Owner for Mint {
|
||||
/// fn owner() -> Pubkey {
|
||||
/// // pub use spl_token::ID is used at the top of the file
|
||||
/// ID
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Implement the "std::ops::Deref" trait for better user experience
|
||||
/// impl Deref for Mint {
|
||||
/// type Target = spl_token::state::Mint;
|
||||
///
|
||||
/// fn deref(&self) -> &Self::Target {
|
||||
/// &self.0
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct Account<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> {
|
||||
account: T,
|
||||
|
|
Loading…
Reference in New Issue