context.rs 9.9 KB

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