gemachain_program/
account_info.rs

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/// Account information
9#[derive(Clone)]
10pub struct AccountInfo<'a> {
11    /// Public key of the account
12    pub key: &'a Pubkey,
13    /// Was the transaction signed by this account's public key?
14    pub is_signer: bool,
15    /// Is the account writable?
16    pub is_writable: bool,
17    /// The carats in the account.  Modifiable by programs.
18    pub carats: Rc<RefCell<&'a mut u64>>,
19    /// The data held in this account.  Modifiable by programs.
20    pub data: Rc<RefCell<&'a mut [u8]>>,
21    /// Program that owns this account
22    pub owner: &'a Pubkey,
23    /// This account's data contains a loaded program (and is now read-only)
24    pub executable: bool,
25    /// The epoch at which this account will next owe rent
26    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
151/// Constructs an `AccountInfo` from self, used in conversion implementations.
152pub 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
161/// Provides information required to construct an `AccountInfo`, used in
162/// conversion implementations.
163pub trait Account {
164    fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch);
165}
166
167/// Convert (&'a Pubkey, &'a mut T) where T: Account into an `AccountInfo`
168impl<'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
178/// Convert (&'a Pubkey, bool, &'a mut T)  where T: Account into an
179/// `AccountInfo`.
180impl<'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
190/// Convert &'a mut (Pubkey, T) where T: Account into an `AccountInfo`.
191impl<'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
201/// Return the next `AccountInfo` or a `NotEnoughAccountKeys` error.
202pub 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
208/// Return a slice of the next `count` `AccountInfo`s or a
209/// `NotEnoughAccountKeys` error.
210pub 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}