cbe_sdk/
account.rs

1//! The Cartallum CBE [`Account`] type.
2
3use {
4    crate::{
5        clock::{Epoch, INITIAL_RENT_EPOCH},
6        scoobies::ScoobiesError,
7        pubkey::Pubkey,
8    },
9    serde::{
10        ser::{Serialize, Serializer},
11        Deserialize,
12    },
13    cbe_program::{account_info::AccountInfo, debug_account_data::*, sysvar::Sysvar},
14    std::{
15        cell::{Ref, RefCell},
16        fmt, ptr,
17        rc::Rc,
18        sync::Arc,
19    },
20};
21
22/// An Account with data that is stored on chain
23#[repr(C)]
24#[frozen_abi(digest = "HawRVHh7t4d3H3bitWHFt25WhhoDmbJMCfWdESQQoYEy")]
25#[derive(Deserialize, PartialEq, Eq, Clone, Default, AbiExample)]
26#[serde(rename_all = "camelCase")]
27pub struct Account {
28    /// scoobies in the account
29    pub scoobies: u64,
30    /// data held in this account
31    #[serde(with = "serde_bytes")]
32    pub data: Vec<u8>,
33    /// the program that owns this account. If executable, the program that loads this account.
34    pub owner: Pubkey,
35    /// this account's data contains a loaded program (and is now read-only)
36    pub executable: bool,
37    /// the epoch at which this account will next owe rent
38    pub rent_epoch: Epoch,
39}
40
41// mod because we need 'Account' below to have the name 'Account' to match expected serialization
42mod account_serialize {
43    use {
44        crate::{account::ReadableAccount, clock::Epoch, pubkey::Pubkey},
45        serde::{ser::Serializer, Serialize},
46    };
47    #[repr(C)]
48    #[frozen_abi(digest = "HawRVHh7t4d3H3bitWHFt25WhhoDmbJMCfWdESQQoYEy")]
49    #[derive(Serialize, AbiExample)]
50    #[serde(rename_all = "camelCase")]
51    struct Account<'a> {
52        scoobies: u64,
53        #[serde(with = "serde_bytes")]
54        // a slice so we don't have to make a copy just to serialize this
55        data: &'a [u8],
56        // can't be &pubkey because abi example doesn't support it
57        owner: Pubkey,
58        executable: bool,
59        rent_epoch: Epoch,
60    }
61
62    /// allows us to implement serialize on AccountSharedData that is equivalent to Account::serialize without making a copy of the Vec<u8>
63    pub fn serialize_account<S>(
64        account: &(impl ReadableAccount + Serialize),
65        serializer: S,
66    ) -> Result<S::Ok, S::Error>
67    where
68        S: Serializer,
69    {
70        let temp = Account {
71            scoobies: account.scoobies(),
72            data: account.data(),
73            owner: *account.owner(),
74            executable: account.executable(),
75            rent_epoch: account.rent_epoch(),
76        };
77        temp.serialize(serializer)
78    }
79}
80
81impl Serialize for Account {
82    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83    where
84        S: Serializer,
85    {
86        crate::account::account_serialize::serialize_account(self, serializer)
87    }
88}
89
90impl Serialize for AccountSharedData {
91    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92    where
93        S: Serializer,
94    {
95        crate::account::account_serialize::serialize_account(self, serializer)
96    }
97}
98
99/// An Account with data that is stored on chain
100/// This will be the in-memory representation of the 'Account' struct data.
101/// The existing 'Account' structure cannot easily change due to downstream projects.
102#[derive(PartialEq, Eq, Clone, Default, AbiExample, Deserialize)]
103#[serde(from = "Account")]
104pub struct AccountSharedData {
105    /// scoobies in the account
106    scoobies: u64,
107    /// data held in this account
108    data: Arc<Vec<u8>>,
109    /// the program that owns this account. If executable, the program that loads this account.
110    owner: Pubkey,
111    /// this account's data contains a loaded program (and is now read-only)
112    executable: bool,
113    /// the epoch at which this account will next owe rent
114    rent_epoch: Epoch,
115}
116
117/// Compares two ReadableAccounts
118///
119/// Returns true if accounts are essentially equivalent as in all fields are equivalent.
120pub fn accounts_equal<T: ReadableAccount, U: ReadableAccount>(me: &T, other: &U) -> bool {
121    me.scoobies() == other.scoobies()
122        && me.executable() == other.executable()
123        && me.rent_epoch() == other.rent_epoch()
124        && me.owner() == other.owner()
125        && me.data() == other.data()
126}
127
128impl From<AccountSharedData> for Account {
129    fn from(mut other: AccountSharedData) -> Self {
130        let account_data = Arc::make_mut(&mut other.data);
131        Self {
132            scoobies: other.scoobies,
133            data: std::mem::take(account_data),
134            owner: other.owner,
135            executable: other.executable,
136            rent_epoch: other.rent_epoch,
137        }
138    }
139}
140
141impl From<Account> for AccountSharedData {
142    fn from(other: Account) -> Self {
143        Self {
144            scoobies: other.scoobies,
145            data: Arc::new(other.data),
146            owner: other.owner,
147            executable: other.executable,
148            rent_epoch: other.rent_epoch,
149        }
150    }
151}
152
153pub trait WritableAccount: ReadableAccount {
154    fn set_scoobies(&mut self, scoobies: u64);
155    fn checked_add_scoobies(&mut self, scoobies: u64) -> Result<(), ScoobiesError> {
156        self.set_scoobies(
157            self.scoobies()
158                .checked_add(scoobies)
159                .ok_or(ScoobiesError::ArithmeticOverflow)?,
160        );
161        Ok(())
162    }
163    fn checked_sub_scoobies(&mut self, scoobies: u64) -> Result<(), ScoobiesError> {
164        self.set_scoobies(
165            self.scoobies()
166                .checked_sub(scoobies)
167                .ok_or(ScoobiesError::ArithmeticUnderflow)?,
168        );
169        Ok(())
170    }
171    fn saturating_add_scoobies(&mut self, scoobies: u64) {
172        self.set_scoobies(self.scoobies().saturating_add(scoobies))
173    }
174    fn saturating_sub_scoobies(&mut self, scoobies: u64) {
175        self.set_scoobies(self.scoobies().saturating_sub(scoobies))
176    }
177    fn data_mut(&mut self) -> &mut Vec<u8>;
178    fn data_as_mut_slice(&mut self) -> &mut [u8];
179    fn set_owner(&mut self, owner: Pubkey);
180    fn copy_into_owner_from_slice(&mut self, source: &[u8]);
181    fn set_executable(&mut self, executable: bool);
182    fn set_rent_epoch(&mut self, epoch: Epoch);
183    fn create(
184        scoobies: u64,
185        data: Vec<u8>,
186        owner: Pubkey,
187        executable: bool,
188        rent_epoch: Epoch,
189    ) -> Self;
190}
191
192pub trait ReadableAccount: Sized {
193    fn scoobies(&self) -> u64;
194    fn data(&self) -> &[u8];
195    fn owner(&self) -> &Pubkey;
196    fn executable(&self) -> bool;
197    fn rent_epoch(&self) -> Epoch;
198    fn to_account_shared_data(&self) -> AccountSharedData {
199        AccountSharedData::create(
200            self.scoobies(),
201            self.data().to_vec(),
202            *self.owner(),
203            self.executable(),
204            self.rent_epoch(),
205        )
206    }
207}
208
209impl ReadableAccount for Account {
210    fn scoobies(&self) -> u64 {
211        self.scoobies
212    }
213    fn data(&self) -> &[u8] {
214        &self.data
215    }
216    fn owner(&self) -> &Pubkey {
217        &self.owner
218    }
219    fn executable(&self) -> bool {
220        self.executable
221    }
222    fn rent_epoch(&self) -> Epoch {
223        self.rent_epoch
224    }
225}
226
227impl WritableAccount for Account {
228    fn set_scoobies(&mut self, scoobies: u64) {
229        self.scoobies = scoobies;
230    }
231    fn data_mut(&mut self) -> &mut Vec<u8> {
232        &mut self.data
233    }
234    fn data_as_mut_slice(&mut self) -> &mut [u8] {
235        &mut self.data
236    }
237    fn set_owner(&mut self, owner: Pubkey) {
238        self.owner = owner;
239    }
240    fn copy_into_owner_from_slice(&mut self, source: &[u8]) {
241        self.owner.as_mut().copy_from_slice(source);
242    }
243    fn set_executable(&mut self, executable: bool) {
244        self.executable = executable;
245    }
246    fn set_rent_epoch(&mut self, epoch: Epoch) {
247        self.rent_epoch = epoch;
248    }
249    fn create(
250        scoobies: u64,
251        data: Vec<u8>,
252        owner: Pubkey,
253        executable: bool,
254        rent_epoch: Epoch,
255    ) -> Self {
256        Account {
257            scoobies,
258            data,
259            owner,
260            executable,
261            rent_epoch,
262        }
263    }
264}
265
266impl WritableAccount for AccountSharedData {
267    fn set_scoobies(&mut self, scoobies: u64) {
268        self.scoobies = scoobies;
269    }
270    fn data_mut(&mut self) -> &mut Vec<u8> {
271        Arc::make_mut(&mut self.data)
272    }
273    fn data_as_mut_slice(&mut self) -> &mut [u8] {
274        &mut self.data_mut()[..]
275    }
276    fn set_owner(&mut self, owner: Pubkey) {
277        self.owner = owner;
278    }
279    fn copy_into_owner_from_slice(&mut self, source: &[u8]) {
280        self.owner.as_mut().copy_from_slice(source);
281    }
282    fn set_executable(&mut self, executable: bool) {
283        self.executable = executable;
284    }
285    fn set_rent_epoch(&mut self, epoch: Epoch) {
286        self.rent_epoch = epoch;
287    }
288    fn create(
289        scoobies: u64,
290        data: Vec<u8>,
291        owner: Pubkey,
292        executable: bool,
293        rent_epoch: Epoch,
294    ) -> Self {
295        AccountSharedData {
296            scoobies,
297            data: Arc::new(data),
298            owner,
299            executable,
300            rent_epoch,
301        }
302    }
303}
304
305impl ReadableAccount for AccountSharedData {
306    fn scoobies(&self) -> u64 {
307        self.scoobies
308    }
309    fn data(&self) -> &[u8] {
310        &self.data
311    }
312    fn owner(&self) -> &Pubkey {
313        &self.owner
314    }
315    fn executable(&self) -> bool {
316        self.executable
317    }
318    fn rent_epoch(&self) -> Epoch {
319        self.rent_epoch
320    }
321    fn to_account_shared_data(&self) -> AccountSharedData {
322        // avoid data copy here
323        self.clone()
324    }
325}
326
327impl ReadableAccount for Ref<'_, AccountSharedData> {
328    fn scoobies(&self) -> u64 {
329        self.scoobies
330    }
331    fn data(&self) -> &[u8] {
332        &self.data
333    }
334    fn owner(&self) -> &Pubkey {
335        &self.owner
336    }
337    fn executable(&self) -> bool {
338        self.executable
339    }
340    fn rent_epoch(&self) -> Epoch {
341        self.rent_epoch
342    }
343    fn to_account_shared_data(&self) -> AccountSharedData {
344        AccountSharedData {
345            scoobies: self.scoobies(),
346            // avoid data copy here
347            data: Arc::clone(&self.data),
348            owner: *self.owner(),
349            executable: self.executable(),
350            rent_epoch: self.rent_epoch(),
351        }
352    }
353}
354
355impl ReadableAccount for Ref<'_, Account> {
356    fn scoobies(&self) -> u64 {
357        self.scoobies
358    }
359    fn data(&self) -> &[u8] {
360        &self.data
361    }
362    fn owner(&self) -> &Pubkey {
363        &self.owner
364    }
365    fn executable(&self) -> bool {
366        self.executable
367    }
368    fn rent_epoch(&self) -> Epoch {
369        self.rent_epoch
370    }
371}
372
373fn debug_fmt<T: ReadableAccount>(item: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374    let mut f = f.debug_struct("Account");
375
376    f.field("scoobies", &item.scoobies())
377        .field("data.len", &item.data().len())
378        .field("owner", &item.owner())
379        .field("executable", &item.executable())
380        .field("rent_epoch", &item.rent_epoch());
381    debug_account_data(item.data(), &mut f);
382
383    f.finish()
384}
385
386impl fmt::Debug for Account {
387    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388        debug_fmt(self, f)
389    }
390}
391
392impl fmt::Debug for AccountSharedData {
393    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394        debug_fmt(self, f)
395    }
396}
397
398fn shared_new<T: WritableAccount>(scoobies: u64, space: usize, owner: &Pubkey) -> T {
399    T::create(
400        scoobies,
401        vec![0u8; space],
402        *owner,
403        bool::default(),
404        Epoch::default(),
405    )
406}
407
408fn shared_new_rent_epoch<T: WritableAccount>(
409    scoobies: u64,
410    space: usize,
411    owner: &Pubkey,
412    rent_epoch: Epoch,
413) -> T {
414    T::create(
415        scoobies,
416        vec![0u8; space],
417        *owner,
418        bool::default(),
419        rent_epoch,
420    )
421}
422
423fn shared_new_ref<T: WritableAccount>(
424    scoobies: u64,
425    space: usize,
426    owner: &Pubkey,
427) -> Rc<RefCell<T>> {
428    Rc::new(RefCell::new(shared_new::<T>(scoobies, space, owner)))
429}
430
431fn shared_new_data<T: serde::Serialize, U: WritableAccount>(
432    scoobies: u64,
433    state: &T,
434    owner: &Pubkey,
435) -> Result<U, bincode::Error> {
436    let data = bincode::serialize(state)?;
437    Ok(U::create(
438        scoobies,
439        data,
440        *owner,
441        bool::default(),
442        Epoch::default(),
443    ))
444}
445fn shared_new_ref_data<T: serde::Serialize, U: WritableAccount>(
446    scoobies: u64,
447    state: &T,
448    owner: &Pubkey,
449) -> Result<RefCell<U>, bincode::Error> {
450    Ok(RefCell::new(shared_new_data::<T, U>(
451        scoobies, state, owner,
452    )?))
453}
454
455fn shared_new_data_with_space<T: serde::Serialize, U: WritableAccount>(
456    scoobies: u64,
457    state: &T,
458    space: usize,
459    owner: &Pubkey,
460) -> Result<U, bincode::Error> {
461    let mut account = shared_new::<U>(scoobies, space, owner);
462
463    shared_serialize_data(&mut account, state)?;
464
465    Ok(account)
466}
467fn shared_new_ref_data_with_space<T: serde::Serialize, U: WritableAccount>(
468    scoobies: u64,
469    state: &T,
470    space: usize,
471    owner: &Pubkey,
472) -> Result<RefCell<U>, bincode::Error> {
473    Ok(RefCell::new(shared_new_data_with_space::<T, U>(
474        scoobies, state, space, owner,
475    )?))
476}
477
478fn shared_deserialize_data<T: serde::de::DeserializeOwned, U: ReadableAccount>(
479    account: &U,
480) -> Result<T, bincode::Error> {
481    bincode::deserialize(account.data())
482}
483
484fn shared_serialize_data<T: serde::Serialize, U: WritableAccount>(
485    account: &mut U,
486    state: &T,
487) -> Result<(), bincode::Error> {
488    if bincode::serialized_size(state)? > account.data().len() as u64 {
489        return Err(Box::new(bincode::ErrorKind::SizeLimit));
490    }
491    bincode::serialize_into(account.data_as_mut_slice(), state)
492}
493
494impl Account {
495    pub fn new(scoobies: u64, space: usize, owner: &Pubkey) -> Self {
496        shared_new(scoobies, space, owner)
497    }
498    pub fn new_ref(scoobies: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
499        shared_new_ref(scoobies, space, owner)
500    }
501    pub fn new_data<T: serde::Serialize>(
502        scoobies: u64,
503        state: &T,
504        owner: &Pubkey,
505    ) -> Result<Self, bincode::Error> {
506        shared_new_data(scoobies, state, owner)
507    }
508    pub fn new_ref_data<T: serde::Serialize>(
509        scoobies: u64,
510        state: &T,
511        owner: &Pubkey,
512    ) -> Result<RefCell<Self>, bincode::Error> {
513        shared_new_ref_data(scoobies, state, owner)
514    }
515    pub fn new_data_with_space<T: serde::Serialize>(
516        scoobies: u64,
517        state: &T,
518        space: usize,
519        owner: &Pubkey,
520    ) -> Result<Self, bincode::Error> {
521        shared_new_data_with_space(scoobies, state, space, owner)
522    }
523    pub fn new_ref_data_with_space<T: serde::Serialize>(
524        scoobies: u64,
525        state: &T,
526        space: usize,
527        owner: &Pubkey,
528    ) -> Result<RefCell<Self>, bincode::Error> {
529        shared_new_ref_data_with_space(scoobies, state, space, owner)
530    }
531    pub fn new_rent_epoch(scoobies: u64, space: usize, owner: &Pubkey, rent_epoch: Epoch) -> Self {
532        shared_new_rent_epoch(scoobies, space, owner, rent_epoch)
533    }
534    pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
535        shared_deserialize_data(self)
536    }
537    pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
538        shared_serialize_data(self, state)
539    }
540}
541
542impl AccountSharedData {
543    pub fn set_data_from_slice(&mut self, new_data: &[u8]) {
544        let data = match Arc::get_mut(&mut self.data) {
545            // The buffer isn't shared, so we're going to memcpy in place.
546            Some(data) => data,
547            // If the buffer is shared, the cheapest thing to do is to clone the
548            // incoming slice and replace the buffer.
549            None => return self.set_data(new_data.to_vec()),
550        };
551
552        let new_len = new_data.len();
553
554        // Reserve additional capacity if needed. Here we make the assumption
555        // that growing the current buffer is cheaper than doing a whole new
556        // allocation to make `new_data` owned.
557        //
558        // This assumption holds true during CPI, especially when the account
559        // size doesn't change but the account is only changed in place. And
560        // it's also true when the account is grown by a small margin (the
561        // realloc limit is quite low), in which case the allocator can just
562        // update the allocation metadata without moving.
563        //
564        // Shrinking and copying in place is always faster than making
565        // `new_data` owned, since shrinking boils down to updating the Vec's
566        // length.
567
568        data.reserve(new_len.saturating_sub(data.len()));
569
570        // Safety:
571        // We just reserved enough capacity. We set data::len to 0 to avoid
572        // possible UB on panic (dropping uninitialized elements), do the copy,
573        // finally set the new length once everything is initialized.
574        #[allow(clippy::uninit_vec)]
575        // this is a false positive, the lint doesn't currently special case set_len(0)
576        unsafe {
577            data.set_len(0);
578            ptr::copy_nonoverlapping(new_data.as_ptr(), data.as_mut_ptr(), new_len);
579            data.set_len(new_len);
580        };
581    }
582
583    pub fn set_data(&mut self, data: Vec<u8>) {
584        self.data = Arc::new(data);
585    }
586
587    pub fn new(scoobies: u64, space: usize, owner: &Pubkey) -> Self {
588        shared_new(scoobies, space, owner)
589    }
590    pub fn new_ref(scoobies: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
591        shared_new_ref(scoobies, space, owner)
592    }
593    pub fn new_data<T: serde::Serialize>(
594        scoobies: u64,
595        state: &T,
596        owner: &Pubkey,
597    ) -> Result<Self, bincode::Error> {
598        shared_new_data(scoobies, state, owner)
599    }
600    pub fn new_ref_data<T: serde::Serialize>(
601        scoobies: u64,
602        state: &T,
603        owner: &Pubkey,
604    ) -> Result<RefCell<Self>, bincode::Error> {
605        shared_new_ref_data(scoobies, state, owner)
606    }
607    pub fn new_data_with_space<T: serde::Serialize>(
608        scoobies: u64,
609        state: &T,
610        space: usize,
611        owner: &Pubkey,
612    ) -> Result<Self, bincode::Error> {
613        shared_new_data_with_space(scoobies, state, space, owner)
614    }
615    pub fn new_ref_data_with_space<T: serde::Serialize>(
616        scoobies: u64,
617        state: &T,
618        space: usize,
619        owner: &Pubkey,
620    ) -> Result<RefCell<Self>, bincode::Error> {
621        shared_new_ref_data_with_space(scoobies, state, space, owner)
622    }
623    pub fn new_rent_epoch(scoobies: u64, space: usize, owner: &Pubkey, rent_epoch: Epoch) -> Self {
624        shared_new_rent_epoch(scoobies, space, owner, rent_epoch)
625    }
626    pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
627        shared_deserialize_data(self)
628    }
629    pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
630        shared_serialize_data(self, state)
631    }
632}
633
634pub type InheritableAccountFields = (u64, Epoch);
635pub const DUMMY_INHERITABLE_ACCOUNT_FIELDS: InheritableAccountFields = (1, INITIAL_RENT_EPOCH);
636
637/// Create an `Account` from a `Sysvar`.
638#[deprecated(
639    since = "1.5.17",
640    note = "Please use `create_account_for_test` instead"
641)]
642pub fn create_account<S: Sysvar>(sysvar: &S, scoobies: u64) -> Account {
643    create_account_with_fields(sysvar, (scoobies, INITIAL_RENT_EPOCH))
644}
645
646pub fn create_account_with_fields<S: Sysvar>(
647    sysvar: &S,
648    (scoobies, rent_epoch): InheritableAccountFields,
649) -> Account {
650    let data_len = S::size_of().max(bincode::serialized_size(sysvar).unwrap() as usize);
651    let mut account = Account::new(scoobies, data_len, &cbe_program::sysvar::id());
652    to_account::<S, Account>(sysvar, &mut account).unwrap();
653    account.rent_epoch = rent_epoch;
654    account
655}
656
657pub fn create_account_for_test<S: Sysvar>(sysvar: &S) -> Account {
658    create_account_with_fields(sysvar, DUMMY_INHERITABLE_ACCOUNT_FIELDS)
659}
660
661/// Create an `Account` from a `Sysvar`.
662#[deprecated(
663    since = "1.5.17",
664    note = "Please use `create_account_shared_data_for_test` instead"
665)]
666pub fn create_account_shared_data<S: Sysvar>(sysvar: &S, scoobies: u64) -> AccountSharedData {
667    AccountSharedData::from(create_account_with_fields(
668        sysvar,
669        (scoobies, INITIAL_RENT_EPOCH),
670    ))
671}
672
673pub fn create_account_shared_data_with_fields<S: Sysvar>(
674    sysvar: &S,
675    fields: InheritableAccountFields,
676) -> AccountSharedData {
677    AccountSharedData::from(create_account_with_fields(sysvar, fields))
678}
679
680pub fn create_account_shared_data_for_test<S: Sysvar>(sysvar: &S) -> AccountSharedData {
681    AccountSharedData::from(create_account_with_fields(
682        sysvar,
683        DUMMY_INHERITABLE_ACCOUNT_FIELDS,
684    ))
685}
686
687/// Create a `Sysvar` from an `Account`'s data.
688pub fn from_account<S: Sysvar, T: ReadableAccount>(account: &T) -> Option<S> {
689    bincode::deserialize(account.data()).ok()
690}
691
692/// Serialize a `Sysvar` into an `Account`'s data.
693pub fn to_account<S: Sysvar, T: WritableAccount>(sysvar: &S, account: &mut T) -> Option<()> {
694    bincode::serialize_into(account.data_as_mut_slice(), sysvar).ok()
695}
696
697/// Return the information required to construct an `AccountInfo`.  Used by the
698/// `AccountInfo` conversion implementations.
699impl cbe_program::account_info::Account for Account {
700    fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch) {
701        (
702            &mut self.scoobies,
703            &mut self.data,
704            &self.owner,
705            self.executable,
706            self.rent_epoch,
707        )
708    }
709}
710
711/// Create `AccountInfo`s
712pub fn create_is_signer_account_infos<'a>(
713    accounts: &'a mut [(&'a Pubkey, bool, &'a mut Account)],
714) -> Vec<AccountInfo<'a>> {
715    accounts
716        .iter_mut()
717        .map(|(key, is_signer, account)| {
718            AccountInfo::new(
719                key,
720                *is_signer,
721                false,
722                &mut account.scoobies,
723                &mut account.data,
724                &account.owner,
725                account.executable,
726                account.rent_epoch,
727            )
728        })
729        .collect()
730}
731
732#[cfg(test)]
733pub mod tests {
734    use super::*;
735
736    fn make_two_accounts(key: &Pubkey) -> (Account, AccountSharedData) {
737        let mut account1 = Account::new(1, 2, key);
738        account1.executable = true;
739        account1.rent_epoch = 4;
740        let mut account2 = AccountSharedData::new(1, 2, key);
741        account2.executable = true;
742        account2.rent_epoch = 4;
743        assert!(accounts_equal(&account1, &account2));
744        (account1, account2)
745    }
746
747    #[test]
748    fn test_account_data_copy_as_slice() {
749        let key = Pubkey::new_unique();
750        let key2 = Pubkey::new_unique();
751        let (mut account1, mut account2) = make_two_accounts(&key);
752        account1.copy_into_owner_from_slice(key2.as_ref());
753        account2.copy_into_owner_from_slice(key2.as_ref());
754        assert!(accounts_equal(&account1, &account2));
755        assert_eq!(account1.owner(), &key2);
756    }
757
758    #[test]
759    fn test_account_set_data_from_slice() {
760        let key = Pubkey::new_unique();
761        let (_, mut account) = make_two_accounts(&key);
762        assert_eq!(account.data(), &vec![0, 0]);
763        account.set_data_from_slice(&[1, 2]);
764        assert_eq!(account.data(), &vec![1, 2]);
765        account.set_data_from_slice(&[1, 2, 3]);
766        assert_eq!(account.data(), &vec![1, 2, 3]);
767        account.set_data_from_slice(&[4, 5, 6]);
768        assert_eq!(account.data(), &vec![4, 5, 6]);
769        account.set_data_from_slice(&[4, 5, 6, 0]);
770        assert_eq!(account.data(), &vec![4, 5, 6, 0]);
771        account.set_data_from_slice(&[]);
772        assert_eq!(account.data().len(), 0);
773        account.set_data_from_slice(&[44]);
774        assert_eq!(account.data(), &vec![44]);
775        account.set_data_from_slice(&[44]);
776        assert_eq!(account.data(), &vec![44]);
777    }
778
779    #[test]
780    fn test_account_data_set_data() {
781        let key = Pubkey::new_unique();
782        let (_, mut account) = make_two_accounts(&key);
783        assert_eq!(account.data(), &vec![0, 0]);
784        account.set_data(vec![1, 2]);
785        assert_eq!(account.data(), &vec![1, 2]);
786        account.set_data(vec![]);
787        assert_eq!(account.data().len(), 0);
788    }
789
790    #[test]
791    #[should_panic(
792        expected = "called `Result::unwrap()` on an `Err` value: Io(Kind(UnexpectedEof))"
793    )]
794    fn test_account_deserialize() {
795        let key = Pubkey::new_unique();
796        let (account1, _account2) = make_two_accounts(&key);
797        account1.deserialize_data::<String>().unwrap();
798    }
799
800    #[test]
801    #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: SizeLimit")]
802    fn test_account_serialize() {
803        let key = Pubkey::new_unique();
804        let (mut account1, _account2) = make_two_accounts(&key);
805        account1.serialize_data(&"hello world").unwrap();
806    }
807
808    #[test]
809    #[should_panic(
810        expected = "called `Result::unwrap()` on an `Err` value: Io(Kind(UnexpectedEof))"
811    )]
812    fn test_account_shared_data_deserialize() {
813        let key = Pubkey::new_unique();
814        let (_account1, account2) = make_two_accounts(&key);
815        account2.deserialize_data::<String>().unwrap();
816    }
817
818    #[test]
819    #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: SizeLimit")]
820    fn test_account_shared_data_serialize() {
821        let key = Pubkey::new_unique();
822        let (_account1, mut account2) = make_two_accounts(&key);
823        account2.serialize_data(&"hello world").unwrap();
824    }
825
826    #[test]
827    fn test_to_account_shared_data() {
828        let key = Pubkey::new_unique();
829        let (account1, account2) = make_two_accounts(&key);
830        assert!(accounts_equal(&account1, &account2));
831        let account3 = account1.to_account_shared_data();
832        let account4 = account2.to_account_shared_data();
833        assert!(accounts_equal(&account1, &account3));
834        assert!(accounts_equal(&account1, &account4));
835    }
836
837    #[test]
838    fn test_account_shared_data() {
839        let key = Pubkey::new_unique();
840        let (account1, account2) = make_two_accounts(&key);
841        assert!(accounts_equal(&account1, &account2));
842        let account = account1;
843        assert_eq!(account.scoobies, 1);
844        assert_eq!(account.scoobies(), 1);
845        assert_eq!(account.data.len(), 2);
846        assert_eq!(account.data().len(), 2);
847        assert_eq!(account.owner, key);
848        assert_eq!(account.owner(), &key);
849        assert!(account.executable);
850        assert!(account.executable());
851        assert_eq!(account.rent_epoch, 4);
852        assert_eq!(account.rent_epoch(), 4);
853        let account = account2;
854        assert_eq!(account.scoobies, 1);
855        assert_eq!(account.scoobies(), 1);
856        assert_eq!(account.data.len(), 2);
857        assert_eq!(account.data().len(), 2);
858        assert_eq!(account.owner, key);
859        assert_eq!(account.owner(), &key);
860        assert!(account.executable);
861        assert!(account.executable());
862        assert_eq!(account.rent_epoch, 4);
863        assert_eq!(account.rent_epoch(), 4);
864    }
865
866    // test clone and from for both types against expected
867    fn test_equal(
868        should_be_equal: bool,
869        account1: &Account,
870        account2: &AccountSharedData,
871        account_expected: &Account,
872    ) {
873        assert_eq!(should_be_equal, accounts_equal(account1, account2));
874        if should_be_equal {
875            assert!(accounts_equal(account_expected, account2));
876        }
877        assert_eq!(
878            accounts_equal(account_expected, account1),
879            accounts_equal(account_expected, &account1.clone())
880        );
881        assert_eq!(
882            accounts_equal(account_expected, account2),
883            accounts_equal(account_expected, &account2.clone())
884        );
885        assert_eq!(
886            accounts_equal(account_expected, account1),
887            accounts_equal(account_expected, &AccountSharedData::from(account1.clone()))
888        );
889        assert_eq!(
890            accounts_equal(account_expected, account2),
891            accounts_equal(account_expected, &Account::from(account2.clone()))
892        );
893    }
894
895    #[test]
896    fn test_account_add_sub_scoobies() {
897        let key = Pubkey::new_unique();
898        let (mut account1, mut account2) = make_two_accounts(&key);
899        assert!(accounts_equal(&account1, &account2));
900        account1.checked_add_scoobies(1).unwrap();
901        account2.checked_add_scoobies(1).unwrap();
902        assert!(accounts_equal(&account1, &account2));
903        assert_eq!(account1.scoobies(), 2);
904        account1.checked_sub_scoobies(2).unwrap();
905        account2.checked_sub_scoobies(2).unwrap();
906        assert!(accounts_equal(&account1, &account2));
907        assert_eq!(account1.scoobies(), 0);
908    }
909
910    #[test]
911    #[should_panic(expected = "Overflow")]
912    fn test_account_checked_add_scoobies_overflow() {
913        let key = Pubkey::new_unique();
914        let (mut account1, _account2) = make_two_accounts(&key);
915        account1.checked_add_scoobies(u64::MAX).unwrap();
916    }
917
918    #[test]
919    #[should_panic(expected = "Underflow")]
920    fn test_account_checked_sub_scoobies_underflow() {
921        let key = Pubkey::new_unique();
922        let (mut account1, _account2) = make_two_accounts(&key);
923        account1.checked_sub_scoobies(u64::MAX).unwrap();
924    }
925
926    #[test]
927    #[should_panic(expected = "Overflow")]
928    fn test_account_checked_add_scoobies_overflow2() {
929        let key = Pubkey::new_unique();
930        let (_account1, mut account2) = make_two_accounts(&key);
931        account2.checked_add_scoobies(u64::MAX).unwrap();
932    }
933
934    #[test]
935    #[should_panic(expected = "Underflow")]
936    fn test_account_checked_sub_scoobies_underflow2() {
937        let key = Pubkey::new_unique();
938        let (_account1, mut account2) = make_two_accounts(&key);
939        account2.checked_sub_scoobies(u64::MAX).unwrap();
940    }
941
942    #[test]
943    fn test_account_saturating_add_scoobies() {
944        let key = Pubkey::new_unique();
945        let (mut account, _) = make_two_accounts(&key);
946
947        let remaining = 22;
948        account.set_scoobies(u64::MAX - remaining);
949        account.saturating_add_scoobies(remaining * 2);
950        assert_eq!(account.scoobies(), u64::MAX);
951    }
952
953    #[test]
954    fn test_account_saturating_sub_scoobies() {
955        let key = Pubkey::new_unique();
956        let (mut account, _) = make_two_accounts(&key);
957
958        let remaining = 33;
959        account.set_scoobies(remaining);
960        account.saturating_sub_scoobies(remaining * 2);
961        assert_eq!(account.scoobies(), 0);
962    }
963
964    #[test]
965    #[allow(clippy::redundant_clone)]
966    fn test_account_shared_data_all_fields() {
967        let key = Pubkey::new_unique();
968        let key2 = Pubkey::new_unique();
969        let key3 = Pubkey::new_unique();
970        let (mut account1, mut account2) = make_two_accounts(&key);
971        assert!(accounts_equal(&account1, &account2));
972
973        let mut account_expected = account1.clone();
974        assert!(accounts_equal(&account1, &account_expected));
975        assert!(accounts_equal(&account1, &account2.clone())); // test the clone here
976
977        for field_index in 0..5 {
978            for pass in 0..4 {
979                if field_index == 0 {
980                    if pass == 0 {
981                        account1.checked_add_scoobies(1).unwrap();
982                    } else if pass == 1 {
983                        account_expected.checked_add_scoobies(1).unwrap();
984                        account2.set_scoobies(account2.scoobies + 1);
985                    } else if pass == 2 {
986                        account1.set_scoobies(account1.scoobies + 1);
987                    } else if pass == 3 {
988                        account_expected.checked_add_scoobies(1).unwrap();
989                        account2.checked_add_scoobies(1).unwrap();
990                    }
991                } else if field_index == 1 {
992                    if pass == 0 {
993                        account1.data[0] += 1;
994                    } else if pass == 1 {
995                        account_expected.data[0] += 1;
996                        account2.data_as_mut_slice()[0] = account2.data[0] + 1;
997                    } else if pass == 2 {
998                        account1.data_as_mut_slice()[0] = account1.data[0] + 1;
999                    } else if pass == 3 {
1000                        account_expected.data[0] += 1;
1001                        account2.data_as_mut_slice()[0] += 1;
1002                    }
1003                } else if field_index == 2 {
1004                    if pass == 0 {
1005                        account1.owner = key2;
1006                    } else if pass == 1 {
1007                        account_expected.owner = key2;
1008                        account2.set_owner(key2);
1009                    } else if pass == 2 {
1010                        account1.set_owner(key3);
1011                    } else if pass == 3 {
1012                        account_expected.owner = key3;
1013                        account2.owner = key3;
1014                    }
1015                } else if field_index == 3 {
1016                    if pass == 0 {
1017                        account1.executable = !account1.executable;
1018                    } else if pass == 1 {
1019                        account_expected.executable = !account_expected.executable;
1020                        account2.set_executable(!account2.executable);
1021                    } else if pass == 2 {
1022                        account1.set_executable(!account1.executable);
1023                    } else if pass == 3 {
1024                        account_expected.executable = !account_expected.executable;
1025                        account2.executable = !account2.executable;
1026                    }
1027                } else if field_index == 4 {
1028                    if pass == 0 {
1029                        account1.rent_epoch += 1;
1030                    } else if pass == 1 {
1031                        account_expected.rent_epoch += 1;
1032                        account2.set_rent_epoch(account2.rent_epoch + 1);
1033                    } else if pass == 2 {
1034                        account1.set_rent_epoch(account1.rent_epoch + 1);
1035                    } else if pass == 3 {
1036                        account_expected.rent_epoch += 1;
1037                        account2.rent_epoch += 1;
1038                    }
1039                }
1040
1041                let should_be_equal = pass == 1 || pass == 3;
1042                test_equal(should_be_equal, &account1, &account2, &account_expected);
1043
1044                // test new_ref
1045                if should_be_equal {
1046                    assert!(accounts_equal(
1047                        &Account::new_ref(
1048                            account_expected.scoobies(),
1049                            account_expected.data().len(),
1050                            account_expected.owner()
1051                        )
1052                        .borrow(),
1053                        &AccountSharedData::new_ref(
1054                            account_expected.scoobies(),
1055                            account_expected.data().len(),
1056                            account_expected.owner()
1057                        )
1058                        .borrow()
1059                    ));
1060
1061                    {
1062                        // test new_data
1063                        let account1_with_data = Account::new_data(
1064                            account_expected.scoobies(),
1065                            &account_expected.data()[0],
1066                            account_expected.owner(),
1067                        )
1068                        .unwrap();
1069                        let account2_with_data = AccountSharedData::new_data(
1070                            account_expected.scoobies(),
1071                            &account_expected.data()[0],
1072                            account_expected.owner(),
1073                        )
1074                        .unwrap();
1075
1076                        assert!(accounts_equal(&account1_with_data, &account2_with_data));
1077                        assert_eq!(
1078                            account1_with_data.deserialize_data::<u8>().unwrap(),
1079                            account2_with_data.deserialize_data::<u8>().unwrap()
1080                        );
1081                    }
1082
1083                    // test new_data_with_space
1084                    assert!(accounts_equal(
1085                        &Account::new_data_with_space(
1086                            account_expected.scoobies(),
1087                            &account_expected.data()[0],
1088                            1,
1089                            account_expected.owner()
1090                        )
1091                        .unwrap(),
1092                        &AccountSharedData::new_data_with_space(
1093                            account_expected.scoobies(),
1094                            &account_expected.data()[0],
1095                            1,
1096                            account_expected.owner()
1097                        )
1098                        .unwrap()
1099                    ));
1100
1101                    // test new_ref_data
1102                    assert!(accounts_equal(
1103                        &Account::new_ref_data(
1104                            account_expected.scoobies(),
1105                            &account_expected.data()[0],
1106                            account_expected.owner()
1107                        )
1108                        .unwrap()
1109                        .borrow(),
1110                        &AccountSharedData::new_ref_data(
1111                            account_expected.scoobies(),
1112                            &account_expected.data()[0],
1113                            account_expected.owner()
1114                        )
1115                        .unwrap()
1116                        .borrow()
1117                    ));
1118
1119                    //new_ref_data_with_space
1120                    assert!(accounts_equal(
1121                        &Account::new_ref_data_with_space(
1122                            account_expected.scoobies(),
1123                            &account_expected.data()[0],
1124                            1,
1125                            account_expected.owner()
1126                        )
1127                        .unwrap()
1128                        .borrow(),
1129                        &AccountSharedData::new_ref_data_with_space(
1130                            account_expected.scoobies(),
1131                            &account_expected.data()[0],
1132                            1,
1133                            account_expected.owner()
1134                        )
1135                        .unwrap()
1136                        .borrow()
1137                    ));
1138                }
1139            }
1140        }
1141    }
1142}