1use {
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#[derive(Clone)]
18#[repr(C)]
19pub struct AccountInfo<'a> {
20 pub key: &'a Pubkey,
22 pub lamports: Rc<RefCell<&'a mut u64>>,
24 pub data: Rc<RefCell<&'a mut [u8]>>,
26 pub owner: &'a Pubkey,
28 pub rent_epoch: Epoch,
30 pub is_signer: bool,
32 pub is_writable: bool,
34 pub executable: bool,
36}
37
38impl<'a> fmt::Debug for AccountInfo<'a> {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 let mut f = f.debug_struct("AccountInfo");
41
42 f.field("key", &self.key)
43 .field("owner", &self.owner)
44 .field("is_signer", &self.is_signer)
45 .field("is_writable", &self.is_writable)
46 .field("executable", &self.executable)
47 .field("rent_epoch", &self.rent_epoch)
48 .field("lamports", &self.lamports())
49 .field("data.len", &self.data_len());
50 debug_account_data(&self.data.borrow(), &mut f);
51
52 f.finish_non_exhaustive()
53 }
54}
55
56impl<'a> AccountInfo<'a> {
57 pub fn signer_key(&self) -> Option<&Pubkey> {
58 if self.is_signer {
59 Some(self.key)
60 } else {
61 None
62 }
63 }
64
65 pub fn unsigned_key(&self) -> &Pubkey {
66 self.key
67 }
68
69 pub fn lamports(&self) -> u64 {
70 **self.lamports.borrow()
71 }
72
73 pub fn try_lamports(&self) -> Result<u64, ProgramError> {
74 Ok(**self.try_borrow_lamports()?)
75 }
76
77 pub unsafe fn original_data_len(&self) -> usize {
85 let key_ptr = self.key as *const _ as *const u8;
86 let original_data_len_ptr = key_ptr.offset(-4) as *const u32;
87 *original_data_len_ptr as usize
88 }
89
90 pub fn data_len(&self) -> usize {
91 self.data.borrow().len()
92 }
93
94 pub fn try_data_len(&self) -> Result<usize, ProgramError> {
95 Ok(self.try_borrow_data()?.len())
96 }
97
98 pub fn data_is_empty(&self) -> bool {
99 self.data.borrow().is_empty()
100 }
101
102 pub fn try_data_is_empty(&self) -> Result<bool, ProgramError> {
103 Ok(self.try_borrow_data()?.is_empty())
104 }
105
106 pub fn try_borrow_lamports(&self) -> Result<Ref<&mut u64>, ProgramError> {
107 self.lamports
108 .try_borrow()
109 .map_err(|_| ProgramError::AccountBorrowFailed)
110 }
111
112 pub fn try_borrow_mut_lamports(&self) -> Result<RefMut<&'a mut u64>, ProgramError> {
113 self.lamports
114 .try_borrow_mut()
115 .map_err(|_| ProgramError::AccountBorrowFailed)
116 }
117
118 pub fn try_borrow_data(&self) -> Result<Ref<&mut [u8]>, ProgramError> {
119 self.data
120 .try_borrow()
121 .map_err(|_| ProgramError::AccountBorrowFailed)
122 }
123
124 pub fn try_borrow_mut_data(&self) -> Result<RefMut<&'a mut [u8]>, ProgramError> {
125 self.data
126 .try_borrow_mut()
127 .map_err(|_| ProgramError::AccountBorrowFailed)
128 }
129
130 pub fn realloc(&self, new_len: usize, zero_init: bool) -> Result<(), ProgramError> {
149 let mut data = self.try_borrow_mut_data()?;
150 let old_len = data.len();
151
152 if new_len == old_len {
154 return Ok(());
155 }
156
157 let original_data_len = unsafe { self.original_data_len() };
160 if new_len.saturating_sub(original_data_len) > MAX_PERMITTED_DATA_INCREASE {
161 return Err(ProgramError::InvalidRealloc);
162 }
163
164 unsafe {
166 let data_ptr = data.as_mut_ptr();
167
168 *(data_ptr.offset(-8) as *mut u64) = new_len as u64;
170
171 *data = from_raw_parts_mut(data_ptr, new_len)
173 }
174
175 if zero_init {
176 let len_increase = new_len.saturating_sub(old_len);
177 if len_increase > 0 {
178 sol_memset(&mut data[old_len..], 0, len_increase);
179 }
180 }
181
182 Ok(())
183 }
184
185 pub fn assign(&self, new_owner: &Pubkey) {
186 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 rent_epoch: Epoch,
204 ) -> Self {
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 rent_epoch,
214 }
215 }
216
217 pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
218 bincode::deserialize(&self.data.borrow())
219 }
220
221 pub fn serialize_data<T: serde::Serialize>(&self, state: &T) -> Result<(), bincode::Error> {
222 if bincode::serialized_size(state)? > self.data_len() as u64 {
223 return Err(Box::new(bincode::ErrorKind::SizeLimit));
224 }
225 bincode::serialize_into(&mut self.data.borrow_mut()[..], state)
226 }
227}
228
229pub trait IntoAccountInfo<'a> {
231 fn into_account_info(self) -> AccountInfo<'a>;
232}
233impl<'a, T: IntoAccountInfo<'a>> From<T> for AccountInfo<'a> {
234 fn from(src: T) -> Self {
235 src.into_account_info()
236 }
237}
238
239pub trait Account {
242 fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch);
243}
244
245impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, &'a mut T) {
247 fn into_account_info(self) -> AccountInfo<'a> {
248 let (key, account) = self;
249 let (lamports, data, owner, executable, rent_epoch) = account.get();
250 AccountInfo::new(
251 key, false, false, lamports, data, owner, executable, rent_epoch,
252 )
253 }
254}
255
256impl<'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, rent_epoch) = account.get();
262 AccountInfo::new(
263 key, is_signer, false, lamports, data, owner, executable, rent_epoch,
264 )
265 }
266}
267
268impl<'a, T: Account> IntoAccountInfo<'a> for &'a mut (Pubkey, T) {
270 fn into_account_info(self) -> AccountInfo<'a> {
271 let (ref key, account) = self;
272 let (lamports, data, owner, executable, rent_epoch) = account.get();
273 AccountInfo::new(
274 key, false, false, lamports, data, owner, executable, rent_epoch,
275 )
276 }
277}
278
279pub fn next_account_info<'a, 'b, I: Iterator<Item = &'a AccountInfo<'b>>>(
326 iter: &mut I,
327) -> Result<I::Item, ProgramError> {
328 iter.next().ok_or(ProgramError::NotEnoughAccountKeys)
329}
330
331pub fn next_account_infos<'a, 'b: 'a>(
378 iter: &mut std::slice::Iter<'a, AccountInfo<'b>>,
379 count: usize,
380) -> Result<&'a [AccountInfo<'b>], ProgramError> {
381 let accounts = iter.as_slice();
382 if accounts.len() < count {
383 return Err(ProgramError::NotEnoughAccountKeys);
384 }
385 let (accounts, remaining) = accounts.split_at(count);
386 *iter = remaining.iter();
387 Ok(accounts)
388}
389
390impl<'a> AsRef<AccountInfo<'a>> for AccountInfo<'a> {
391 fn as_ref(&self) -> &AccountInfo<'a> {
392 self
393 }
394}
395
396#[cfg(test)]
397mod tests {
398 use super::*;
399
400 #[test]
401 fn test_next_account_infos() {
402 let k1 = Pubkey::new_unique();
403 let k2 = Pubkey::new_unique();
404 let k3 = Pubkey::new_unique();
405 let k4 = Pubkey::new_unique();
406 let k5 = Pubkey::new_unique();
407 let l1 = &mut 0;
408 let l2 = &mut 0;
409 let l3 = &mut 0;
410 let l4 = &mut 0;
411 let l5 = &mut 0;
412 let d1 = &mut [0u8];
413 let d2 = &mut [0u8];
414 let d3 = &mut [0u8];
415 let d4 = &mut [0u8];
416 let d5 = &mut [0u8];
417
418 let infos = &[
419 AccountInfo::new(&k1, false, false, l1, d1, &k1, false, 0),
420 AccountInfo::new(&k2, false, false, l2, d2, &k2, false, 0),
421 AccountInfo::new(&k3, false, false, l3, d3, &k3, false, 0),
422 AccountInfo::new(&k4, false, false, l4, d4, &k4, false, 0),
423 AccountInfo::new(&k5, false, false, l5, d5, &k5, false, 0),
424 ];
425 let infos_iter = &mut infos.iter();
426 let info1 = next_account_info(infos_iter).unwrap();
427 let info2_3_4 = next_account_infos(infos_iter, 3).unwrap();
428 let info5 = next_account_info(infos_iter).unwrap();
429
430 assert_eq!(k1, *info1.key);
431 assert_eq!(k2, *info2_3_4[0].key);
432 assert_eq!(k3, *info2_3_4[1].key);
433 assert_eq!(k4, *info2_3_4[2].key);
434 assert_eq!(k5, *info5.key);
435 }
436
437 #[test]
438 fn test_account_info_as_ref() {
439 let k = Pubkey::new_unique();
440 let l = &mut 0;
441 let d = &mut [0u8];
442 let info = AccountInfo::new(&k, false, false, l, d, &k, false, 0);
443 assert_eq!(info.key, info.as_ref().key);
444 }
445
446 #[test]
447 fn test_account_info_debug_data() {
448 let key = Pubkey::new_unique();
449 let mut lamports = 42;
450 let mut data = vec![5; 80];
451 let data_str = format!("{:?}", Hex(&data[..MAX_DEBUG_ACCOUNT_DATA]));
452 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false, 0);
453 assert_eq!(
454 format!("{info:?}"),
455 format!(
456 "AccountInfo {{ \
457 key: {}, \
458 owner: {}, \
459 is_signer: {}, \
460 is_writable: {}, \
461 executable: {}, \
462 rent_epoch: {}, \
463 lamports: {}, \
464 data.len: {}, \
465 data: {}, .. }}",
466 key,
467 key,
468 false,
469 false,
470 false,
471 0,
472 lamports,
473 data.len(),
474 data_str,
475 )
476 );
477
478 let mut data = vec![5; 40];
479 let data_str = format!("{:?}", Hex(&data));
480 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false, 0);
481 assert_eq!(
482 format!("{info:?}"),
483 format!(
484 "AccountInfo {{ \
485 key: {}, \
486 owner: {}, \
487 is_signer: {}, \
488 is_writable: {}, \
489 executable: {}, \
490 rent_epoch: {}, \
491 lamports: {}, \
492 data.len: {}, \
493 data: {}, .. }}",
494 key,
495 key,
496 false,
497 false,
498 false,
499 0,
500 lamports,
501 data.len(),
502 data_str,
503 )
504 );
505
506 let mut data = vec![];
507 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false, 0);
508 assert_eq!(
509 format!("{info:?}"),
510 format!(
511 "AccountInfo {{ \
512 key: {}, \
513 owner: {}, \
514 is_signer: {}, \
515 is_writable: {}, \
516 executable: {}, \
517 rent_epoch: {}, \
518 lamports: {}, \
519 data.len: {}, .. }}",
520 key,
521 key,
522 false,
523 false,
524 false,
525 0,
526 lamports,
527 data.len(),
528 )
529 );
530 }
531}