cpi_account.rs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. use crate::error::ErrorCode;
  2. use crate::{
  3. AccountDeserialize, Accounts, AccountsExit, ToAccountInfo, ToAccountInfos, ToAccountMetas,
  4. };
  5. use solana_program::account_info::AccountInfo;
  6. use solana_program::entrypoint::ProgramResult;
  7. use solana_program::instruction::AccountMeta;
  8. use solana_program::program_error::ProgramError;
  9. use solana_program::pubkey::Pubkey;
  10. use std::ops::{Deref, DerefMut};
  11. /// Container for any account *not* owned by the current program.
  12. #[derive(Clone)]
  13. pub struct CpiAccount<'a, T: AccountDeserialize + Clone> {
  14. info: AccountInfo<'a>,
  15. account: Box<T>,
  16. }
  17. impl<'a, T: AccountDeserialize + Clone> CpiAccount<'a, T> {
  18. pub fn new(info: AccountInfo<'a>, account: Box<T>) -> CpiAccount<'a, T> {
  19. Self { info, account }
  20. }
  21. /// Deserializes the given `info` into a `CpiAccount`.
  22. pub fn try_from(info: &AccountInfo<'a>) -> Result<CpiAccount<'a, T>, ProgramError> {
  23. let mut data: &[u8] = &info.try_borrow_data()?;
  24. Ok(CpiAccount::new(
  25. info.clone(),
  26. Box::new(T::try_deserialize(&mut data)?),
  27. ))
  28. }
  29. pub fn try_from_init(info: &AccountInfo<'a>) -> Result<CpiAccount<'a, T>, ProgramError> {
  30. Self::try_from(info)
  31. }
  32. /// Reloads the account from storage. This is useful, for example, when
  33. /// observing side effects after CPI.
  34. pub fn reload(&self) -> Result<CpiAccount<'a, T>, ProgramError> {
  35. let info = self.to_account_info();
  36. let mut data: &[u8] = &info.try_borrow_data()?;
  37. Ok(CpiAccount::new(
  38. info.clone(),
  39. Box::new(T::try_deserialize(&mut data)?),
  40. ))
  41. }
  42. }
  43. impl<'info, T> Accounts<'info> for CpiAccount<'info, T>
  44. where
  45. T: AccountDeserialize + Clone,
  46. {
  47. #[inline(never)]
  48. fn try_accounts(
  49. _program_id: &Pubkey,
  50. accounts: &mut &[AccountInfo<'info>],
  51. _ix_data: &[u8],
  52. ) -> Result<Self, ProgramError> {
  53. if accounts.is_empty() {
  54. return Err(ErrorCode::AccountNotEnoughKeys.into());
  55. }
  56. let account = &accounts[0];
  57. *accounts = &accounts[1..];
  58. // No owner check is done here.
  59. let pa = CpiAccount::try_from(account)?;
  60. Ok(pa)
  61. }
  62. }
  63. impl<'info, T: AccountDeserialize + Clone> ToAccountMetas for CpiAccount<'info, T> {
  64. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  65. let is_signer = is_signer.unwrap_or(self.info.is_signer);
  66. let meta = match self.info.is_writable {
  67. false => AccountMeta::new_readonly(*self.info.key, is_signer),
  68. true => AccountMeta::new(*self.info.key, is_signer),
  69. };
  70. vec![meta]
  71. }
  72. }
  73. impl<'info, T: AccountDeserialize + Clone> ToAccountInfos<'info> for CpiAccount<'info, T> {
  74. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  75. vec![self.info.clone()]
  76. }
  77. }
  78. impl<'info, T: AccountDeserialize + Clone> ToAccountInfo<'info> for CpiAccount<'info, T> {
  79. fn to_account_info(&self) -> AccountInfo<'info> {
  80. self.info.clone()
  81. }
  82. }
  83. impl<'a, T: AccountDeserialize + Clone> Deref for CpiAccount<'a, T> {
  84. type Target = T;
  85. fn deref(&self) -> &Self::Target {
  86. &self.account
  87. }
  88. }
  89. impl<'a, T: AccountDeserialize + Clone> DerefMut for CpiAccount<'a, T> {
  90. fn deref_mut(&mut self) -> &mut Self::Target {
  91. &mut self.account
  92. }
  93. }
  94. impl<'info, T: AccountDeserialize + Clone> AccountsExit<'info> for CpiAccount<'info, T> {
  95. fn exit(&self, _program_id: &Pubkey) -> ProgramResult {
  96. // no-op
  97. Ok(())
  98. }
  99. }