program.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. //! Type validating that the account is the given Program
  2. use crate::error::ErrorCode;
  3. use crate::*;
  4. use solana_program::account_info::AccountInfo;
  5. use solana_program::bpf_loader_upgradeable::{self, UpgradeableLoaderState};
  6. use solana_program::instruction::AccountMeta;
  7. use solana_program::pubkey::Pubkey;
  8. use std::collections::BTreeMap;
  9. use std::fmt;
  10. use std::marker::PhantomData;
  11. use std::ops::Deref;
  12. /// Type validating that the account is the given Program
  13. ///
  14. /// The type has a `programdata_address` property that will be set
  15. /// if the program is owned by the [`BPFUpgradeableLoader`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/index.html)
  16. /// and will contain the `programdata_address` property of the `Program` variant of the [`UpgradeableLoaderState`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/enum.UpgradeableLoaderState.html) enum.
  17. ///
  18. /// Checks:
  19. ///
  20. /// - `Account.info.key == Program`
  21. /// - `Account.info.executable == true`
  22. ///
  23. /// # Example
  24. /// ```ignore
  25. ///
  26. /// #[program]
  27. /// mod my_program {
  28. /// fn set_admin_settings(...){...}
  29. /// }
  30. ///
  31. /// #[account]
  32. /// #[derive(Default)]
  33. /// pub struct AdminSettings {
  34. /// ...
  35. /// }
  36. ///
  37. /// #[derive(Accounts)]
  38. /// pub struct SetAdminSettings<'info> {
  39. /// #[account(mut, seeds = [b"admin"], bump)]
  40. /// pub admin_settings: Account<'info, AdminSettings>,
  41. /// #[account(constraint = program.programdata_address() == Some(program_data.key()))]
  42. /// pub program: Program<'info, MyProgram>,
  43. /// #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
  44. /// pub program_data: Account<'info, ProgramData>,
  45. /// pub authority: Signer<'info>,
  46. /// }
  47. /// ```
  48. /// The given program has a function with which the upgrade authority can set admin settings.
  49. ///
  50. /// The required constraints are as follows:
  51. ///
  52. /// - `program` is the account of the program itself.
  53. /// Its constraint checks that `program_data` is the account that contains the program's upgrade authority.
  54. /// Implicitly, this checks that `program` is a BPFUpgradeable program (`program.programdata_address()`
  55. /// will be `None` if it's not).
  56. /// - `program_data`'s constraint checks that its upgrade authority is the `authority` account.
  57. /// - Finally, `authority` needs to sign the transaction.
  58. #[derive(Clone)]
  59. pub struct Program<'info, T: Id + Clone> {
  60. info: AccountInfo<'info>,
  61. programdata_address: Option<Pubkey>,
  62. _phantom: PhantomData<T>,
  63. }
  64. impl<'info, T: Id + Clone + fmt::Debug> fmt::Debug for Program<'info, T> {
  65. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  66. f.debug_struct("Program")
  67. .field("info", &self.info)
  68. .field("programdata_address", &self.programdata_address)
  69. .finish()
  70. }
  71. }
  72. impl<'a, T: Id + Clone> Program<'a, T> {
  73. fn new(info: AccountInfo<'a>, programdata_address: Option<Pubkey>) -> Program<'a, T> {
  74. Self {
  75. info,
  76. programdata_address,
  77. _phantom: PhantomData,
  78. }
  79. }
  80. /// Deserializes the given `info` into a `Program`.
  81. #[inline(never)]
  82. pub fn try_from(info: &AccountInfo<'a>) -> Result<Program<'a, T>> {
  83. if info.key != &T::id() {
  84. return Err(ErrorCode::InvalidProgramId.into());
  85. }
  86. if !info.executable {
  87. return Err(ErrorCode::InvalidProgramExecutable.into());
  88. }
  89. let programdata_address = if *info.owner == bpf_loader_upgradeable::ID {
  90. let mut data: &[u8] = &info.try_borrow_data()?;
  91. let upgradable_loader_state =
  92. UpgradeableLoaderState::try_deserialize_unchecked(&mut data)?;
  93. match upgradable_loader_state {
  94. UpgradeableLoaderState::Uninitialized
  95. | UpgradeableLoaderState::Buffer {
  96. authority_address: _,
  97. }
  98. | UpgradeableLoaderState::ProgramData {
  99. slot: _,
  100. upgrade_authority_address: _,
  101. } => {
  102. // Unreachable because check above already
  103. // ensures that program is executable
  104. // and therefore a program account.
  105. unreachable!()
  106. }
  107. UpgradeableLoaderState::Program {
  108. programdata_address,
  109. } => Some(programdata_address),
  110. }
  111. } else {
  112. None
  113. };
  114. Ok(Program::new(info.clone(), programdata_address))
  115. }
  116. pub fn programdata_address(&self) -> Option<Pubkey> {
  117. self.programdata_address
  118. }
  119. }
  120. impl<'info, T> Accounts<'info> for Program<'info, T>
  121. where
  122. T: Id + Clone,
  123. {
  124. #[inline(never)]
  125. fn try_accounts(
  126. _program_id: &Pubkey,
  127. accounts: &mut &[AccountInfo<'info>],
  128. _ix_data: &[u8],
  129. _bumps: &mut BTreeMap<String, u8>,
  130. ) -> Result<Self> {
  131. if accounts.is_empty() {
  132. return Err(ErrorCode::AccountNotEnoughKeys.into());
  133. }
  134. let account = &accounts[0];
  135. *accounts = &accounts[1..];
  136. Program::try_from(account)
  137. }
  138. }
  139. impl<'info, T: Id + Clone> ToAccountMetas for Program<'info, T> {
  140. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  141. let is_signer = is_signer.unwrap_or(self.info.is_signer);
  142. let meta = match self.info.is_writable {
  143. false => AccountMeta::new_readonly(*self.info.key, is_signer),
  144. true => AccountMeta::new(*self.info.key, is_signer),
  145. };
  146. vec![meta]
  147. }
  148. }
  149. impl<'info, T: Id + Clone> ToAccountInfos<'info> for Program<'info, T> {
  150. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  151. vec![self.info.clone()]
  152. }
  153. }
  154. impl<'info, T: Id + Clone> AsRef<AccountInfo<'info>> for Program<'info, T> {
  155. fn as_ref(&self) -> &AccountInfo<'info> {
  156. &self.info
  157. }
  158. }
  159. impl<'info, T: Id + Clone> Deref for Program<'info, T> {
  160. type Target = AccountInfo<'info>;
  161. fn deref(&self) -> &Self::Target {
  162. &self.info
  163. }
  164. }
  165. impl<'info, T: AccountDeserialize + Id + Clone> AccountsExit<'info> for Program<'info, T> {}