Skip to main content

magicblock_account/
traits.rs

1use {
2    crate::{
3        Account, AccountSharedData,
4        cow::{DirtyMarkers, StateFlags},
5    },
6    solana_account_info::debug_account_data::debug_account_data,
7    solana_clock::Epoch,
8    solana_instruction_error::LamportsError,
9    solana_pubkey::Pubkey,
10    std::{fmt, ops::Deref},
11};
12
13/// Read-only access to account state.
14pub trait ReadableAccount: Sized {
15    /// Returns the lamport balance.
16    fn lamports(&self) -> u64;
17
18    /// Returns the account data.
19    fn data(&self) -> &[u8];
20
21    /// Returns the account owner.
22    fn owner(&self) -> &Pubkey;
23
24    /// Returns whether the account is executable.
25    fn executable(&self) -> bool;
26
27    /// Returns the rent epoch view for this account.
28    fn rent_epoch(&self) -> Epoch;
29}
30
31/// Writable access to account state.
32pub trait WritableAccount: ReadableAccount {
33    /// Replaces the lamport balance.
34    fn set_lamports(&mut self, lamports: u64);
35
36    /// Adds lamports or returns an overflow error.
37    fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), LamportsError> {
38        self.set_lamports(
39            self.lamports().checked_add(lamports).ok_or(LamportsError::ArithmeticOverflow)?,
40        );
41        Ok(())
42    }
43
44    /// Subtracts lamports or returns an underflow error.
45    fn checked_sub_lamports(&mut self, lamports: u64) -> Result<(), LamportsError> {
46        self.set_lamports(
47            self.lamports()
48                .checked_sub(lamports)
49                .ok_or(LamportsError::ArithmeticUnderflow)?,
50        );
51        Ok(())
52    }
53
54    /// Adds lamports and saturates on overflow.
55    fn saturating_add_lamports(&mut self, lamports: u64) {
56        self.set_lamports(self.lamports().saturating_add(lamports))
57    }
58
59    /// Subtracts lamports and saturates on underflow.
60    fn saturating_sub_lamports(&mut self, lamports: u64) {
61        self.set_lamports(self.lamports().saturating_sub(lamports))
62    }
63
64    /// Returns mutable access to the account data.
65    fn data_as_mut_slice(&mut self) -> &mut [u8];
66
67    /// Replaces the owner.
68    fn set_owner(&mut self, owner: Pubkey);
69
70    /// Copies 32 raw bytes into the owner pubkey.
71    fn copy_into_owner_from_slice(&mut self, source: &[u8]);
72
73    /// Sets the executable flag.
74    fn set_executable(&mut self, executable: bool);
75
76    /// Sets the rent epoch view if the implementation stores one.
77    ///
78    /// Implementations that do not store rent epoch may ignore this.
79    fn set_rent_epoch(&mut self, epoch: Epoch);
80}
81
82/// Returns `true` when the readable account fields match.
83///
84/// This ignores storage form and any non-readable metadata.
85pub fn accounts_equal<T: ReadableAccount, U: ReadableAccount>(me: &T, other: &U) -> bool {
86    me.lamports() == other.lamports()
87        && me.executable() == other.executable()
88        && me.rent_epoch() == other.rent_epoch()
89        && me.owner() == other.owner()
90        && me.data() == other.data()
91}
92
93/// Formats readable accounts with the same debug shape as `Account`.
94pub(crate) fn debug_fmt<T: ReadableAccount>(
95    item: &T,
96    f: &mut fmt::Formatter<'_>,
97    add: impl FnOnce(&mut fmt::DebugStruct<'_, '_>),
98) -> fmt::Result {
99    let mut f = f.debug_struct("Account");
100
101    f.field("lamports", &item.lamports())
102        .field("data.len", &item.data().len())
103        .field("owner", &item.owner())
104        .field("executable", &item.executable())
105        .field("rent_epoch", &item.rent_epoch());
106    add(&mut f);
107    debug_account_data(item.data(), &mut f);
108
109    f.finish()
110}
111
112impl<T> ReadableAccount for T
113where
114    T: Deref,
115    T::Target: ReadableAccount,
116{
117    fn lamports(&self) -> u64 {
118        self.deref().lamports()
119    }
120
121    fn data(&self) -> &[u8] {
122        self.deref().data()
123    }
124
125    fn owner(&self) -> &Pubkey {
126        self.deref().owner()
127    }
128
129    fn executable(&self) -> bool {
130        self.deref().executable()
131    }
132
133    fn rent_epoch(&self) -> Epoch {
134        self.deref().rent_epoch()
135    }
136}
137
138impl ReadableAccount for Account {
139    fn lamports(&self) -> u64 {
140        self.lamports
141    }
142
143    fn data(&self) -> &[u8] {
144        &self.data
145    }
146
147    fn owner(&self) -> &Pubkey {
148        &self.owner
149    }
150
151    fn executable(&self) -> bool {
152        self.executable
153    }
154
155    fn rent_epoch(&self) -> Epoch {
156        self.rent_epoch
157    }
158}
159
160impl WritableAccount for Account {
161    fn set_lamports(&mut self, lamports: u64) {
162        self.lamports = lamports;
163    }
164
165    fn data_as_mut_slice(&mut self) -> &mut [u8] {
166        &mut self.data
167    }
168
169    fn set_owner(&mut self, owner: Pubkey) {
170        self.owner = owner;
171    }
172
173    fn copy_into_owner_from_slice(&mut self, source: &[u8]) {
174        self.owner.as_mut().copy_from_slice(source);
175    }
176
177    fn set_executable(&mut self, executable: bool) {
178        self.executable = executable;
179    }
180
181    fn set_rent_epoch(&mut self, epoch: Epoch) {
182        self.rent_epoch = epoch;
183    }
184}
185
186impl ReadableAccount for AccountSharedData {
187    fn lamports(&self) -> u64 {
188        self.lamports
189    }
190
191    fn data(&self) -> &[u8] {
192        self.cow.data()
193    }
194
195    fn owner(&self) -> &Pubkey {
196        &self.owner
197    }
198
199    fn executable(&self) -> bool {
200        self.flags.contains(StateFlags::EXECUTABLE)
201    }
202
203    fn rent_epoch(&self) -> Epoch {
204        Epoch::MAX
205    }
206}
207
208impl WritableAccount for AccountSharedData {
209    fn set_lamports(&mut self, lamports: u64) {
210        if self.lamports == lamports {
211            return;
212        }
213        self.translate();
214        self.dirty.insert(DirtyMarkers::LAMPORTS);
215        self.lamports = lamports;
216    }
217
218    fn data_as_mut_slice(&mut self) -> &mut [u8] {
219        self.translate();
220        self.mark_data_dirty();
221        self.cow.data_mut()
222    }
223
224    fn set_owner(&mut self, owner: Pubkey) {
225        if self.owner == owner {
226            return;
227        }
228        self.translate();
229        self.dirty.insert(DirtyMarkers::OWNER);
230        self.owner = owner;
231    }
232
233    fn copy_into_owner_from_slice(&mut self, source: &[u8]) {
234        self.translate();
235        self.dirty.insert(DirtyMarkers::OWNER);
236        self.owner.as_mut().copy_from_slice(source);
237    }
238
239    fn set_executable(&mut self, executable: bool) {
240        let mut flags = self.flags;
241        flags.set(StateFlags::EXECUTABLE, executable);
242        self.set_flags(flags);
243    }
244
245    fn set_rent_epoch(&mut self, _: Epoch) {}
246}