1#![cfg_attr(docsrs, feature(doc_cfg))]
3use {
4 solana_address::Address,
5 solana_program_error::ProgramError,
6 solana_program_memory::sol_memset,
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 Address,
25 pub lamports: Rc<RefCell<&'a mut u64>>,
27 pub data: Rc<RefCell<&'a mut [u8]>>,
29 pub owner: &'a Address,
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<&Address> {
66 if self.is_signer {
67 Some(self.key)
68 } else {
69 None
70 }
71 }
72
73 pub fn unsigned_key(&self) -> &Address {
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 { sol_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: &Address) {
186 unsafe {
188 std::ptr::write_volatile(
189 self.owner as *const Address as *mut [u8; 32],
190 new_owner.to_bytes(),
191 );
192 }
193 }
194
195 pub fn new(
196 key: &'a Address,
197 is_signer: bool,
198 is_writable: bool,
199 lamports: &'a mut u64,
200 data: &'a mut [u8],
201 owner: &'a Address,
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_core::de::DeserializeOwned>(
219 &self,
220 ) -> Result<T, bincode::Error> {
221 bincode::deserialize(&self.data.borrow())
222 }
223
224 #[cfg(feature = "bincode")]
225 pub fn serialize_data<T: serde_core::Serialize>(
226 &self,
227 state: &T,
228 ) -> Result<(), bincode::Error> {
229 if bincode::serialized_size(state)? > self.data_len() as u64 {
230 return Err(Box::new(bincode::ErrorKind::SizeLimit));
231 }
232 bincode::serialize_into(&mut self.data.borrow_mut()[..], state)
233 }
234}
235
236pub trait IntoAccountInfo<'a> {
238 fn into_account_info(self) -> AccountInfo<'a>;
239}
240impl<'a, T: IntoAccountInfo<'a>> From<T> for AccountInfo<'a> {
241 fn from(src: T) -> Self {
242 src.into_account_info()
243 }
244}
245
246pub trait Account {
249 fn get(&mut self) -> (&mut u64, &mut [u8], &Address, bool);
250}
251
252impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Address, &'a mut T) {
254 fn into_account_info(self) -> AccountInfo<'a> {
255 let (key, account) = self;
256 let (lamports, data, owner, executable) = account.get();
257 AccountInfo::new(key, false, false, lamports, data, owner, executable)
258 }
259}
260
261impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Address, bool, &'a mut T) {
264 fn into_account_info(self) -> AccountInfo<'a> {
265 let (key, is_signer, account) = self;
266 let (lamports, data, owner, executable) = account.get();
267 AccountInfo::new(key, is_signer, false, lamports, data, owner, executable)
268 }
269}
270
271impl<'a, T: Account> IntoAccountInfo<'a> for &'a mut (Address, T) {
273 fn into_account_info(self) -> AccountInfo<'a> {
274 let (ref key, account) = self;
275 let (lamports, data, owner, executable) = account.get();
276 AccountInfo::new(key, false, false, lamports, data, owner, executable)
277 }
278}
279
280pub 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>(
375 iter: &mut std::slice::Iter<'a, AccountInfo<'b>>,
376 count: usize,
377) -> Result<&'a [AccountInfo<'b>], ProgramError> {
378 let accounts = iter.as_slice();
379 if accounts.len() < count {
380 return Err(ProgramError::NotEnoughAccountKeys);
381 }
382 let (accounts, remaining) = accounts.split_at(count);
383 *iter = remaining.iter();
384 Ok(accounts)
385}
386
387impl<'a> AsRef<AccountInfo<'a>> for AccountInfo<'a> {
388 fn as_ref(&self) -> &AccountInfo<'a> {
389 self
390 }
391}
392
393#[doc(hidden)]
394#[allow(clippy::arithmetic_side_effects)]
395pub fn check_type_assumptions() {
396 use std::mem::offset_of;
397
398 let key = Address::new_from_array([10; 32]);
399 let mut lamports = 31;
400 let mut data = vec![1, 2, 3, 4, 5];
401 let owner = Address::new_from_array([22; 32]);
402 let account_info = AccountInfo::new(&key, true, false, &mut lamports, &mut data, &owner, true);
403 let account_info_addr = &account_info as *const _ as u64;
404
405 assert_eq!(offset_of!(AccountInfo, key), 0);
407 let key_ptr = (account_info_addr) as *const &Address;
408 unsafe {
409 assert_eq!(**key_ptr, key);
410 }
411
412 assert_eq!(offset_of!(AccountInfo, lamports), 8);
414 let lamports_ptr = (account_info_addr + 8) as *const Rc<RefCell<&mut u64>>;
415 unsafe {
416 assert_eq!(**(*lamports_ptr).as_ptr(), 31);
417 }
418
419 assert_eq!(offset_of!(AccountInfo, data), 16);
421 let data_ptr = (account_info_addr + 16) as *const Rc<RefCell<&mut [u8]>>;
422 unsafe {
423 assert_eq!((&(*(*data_ptr).as_ptr()))[..], data[..]);
424 }
425
426 assert_eq!(offset_of!(AccountInfo, owner), 24);
428 let owner_ptr = (account_info_addr + 24) as *const &Address;
429 unsafe {
430 assert_eq!(**owner_ptr, owner);
431 }
432
433 #[allow(deprecated)]
435 {
436 assert_eq!(offset_of!(AccountInfo, _unused), 32);
437 let unused_ptr = (account_info_addr + 32) as *const u64;
438 unsafe {
439 assert_eq!(*unused_ptr, 0);
440 }
441 }
442
443 assert_eq!(offset_of!(AccountInfo, is_signer), 40);
445 let is_signer_ptr = (account_info_addr + 40) as *const bool;
446 unsafe {
447 assert!(*is_signer_ptr);
448 }
449
450 assert_eq!(offset_of!(AccountInfo, is_writable), 41);
452 let is_writable_ptr = (account_info_addr + 41) as *const bool;
453 unsafe {
454 assert!(!*is_writable_ptr);
455 }
456
457 assert_eq!(offset_of!(AccountInfo, executable), 42);
459 let executable_ptr = (account_info_addr + 42) as *const bool;
460 unsafe {
461 assert!(*executable_ptr);
462 }
463}
464
465#[cfg(test)]
466mod tests {
467 use {
468 super::*,
469 crate::debug_account_data::{Hex, MAX_DEBUG_ACCOUNT_DATA},
470 };
471
472 #[test]
473 fn test_next_account_infos() {
474 let k1 = Address::new_unique();
475 let k2 = Address::new_unique();
476 let k3 = Address::new_unique();
477 let k4 = Address::new_unique();
478 let k5 = Address::new_unique();
479 let l1 = &mut 0;
480 let l2 = &mut 0;
481 let l3 = &mut 0;
482 let l4 = &mut 0;
483 let l5 = &mut 0;
484 let d1 = &mut [0u8];
485 let d2 = &mut [0u8];
486 let d3 = &mut [0u8];
487 let d4 = &mut [0u8];
488 let d5 = &mut [0u8];
489
490 let infos = &[
491 AccountInfo::new(&k1, false, false, l1, d1, &k1, false),
492 AccountInfo::new(&k2, false, false, l2, d2, &k2, false),
493 AccountInfo::new(&k3, false, false, l3, d3, &k3, false),
494 AccountInfo::new(&k4, false, false, l4, d4, &k4, false),
495 AccountInfo::new(&k5, false, false, l5, d5, &k5, false),
496 ];
497 let infos_iter = &mut infos.iter();
498 let info1 = next_account_info(infos_iter).unwrap();
499 let info2_3_4 = next_account_infos(infos_iter, 3).unwrap();
500 let info5 = next_account_info(infos_iter).unwrap();
501
502 assert_eq!(k1, *info1.key);
503 assert_eq!(k2, *info2_3_4[0].key);
504 assert_eq!(k3, *info2_3_4[1].key);
505 assert_eq!(k4, *info2_3_4[2].key);
506 assert_eq!(k5, *info5.key);
507 }
508
509 #[test]
510 fn test_account_info_as_ref() {
511 let k = Address::new_unique();
512 let l = &mut 0;
513 let d = &mut [0u8];
514 let info = AccountInfo::new(&k, false, false, l, d, &k, false);
515 assert_eq!(info.key, info.as_ref().key);
516 }
517
518 #[test]
519 fn test_account_info_debug_data() {
520 let key = Address::new_unique();
521 let mut lamports = 42;
522 let mut data = vec![5; 80];
523 let data_str = format!("{:?}", Hex(&data[..MAX_DEBUG_ACCOUNT_DATA]));
524 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
525 assert_eq!(
526 format!("{info:?}"),
527 format!(
528 "AccountInfo {{ \
529 key: {}, \
530 owner: {}, \
531 is_signer: {}, \
532 is_writable: {}, \
533 executable: {}, \
534 lamports: {}, \
535 data.len: {}, \
536 data: {}, .. }}",
537 key,
538 key,
539 false,
540 false,
541 false,
542 lamports,
543 data.len(),
544 data_str,
545 )
546 );
547
548 let mut data = vec![5; 40];
549 let data_str = format!("{:?}", Hex(&data));
550 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
551 assert_eq!(
552 format!("{info:?}"),
553 format!(
554 "AccountInfo {{ \
555 key: {}, \
556 owner: {}, \
557 is_signer: {}, \
558 is_writable: {}, \
559 executable: {}, \
560 lamports: {}, \
561 data.len: {}, \
562 data: {}, .. }}",
563 key,
564 key,
565 false,
566 false,
567 false,
568 lamports,
569 data.len(),
570 data_str,
571 )
572 );
573
574 let mut data = vec![];
575 let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false);
576 assert_eq!(
577 format!("{info:?}"),
578 format!(
579 "AccountInfo {{ \
580 key: {}, \
581 owner: {}, \
582 is_signer: {}, \
583 is_writable: {}, \
584 executable: {}, \
585 lamports: {}, \
586 data.len: {}, .. }}",
587 key,
588 key,
589 false,
590 false,
591 false,
592 lamports,
593 data.len(),
594 )
595 );
596 }
597
598 #[test]
599 fn test_layout_assumptions() {
600 super::check_type_assumptions();
601 }
602}