solana_account_info/
lib.rs

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