Skip to main content

magicblock_account/cow/
owned.rs

1use super::borrowed::{AccountHeader, DataHeader, STATIC_SIZE};
2use super::{ALIGNMENT, StateFlags};
3use crate::cow::AccountCore;
4use crate::cow::borrowed::IMAGE_OFFSET;
5use crate::{Account, AccountMode, AccountSharedData, StorageUnit};
6use solana_clock::Slot;
7use solana_pubkey::Pubkey;
8use std::{ptr::NonNull, sync::Arc};
9
10/// Heap-backed account, used after promotion from borrowed or direct construction.
11#[derive(Clone, Default, Eq, PartialEq)]
12#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
13pub struct OwnedAccount {
14    /// Core account fields.
15    pub(crate) core: AccountCore,
16    /// Heap-owned data buffer.
17    pub(crate) data: Arc<Vec<u8>>,
18}
19
20impl OwnedAccount {
21    /// Returns the exact storage units needed to serialize this account.
22    pub fn units(&self) -> u32 {
23        self.allocation() * 2 + IMAGE_OFFSET as u32
24    }
25
26    /// Returns the storage units needed for one image, rounded up to alignment.
27    fn allocation(&self) -> u32 {
28        (STATIC_SIZE + self.data.len()).div_ceil(ALIGNMENT) as u32
29    }
30
31    /// Writes the account into a buffer sized by `units`.
32    ///
33    /// # Safety
34    ///
35    /// `buf` must be exactly `units()` storage units long.
36    /// `pubkey` is written into the image prefix so borrowed iteration can
37    /// recover the full account key without consulting the index.
38    pub unsafe fn serialize(&self, buf: &mut [StorageUnit], pubkey: &Pubkey) {
39        let ptr = NonNull::new_unchecked(buf.as_mut_ptr());
40        debug_assert_eq!(self.units() as usize, buf.len());
41
42        fn write<U, T: Sized>(ptr: NonNull<U>, v: T) -> NonNull<T> {
43            // SAFETY: `serialize` requires a buffer sized for the full layout.
44            unsafe {
45                ptr.cast().write(v);
46                ptr.cast().add(1)
47            }
48        }
49
50        let allocation = self.allocation();
51        let ptr = write(ptr, AccountHeader::new(allocation));
52        // The image prefix stores the account pubkey for later iteration.
53        let ptr = write(ptr, *pubkey);
54        let ptr = write(ptr, self.core);
55        let len = self.data.len();
56        let ptr = write(ptr, DataHeader::new(len as u32, allocation)).cast();
57        self.data.as_ptr().copy_to_nonoverlapping(ptr.as_ptr(), len);
58    }
59
60    /// Tests the exact account mode without grouping modes by mutability.
61    pub fn is(&self, mode: AccountMode) -> bool {
62        self.core.mode == mode
63    }
64
65    /// Returns the owner pubkey.
66    pub fn owner(&self) -> Pubkey {
67        self.core.owner
68    }
69
70    /// Returns the lamport balance.
71    pub fn lamports(&self) -> u64 {
72        self.core.lamports
73    }
74
75    /// Returns the account's exact lifecycle mode.
76    pub fn mode(&self) -> AccountMode {
77        self.core.mode
78    }
79
80    /// Returns the account's on-chain slot.
81    pub fn slot(&self) -> u64 {
82        self.core.slot
83    }
84
85    /// Returns the account modifier flags.
86    pub fn flags(&self) -> StateFlags {
87        self.core.flags
88    }
89
90    /// Returns the account data.
91    pub fn data(&self) -> &[u8] {
92        &self.data
93    }
94}
95
96/// Builder for an owned account representation.
97///
98/// Use this when the account does not start from a borrowed external buffer.
99#[derive(Default, Clone)]
100pub struct AccountBuilder(OwnedAccount);
101
102impl AccountBuilder {
103    /// Sets the lamport balance.
104    pub fn lamports(mut self, lamports: u64) -> Self {
105        self.0.core.lamports = lamports;
106        self
107    }
108
109    /// Sets the data buffer.
110    pub fn data(mut self, data: impl Into<Arc<Vec<u8>>>) -> Self {
111        self.0.data = data.into();
112        self
113    }
114
115    /// Sets the owner.
116    pub fn owner(mut self, owner: Pubkey) -> Self {
117        self.0.core.owner = owner;
118        self
119    }
120
121    /// Sets the account persistence mode of the account
122    pub fn mode(mut self, mode: AccountMode) -> Self {
123        self.0.core.mode = mode;
124        self
125    }
126
127    /// Sets the executable flag.
128    pub fn executable(mut self, executable: bool) -> Self {
129        self.0.core.flags.set(StateFlags::EXECUTABLE, executable);
130        self
131    }
132
133    /// Sets the on chain slot.
134    pub fn slot(mut self, slot: Slot) -> Self {
135        self.0.core.slot = slot;
136        self
137    }
138
139    /// Borrows the account under construction.
140    pub fn read(&self) -> &OwnedAccount {
141        &self.0
142    }
143
144    /// Finishes building the owned account.
145    pub fn build<A: From<OwnedAccount>>(self) -> A {
146        self.0.into()
147    }
148}
149
150impl From<Account> for OwnedAccount {
151    fn from(value: Account) -> Self {
152        AccountBuilder::default()
153            .lamports(value.lamports)
154            .data(value.data)
155            .owner(value.owner)
156            .executable(value.executable)
157            .build()
158    }
159}
160
161impl From<AccountBuilder> for OwnedAccount {
162    fn from(value: AccountBuilder) -> Self {
163        value.0
164    }
165}
166
167impl From<Account> for AccountBuilder {
168    fn from(value: Account) -> Self {
169        Self(value.into())
170    }
171}
172
173impl From<AccountSharedData> for AccountBuilder {
174    fn from(value: AccountSharedData) -> Self {
175        Self(value.owned())
176    }
177}