account.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. //! Account container that checks ownership on deserialization.
  2. use crate::bpf_writer::BpfWriter;
  3. use crate::error::{Error, ErrorCode};
  4. use crate::{
  5. AccountDeserialize, AccountSerialize, Accounts, AccountsClose, AccountsExit, Key, Owner,
  6. Result, ToAccountInfo, ToAccountInfos, ToAccountMetas,
  7. };
  8. use solana_program::account_info::AccountInfo;
  9. use solana_program::instruction::AccountMeta;
  10. use solana_program::pubkey::Pubkey;
  11. use solana_program::system_program;
  12. use std::collections::{BTreeMap, BTreeSet};
  13. use std::fmt;
  14. use std::ops::{Deref, DerefMut};
  15. /// Wrapper around [`AccountInfo`](crate::solana_program::account_info::AccountInfo)
  16. /// that verifies program ownership and deserializes underlying data into a Rust type.
  17. ///
  18. /// # Table of Contents
  19. /// - [Basic Functionality](#basic-functionality)
  20. /// - [Using Account with non-anchor types](#using-account-with-non-anchor-types)
  21. /// - [Out of the box wrapper types](#out-of-the-box-wrapper-types)
  22. ///
  23. /// # Basic Functionality
  24. ///
  25. /// Account checks that `Account.info.owner == T::owner()`.
  26. /// This means that the data type that Accounts wraps around (`=T`) needs to
  27. /// implement the [Owner trait](crate::Owner).
  28. /// The `#[account]` attribute implements the Owner trait for
  29. /// a struct using the `crate::ID` declared by [`declareId`](crate::declare_id)
  30. /// in the same program. It follows that Account can also be used
  31. /// with a `T` that comes from a different program.
  32. ///
  33. /// Checks:
  34. ///
  35. /// - `Account.info.owner == T::owner()`
  36. /// - `!(Account.info.owner == SystemProgram && Account.info.lamports() == 0)`
  37. ///
  38. /// # Example
  39. /// ```ignore
  40. /// use anchor_lang::prelude::*;
  41. /// use other_program::Auth;
  42. ///
  43. /// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
  44. ///
  45. /// #[program]
  46. /// mod hello_anchor {
  47. /// use super::*;
  48. /// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
  49. /// if (*ctx.accounts.auth_account).authorized {
  50. /// (*ctx.accounts.my_account).data = data;
  51. /// }
  52. /// Ok(())
  53. /// }
  54. /// }
  55. ///
  56. /// #[account]
  57. /// #[derive(Default)]
  58. /// pub struct MyData {
  59. /// pub data: u64
  60. /// }
  61. ///
  62. /// #[derive(Accounts)]
  63. /// pub struct SetData<'info> {
  64. /// #[account(mut)]
  65. /// pub my_account: Account<'info, MyData> // checks that my_account.info.owner == Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
  66. /// pub auth_account: Account<'info, Auth> // checks that auth_account.info.owner == FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9
  67. /// }
  68. ///
  69. /// // In a different program
  70. ///
  71. /// ...
  72. /// declare_id!("FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9");
  73. /// #[account]
  74. /// #[derive(Default)]
  75. /// pub struct Auth {
  76. /// pub authorized: bool
  77. /// }
  78. /// ...
  79. /// ```
  80. ///
  81. /// # Using Account with non-anchor programs
  82. ///
  83. /// Account can also be used with non-anchor programs. The data types from
  84. /// those programs are not annotated with `#[account]` so you have to
  85. /// - create a wrapper type around the structs you want to wrap with Account
  86. /// - implement the functions required by Account yourself
  87. /// instead of using `#[account]`. You only have to implement a fraction of the
  88. /// functions `#[account]` generates. See the example below for the code you have
  89. /// to write.
  90. ///
  91. /// The mint wrapper type that Anchor provides out of the box for the token program ([source](https://github.com/coral-xyz/anchor/blob/master/spl/src/token.rs))
  92. /// ```ignore
  93. /// #[derive(Clone)]
  94. /// pub struct Mint(spl_token::state::Mint);
  95. ///
  96. /// // This is necessary so we can use "anchor_spl::token::Mint::LEN"
  97. /// // because rust does not resolve "anchor_spl::token::Mint::LEN" to
  98. /// // "spl_token::state::Mint::LEN" automatically
  99. /// impl Mint {
  100. /// pub const LEN: usize = spl_token::state::Mint::LEN;
  101. /// }
  102. ///
  103. /// // You don't have to implement the "try_deserialize" function
  104. /// // from this trait. It delegates to
  105. /// // "try_deserialize_unchecked" by default which is what we want here
  106. /// // because non-anchor accounts don't have a discriminator to check
  107. /// impl anchor_lang::AccountDeserialize for Mint {
  108. /// fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self> {
  109. /// spl_token::state::Mint::unpack(buf).map(Mint)
  110. /// }
  111. /// }
  112. /// // AccountSerialize defaults to a no-op which is what we want here
  113. /// // because it's a foreign program, so our program does not
  114. /// // have permission to write to the foreign program's accounts anyway
  115. /// impl anchor_lang::AccountSerialize for Mint {}
  116. ///
  117. /// impl anchor_lang::Owner for Mint {
  118. /// fn owner() -> Pubkey {
  119. /// // pub use spl_token::ID is used at the top of the file
  120. /// ID
  121. /// }
  122. /// }
  123. ///
  124. /// // Implement the "std::ops::Deref" trait for better user experience
  125. /// impl Deref for Mint {
  126. /// type Target = spl_token::state::Mint;
  127. ///
  128. /// fn deref(&self) -> &Self::Target {
  129. /// &self.0
  130. /// }
  131. /// }
  132. /// ```
  133. ///
  134. /// ## Out of the box wrapper types
  135. ///
  136. /// ### Accessing BPFUpgradeableLoader Data
  137. ///
  138. /// Anchor provides wrapper types to access data stored in programs owned by the BPFUpgradeableLoader
  139. /// such as the upgrade authority. If you're interested in the data of a program account, you can use
  140. /// ```ignore
  141. /// Account<'info, BpfUpgradeableLoaderState>
  142. /// ```
  143. /// and then match on its contents inside your instruction function.
  144. ///
  145. /// Alternatively, you can use
  146. /// ```ignore
  147. /// Account<'info, ProgramData>
  148. /// ```
  149. /// to let anchor do the matching for you and return the ProgramData variant of BpfUpgradeableLoaderState.
  150. ///
  151. /// # Example
  152. /// ```ignore
  153. /// use anchor_lang::prelude::*;
  154. /// use crate::program::MyProgram;
  155. ///
  156. /// declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");
  157. ///
  158. /// #[program]
  159. /// pub mod my_program {
  160. /// use super::*;
  161. ///
  162. /// pub fn set_initial_admin(
  163. /// ctx: Context<SetInitialAdmin>,
  164. /// admin_key: Pubkey
  165. /// ) -> Result<()> {
  166. /// ctx.accounts.admin_settings.admin_key = admin_key;
  167. /// Ok(())
  168. /// }
  169. ///
  170. /// pub fn set_admin(...){...}
  171. ///
  172. /// pub fn set_settings(...){...}
  173. /// }
  174. ///
  175. /// #[account]
  176. /// #[derive(Default, Debug)]
  177. /// pub struct AdminSettings {
  178. /// admin_key: Pubkey
  179. /// }
  180. ///
  181. /// #[derive(Accounts)]
  182. /// pub struct SetInitialAdmin<'info> {
  183. /// #[account(init, payer = authority, seeds = [b"admin"], bump)]
  184. /// pub admin_settings: Account<'info, AdminSettings>,
  185. /// #[account(mut)]
  186. /// pub authority: Signer<'info>,
  187. /// #[account(constraint = program.programdata_address()? == Some(program_data.key()))]
  188. /// pub program: Program<'info, MyProgram>,
  189. /// #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
  190. /// pub program_data: Account<'info, ProgramData>,
  191. /// pub system_program: Program<'info, System>,
  192. /// }
  193. /// ```
  194. ///
  195. /// This example solves a problem you may face if your program has admin settings: How do you set the
  196. /// admin key for restricted functionality after deployment? Setting the admin key itself should
  197. /// be a restricted action but how do you restrict it without having set an admin key?
  198. /// You're stuck in a loop.
  199. /// One solution is to use the upgrade authority of the program as the initial
  200. /// (or permanent) admin key.
  201. ///
  202. /// ### SPL Types
  203. ///
  204. /// Anchor provides wrapper types to access accounts owned by the token program. Use
  205. /// ```ignore
  206. /// use anchor_spl::token::TokenAccount;
  207. ///
  208. /// #[derive(Accounts)]
  209. /// pub struct Example {
  210. /// pub my_acc: Account<'info, TokenAccount>
  211. /// }
  212. /// ```
  213. /// to access token accounts and
  214. /// ```ignore
  215. /// use anchor_spl::token::Mint;
  216. ///
  217. /// #[derive(Accounts)]
  218. /// pub struct Example {
  219. /// pub my_acc: Account<'info, Mint>
  220. /// }
  221. /// ```
  222. /// to access mint accounts.
  223. #[derive(Clone)]
  224. pub struct Account<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> {
  225. account: T,
  226. info: AccountInfo<'info>,
  227. }
  228. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone + fmt::Debug> fmt::Debug
  229. for Account<'info, T>
  230. {
  231. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  232. f.debug_struct("Account")
  233. .field("account", &self.account)
  234. .field("info", &self.info)
  235. .finish()
  236. }
  237. }
  238. impl<'a, T: AccountSerialize + AccountDeserialize + crate::Owner + Clone> Account<'a, T> {
  239. fn new(info: AccountInfo<'a>, account: T) -> Account<'a, T> {
  240. Self { info, account }
  241. }
  242. /// Deserializes the given `info` into a `Account`.
  243. #[inline(never)]
  244. pub fn try_from(info: &AccountInfo<'a>) -> Result<Account<'a, T>> {
  245. if info.owner == &system_program::ID && info.lamports() == 0 {
  246. return Err(ErrorCode::AccountNotInitialized.into());
  247. }
  248. if info.owner != &T::owner() {
  249. return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram)
  250. .with_pubkeys((*info.owner, T::owner())));
  251. }
  252. let mut data: &[u8] = &info.try_borrow_data()?;
  253. Ok(Account::new(info.clone(), T::try_deserialize(&mut data)?))
  254. }
  255. /// Deserializes the given `info` into a `Account` without checking
  256. /// the account discriminator. Be careful when using this and avoid it if
  257. /// possible.
  258. #[inline(never)]
  259. pub fn try_from_unchecked(info: &AccountInfo<'a>) -> Result<Account<'a, T>> {
  260. if info.owner == &system_program::ID && info.lamports() == 0 {
  261. return Err(ErrorCode::AccountNotInitialized.into());
  262. }
  263. if info.owner != &T::owner() {
  264. return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram)
  265. .with_pubkeys((*info.owner, T::owner())));
  266. }
  267. let mut data: &[u8] = &info.try_borrow_data()?;
  268. Ok(Account::new(
  269. info.clone(),
  270. T::try_deserialize_unchecked(&mut data)?,
  271. ))
  272. }
  273. /// Reloads the account from storage. This is useful, for example, when
  274. /// observing side effects after CPI.
  275. pub fn reload(&mut self) -> Result<()> {
  276. let mut data: &[u8] = &self.info.try_borrow_data()?;
  277. self.account = T::try_deserialize(&mut data)?;
  278. Ok(())
  279. }
  280. pub fn into_inner(self) -> T {
  281. self.account
  282. }
  283. /// Sets the inner account.
  284. ///
  285. /// Instead of this:
  286. /// ```ignore
  287. /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
  288. /// (*ctx.accounts.user_to_create).name = new_user.name;
  289. /// (*ctx.accounts.user_to_create).age = new_user.age;
  290. /// (*ctx.accounts.user_to_create).address = new_user.address;
  291. /// }
  292. /// ```
  293. /// You can do this:
  294. /// ```ignore
  295. /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
  296. /// ctx.accounts.user_to_create.set_inner(new_user);
  297. /// }
  298. /// ```
  299. pub fn set_inner(&mut self, inner: T) {
  300. self.account = inner;
  301. }
  302. }
  303. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> Accounts<'info>
  304. for Account<'info, T>
  305. where
  306. T: AccountSerialize + AccountDeserialize + Owner + Clone,
  307. {
  308. #[inline(never)]
  309. fn try_accounts(
  310. _program_id: &Pubkey,
  311. accounts: &mut &[AccountInfo<'info>],
  312. _ix_data: &[u8],
  313. _bumps: &mut BTreeMap<String, u8>,
  314. _reallocs: &mut BTreeSet<Pubkey>,
  315. ) -> Result<Self> {
  316. if accounts.is_empty() {
  317. return Err(ErrorCode::AccountNotEnoughKeys.into());
  318. }
  319. let account = &accounts[0];
  320. *accounts = &accounts[1..];
  321. Account::try_from(account)
  322. }
  323. }
  324. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AccountsExit<'info>
  325. for Account<'info, T>
  326. {
  327. fn exit(&self, program_id: &Pubkey) -> Result<()> {
  328. // Only persist if the owner is the current program.
  329. if &T::owner() == program_id {
  330. let info = self.to_account_info();
  331. let mut data = info.try_borrow_mut_data()?;
  332. let dst: &mut [u8] = &mut data;
  333. let mut writer = BpfWriter::new(dst);
  334. self.account.try_serialize(&mut writer)?;
  335. }
  336. Ok(())
  337. }
  338. }
  339. /// This function is for INTERNAL USE ONLY.
  340. /// Do NOT use this function in a program.
  341. /// Manual closing of `Account<'info, T>` types is NOT supported.
  342. ///
  343. /// Details: Using `close` with `Account<'info, T>` is not safe because
  344. /// it requires the `mut` constraint but for that type the constraint
  345. /// overwrites the "closed account" discriminator at the end of the instruction.
  346. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AccountsClose<'info>
  347. for Account<'info, T>
  348. {
  349. fn close(&self, sol_destination: AccountInfo<'info>) -> Result<()> {
  350. crate::common::close(self.to_account_info(), sol_destination)
  351. }
  352. }
  353. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> ToAccountMetas
  354. for Account<'info, T>
  355. {
  356. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  357. let is_signer = is_signer.unwrap_or(self.info.is_signer);
  358. let meta = match self.info.is_writable {
  359. false => AccountMeta::new_readonly(*self.info.key, is_signer),
  360. true => AccountMeta::new(*self.info.key, is_signer),
  361. };
  362. vec![meta]
  363. }
  364. }
  365. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> ToAccountInfos<'info>
  366. for Account<'info, T>
  367. {
  368. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  369. vec![self.info.clone()]
  370. }
  371. }
  372. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AsRef<AccountInfo<'info>>
  373. for Account<'info, T>
  374. {
  375. fn as_ref(&self) -> &AccountInfo<'info> {
  376. &self.info
  377. }
  378. }
  379. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AsRef<T>
  380. for Account<'info, T>
  381. {
  382. fn as_ref(&self) -> &T {
  383. &self.account
  384. }
  385. }
  386. impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> Deref for Account<'a, T> {
  387. type Target = T;
  388. fn deref(&self) -> &Self::Target {
  389. &(*self).account
  390. }
  391. }
  392. impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> DerefMut for Account<'a, T> {
  393. fn deref_mut(&mut self) -> &mut Self::Target {
  394. #[cfg(feature = "anchor-debug")]
  395. if !self.info.is_writable {
  396. solana_program::msg!("The given Account is not mutable");
  397. panic!();
  398. }
  399. &mut self.account
  400. }
  401. }
  402. impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> Key for Account<'info, T> {
  403. fn key(&self) -> Pubkey {
  404. *self.info.key
  405. }
  406. }