program_account.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. use crate::{
  2. AccountDeserialize, AccountSerialize, Accounts, AccountsInit, CpiAccount, ToAccountInfo,
  3. ToAccountInfos, ToAccountMetas,
  4. };
  5. use solana_sdk::account_info::AccountInfo;
  6. use solana_sdk::instruction::AccountMeta;
  7. use solana_sdk::program_error::ProgramError;
  8. use solana_sdk::pubkey::Pubkey;
  9. use std::ops::{Deref, DerefMut};
  10. /// Container for a serializable `account`. Use this to reference any account
  11. /// owned by the currently executing program.
  12. #[derive(Clone)]
  13. pub struct ProgramAccount<'a, T: AccountSerialize + AccountDeserialize + Clone> {
  14. info: AccountInfo<'a>,
  15. account: T,
  16. }
  17. impl<'a, T: AccountSerialize + AccountDeserialize + Clone> ProgramAccount<'a, T> {
  18. pub fn new(info: AccountInfo<'a>, account: T) -> ProgramAccount<'a, T> {
  19. Self { info, account }
  20. }
  21. /// Deserializes the given `info` into a `ProgramAccount`.
  22. pub fn try_from(info: &AccountInfo<'a>) -> Result<ProgramAccount<'a, T>, ProgramError> {
  23. let mut data: &[u8] = &info.try_borrow_data()?;
  24. Ok(ProgramAccount::new(
  25. info.clone(),
  26. T::try_deserialize(&mut data)?,
  27. ))
  28. }
  29. /// Deserializes the zero-initialized `info` into a `ProgramAccount` without
  30. /// checking the account type. This should only be used upon program account
  31. /// initialization (since the entire account data array is zeroed and thus
  32. /// no account type is set).
  33. pub fn try_from_init(info: &AccountInfo<'a>) -> Result<ProgramAccount<'a, T>, ProgramError> {
  34. let mut data: &[u8] = &info.try_borrow_data()?;
  35. // The discriminator should be zero, since we're initializing.
  36. let mut disc_bytes = [0u8; 8];
  37. disc_bytes.copy_from_slice(&data[..8]);
  38. let discriminator = u64::from_le_bytes(disc_bytes);
  39. if discriminator != 0 {
  40. return Err(ProgramError::InvalidAccountData);
  41. }
  42. Ok(ProgramAccount::new(
  43. info.clone(),
  44. T::try_deserialize_unchecked(&mut data)?,
  45. ))
  46. }
  47. }
  48. impl<'info, T> Accounts<'info> for ProgramAccount<'info, T>
  49. where
  50. T: AccountSerialize + AccountDeserialize + Clone,
  51. {
  52. fn try_accounts(
  53. program_id: &Pubkey,
  54. accounts: &mut &[AccountInfo<'info>],
  55. ) -> Result<Self, ProgramError> {
  56. if accounts.len() == 0 {
  57. return Err(ProgramError::NotEnoughAccountKeys);
  58. }
  59. let account = &accounts[0];
  60. *accounts = &accounts[1..];
  61. let pa = ProgramAccount::try_from(account)?;
  62. if pa.info.owner != program_id {}
  63. Ok(pa)
  64. }
  65. }
  66. impl<'info, T> AccountsInit<'info> for ProgramAccount<'info, T>
  67. where
  68. T: AccountSerialize + AccountDeserialize + Clone,
  69. {
  70. fn try_accounts_init(
  71. program_id: &Pubkey,
  72. accounts: &mut &[AccountInfo<'info>],
  73. ) -> Result<Self, ProgramError> {
  74. if accounts.len() == 0 {
  75. return Err(ProgramError::NotEnoughAccountKeys);
  76. }
  77. let account = &accounts[0];
  78. *accounts = &accounts[1..];
  79. ProgramAccount::try_from_init(account)
  80. }
  81. }
  82. impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountMetas
  83. for ProgramAccount<'info, T>
  84. {
  85. fn to_account_metas(&self) -> Vec<AccountMeta> {
  86. let meta = match self.info.is_writable {
  87. false => AccountMeta::new_readonly(*self.info.key, self.info.is_signer),
  88. true => AccountMeta::new(*self.info.key, self.info.is_signer),
  89. };
  90. vec![meta]
  91. }
  92. }
  93. impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfos<'info>
  94. for ProgramAccount<'info, T>
  95. {
  96. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  97. vec![self.info.clone()]
  98. }
  99. }
  100. impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfo<'info>
  101. for ProgramAccount<'info, T>
  102. {
  103. fn to_account_info(&self) -> AccountInfo<'info> {
  104. self.info.clone()
  105. }
  106. }
  107. impl<'a, T: AccountSerialize + AccountDeserialize + Clone> Deref for ProgramAccount<'a, T> {
  108. type Target = T;
  109. fn deref(&self) -> &Self::Target {
  110. &self.account
  111. }
  112. }
  113. impl<'a, T: AccountSerialize + AccountDeserialize + Clone> DerefMut for ProgramAccount<'a, T> {
  114. fn deref_mut(&mut self) -> &mut Self::Target {
  115. &mut self.account
  116. }
  117. }
  118. impl<'info, T> From<CpiAccount<'info, T>> for ProgramAccount<'info, T>
  119. where
  120. T: AccountSerialize + AccountDeserialize + Clone,
  121. {
  122. fn from(a: CpiAccount<'info, T>) -> Self {
  123. Self {
  124. info: a.to_account_info(),
  125. account: Deref::deref(&a).clone(),
  126. }
  127. }
  128. }