1use crate::{clock::Epoch, program_error::ProgramError, pubkey::Pubkey};
2use std::{
3 cell::{Ref, RefCell, RefMut},
4 cmp, fmt,
5 rc::Rc,
6};
7
8#[derive(Clone)]
10pub struct AccountInfo<'a> {
11 pub key: &'a Pubkey,
13 pub is_signer: bool,
15 pub is_writable: bool,
17 pub carats: Rc<RefCell<&'a mut u64>>,
19 pub data: Rc<RefCell<&'a mut [u8]>>,
21 pub owner: &'a Pubkey,
23 pub executable: bool,
25 pub rent_epoch: Epoch,
27}
28
29impl<'a> fmt::Debug for AccountInfo<'a> {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 let data_len = cmp::min(64, self.data_len());
32 let data_str = if data_len > 0 {
33 format!(
34 " data: {} ...",
35 hex::encode(self.data.borrow()[..data_len].to_vec())
36 )
37 } else {
38 "".to_string()
39 };
40 write!(
41 f,
42 "AccountInfo {{ key: {} owner: {} is_signer: {} is_writable: {} executable: {} rent_epoch: {} carats: {} data.len: {} {} }}",
43 self.key,
44 self.owner,
45 self.is_signer,
46 self.is_writable,
47 self.executable,
48 self.rent_epoch,
49 self.carats(),
50 self.data_len(),
51 data_str,
52 )
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 carats(&self) -> u64 {
70 **self.carats.borrow()
71 }
72
73 pub fn try_carats(&self) -> Result<u64, ProgramError> {
74 Ok(**self.try_borrow_carats()?)
75 }
76
77 pub fn data_len(&self) -> usize {
78 self.data.borrow().len()
79 }
80
81 pub fn try_data_len(&self) -> Result<usize, ProgramError> {
82 Ok(self.try_borrow_data()?.len())
83 }
84
85 pub fn data_is_empty(&self) -> bool {
86 self.data.borrow().is_empty()
87 }
88
89 pub fn try_data_is_empty(&self) -> Result<bool, ProgramError> {
90 Ok(self.try_borrow_data()?.is_empty())
91 }
92
93 pub fn try_borrow_carats(&self) -> Result<Ref<&mut u64>, ProgramError> {
94 self.carats
95 .try_borrow()
96 .map_err(|_| ProgramError::AccountBorrowFailed)
97 }
98
99 pub fn try_borrow_mut_carats(&self) -> Result<RefMut<&'a mut u64>, ProgramError> {
100 self.carats
101 .try_borrow_mut()
102 .map_err(|_| ProgramError::AccountBorrowFailed)
103 }
104
105 pub fn try_borrow_data(&self) -> Result<Ref<&mut [u8]>, ProgramError> {
106 self.data
107 .try_borrow()
108 .map_err(|_| ProgramError::AccountBorrowFailed)
109 }
110
111 pub fn try_borrow_mut_data(&self) -> Result<RefMut<&'a mut [u8]>, ProgramError> {
112 self.data
113 .try_borrow_mut()
114 .map_err(|_| ProgramError::AccountBorrowFailed)
115 }
116
117 pub fn new(
118 key: &'a Pubkey,
119 is_signer: bool,
120 is_writable: bool,
121 carats: &'a mut u64,
122 data: &'a mut [u8],
123 owner: &'a Pubkey,
124 executable: bool,
125 rent_epoch: Epoch,
126 ) -> Self {
127 Self {
128 key,
129 is_signer,
130 is_writable,
131 carats: Rc::new(RefCell::new(carats)),
132 data: Rc::new(RefCell::new(data)),
133 owner,
134 executable,
135 rent_epoch,
136 }
137 }
138
139 pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
140 bincode::deserialize(&self.data.borrow())
141 }
142
143 pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
144 if bincode::serialized_size(state)? > self.data_len() as u64 {
145 return Err(Box::new(bincode::ErrorKind::SizeLimit));
146 }
147 bincode::serialize_into(&mut self.data.borrow_mut()[..], state)
148 }
149}
150
151pub trait IntoAccountInfo<'a> {
153 fn into_account_info(self) -> AccountInfo<'a>;
154}
155impl<'a, T: IntoAccountInfo<'a>> From<T> for AccountInfo<'a> {
156 fn from(src: T) -> Self {
157 src.into_account_info()
158 }
159}
160
161pub trait Account {
164 fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch);
165}
166
167impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, &'a mut T) {
169 fn into_account_info(self) -> AccountInfo<'a> {
170 let (key, account) = self;
171 let (carats, data, owner, executable, rent_epoch) = account.get();
172 AccountInfo::new(
173 key, false, false, carats, data, owner, executable, rent_epoch,
174 )
175 }
176}
177
178impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, bool, &'a mut T) {
181 fn into_account_info(self) -> AccountInfo<'a> {
182 let (key, is_signer, account) = self;
183 let (carats, data, owner, executable, rent_epoch) = account.get();
184 AccountInfo::new(
185 key, is_signer, false, carats, data, owner, executable, rent_epoch,
186 )
187 }
188}
189
190impl<'a, T: Account> IntoAccountInfo<'a> for &'a mut (Pubkey, T) {
192 fn into_account_info(self) -> AccountInfo<'a> {
193 let (ref key, account) = self;
194 let (carats, data, owner, executable, rent_epoch) = account.get();
195 AccountInfo::new(
196 key, false, false, carats, data, owner, executable, rent_epoch,
197 )
198 }
199}
200
201pub fn next_account_info<'a, 'b, I: Iterator<Item = &'a AccountInfo<'b>>>(
203 iter: &mut I,
204) -> Result<I::Item, ProgramError> {
205 iter.next().ok_or(ProgramError::NotEnoughAccountKeys)
206}
207
208pub fn next_account_infos<'a, 'b: 'a>(
211 iter: &mut std::slice::Iter<'a, AccountInfo<'b>>,
212 count: usize,
213) -> Result<&'a [AccountInfo<'b>], ProgramError> {
214 let accounts = iter.as_slice();
215 if accounts.len() < count {
216 return Err(ProgramError::NotEnoughAccountKeys);
217 }
218 let (accounts, remaining) = accounts.split_at(count);
219 *iter = remaining.iter();
220 Ok(accounts)
221}
222
223impl<'a> AsRef<AccountInfo<'a>> for AccountInfo<'a> {
224 fn as_ref(&self) -> &AccountInfo<'a> {
225 self
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 #[test]
234 fn test_next_account_infos() {
235 let k1 = Pubkey::new_unique();
236 let k2 = Pubkey::new_unique();
237 let k3 = Pubkey::new_unique();
238 let k4 = Pubkey::new_unique();
239 let k5 = Pubkey::new_unique();
240 let l1 = &mut 0;
241 let l2 = &mut 0;
242 let l3 = &mut 0;
243 let l4 = &mut 0;
244 let l5 = &mut 0;
245 let d1 = &mut [0u8];
246 let d2 = &mut [0u8];
247 let d3 = &mut [0u8];
248 let d4 = &mut [0u8];
249 let d5 = &mut [0u8];
250
251 let infos = &[
252 AccountInfo::new(&k1, false, false, l1, d1, &k1, false, 0),
253 AccountInfo::new(&k2, false, false, l2, d2, &k2, false, 0),
254 AccountInfo::new(&k3, false, false, l3, d3, &k3, false, 0),
255 AccountInfo::new(&k4, false, false, l4, d4, &k4, false, 0),
256 AccountInfo::new(&k5, false, false, l5, d5, &k5, false, 0),
257 ];
258 let infos_iter = &mut infos.iter();
259 let info1 = next_account_info(infos_iter).unwrap();
260 let info2_3_4 = next_account_infos(infos_iter, 3).unwrap();
261 let info5 = next_account_info(infos_iter).unwrap();
262
263 assert_eq!(k1, *info1.key);
264 assert_eq!(k2, *info2_3_4[0].key);
265 assert_eq!(k3, *info2_3_4[1].key);
266 assert_eq!(k4, *info2_3_4[2].key);
267 assert_eq!(k5, *info5.key);
268 }
269
270 #[test]
271 fn test_account_info_as_ref() {
272 let k = Pubkey::new_unique();
273 let l = &mut 0;
274 let d = &mut [0u8];
275 let info = AccountInfo::new(&k, false, false, l, d, &k, false, 0);
276 assert_eq!(info.key, info.as_ref().key);
277 }
278}