lib.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. use solana_sdk::account_info::AccountInfo;
  2. use solana_sdk::program_error::ProgramError;
  3. use solana_sdk::pubkey::Pubkey;
  4. use std::io::Write;
  5. use std::ops::{Deref, DerefMut};
  6. pub use anchor_attribute_access_control::access_control;
  7. pub use anchor_attribute_account::account;
  8. pub use anchor_attribute_program::program;
  9. pub use anchor_derive_accounts::Accounts;
  10. pub use borsh::{BorshDeserialize as AnchorDeserialize, BorshSerialize as AnchorSerialize};
  11. /// A data structure of Solana accounts that can be deserialized from the input
  12. /// of a Solana program. Due to the freewheeling nature of the accounts array,
  13. /// implementations of this trait should perform any and all constraint checks
  14. /// (in addition to any done within `AccountDeserialize`) on accounts to ensure
  15. /// the accounts maintain any invariants required for the program to run
  16. /// securely.
  17. pub trait Accounts<'info>: Sized {
  18. fn try_accounts(program_id: &Pubkey, from: &[AccountInfo<'info>])
  19. -> Result<Self, ProgramError>;
  20. }
  21. /// A data structure that can be serialized and stored in an `AccountInfo` data
  22. /// array.
  23. ///
  24. /// Implementors of this trait should ensure that any subsequent usage the
  25. /// `AccountDeserialize` trait succeeds if and only if the account is of the
  26. /// correct type. For example, the implementation provided by the `#[account]`
  27. /// attribute sets the first 8 bytes to be a unique account discriminator,
  28. /// defined as the first 8 bytes of the SHA256 of the account's Rust ident.
  29. /// Thus, any subsequent calls via `AccountDeserialize`'s `try_deserialize`
  30. /// will check this discriminator. If it doesn't match, an invalid account
  31. /// was given, and the program will exit with an error.
  32. pub trait AccountSerialize {
  33. /// Serilalizes the account data into `writer`.
  34. fn try_serialize<W: Write>(&self, writer: &mut W) -> Result<(), ProgramError>;
  35. }
  36. /// A data structure that can be deserialized from an `AccountInfo` data array.
  37. pub trait AccountDeserialize: Sized {
  38. /// Deserializes the account data.
  39. fn try_deserialize(buf: &mut &[u8]) -> Result<Self, ProgramError>;
  40. /// Deserializes account data without checking the account discriminator.
  41. /// This should only be used on account initialization, when the
  42. /// discriminator is not yet set (since the entire account data is zeroed).
  43. fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError>;
  44. }
  45. /// A container for a deserialized `account` and raw `AccountInfo` object.
  46. ///
  47. /// Using this within a data structure deriving `Accounts` will ensure the
  48. /// account is owned by the currently executing program.
  49. pub struct ProgramAccount<'a, T: AccountSerialize + AccountDeserialize> {
  50. pub info: AccountInfo<'a>,
  51. pub account: T,
  52. }
  53. impl<'a, T: AccountSerialize + AccountDeserialize> ProgramAccount<'a, T> {
  54. pub fn new(info: AccountInfo<'a>, account: T) -> ProgramAccount<'a, T> {
  55. Self { info, account }
  56. }
  57. /// Deserializes the given `info` into a `ProgramAccount`.
  58. pub fn try_from(info: &AccountInfo<'a>) -> Result<ProgramAccount<'a, T>, ProgramError> {
  59. let mut data: &[u8] = &info.try_borrow_data()?;
  60. Ok(ProgramAccount::new(
  61. info.clone(),
  62. T::try_deserialize(&mut data)?,
  63. ))
  64. }
  65. /// Deserializes the zero-initialized `info` into a `ProgramAccount` without
  66. /// checking the account type. This should only be used upon program account
  67. /// initialization (since the entire account data array is zeroed and thus
  68. /// no account type is set).
  69. pub fn try_from_init(info: &AccountInfo<'a>) -> Result<ProgramAccount<'a, T>, ProgramError> {
  70. let mut data: &[u8] = &info.try_borrow_data()?;
  71. // The discriminator should be zero, since we're initializing.
  72. let mut disc_bytes = [0u8; 8];
  73. disc_bytes.copy_from_slice(&data[..8]);
  74. let discriminator = u64::from_le_bytes(disc_bytes);
  75. if discriminator != 0 {
  76. return Err(ProgramError::InvalidAccountData);
  77. }
  78. Ok(ProgramAccount::new(
  79. info.clone(),
  80. T::try_deserialize_unchecked(&mut data)?,
  81. ))
  82. }
  83. }
  84. impl<'a, T: AccountSerialize + AccountDeserialize> Deref for ProgramAccount<'a, T> {
  85. type Target = T;
  86. fn deref(&self) -> &Self::Target {
  87. &self.account
  88. }
  89. }
  90. impl<'a, T: AccountSerialize + AccountDeserialize> DerefMut for ProgramAccount<'a, T> {
  91. fn deref_mut(&mut self) -> &mut Self::Target {
  92. &mut self.account
  93. }
  94. }
  95. /// A data structure providing non-argument inputs to the Solana program, namely
  96. /// the currently executing program's ID and the set of validated, deserialized
  97. /// accounts.
  98. pub struct Context<'a, 'b, T> {
  99. pub accounts: &'a mut T,
  100. pub program_id: &'b Pubkey,
  101. }
  102. pub mod prelude {
  103. pub use super::{
  104. access_control, account, program, AccountDeserialize, AccountSerialize, Accounts,
  105. AnchorDeserialize, AnchorSerialize, Context, ProgramAccount,
  106. };
  107. pub use solana_program::msg;
  108. pub use solana_sdk::account_info::next_account_info;
  109. pub use solana_sdk::account_info::AccountInfo;
  110. pub use solana_sdk::entrypoint::ProgramResult;
  111. pub use solana_sdk::program_error::ProgramError;
  112. pub use solana_sdk::pubkey::Pubkey;
  113. pub use solana_sdk::sysvar::clock::Clock;
  114. pub use solana_sdk::sysvar::epoch_schedule::EpochSchedule;
  115. pub use solana_sdk::sysvar::fees::Fees;
  116. pub use solana_sdk::sysvar::instructions::Instructions;
  117. pub use solana_sdk::sysvar::recent_blockhashes::RecentBlockhashes;
  118. pub use solana_sdk::sysvar::rent::Rent;
  119. pub use solana_sdk::sysvar::rewards::Rewards;
  120. pub use solana_sdk::sysvar::slot_hashes::SlotHashes;
  121. pub use solana_sdk::sysvar::slot_history::SlotHistory;
  122. pub use solana_sdk::sysvar::stake_history::StakeHistory;
  123. pub use solana_sdk::sysvar::Sysvar;
  124. }