sysvar.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. //! Type validating that the account is a sysvar and deserializing it
  2. use crate::error::ErrorCode;
  3. use crate::{Accounts, AccountsExit, ToAccountInfos, ToAccountMetas};
  4. use solana_program::account_info::AccountInfo;
  5. use solana_program::instruction::AccountMeta;
  6. use solana_program::program_error::ProgramError;
  7. use solana_program::pubkey::Pubkey;
  8. use std::fmt;
  9. use std::ops::{Deref, DerefMut};
  10. /// Type validating that the account is a sysvar and deserializing it.
  11. ///
  12. /// If possible, sysvars should not be used via accounts
  13. /// but by using the [`get`](https://docs.rs/solana-program/latest/solana_program/sysvar/trait.Sysvar.html#method.get)
  14. /// function on the desired sysvar. This is because using `get`
  15. /// does not run the risk of Anchor having a bug in its `Sysvar` type
  16. /// and using `get` also decreases tx size, making space for other
  17. /// accounts that cannot be requested via syscall.
  18. ///
  19. /// # Example
  20. /// ```ignore
  21. /// // OK - via account in the account validation struct
  22. /// #[derive(Accounts)]
  23. /// pub struct Example<'info> {
  24. /// pub clock: Sysvar<'info, Clock>
  25. /// }
  26. /// // BETTER - via syscall in the instruction function
  27. /// fn better(ctx: Context<Better>) -> ProgramResult {
  28. /// let clock = Clock::get()?;
  29. /// }
  30. /// ```
  31. pub struct Sysvar<'info, T: solana_program::sysvar::Sysvar> {
  32. info: AccountInfo<'info>,
  33. account: T,
  34. }
  35. impl<'info, T: solana_program::sysvar::Sysvar + fmt::Debug> fmt::Debug for Sysvar<'info, T> {
  36. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  37. f.debug_struct("Sysvar")
  38. .field("info", &self.info)
  39. .field("account", &self.account)
  40. .finish()
  41. }
  42. }
  43. impl<'info, T: solana_program::sysvar::Sysvar> Sysvar<'info, T> {
  44. pub fn from_account_info(
  45. acc_info: &AccountInfo<'info>,
  46. ) -> Result<Sysvar<'info, T>, ProgramError> {
  47. Ok(Sysvar {
  48. info: acc_info.clone(),
  49. account: T::from_account_info(acc_info)?,
  50. })
  51. }
  52. }
  53. impl<'info, T: solana_program::sysvar::Sysvar> Clone for Sysvar<'info, T> {
  54. fn clone(&self) -> Self {
  55. Self {
  56. info: self.info.clone(),
  57. account: T::from_account_info(&self.info).unwrap(),
  58. }
  59. }
  60. }
  61. impl<'info, T: solana_program::sysvar::Sysvar> Accounts<'info> for Sysvar<'info, T> {
  62. fn try_accounts(
  63. _program_id: &Pubkey,
  64. accounts: &mut &[AccountInfo<'info>],
  65. _ix_data: &[u8],
  66. ) -> Result<Self, ProgramError> {
  67. if accounts.is_empty() {
  68. return Err(ErrorCode::AccountNotEnoughKeys.into());
  69. }
  70. let account = &accounts[0];
  71. *accounts = &accounts[1..];
  72. Sysvar::from_account_info(account)
  73. }
  74. }
  75. impl<'info, T: solana_program::sysvar::Sysvar> ToAccountMetas for Sysvar<'info, T> {
  76. fn to_account_metas(&self, _is_signer: Option<bool>) -> Vec<AccountMeta> {
  77. vec![AccountMeta::new_readonly(*self.info.key, false)]
  78. }
  79. }
  80. impl<'info, T: solana_program::sysvar::Sysvar> ToAccountInfos<'info> for Sysvar<'info, T> {
  81. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  82. vec![self.info.clone()]
  83. }
  84. }
  85. impl<'info, T: solana_program::sysvar::Sysvar> AsRef<AccountInfo<'info>> for Sysvar<'info, T> {
  86. fn as_ref(&self) -> &AccountInfo<'info> {
  87. &self.info
  88. }
  89. }
  90. impl<'a, T: solana_program::sysvar::Sysvar> Deref for Sysvar<'a, T> {
  91. type Target = T;
  92. fn deref(&self) -> &Self::Target {
  93. &self.account
  94. }
  95. }
  96. impl<'a, T: solana_program::sysvar::Sysvar> DerefMut for Sysvar<'a, T> {
  97. fn deref_mut(&mut self) -> &mut Self::Target {
  98. &mut self.account
  99. }
  100. }
  101. impl<'info, T: solana_program::sysvar::Sysvar> AccountsExit<'info> for Sysvar<'info, T> {}