Skip to main content

magicblock_account/
account.rs

1use {
2    crate::{AccountSharedData, ReadableAccount, traits::debug_fmt},
3    solana_account_info::AccountInfo,
4    solana_clock::Epoch,
5    solana_pubkey::Pubkey,
6    solana_sdk_ids::{
7        bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, loader_v4, native_loader,
8    },
9    std::{cell::RefCell, fmt, rc::Rc},
10};
11
12/// An on-chain account with owned data and an explicit rent epoch.
13#[repr(C)]
14#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(rename_all = "camelCase"))]
15#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
16#[derive(PartialEq, Eq, Clone, Default)]
17pub struct Account {
18    /// Lamports in the account.
19    pub lamports: u64,
20    /// Data held in the account.
21    #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
22    pub data: Vec<u8>,
23    /// The program that owns this account.
24    pub owner: Pubkey,
25    /// Whether the account contains executable program data.
26    pub executable: bool,
27    /// The epoch at which this account next owes rent.
28    pub rent_epoch: Epoch,
29}
30
31#[cfg(feature = "serde")]
32mod account_serialize {
33    use {
34        crate::ReadableAccount,
35        serde::{Serialize, ser::Serializer},
36        solana_clock::Epoch,
37        solana_pubkey::Pubkey,
38    };
39
40    #[repr(C)]
41    #[derive(serde::Serialize)]
42    #[serde(rename_all = "camelCase")]
43    /// Serialization shape shared by `Account` and `AccountSharedData`.
44    struct Account<'a> {
45        lamports: u64,
46        #[serde(with = "serde_bytes")]
47        data: &'a [u8],
48        owner: &'a Pubkey,
49        executable: bool,
50        rent_epoch: Epoch,
51    }
52
53    /// Serializes any readable account using the canonical `Account` layout.
54    pub(crate) fn serialize_account<S>(
55        account: &impl ReadableAccount,
56        serializer: S,
57    ) -> Result<S::Ok, S::Error>
58    where
59        S: Serializer,
60    {
61        let account = Account {
62            lamports: account.lamports(),
63            data: account.data(),
64            owner: account.owner(),
65            executable: account.executable(),
66            rent_epoch: account.rent_epoch(),
67        };
68        account.serialize(serializer)
69    }
70}
71
72#[cfg(feature = "serde")]
73impl serde::ser::Serialize for Account {
74    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: serde::ser::Serializer,
77    {
78        account_serialize::serialize_account(self, serializer)
79    }
80}
81
82#[cfg(feature = "serde")]
83impl serde::ser::Serialize for AccountSharedData {
84    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85    where
86        S: serde::ser::Serializer,
87    {
88        account_serialize::serialize_account(self, serializer)
89    }
90}
91
92impl From<AccountSharedData> for Account {
93    fn from(other: AccountSharedData) -> Self {
94        Self {
95            lamports: other.lamports(),
96            data: other.data().to_vec(),
97            owner: *other.owner(),
98            executable: other.executable(),
99            rent_epoch: other.rent_epoch(),
100        }
101    }
102}
103
104impl fmt::Debug for Account {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        debug_fmt(self, f, |_| {})
107    }
108}
109
110impl fmt::Debug for AccountSharedData {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        debug_fmt(self, f, |f| {
113            f.field("slot", &self.slot())
114                .field("mode", &self.mode)
115                .field("flags", self.flags())
116                .field("dirty", self.markers());
117        })
118    }
119}
120
121impl Account {
122    /// Builds an account from its exact field set.
123    ///
124    /// Used by the constructors to keep the owned layout in one place.
125    fn from_parts(
126        lamports: u64,
127        data: Vec<u8>,
128        owner: Pubkey,
129        executable: bool,
130        rent_epoch: Epoch,
131    ) -> Self {
132        Self {
133            lamports,
134            data,
135            owner,
136            executable,
137            rent_epoch,
138        }
139    }
140
141    /// Creates a new account with zero-filled data.
142    pub fn new(lamports: u64, space: usize, owner: &Pubkey) -> Self {
143        Self::new_rent_epoch(lamports, space, owner, Epoch::default())
144    }
145
146    /// Creates a new account wrapped in a `RefCell`.
147    pub fn new_ref(lamports: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
148        Rc::new(RefCell::new(Self::new(lamports, space, owner)))
149    }
150
151    /// Creates a new account whose data is the serialized state.
152    #[cfg(feature = "bincode")]
153    pub fn new_data<T: serde::Serialize>(
154        lamports: u64,
155        state: &T,
156        owner: &Pubkey,
157    ) -> Result<Self, bincode::Error> {
158        let data = bincode::serialize(state)?;
159        Ok(Self::from_parts(
160            lamports,
161            data,
162            *owner,
163            false,
164            Epoch::default(),
165        ))
166    }
167
168    /// Creates a new serialized account wrapped in a `RefCell`.
169    #[cfg(feature = "bincode")]
170    pub fn new_ref_data<T: serde::Serialize>(
171        lamports: u64,
172        state: &T,
173        owner: &Pubkey,
174    ) -> Result<RefCell<Self>, bincode::Error> {
175        Self::new_data(lamports, state, owner).map(RefCell::new)
176    }
177
178    /// Creates a new account with fixed space and serialized state.
179    #[cfg(feature = "bincode")]
180    pub fn new_data_with_space<T: serde::Serialize>(
181        lamports: u64,
182        state: &T,
183        space: usize,
184        owner: &Pubkey,
185    ) -> Result<Self, bincode::Error> {
186        let mut account = Self::new(lamports, space, owner);
187        crate::codec::serialize_data(&mut account, state)?;
188        Ok(account)
189    }
190
191    /// Creates a new fixed-size serialized account wrapped in a `RefCell`.
192    #[cfg(feature = "bincode")]
193    pub fn new_ref_data_with_space<T: serde::Serialize>(
194        lamports: u64,
195        state: &T,
196        space: usize,
197        owner: &Pubkey,
198    ) -> Result<RefCell<Self>, bincode::Error> {
199        Self::new_data_with_space(lamports, state, space, owner).map(RefCell::new)
200    }
201
202    /// Creates a new account with an explicit rent epoch.
203    pub fn new_rent_epoch(lamports: u64, space: usize, owner: &Pubkey, rent_epoch: Epoch) -> Self {
204        Self::from_parts(lamports, vec![0; space], *owner, false, rent_epoch)
205    }
206
207    /// Deserializes the account data as `T`.
208    #[cfg(feature = "bincode")]
209    pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
210        crate::codec::deserialize_data(self)
211    }
212
213    /// Serializes `state` into the existing account data buffer.
214    #[cfg(feature = "bincode")]
215    pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
216        crate::codec::serialize_data(self, state)
217    }
218}
219
220impl solana_account_info::Account for Account {
221    fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool) {
222        (
223            &mut self.lamports,
224            &mut self.data,
225            &self.owner,
226            self.executable,
227        )
228    }
229}
230
231/// Builds `AccountInfo` values for accounts and signer bits.
232///
233/// The returned infos borrow the provided accounts directly.
234pub fn create_is_signer_account_infos<'a>(
235    accounts: &'a mut [(&'a Pubkey, bool, &'a mut Account)],
236) -> Vec<AccountInfo<'a>> {
237    accounts
238        .iter_mut()
239        .map(|(key, is_signer, account)| {
240            AccountInfo::new(
241                key,
242                *is_signer,
243                false,
244                &mut account.lamports,
245                &mut account.data,
246                &account.owner,
247                account.executable,
248            )
249        })
250        .collect()
251}
252
253/// Owners that imply the account contains a loaded program.
254pub const PROGRAM_OWNERS: &[Pubkey] = &[
255    native_loader::id(),
256    bpf_loader_upgradeable::id(),
257    bpf_loader::id(),
258    bpf_loader_deprecated::id(),
259    loader_v4::id(),
260];