From bb20eee8f63b6d553fe7e5f0e8d679e2669c96f2 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 6 Jan 2022 16:05:11 +0100 Subject: [PATCH] lang/docs: Context and CpiContext docs (#1247) --- .github/actions/setup/action.yaml | 2 +- lang/src/context.rs | 115 ++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml index c20d2a5e19..1ac983c81f 100644 --- a/.github/actions/setup/action.yaml +++ b/.github/actions/setup/action.yaml @@ -3,7 +3,7 @@ description: "Setup" runs: using: "composite" steps: - - run: sudo apt-get install -y pkg-config build-essential libudev-dev + - run: sudo apt-get update && sudo apt-get install -y pkg-config build-essential libudev-dev shell: bash - run: echo "ANCHOR_VERSION=$(cat ./VERSION)" >> $GITHUB_ENV shell: bash diff --git a/lang/src/context.rs b/lang/src/context.rs index 01fa9a508f..ccf24e4674 100644 --- a/lang/src/context.rs +++ b/lang/src/context.rs @@ -1,3 +1,5 @@ +//! Data structures that are used to provide non-argument inputs to program endpoints + use crate::{Accounts, ToAccountInfos, ToAccountMetas}; use solana_program::account_info::AccountInfo; use solana_program::instruction::AccountMeta; @@ -5,6 +7,20 @@ use solana_program::pubkey::Pubkey; use std::fmt; /// Provides non-argument inputs to the program. +/// +/// # Example +/// ```ignore +/// pub fn set_data(ctx: Context, age: u64, other_data: u32) -> ProgramResult { +/// // Set account data like this +/// (*ctx.accounts.my_account).age = age; +/// (*ctx.accounts.my_account).other_data = other_data; +/// // or like this +/// let my_account = &mut ctx.account.my_account; +/// my_account.age = age; +/// my_account.other_data = other_data; +/// Ok(()) +/// } +/// ``` pub struct Context<'a, 'b, 'c, 'info, T> { /// Currently executing program id. pub program_id: &'a Pubkey, @@ -40,6 +56,104 @@ impl<'a, 'b, 'c, 'info, T: Accounts<'info>> Context<'a, 'b, 'c, 'info, T> { } /// Context specifying non-argument inputs for cross-program-invocations. +/// +/// # Example with and without PDA signature +/// ```ignore +/// // Callee Program +/// +/// use anchor_lang::prelude::*; +/// +/// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); +/// +/// #[program] +/// pub mod callee { +/// use super::*; +/// pub fn init(ctx: Context) -> ProgramResult { +/// (*ctx.accounts.data).authority = ctx.accounts.authority.key(); +/// Ok(()) +/// } +/// +/// pub fn set_data(ctx: Context, data: u64) -> ProgramResult { +/// (*ctx.accounts.data_acc).data = data; +/// Ok(()) +/// } +/// } +/// +/// #[account] +/// #[derive(Default)] +/// pub struct Data { +/// data: u64, +/// authority: Pubkey, +/// } +/// +/// #[derive(Accounts)] +/// pub struct Init<'info> { +/// #[account(init, payer = payer)] +/// pub data: Account<'info, Data>, +/// pub payer: Signer<'info>, +/// pub authority: UncheckedAccount<'info>, +/// pub system_program: Program<'info, System> +/// } +/// +/// #[derive(Accounts)] +/// pub struct SetData<'info> { +/// #[account(mut, has_one = authority)] +/// pub data_acc: Account<'info, Data>, +/// pub authority: Signer<'info>, +/// } +/// +/// // Caller Program +/// +/// use anchor_lang::prelude::*; +/// use callee::{self, program::Callee}; +/// +/// declare_id!("Sxg7dBh5VLT8S1o6BqncZCPq9nhHHukjfVd6ohQJeAk"); +/// +/// #[program] +/// pub mod caller { +/// use super::*; +/// pub fn do_cpi(ctx: Context, data: u64) -> ProgramResult { +/// let callee_id = ctx.accounts.callee.to_account_info(); +/// let callee_accounts = callee::cpi::accounts::SetData { +/// data_acc: ctx.accounts.data_acc.to_account_info(), +/// authority: ctx.accounts.callee_authority.to_account_info(), +/// }; +/// let cpi_ctx = CpiContext::new(callee_id, callee_accounts); +/// callee::cpi::set_data(cpi_ctx, data) +/// } +/// +/// pub fn do_cpi_with_pda_authority(ctx: Context, bump: u8, data: u64) -> ProgramResult { +/// let seeds = &[&[b"example_seed", bytemuck::bytes_of(&bump)][..]]; +/// let callee_id = ctx.accounts.callee.to_account_info(); +/// let callee_accounts = callee::cpi::accounts::SetData { +/// data_acc: ctx.accounts.data_acc.to_account_info(), +/// authority: ctx.accounts.callee_authority.to_account_info(), +/// }; +/// let cpi_ctx = CpiContext::new_with_signer(callee_id, callee_accounts, seeds); +/// callee::cpi::set_data(cpi_ctx, data) +/// } +/// } +/// +/// // We can use "UncheckedAccount"s here because +/// // the callee program does the checks. +/// // We use "mut" so the autogenerated clients know +/// // that this account should be mutable. +/// #[derive(Accounts)] +/// pub struct DoCpi<'info> { +/// #[account(mut)] +/// pub data_acc: UncheckedAccount<'info>, +/// pub callee_authority: UncheckedAccount<'info>, +/// pub callee: Program<'info, Callee>, +/// } +/// +/// #[derive(Accounts)] +/// pub struct DoCpiWithPDAAuthority<'info> { +/// #[account(mut)] +/// pub data_acc: UncheckedAccount<'info>, +/// pub callee_authority: UncheckedAccount<'info>, +/// pub callee: Program<'info, Callee>, +/// } +/// ``` pub struct CpiContext<'a, 'b, 'c, 'info, T> where T: ToAccountMetas + ToAccountInfos<'info>, @@ -122,6 +236,7 @@ impl<'info, T: ToAccountInfos<'info> + ToAccountMetas> ToAccountMetas /// Context specifying non-argument inputs for cross-program-invocations /// targeted at program state instructions. +#[doc(hidden)] #[deprecated] pub struct CpiStateContext<'a, 'b, 'c, 'info, T: Accounts<'info>> { state: AccountInfo<'info>,