1#![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
16pub const MAX_PERMITTED_DATA_INCREASE: usize = 1_024 * 10;
18
19#[derive(Clone)]
21#[repr(C)]
22pub struct AccountInfo<'a> {
23 pub key: &'a Pubkey,
25 pub lamports: Rc<RefCell<&'a mut u64>>,
27 pub data: Rc<RefCell<&'a mut [u8]>>,
29 pub owner: &'a Pubkey,
31 pub rent_epoch: u64,
33 pub is_signer: bool,
35 pub is_writable: bool,
37 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 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 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 if new_len == old_len {
157 return Ok(());
158 }
159
160 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 unsafe {
169 let data_ptr = data.as_mut_ptr();
170
171 *(data_ptr.offset(-8) as *mut u64) = new_len as u64;
173
174 *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 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
235pub 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
245pub trait Account {
248 fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, u64);
249}
250
251impl<'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
262impl<'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
274impl<'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
285pub 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
335pub 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}