solana_accounts_db/tiered_storage/
meta.rs1use {
4 crate::tiered_storage::owners::OwnerOffset,
5 bytemuck_derive::{Pod, Zeroable},
6 modular_bitfield::prelude::*,
7 solana_sdk::{pubkey::Pubkey, stake_history::Epoch},
8};
9
10#[bitfield(bits = 32)]
12#[repr(C)]
13#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Pod, Zeroable)]
14pub struct AccountMetaFlags {
15 pub has_rent_epoch: bool,
17 pub executable: bool,
19 reserved: B30,
21}
22
23const _: () = assert!(std::mem::size_of::<AccountMetaFlags>() == 4);
25
26pub trait TieredAccountMeta: Sized {
29 fn new() -> Self;
31
32 fn with_lamports(self, lamports: u64) -> Self;
34
35 fn with_account_data_padding(self, padding: u8) -> Self;
38
39 fn with_owner_offset(self, owner_offset: OwnerOffset) -> Self;
41
42 fn with_account_data_size(self, account_data_size: u64) -> Self;
45
46 fn with_flags(self, flags: &AccountMetaFlags) -> Self;
49
50 fn lamports(&self) -> u64;
52
53 fn account_data_padding(&self) -> u8;
55
56 fn owner_offset(&self) -> OwnerOffset;
58
59 fn flags(&self) -> &AccountMetaFlags;
61
62 fn supports_shared_account_block() -> bool;
65
66 fn rent_epoch(&self, _account_block: &[u8]) -> Option<Epoch>;
70
71 fn final_rent_epoch(&self, account_block: &[u8]) -> Epoch;
78
79 fn optional_fields_offset(&self, _account_block: &[u8]) -> usize;
82
83 fn account_data_size(&self, _account_block: &[u8]) -> usize;
86
87 fn account_data<'a>(&self, _account_block: &'a [u8]) -> &'a [u8];
90}
91
92impl AccountMetaFlags {
93 pub fn new_from(optional_fields: &AccountMetaOptionalFields) -> Self {
94 let mut flags = AccountMetaFlags::default();
95 flags.set_has_rent_epoch(optional_fields.rent_epoch.is_some());
96 flags.set_executable(false);
97 flags
98 }
99}
100
101#[derive(Debug, PartialEq, Eq, Clone)]
106pub struct AccountMetaOptionalFields {
107 pub rent_epoch: Option<Epoch>,
109}
110
111impl AccountMetaOptionalFields {
112 pub fn size(&self) -> usize {
114 self.rent_epoch.map_or(0, |_| std::mem::size_of::<Epoch>())
115 }
116
117 pub fn size_from_flags(flags: &AccountMetaFlags) -> usize {
120 let mut fields_size = 0;
121 if flags.has_rent_epoch() {
122 fields_size += std::mem::size_of::<Epoch>();
123 }
124
125 fields_size
126 }
127
128 pub fn rent_epoch_offset(_flags: &AccountMetaFlags) -> usize {
131 0
132 }
133}
134
135const MIN_ACCOUNT_ADDRESS: Pubkey = Pubkey::new_from_array([0x00u8; 32]);
136const MAX_ACCOUNT_ADDRESS: Pubkey = Pubkey::new_from_array([0xFFu8; 32]);
137
138#[derive(Debug)]
139pub struct AccountAddressRange {
141 pub min: Pubkey,
143 pub max: Pubkey,
145}
146
147impl Default for AccountAddressRange {
148 fn default() -> Self {
149 Self {
150 min: MAX_ACCOUNT_ADDRESS,
151 max: MIN_ACCOUNT_ADDRESS,
152 }
153 }
154}
155
156impl AccountAddressRange {
157 pub fn update(&mut self, address: &Pubkey) {
158 if self.min > *address {
159 self.min = *address;
160 }
161 if self.max < *address {
162 self.max = *address;
163 }
164 }
165}
166
167#[cfg(test)]
168pub mod tests {
169 use super::*;
170
171 #[test]
172 fn test_account_meta_flags_new() {
173 let flags = AccountMetaFlags::new();
174
175 assert!(!flags.has_rent_epoch());
176 assert_eq!(flags.reserved(), 0u32);
177
178 assert_eq!(
179 std::mem::size_of::<AccountMetaFlags>(),
180 std::mem::size_of::<u32>()
181 );
182 }
183
184 fn verify_flags_serialization(flags: &AccountMetaFlags) {
185 assert_eq!(AccountMetaFlags::from_bytes(flags.into_bytes()), *flags);
186 }
187
188 #[test]
189 fn test_account_meta_flags_set() {
190 let mut flags = AccountMetaFlags::new();
191
192 flags.set_has_rent_epoch(true);
193
194 assert!(flags.has_rent_epoch());
195 assert!(!flags.executable());
196 verify_flags_serialization(&flags);
197
198 flags.set_executable(true);
199 assert!(flags.has_rent_epoch());
200 assert!(flags.executable());
201 verify_flags_serialization(&flags);
202
203 assert_eq!(flags.reserved(), 0u32);
205 }
206
207 fn update_and_verify_flags(opt_fields: &AccountMetaOptionalFields) {
208 let flags: AccountMetaFlags = AccountMetaFlags::new_from(opt_fields);
209 assert_eq!(flags.has_rent_epoch(), opt_fields.rent_epoch.is_some());
210 assert_eq!(flags.reserved(), 0u32);
211 }
212
213 #[test]
214 fn test_optional_fields_update_flags() {
215 let test_epoch = 5432312;
216
217 for rent_epoch in [None, Some(test_epoch)] {
218 update_and_verify_flags(&AccountMetaOptionalFields { rent_epoch });
219 }
220 }
221
222 #[test]
223 fn test_optional_fields_size() {
224 let test_epoch = 5432312;
225
226 for rent_epoch in [None, Some(test_epoch)] {
227 let opt_fields = AccountMetaOptionalFields { rent_epoch };
228 assert_eq!(
229 opt_fields.size(),
230 rent_epoch.map_or(0, |_| std::mem::size_of::<Epoch>()),
231 );
232 assert_eq!(
233 opt_fields.size(),
234 AccountMetaOptionalFields::size_from_flags(&AccountMetaFlags::new_from(
235 &opt_fields
236 ))
237 );
238 }
239 }
240
241 #[test]
242 fn test_optional_fields_offset() {
243 let test_epoch = 5432312;
244
245 for rent_epoch in [None, Some(test_epoch)] {
246 let rent_epoch_offset = 0;
247 let derived_size = if rent_epoch.is_some() {
248 std::mem::size_of::<Epoch>()
249 } else {
250 0
251 };
252 let opt_fields = AccountMetaOptionalFields { rent_epoch };
253 let flags = AccountMetaFlags::new_from(&opt_fields);
254 assert_eq!(
255 AccountMetaOptionalFields::rent_epoch_offset(&flags),
256 rent_epoch_offset
257 );
258 assert_eq!(
259 AccountMetaOptionalFields::size_from_flags(&flags),
260 derived_size
261 );
262 }
263 }
264
265 #[test]
266 fn test_pubkey_range_update_single() {
267 let address = solana_pubkey::new_rand();
268 let mut address_range = AccountAddressRange::default();
269
270 address_range.update(&address);
271 assert_eq!(address_range.min, address);
273 assert_eq!(address_range.max, address);
274 }
275
276 #[test]
277 fn test_pubkey_range_update_multiple() {
278 const NUM_PUBKEYS: usize = 20;
279
280 let mut address_range = AccountAddressRange::default();
281 let mut addresses = Vec::with_capacity(NUM_PUBKEYS);
282
283 let mut min_index = 0;
284 let mut max_index = 0;
285
286 for i in 0..NUM_PUBKEYS {
288 let address = solana_pubkey::new_rand();
289 addresses.push(address);
290
291 if address < addresses[min_index] {
293 min_index = i;
294 }
295 if address > addresses[max_index] {
296 max_index = i;
297 }
298 }
299
300 addresses
301 .iter()
302 .for_each(|address| address_range.update(address));
303
304 assert_eq!(address_range.min, addresses[min_index]);
305 assert_eq!(address_range.max, addresses[max_index]);
306 }
307}