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)]
18pub struct AccountInfo<'a> {
19 pub key: &'a Pubkey,
21 pub is_signer: bool,
23 pub is_writable: bool,
25 pub lamports: Rc<RefCell<&'a mut u64>>,
27 pub data: Rc<RefCell<&'a mut [u8]>>,
29 pub owner: &'a Pubkey,
31 pub executable: bool,
33 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 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 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 if new_len == old_len {
153 return Ok(());
154 }
155
156 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 unsafe {
165 let data_ptr = data.as_mut_ptr();
166
167 *(data_ptr.offset(-8) as *mut u64) = new_len as u64;
169
170 *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 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
228pub 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
238pub trait Account {
241 fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch);
242}
243
244impl<'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
255impl<'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
267impl<'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
278pub 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
330pub 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}