1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3use {
4 atlas_program_error::ProgramError,
5 atlas_program_memory::atlas_memset,
6 atlas_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 #[deprecated(
35 since = "3.0.0",
36 note = "Do not use this field, it will not exist in ABIv2"
37 )]
38 pub _unused: u64,
39 pub is_signer: bool,
41 pub is_writable: bool,
43 pub executable: bool,
45}
46
47impl fmt::Debug for AccountInfo<'_> {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let mut f = f.debug_struct("AccountInfo");
50
51 f.field("key", &self.key)
52 .field("owner", &self.owner)
53 .field("is_signer", &self.is_signer)
54 .field("is_writable", &self.is_writable)
55 .field("executable", &self.executable)
56 .field("lamports", &self.lamports())
57 .field("data.len", &self.data_len());
58 debug_account_data::debug_account_data(&self.data.borrow(), &mut f);
59
60 f.finish_non_exhaustive()
61 }
62}
63
64impl<'a> AccountInfo<'a> {
65 pub fn signer_key(&self) -> Option<&Pubkey> {
66 if self.is_signer {
67 Some(self.key)
68 } else {
69 None
70 }
71 }
72
73 pub fn unsigned_key(&self) -> &Pubkey {
74 self.key
75 }
76
77 pub fn lamports(&self) -> u64 {
78 **self.lamports.borrow()
79 }
80
81 pub fn try_lamports(&self) -> Result<u64, ProgramError> {
82 Ok(**self.try_borrow_lamports()?)
83 }
84
85 pub unsafe fn original_data_len(&self) -> usize {
93 let key_ptr = self.key as *const _ as *const u8;
94 let original_data_len_ptr = key_ptr.offset(-4) as *const u32;
95 *original_data_len_ptr as usize
96 }
97
98 pub fn data_len(&self) -> usize {
99 self.data.borrow().len()
100 }
101
102 pub fn try_data_len(&self) -> Result<usize, ProgramError> {
103 Ok(self.try_borrow_data()?.len())
104 }
105
106 pub fn data_is_empty(&self) -> bool {
107 self.data.borrow().is_empty()
108 }
109
110 pub fn try_data_is_empty(&self) -> Result<bool, ProgramError> {
111 Ok(self.try_borrow_data()?.is_empty())
112 }
113
114 pub fn try_borrow_lamports(&self) -> Result<Ref<'_, &mut u64>, ProgramError> {
115 self.lamports
116 .try_borrow()
117 .map_err(|_| ProgramError::AccountBorrowFailed)
118 }
119
120 pub fn try_borrow_mut_lamports(&self) -> Result<RefMut<'_, &'a mut u64>, ProgramError> {
121 self.lamports
122 .try_borrow_mut()
123 .map_err(|_| ProgramError::AccountBorrowFailed)
124 }
125
126 pub fn try_borrow_data(&self) -> Result<Ref<'_, &mut [u8]>, ProgramError> {
127 self.data
128 .try_borrow()
129 .map_err(|_| ProgramError::AccountBorrowFailed)
130 }
131
132 pub fn try_borrow_mut_data(&self) -> Result<RefMut<'_, &'a mut [u8]>, ProgramError> {
133 self.data
134 .try_borrow_mut()
135 .map_err(|_| ProgramError::AccountBorrowFailed)
136 }
137
138 pub fn resize(&self, new_len: usize) -> Result<(), ProgramError> {
150 let mut data = self.try_borrow_mut_data()?;
151 let old_len = data.len();
152
153 if new_len == old_len {
155 return Ok(());
156 }
157
158 let original_data_len = unsafe { self.original_data_len() };
161 if new_len.saturating_sub(original_data_len) > MAX_PERMITTED_DATA_INCREASE {
162 return Err(ProgramError::InvalidRealloc);
163 }
164
165 unsafe {
167 let data_ptr = data.as_mut_ptr();
168
169 *(data_ptr.offset(-8) as *mut u64) = new_len as u64;
171
172 *data = from_raw_parts_mut(data_ptr, new_len)
174 }
175
176 let len_increase = new_len.saturating_sub(old_len);
177 if len_increase > 0 {
178 unsafe { atlas_memset(&mut data[old_len..], 0, len_increase) };
179 }
180
181 Ok(())
182 }
183
184 #[allow(invalid_reference_casting)]
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 ) -> Self {
204 #[allow(deprecated)]
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 _unused: 0,
214 }
215 }
216
217 #[cfg(feature = "bincode")]
218 pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
219 bincode::deserialize(&self.data.borrow())
220 }
221
222 #[cfg(feature = "bincode")]
223 pub fn serialize_data<T: serde::Serialize>(&self, state: &T) -> Result<(), bincode::Error> {
224 if bincode::serialized_size(state)? > self.data_len() as u64 {
225 return Err(Box::new(bincode::ErrorKind::SizeLimit));
226 }
227 bincode::serialize_into(&mut self.data.borrow_mut()[..], state)
228 }
229}
230
231pub trait IntoAccountInfo<'a> {
233 fn into_account_info(self) -> AccountInfo<'a>;
234}
235impl<'a, T: IntoAccountInfo<'a>> From<T> for AccountInfo<'a> {
236 fn from(src: T) -> Self {
237 src.into_account_info()
238 }
239}
240
241pub trait Account {
244 fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool);
245}
246
247impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, &'a mut T) {
249 fn into_account_info(self) -> AccountInfo<'a> {
250 let (key, account) = self;
251 let (lamports, data, owner, executable) = account.get();
252 AccountInfo::new(key, false, false, lamports, data, owner, executable)
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) = account.get();
262 AccountInfo::new(key, is_signer, false, lamports, data, owner, executable)
263 }
264}
265
266impl<'a, T: Account> IntoAccountInfo<'a> for &'a mut (Pubkey, T) {
268 fn into_account_info(self) -> AccountInfo<'a> {
269 let (ref key, account) = self;
270 let (lamports, data, owner, executable) = account.get();
271 AccountInfo::new(key, false, false, lamports, data, owner, executable)
272 }
273}
274
275pub fn next_account_info<'a, 'b, I: Iterator<Item = &'a AccountInfo<'b>>>(
320 iter: &mut I,
321) -> Result<I::Item, ProgramError> {
322 iter.next().ok_or(ProgramError::NotEnoughAccountKeys)
323}
324
325pub fn next_account_infos<'a, 'b: 'a>(
370 iter: &mut std::slice::Iter<'a, AccountInfo<'b>>,
371 count: usize,
372) -> Result<&'a [AccountInfo<'b>], ProgramError> {
373 let accounts = iter.as_slice();
374 if accounts.len() < count {
375 return Err(ProgramError::NotEnoughAccountKeys);
376 }
377 let (accounts, remaining) = accounts.split_at(count);
378 *iter = remaining.iter();
379 Ok(accounts)
380}
381
382impl<'a> AsRef<AccountInfo<'a>> for AccountInfo<'a> {
383 fn as_ref(&self) -> &AccountInfo<'a> {
384 self
385 }
386}
387
388#[doc(hidden)]
389#[allow(clippy::arithmetic_side_effects)]
390pub fn check_type_assumptions() {
391 use std::mem::offset_of;
392
393 let key = Pubkey::new_from_array([10; 32]);
394 let mut lamports = 31;
395 let mut data = vec![1, 2, 3, 4, 5];
396 let owner = Pubkey::new_from_array([22; 32]);
397 let account_info = AccountInfo::new(&key, true, false, &mut lamports, &mut data, &owner, true);
398 let account_info_addr = &account_info as *const _ as u64;
399
400 assert_eq!(offset_of!(AccountInfo, key), 0);
402 let key_ptr = (account_info_addr) as *const &Pubkey;
403 unsafe {
404 assert_eq!(**key_ptr, key);
405 }
406
407 assert_eq!(offset_of!(AccountInfo, lamports), 8);
409 let lamports_ptr = (account_info_addr + 8) as *const Rc<RefCell<&mut u64>>;
410 unsafe {
411 assert_eq!(**(*lamports_ptr).as_ptr(), 31);
412 }
413
414 assert_eq!(offset_of!(AccountInfo, data), 16);
416 let data_ptr = (account_info_addr + 16) as *const Rc<RefCell<&mut [u8]>>;
417 unsafe {
418 assert_eq!((&(*(*data_ptr).as_ptr()))[..], data[..]);
419 }
420
421 assert_eq!(offset_of!(AccountInfo, owner), 24);
423 let owner_ptr = (account_info_addr + 24) as *const &Pubkey;
424 unsafe {
425 assert_eq!(**owner_ptr, owner);
426 }
427
428 #[allow(deprecated)]
430 {
431 assert_eq!(offset_of!(AccountInfo, _unused), 32);
432 let unused_ptr = (account_info_addr + 32) as *const u64;
433 unsafe {
434 assert_eq!(*unused_ptr, 0);
435 }
436 }
437
438 assert_eq!(offset_of!(AccountInfo, is_signer), 40);
440 let is_signer_ptr = (account_info_addr + 40) as *const bool;
441 unsafe {
442 assert!(*is_signer_ptr);
443 }
444
445 assert_eq!(offset_of!(AccountInfo, is_writable), 41);
447 let is_writable_ptr = (account_info_addr + 41) as *const bool;
448 unsafe {
449 assert!(!*is_writable_ptr);
450 }
451
452 assert_eq!(offset_of!(AccountInfo, executable), 42);
454 let executable_ptr = (account_info_addr + 42) as *const bool;
455 unsafe {
456 assert!(*executable_ptr);
457 }
458}
459
460#[cfg(test)]
461mod tests {
462 use {
463 super::*,
464 crate::debug_account_data::{Hex, MAX_DEBUG_ACCOUNT_DATA},
465 };
466
467 #[test]
468 fn test_next_account_infos() {
469 let k1 = Pubkey::new_unique();
470 let k2 = Pubkey::new_unique();
471 let k3 = Pubkey::new_unique();
472 let k4 = Pubkey::new_unique();
473 let k5 = Pubkey::new_unique();
474 let l1 = &mut 0;
475 let l2 = &mut 0;
476 let l3 = &mut 0;
477 let l4 = &mut 0;
478 let l5 = &mut 0;
479 let d1 = &mut [0u8];
480 let d2 = &mut [0u8];
481 let d3 = &mut [0u8];
482 let d4 = &mut [0u8];
483 let d5 = &mut [0u8];
484
485 let infos = &[
486 AccountInfo::new(&k1, false, false, l1, d1, &k1, false),
487 AccountInfo::new(&k2, false, false, l2, d2, &k2, false),
488 AccountInfo::new(&k3, false, false, l3, d3, &k3, false),
489 AccountInfo::new(&k4, false, false, l4, d4, &k4, false),
490 AccountInfo::new(&k5, false, false, l5, d5, &k5, false),
491 ];
492 let infos_iter = &mut infos.iter();
493 let info1 = next_account_info(infos_iter).unwrap();
494 let info2_3_4 = next_account_infos(infos_iter, 3).unwrap();
495 let info5 = next_account_info(infos_iter).unwrap();
496
497 assert_eq!(k1, *info1.key);
498 assert_eq!(k2, *info2_3_4[0].key);
499 assert_eq!(k3, *info2_3_4[1].key);
500 assert_eq!(k4, *info2_3_4[2].key);
501 assert_eq!(k5, *info5.key);
502 }
503
504 #[test]
505 fn test_account_info_as_ref() {
506 let k = Pubkey::new_unique();
507 let l = &mut 0;
508 let d = &mut [0u8];
509 let info = AccountInfo::new(&k, false, false, l, d, &k, false);
510 assert_eq!(info.key, info.as_ref().key);
511 }
512
513 #[test]
514 fn test_account_info_debug_data() {
515 let key = Pubkey::new_unique();
516 let mut lamports = 42;
517 let mut data = vec![5; 80];
518 let data_str = format!("{:?}", Hex(&data[..MAX_DEBUG_ACCOUNT_DATA]));
519 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
520 assert_eq!(
521 format!("{info:?}"),
522 format!(
523 "AccountInfo {{ \
524 key: {}, \
525 owner: {}, \
526 is_signer: {}, \
527 is_writable: {}, \
528 executable: {}, \
529 lamports: {}, \
530 data.len: {}, \
531 data: {}, .. }}",
532 key,
533 key,
534 false,
535 false,
536 false,
537 lamports,
538 data.len(),
539 data_str,
540 )
541 );
542
543 let mut data = vec![5; 40];
544 let data_str = format!("{:?}", Hex(&data));
545 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
546 assert_eq!(
547 format!("{info:?}"),
548 format!(
549 "AccountInfo {{ \
550 key: {}, \
551 owner: {}, \
552 is_signer: {}, \
553 is_writable: {}, \
554 executable: {}, \
555 lamports: {}, \
556 data.len: {}, \
557 data: {}, .. }}",
558 key,
559 key,
560 false,
561 false,
562 false,
563 lamports,
564 data.len(),
565 data_str,
566 )
567 );
568
569 let mut data = vec![];
570 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
571 assert_eq!(
572 format!("{info:?}"),
573 format!(
574 "AccountInfo {{ \
575 key: {}, \
576 owner: {}, \
577 is_signer: {}, \
578 is_writable: {}, \
579 executable: {}, \
580 lamports: {}, \
581 data.len: {}, .. }}",
582 key,
583 key,
584 false,
585 false,
586 false,
587 lamports,
588 data.len(),
589 )
590 );
591 }
592
593 #[test]
594 fn test_layout_assumptions() {
595 super::check_type_assumptions();
596 }
597}