atlas_account_info/
lib.rs

1//! Account information.
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3use {
4    atlas_program_error::ProgramError,
5    atlas_program_memory::atlas_memset,
6    atlas_pubkey::Pubkey,
7    std::{
8        cell::{Ref, RefCell, RefMut},
9        fmt,
10        rc::Rc,
11        slice::from_raw_parts_mut,
12    },
13};
14pub mod debug_account_data;
15
16/// Maximum number of bytes a program may add to an account during a single realloc
17pub const MAX_PERMITTED_DATA_INCREASE: usize = 1_024 * 10;
18
19/// Account information
20#[derive(Clone)]
21#[repr(C)]
22pub struct AccountInfo<'a> {
23    /// Public key of the account
24    pub key: &'a Pubkey,
25    /// The lamports in the account.  Modifiable by programs.
26    pub lamports: Rc<RefCell<&'a mut u64>>,
27    /// The data held in this account.  Modifiable by programs.
28    pub data: Rc<RefCell<&'a mut [u8]>>,
29    /// Program that owns this account
30    pub owner: &'a Pubkey,
31    /// Formerly, the epoch at which this account will next owe rent. A field
32    /// must remain because the runtime depends on the exact layout of this
33    /// struct.
34    #[deprecated(
35        since = "3.0.0",
36        note = "Do not use this field, it will not exist in ABIv2"
37    )]
38    pub _unused: u64,
39    /// Was the transaction signed by this account's public key?
40    pub is_signer: bool,
41    /// Is the account writable?
42    pub is_writable: bool,
43    /// This account's data contains a loaded program (and is now read-only)
44    pub executable: bool,
45}
46
47impl fmt::Debug for AccountInfo<'_> {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        let mut f = f.debug_struct("AccountInfo");
50
51        f.field("key", &self.key)
52            .field("owner", &self.owner)
53            .field("is_signer", &self.is_signer)
54            .field("is_writable", &self.is_writable)
55            .field("executable", &self.executable)
56            .field("lamports", &self.lamports())
57            .field("data.len", &self.data_len());
58        debug_account_data::debug_account_data(&self.data.borrow(), &mut f);
59
60        f.finish_non_exhaustive()
61    }
62}
63
64impl<'a> AccountInfo<'a> {
65    pub fn signer_key(&self) -> Option<&Pubkey> {
66        if self.is_signer {
67            Some(self.key)
68        } else {
69            None
70        }
71    }
72
73    pub fn unsigned_key(&self) -> &Pubkey {
74        self.key
75    }
76
77    pub fn lamports(&self) -> u64 {
78        **self.lamports.borrow()
79    }
80
81    pub fn try_lamports(&self) -> Result<u64, ProgramError> {
82        Ok(**self.try_borrow_lamports()?)
83    }
84
85    /// Return the account's original data length when it was serialized for the
86    /// current program invocation.
87    ///
88    /// # Safety
89    ///
90    /// This method assumes that the original data length was serialized as a u32
91    /// integer in the 4 bytes immediately preceding the serialized account key.
92    pub unsafe fn original_data_len(&self) -> usize {
93        let key_ptr = self.key as *const _ as *const u8;
94        let original_data_len_ptr = key_ptr.offset(-4) as *const u32;
95        *original_data_len_ptr as usize
96    }
97
98    pub fn data_len(&self) -> usize {
99        self.data.borrow().len()
100    }
101
102    pub fn try_data_len(&self) -> Result<usize, ProgramError> {
103        Ok(self.try_borrow_data()?.len())
104    }
105
106    pub fn data_is_empty(&self) -> bool {
107        self.data.borrow().is_empty()
108    }
109
110    pub fn try_data_is_empty(&self) -> Result<bool, ProgramError> {
111        Ok(self.try_borrow_data()?.is_empty())
112    }
113
114    pub fn try_borrow_lamports(&self) -> Result<Ref<'_, &mut u64>, ProgramError> {
115        self.lamports
116            .try_borrow()
117            .map_err(|_| ProgramError::AccountBorrowFailed)
118    }
119
120    pub fn try_borrow_mut_lamports(&self) -> Result<RefMut<'_, &'a mut u64>, ProgramError> {
121        self.lamports
122            .try_borrow_mut()
123            .map_err(|_| ProgramError::AccountBorrowFailed)
124    }
125
126    pub fn try_borrow_data(&self) -> Result<Ref<'_, &mut [u8]>, ProgramError> {
127        self.data
128            .try_borrow()
129            .map_err(|_| ProgramError::AccountBorrowFailed)
130    }
131
132    pub fn try_borrow_mut_data(&self) -> Result<RefMut<'_, &'a mut [u8]>, ProgramError> {
133        self.data
134            .try_borrow_mut()
135            .map_err(|_| ProgramError::AccountBorrowFailed)
136    }
137
138    /// Resize the account's data: Either truncating or zero extending.
139    ///
140    /// Note:  Account data can be increased within a single call by up to
141    /// `atlas_program::entrypoint::MAX_PERMITTED_DATA_INCREASE` bytes.
142    ///
143    /// # Safety
144    ///
145    /// This method makes assumptions about the layout and location of memory
146    /// referenced by `AccountInfo` fields. It should only be called for
147    /// instances of `AccountInfo` that were created by the runtime and received
148    /// in the `process_instruction` entrypoint of a program.
149    pub fn resize(&self, new_len: usize) -> Result<(), ProgramError> {
150        let mut data = self.try_borrow_mut_data()?;
151        let old_len = data.len();
152
153        // Return early if length hasn't changed
154        if new_len == old_len {
155            return Ok(());
156        }
157
158        // Return early if the length increase from the original serialized data
159        // length is too large and would result in an out of bounds allocation.
160        let original_data_len = unsafe { self.original_data_len() };
161        if new_len.saturating_sub(original_data_len) > MAX_PERMITTED_DATA_INCREASE {
162            return Err(ProgramError::InvalidRealloc);
163        }
164
165        // realloc
166        unsafe {
167            let data_ptr = data.as_mut_ptr();
168
169            // First set new length in the serialized data
170            *(data_ptr.offset(-8) as *mut u64) = new_len as u64;
171
172            // Then recreate the local slice with the new length
173            *data = from_raw_parts_mut(data_ptr, new_len)
174        }
175
176        let len_increase = new_len.saturating_sub(old_len);
177        if len_increase > 0 {
178            unsafe { atlas_memset(&mut data[old_len..], 0, len_increase) };
179        }
180
181        Ok(())
182    }
183
184    #[allow(invalid_reference_casting)]
185    pub fn assign(&self, new_owner: &Pubkey) {
186        // Set the non-mut owner field
187        unsafe {
188            std::ptr::write_volatile(
189                self.owner as *const Pubkey as *mut [u8; 32],
190                new_owner.to_bytes(),
191            );
192        }
193    }
194
195    pub fn new(
196        key: &'a Pubkey,
197        is_signer: bool,
198        is_writable: bool,
199        lamports: &'a mut u64,
200        data: &'a mut [u8],
201        owner: &'a Pubkey,
202        executable: bool,
203    ) -> Self {
204        #[allow(deprecated)]
205        Self {
206            key,
207            is_signer,
208            is_writable,
209            lamports: Rc::new(RefCell::new(lamports)),
210            data: Rc::new(RefCell::new(data)),
211            owner,
212            executable,
213            _unused: 0,
214        }
215    }
216
217    #[cfg(feature = "bincode")]
218    pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
219        bincode::deserialize(&self.data.borrow())
220    }
221
222    #[cfg(feature = "bincode")]
223    pub fn serialize_data<T: serde::Serialize>(&self, state: &T) -> Result<(), bincode::Error> {
224        if bincode::serialized_size(state)? > self.data_len() as u64 {
225            return Err(Box::new(bincode::ErrorKind::SizeLimit));
226        }
227        bincode::serialize_into(&mut self.data.borrow_mut()[..], state)
228    }
229}
230
231/// Constructs an `AccountInfo` from self, used in conversion implementations.
232pub trait IntoAccountInfo<'a> {
233    fn into_account_info(self) -> AccountInfo<'a>;
234}
235impl<'a, T: IntoAccountInfo<'a>> From<T> for AccountInfo<'a> {
236    fn from(src: T) -> Self {
237        src.into_account_info()
238    }
239}
240
241/// Provides information required to construct an `AccountInfo`, used in
242/// conversion implementations.
243pub trait Account {
244    fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool);
245}
246
247/// Convert (&'a Pubkey, &'a mut T) where T: Account into an `AccountInfo`
248impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, &'a mut T) {
249    fn into_account_info(self) -> AccountInfo<'a> {
250        let (key, account) = self;
251        let (lamports, data, owner, executable) = account.get();
252        AccountInfo::new(key, false, false, lamports, data, owner, executable)
253    }
254}
255
256/// Convert (&'a Pubkey, bool, &'a mut T)  where T: Account into an
257/// `AccountInfo`.
258impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, bool, &'a mut T) {
259    fn into_account_info(self) -> AccountInfo<'a> {
260        let (key, is_signer, account) = self;
261        let (lamports, data, owner, executable) = account.get();
262        AccountInfo::new(key, is_signer, false, lamports, data, owner, executable)
263    }
264}
265
266/// Convert &'a mut (Pubkey, T) where T: Account into an `AccountInfo`.
267impl<'a, T: Account> IntoAccountInfo<'a> for &'a mut (Pubkey, T) {
268    fn into_account_info(self) -> AccountInfo<'a> {
269        let (ref key, account) = self;
270        let (lamports, data, owner, executable) = account.get();
271        AccountInfo::new(key, false, false, lamports, data, owner, executable)
272    }
273}
274
275/// Convenience function for accessing the next item in an [`AccountInfo`]
276/// iterator.
277///
278/// This is simply a wrapper around [`Iterator::next`] that returns a
279/// [`ProgramError`] instead of an option.
280///
281/// # Errors
282///
283/// Returns [`ProgramError::NotEnoughAccountKeys`] if there are no more items in
284/// the iterator.
285///
286/// # Examples
287///
288/// ```
289/// use atlas_program_error::ProgramResult;
290/// use atlas_account_info::{AccountInfo, next_account_info};
291/// use atlas_pubkey::Pubkey;
292/// # use atlas_program_error::ProgramError;
293///
294/// pub fn process_instruction(
295///     program_id: &Pubkey,
296///     accounts: &[AccountInfo],
297///     instruction_data: &[u8],
298/// ) -> ProgramResult {
299///     let accounts_iter = &mut accounts.iter();
300///     let signer = next_account_info(accounts_iter)?;
301///     let payer = next_account_info(accounts_iter)?;
302///
303///     // do stuff ...
304///
305///     Ok(())
306/// }
307/// # let p = Pubkey::new_unique();
308/// # let l = &mut 0;
309/// # let d = &mut [0u8];
310/// # let a = AccountInfo::new(&p, false, false, l, d, &p, false);
311/// # let accounts = &[a.clone(), a];
312/// # process_instruction(
313/// #    &Pubkey::new_unique(),
314/// #    accounts,
315/// #    &[],
316/// # )?;
317/// # Ok::<(), ProgramError>(())
318/// ```
319pub fn next_account_info<'a, 'b, I: Iterator<Item = &'a AccountInfo<'b>>>(
320    iter: &mut I,
321) -> Result<I::Item, ProgramError> {
322    iter.next().ok_or(ProgramError::NotEnoughAccountKeys)
323}
324
325/// Convenience function for accessing multiple next items in an [`AccountInfo`]
326/// iterator.
327///
328/// Returns a slice containing the next `count` [`AccountInfo`]s.
329///
330/// # Errors
331///
332/// Returns [`ProgramError::NotEnoughAccountKeys`] if there are not enough items
333/// in the iterator to satisfy the request.
334///
335/// # Examples
336///
337/// ```
338/// use atlas_program_error::ProgramResult;
339/// use atlas_account_info::{AccountInfo, next_account_info, next_account_infos};
340/// use atlas_pubkey::Pubkey;
341/// # use atlas_program_error::ProgramError;
342///
343/// pub fn process_instruction(
344///     program_id: &Pubkey,
345///     accounts: &[AccountInfo],
346///     instruction_data: &[u8],
347/// ) -> ProgramResult {
348///     let accounts_iter = &mut accounts.iter();
349///     let signer = next_account_info(accounts_iter)?;
350///     let payer = next_account_info(accounts_iter)?;
351///     let outputs = next_account_infos(accounts_iter, 3)?;
352///
353///     // do stuff ...
354///
355///     Ok(())
356/// }
357/// # let p = Pubkey::new_unique();
358/// # let l = &mut 0;
359/// # let d = &mut [0u8];
360/// # let a = AccountInfo::new(&p, false, false, l, d, &p, false);
361/// # let accounts = &[a.clone(), a.clone(), a.clone(), a.clone(), a];
362/// # process_instruction(
363/// #    &Pubkey::new_unique(),
364/// #    accounts,
365/// #    &[],
366/// # )?;
367/// # Ok::<(), ProgramError>(())
368/// ```
369pub fn next_account_infos<'a, 'b: 'a>(
370    iter: &mut std::slice::Iter<'a, AccountInfo<'b>>,
371    count: usize,
372) -> Result<&'a [AccountInfo<'b>], ProgramError> {
373    let accounts = iter.as_slice();
374    if accounts.len() < count {
375        return Err(ProgramError::NotEnoughAccountKeys);
376    }
377    let (accounts, remaining) = accounts.split_at(count);
378    *iter = remaining.iter();
379    Ok(accounts)
380}
381
382impl<'a> AsRef<AccountInfo<'a>> for AccountInfo<'a> {
383    fn as_ref(&self) -> &AccountInfo<'a> {
384        self
385    }
386}
387
388#[doc(hidden)]
389#[allow(clippy::arithmetic_side_effects)]
390pub fn check_type_assumptions() {
391    use std::mem::offset_of;
392
393    let key = Pubkey::new_from_array([10; 32]);
394    let mut lamports = 31;
395    let mut data = vec![1, 2, 3, 4, 5];
396    let owner = Pubkey::new_from_array([22; 32]);
397    let account_info = AccountInfo::new(&key, true, false, &mut lamports, &mut data, &owner, true);
398    let account_info_addr = &account_info as *const _ as u64;
399
400    // key
401    assert_eq!(offset_of!(AccountInfo, key), 0);
402    let key_ptr = (account_info_addr) as *const &Pubkey;
403    unsafe {
404        assert_eq!(**key_ptr, key);
405    }
406
407    // lamports
408    assert_eq!(offset_of!(AccountInfo, lamports), 8);
409    let lamports_ptr = (account_info_addr + 8) as *const Rc<RefCell<&mut u64>>;
410    unsafe {
411        assert_eq!(**(*lamports_ptr).as_ptr(), 31);
412    }
413
414    // data
415    assert_eq!(offset_of!(AccountInfo, data), 16);
416    let data_ptr = (account_info_addr + 16) as *const Rc<RefCell<&mut [u8]>>;
417    unsafe {
418        assert_eq!((&(*(*data_ptr).as_ptr()))[..], data[..]);
419    }
420
421    // owner
422    assert_eq!(offset_of!(AccountInfo, owner), 24);
423    let owner_ptr = (account_info_addr + 24) as *const &Pubkey;
424    unsafe {
425        assert_eq!(**owner_ptr, owner);
426    }
427
428    // previously rent_epoch
429    #[allow(deprecated)]
430    {
431        assert_eq!(offset_of!(AccountInfo, _unused), 32);
432        let unused_ptr = (account_info_addr + 32) as *const u64;
433        unsafe {
434            assert_eq!(*unused_ptr, 0);
435        }
436    }
437
438    // is_signer
439    assert_eq!(offset_of!(AccountInfo, is_signer), 40);
440    let is_signer_ptr = (account_info_addr + 40) as *const bool;
441    unsafe {
442        assert!(*is_signer_ptr);
443    }
444
445    // is_writable
446    assert_eq!(offset_of!(AccountInfo, is_writable), 41);
447    let is_writable_ptr = (account_info_addr + 41) as *const bool;
448    unsafe {
449        assert!(!*is_writable_ptr);
450    }
451
452    // executable
453    assert_eq!(offset_of!(AccountInfo, executable), 42);
454    let executable_ptr = (account_info_addr + 42) as *const bool;
455    unsafe {
456        assert!(*executable_ptr);
457    }
458}
459
460#[cfg(test)]
461mod tests {
462    use {
463        super::*,
464        crate::debug_account_data::{Hex, MAX_DEBUG_ACCOUNT_DATA},
465    };
466
467    #[test]
468    fn test_next_account_infos() {
469        let k1 = Pubkey::new_unique();
470        let k2 = Pubkey::new_unique();
471        let k3 = Pubkey::new_unique();
472        let k4 = Pubkey::new_unique();
473        let k5 = Pubkey::new_unique();
474        let l1 = &mut 0;
475        let l2 = &mut 0;
476        let l3 = &mut 0;
477        let l4 = &mut 0;
478        let l5 = &mut 0;
479        let d1 = &mut [0u8];
480        let d2 = &mut [0u8];
481        let d3 = &mut [0u8];
482        let d4 = &mut [0u8];
483        let d5 = &mut [0u8];
484
485        let infos = &[
486            AccountInfo::new(&k1, false, false, l1, d1, &k1, false),
487            AccountInfo::new(&k2, false, false, l2, d2, &k2, false),
488            AccountInfo::new(&k3, false, false, l3, d3, &k3, false),
489            AccountInfo::new(&k4, false, false, l4, d4, &k4, false),
490            AccountInfo::new(&k5, false, false, l5, d5, &k5, false),
491        ];
492        let infos_iter = &mut infos.iter();
493        let info1 = next_account_info(infos_iter).unwrap();
494        let info2_3_4 = next_account_infos(infos_iter, 3).unwrap();
495        let info5 = next_account_info(infos_iter).unwrap();
496
497        assert_eq!(k1, *info1.key);
498        assert_eq!(k2, *info2_3_4[0].key);
499        assert_eq!(k3, *info2_3_4[1].key);
500        assert_eq!(k4, *info2_3_4[2].key);
501        assert_eq!(k5, *info5.key);
502    }
503
504    #[test]
505    fn test_account_info_as_ref() {
506        let k = Pubkey::new_unique();
507        let l = &mut 0;
508        let d = &mut [0u8];
509        let info = AccountInfo::new(&k, false, false, l, d, &k, false);
510        assert_eq!(info.key, info.as_ref().key);
511    }
512
513    #[test]
514    fn test_account_info_debug_data() {
515        let key = Pubkey::new_unique();
516        let mut lamports = 42;
517        let mut data = vec![5; 80];
518        let data_str = format!("{:?}", Hex(&data[..MAX_DEBUG_ACCOUNT_DATA]));
519        let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
520        assert_eq!(
521            format!("{info:?}"),
522            format!(
523                "AccountInfo {{ \
524                key: {}, \
525                owner: {}, \
526                is_signer: {}, \
527                is_writable: {}, \
528                executable: {}, \
529                lamports: {}, \
530                data.len: {}, \
531                data: {}, .. }}",
532                key,
533                key,
534                false,
535                false,
536                false,
537                lamports,
538                data.len(),
539                data_str,
540            )
541        );
542
543        let mut data = vec![5; 40];
544        let data_str = format!("{:?}", Hex(&data));
545        let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
546        assert_eq!(
547            format!("{info:?}"),
548            format!(
549                "AccountInfo {{ \
550                key: {}, \
551                owner: {}, \
552                is_signer: {}, \
553                is_writable: {}, \
554                executable: {}, \
555                lamports: {}, \
556                data.len: {}, \
557                data: {}, .. }}",
558                key,
559                key,
560                false,
561                false,
562                false,
563                lamports,
564                data.len(),
565                data_str,
566            )
567        );
568
569        let mut data = vec![];
570        let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
571        assert_eq!(
572            format!("{info:?}"),
573            format!(
574                "AccountInfo {{ \
575                key: {}, \
576                owner: {}, \
577                is_signer: {}, \
578                is_writable: {}, \
579                executable: {}, \
580                lamports: {}, \
581                data.len: {}, .. }}",
582                key,
583                key,
584                false,
585                false,
586                false,
587                lamports,
588                data.len(),
589            )
590        );
591    }
592
593    #[test]
594    fn test_layout_assumptions() {
595        super::check_type_assumptions();
596    }
597}