solana_program/
account_info.rs

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