context.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. //! Data structures that are used to provide non-argument inputs to program endpoints
  2. use crate::{Accounts, Bumps, ToAccountInfos, ToAccountMetas};
  3. use solana_program::account_info::AccountInfo;
  4. use solana_program::instruction::AccountMeta;
  5. use solana_program::pubkey::Pubkey;
  6. use std::fmt;
  7. /// Provides non-argument inputs to the program.
  8. ///
  9. /// # Example
  10. /// ```ignore
  11. /// pub fn set_data(ctx: Context<SetData>, age: u64, other_data: u32) -> Result<()> {
  12. /// // Set account data like this
  13. /// (*ctx.accounts.my_account).age = age;
  14. /// (*ctx.accounts.my_account).other_data = other_data;
  15. /// // or like this
  16. /// let my_account = &mut ctx.account.my_account;
  17. /// my_account.age = age;
  18. /// my_account.other_data = other_data;
  19. /// Ok(())
  20. /// }
  21. /// ```
  22. pub struct Context<'a, 'b, 'c, 'info, T: Bumps> {
  23. /// Currently executing program id.
  24. pub program_id: &'a Pubkey,
  25. /// Deserialized accounts.
  26. pub accounts: &'b mut T,
  27. /// Remaining accounts given but not deserialized or validated.
  28. /// Be very careful when using this directly.
  29. pub remaining_accounts: &'c [AccountInfo<'info>],
  30. /// Bump seeds found during constraint validation. This is provided as a
  31. /// convenience so that handlers don't have to recalculate bump seeds or
  32. /// pass them in as arguments.
  33. /// Type is the bumps struct generated by #[derive(Accounts)]
  34. pub bumps: T::Bumps,
  35. }
  36. impl<'a, 'b, 'c, 'info, T> fmt::Debug for Context<'a, 'b, 'c, 'info, T>
  37. where
  38. T: fmt::Debug + Bumps,
  39. {
  40. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  41. f.debug_struct("Context")
  42. .field("program_id", &self.program_id)
  43. .field("accounts", &self.accounts)
  44. .field("remaining_accounts", &self.remaining_accounts)
  45. .field("bumps", &self.bumps)
  46. .finish()
  47. }
  48. }
  49. impl<'a, 'b, 'c, 'info, T> Context<'a, 'b, 'c, 'info, T>
  50. where
  51. T: Bumps + Accounts<'info, T::Bumps>,
  52. {
  53. pub fn new(
  54. program_id: &'a Pubkey,
  55. accounts: &'b mut T,
  56. remaining_accounts: &'c [AccountInfo<'info>],
  57. bumps: T::Bumps,
  58. ) -> Self {
  59. Self {
  60. program_id,
  61. accounts,
  62. remaining_accounts,
  63. bumps,
  64. }
  65. }
  66. }
  67. /// Context specifying non-argument inputs for cross-program-invocations.
  68. ///
  69. /// # Example with and without PDA signature
  70. /// ```ignore
  71. /// // Callee Program
  72. ///
  73. /// use anchor_lang::prelude::*;
  74. ///
  75. /// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
  76. ///
  77. /// #[program]
  78. /// pub mod callee {
  79. /// use super::*;
  80. /// pub fn init(ctx: Context<Init>) -> Result<()> {
  81. /// (*ctx.accounts.data).authority = ctx.accounts.authority.key();
  82. /// Ok(())
  83. /// }
  84. ///
  85. /// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
  86. /// (*ctx.accounts.data_acc).data = data;
  87. /// Ok(())
  88. /// }
  89. /// }
  90. ///
  91. /// #[account]
  92. /// #[derive(Default)]
  93. /// pub struct Data {
  94. /// data: u64,
  95. /// authority: Pubkey,
  96. /// }
  97. ///
  98. /// #[derive(Accounts)]
  99. /// pub struct Init<'info> {
  100. /// #[account(init, payer = payer)]
  101. /// pub data: Account<'info, Data>,
  102. /// pub payer: Signer<'info>,
  103. /// pub authority: UncheckedAccount<'info>,
  104. /// pub system_program: Program<'info, System>
  105. /// }
  106. ///
  107. /// #[derive(Accounts)]
  108. /// pub struct SetData<'info> {
  109. /// #[account(mut, has_one = authority)]
  110. /// pub data_acc: Account<'info, Data>,
  111. /// pub authority: Signer<'info>,
  112. /// }
  113. ///
  114. /// // Caller Program
  115. ///
  116. /// use anchor_lang::prelude::*;
  117. /// use callee::{self, program::Callee};
  118. ///
  119. /// declare_id!("Sxg7dBh5VLT8S1o6BqncZCPq9nhHHukjfVd6ohQJeAk");
  120. ///
  121. /// #[program]
  122. /// pub mod caller {
  123. /// use super::*;
  124. /// pub fn do_cpi(ctx: Context<DoCpi>, data: u64) -> Result<()> {
  125. /// let callee_id = ctx.accounts.callee.to_account_info();
  126. /// let callee_accounts = callee::cpi::accounts::SetData {
  127. /// data_acc: ctx.accounts.data_acc.to_account_info(),
  128. /// authority: ctx.accounts.callee_authority.to_account_info(),
  129. /// };
  130. /// let cpi_ctx = CpiContext::new(callee_id, callee_accounts);
  131. /// callee::cpi::set_data(cpi_ctx, data)
  132. /// }
  133. ///
  134. /// pub fn do_cpi_with_pda_authority(ctx: Context<DoCpiWithPDAAuthority>, bump: u8, data: u64) -> Result<()> {
  135. /// let seeds = &[&[b"example_seed", bytemuck::bytes_of(&bump)][..]];
  136. /// let callee_id = ctx.accounts.callee.to_account_info();
  137. /// let callee_accounts = callee::cpi::accounts::SetData {
  138. /// data_acc: ctx.accounts.data_acc.to_account_info(),
  139. /// authority: ctx.accounts.callee_authority.to_account_info(),
  140. /// };
  141. /// let cpi_ctx = CpiContext::new_with_signer(callee_id, callee_accounts, seeds);
  142. /// callee::cpi::set_data(cpi_ctx, data)
  143. /// }
  144. /// }
  145. ///
  146. /// // We can use "UncheckedAccount"s here because
  147. /// // the callee program does the checks.
  148. /// // We use "mut" so the autogenerated clients know
  149. /// // that this account should be mutable.
  150. /// #[derive(Accounts)]
  151. /// pub struct DoCpi<'info> {
  152. /// #[account(mut)]
  153. /// pub data_acc: UncheckedAccount<'info>,
  154. /// pub callee_authority: UncheckedAccount<'info>,
  155. /// pub callee: Program<'info, Callee>,
  156. /// }
  157. ///
  158. /// #[derive(Accounts)]
  159. /// pub struct DoCpiWithPDAAuthority<'info> {
  160. /// #[account(mut)]
  161. /// pub data_acc: UncheckedAccount<'info>,
  162. /// pub callee_authority: UncheckedAccount<'info>,
  163. /// pub callee: Program<'info, Callee>,
  164. /// }
  165. /// ```
  166. pub struct CpiContext<'a, 'b, 'c, 'info, T>
  167. where
  168. T: ToAccountMetas + ToAccountInfos<'info>,
  169. {
  170. pub accounts: T,
  171. pub remaining_accounts: Vec<AccountInfo<'info>>,
  172. pub program: AccountInfo<'info>,
  173. pub signer_seeds: &'a [&'b [&'c [u8]]],
  174. }
  175. impl<'a, 'b, 'c, 'info, T> CpiContext<'a, 'b, 'c, 'info, T>
  176. where
  177. T: ToAccountMetas + ToAccountInfos<'info>,
  178. {
  179. pub fn new(program: AccountInfo<'info>, accounts: T) -> Self {
  180. Self {
  181. accounts,
  182. program,
  183. remaining_accounts: Vec::new(),
  184. signer_seeds: &[],
  185. }
  186. }
  187. #[must_use]
  188. pub fn new_with_signer(
  189. program: AccountInfo<'info>,
  190. accounts: T,
  191. signer_seeds: &'a [&'b [&'c [u8]]],
  192. ) -> Self {
  193. Self {
  194. accounts,
  195. program,
  196. signer_seeds,
  197. remaining_accounts: Vec::new(),
  198. }
  199. }
  200. #[must_use]
  201. pub fn with_signer(mut self, signer_seeds: &'a [&'b [&'c [u8]]]) -> Self {
  202. self.signer_seeds = signer_seeds;
  203. self
  204. }
  205. #[must_use]
  206. pub fn with_remaining_accounts(mut self, ra: Vec<AccountInfo<'info>>) -> Self {
  207. self.remaining_accounts = ra;
  208. self
  209. }
  210. }
  211. impl<'info, T: ToAccountInfos<'info> + ToAccountMetas> ToAccountInfos<'info>
  212. for CpiContext<'_, '_, '_, 'info, T>
  213. {
  214. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  215. let mut infos = self.accounts.to_account_infos();
  216. infos.extend_from_slice(&self.remaining_accounts);
  217. infos.push(self.program.clone());
  218. infos
  219. }
  220. }
  221. impl<'info, T: ToAccountInfos<'info> + ToAccountMetas> ToAccountMetas
  222. for CpiContext<'_, '_, '_, 'info, T>
  223. {
  224. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  225. let mut metas = self.accounts.to_account_metas(is_signer);
  226. metas.append(
  227. &mut self
  228. .remaining_accounts
  229. .iter()
  230. .map(|acc| match acc.is_writable {
  231. false => AccountMeta::new_readonly(*acc.key, acc.is_signer),
  232. true => AccountMeta::new(*acc.key, acc.is_signer),
  233. })
  234. .collect(),
  235. );
  236. metas
  237. }
  238. }