Skip to content

Commit 3038d47

Browse files
authored
[TieredStorage] Store account address range (pyth-network#172)
#### Problem The TieredStorageFooter has the min_account_address and max_account_address fields to describe the account address range in its file. But the current implementation hasn't updated the fields yet. #### Summary of Changes This PR enables the TieredStorage to persist address range information into its footer via min_account_address and max_account_address. #### Test Plan Updated tiered-storage test to verify persisted account address range.
1 parent 0e932c7 commit 3038d47

File tree

4 files changed

+117
-5
lines changed

4 files changed

+117
-5
lines changed

accounts-db/src/tiered_storage.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ mod tests {
183183
mem::ManuallyDrop,
184184
},
185185
tempfile::tempdir,
186-
test_utils::{create_test_account, verify_test_account},
186+
test_utils::{create_test_account, verify_test_account_with_footer},
187187
};
188188

189189
impl TieredStorage {
@@ -368,13 +368,33 @@ mod tests {
368368

369369
let mut index_offset = IndexOffset(0);
370370
let mut verified_accounts = HashSet::new();
371+
let footer = reader.footer();
372+
373+
const MIN_PUBKEY: Pubkey = Pubkey::new_from_array([0x00u8; 32]);
374+
const MAX_PUBKEY: Pubkey = Pubkey::new_from_array([0xFFu8; 32]);
375+
let mut min_pubkey_ref = &MAX_PUBKEY;
376+
let mut max_pubkey_ref = &MIN_PUBKEY;
377+
371378
while let Some((stored_meta, next)) = reader.get_account(index_offset).unwrap() {
372379
if let Some(account) = expected_accounts_map.get(stored_meta.pubkey()) {
373-
verify_test_account(&stored_meta, *account, stored_meta.pubkey());
380+
verify_test_account_with_footer(
381+
&stored_meta,
382+
*account,
383+
stored_meta.pubkey(),
384+
footer,
385+
);
374386
verified_accounts.insert(stored_meta.pubkey());
387+
if *min_pubkey_ref > *stored_meta.pubkey() {
388+
min_pubkey_ref = stored_meta.pubkey();
389+
}
390+
if *max_pubkey_ref < *stored_meta.pubkey() {
391+
max_pubkey_ref = stored_meta.pubkey();
392+
}
375393
}
376394
index_offset = next;
377395
}
396+
assert_eq!(footer.min_account_address, *min_pubkey_ref);
397+
assert_eq!(footer.max_account_address, *max_pubkey_ref);
378398
assert!(!verified_accounts.is_empty());
379399
assert_eq!(verified_accounts.len(), expected_accounts_map.len())
380400
}

accounts-db/src/tiered_storage/hot.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use {
1010
file::{TieredReadableFile, TieredWritableFile},
1111
footer::{AccountBlockFormat, AccountMetaFormat, TieredStorageFooter},
1212
index::{AccountIndexWriterEntry, AccountOffset, IndexBlockFormat, IndexOffset},
13-
meta::{AccountMetaFlags, AccountMetaOptionalFields, TieredAccountMeta},
13+
meta::{
14+
AccountAddressRange, AccountMetaFlags, AccountMetaOptionalFields, TieredAccountMeta,
15+
},
1416
mmap_utils::{get_pod, get_slice},
1517
owners::{OwnerOffset, OwnersBlockFormat, OwnersTable, OWNER_NO_OWNER},
1618
StorableAccounts, StorableAccountsWithHashesAndWriteVersions, TieredStorageError,
@@ -620,6 +622,7 @@ impl HotStorageWriter {
620622
let mut index = vec![];
621623
let mut owners_table = OwnersTable::default();
622624
let mut cursor = 0;
625+
let mut address_range = AccountAddressRange::default();
623626

624627
// writing accounts blocks
625628
let len = accounts.accounts.len();
@@ -631,6 +634,7 @@ impl HotStorageWriter {
631634
address,
632635
offset: HotAccountOffset::new(cursor)?,
633636
};
637+
address_range.update(address);
634638

635639
// Obtain necessary fields from the account, or default fields
636640
// for a zero-lamport account in the None case.
@@ -691,7 +695,8 @@ impl HotStorageWriter {
691695
footer
692696
.owners_block_format
693697
.write_owners_block(&mut self.storage, &owners_table)?;
694-
698+
footer.min_account_address = *address_range.min;
699+
footer.max_account_address = *address_range.max;
695700
footer.write_footer_block(&mut self.storage)?;
696701

697702
Ok(stored_infos)

accounts-db/src/tiered_storage/meta.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use {
44
crate::tiered_storage::owners::OwnerOffset,
55
bytemuck::{Pod, Zeroable},
66
modular_bitfield::prelude::*,
7-
solana_sdk::stake_history::Epoch,
7+
solana_sdk::{pubkey::Pubkey, stake_history::Epoch},
88
};
99

1010
/// The struct that handles the account meta flags.
@@ -124,6 +124,38 @@ impl AccountMetaOptionalFields {
124124
}
125125
}
126126

127+
const MIN_ACCOUNT_ADDRESS: Pubkey = Pubkey::new_from_array([0x00u8; 32]);
128+
const MAX_ACCOUNT_ADDRESS: Pubkey = Pubkey::new_from_array([0xFFu8; 32]);
129+
130+
#[derive(Debug)]
131+
/// A struct that maintains an address-range using its min and max fields.
132+
pub struct AccountAddressRange<'a> {
133+
/// The minimum address observed via update()
134+
pub min: &'a Pubkey,
135+
/// The maximum address observed via update()
136+
pub max: &'a Pubkey,
137+
}
138+
139+
impl Default for AccountAddressRange<'_> {
140+
fn default() -> Self {
141+
Self {
142+
min: &MAX_ACCOUNT_ADDRESS,
143+
max: &MIN_ACCOUNT_ADDRESS,
144+
}
145+
}
146+
}
147+
148+
impl<'a> AccountAddressRange<'a> {
149+
pub fn update(&mut self, address: &'a Pubkey) {
150+
if *self.min > *address {
151+
self.min = address;
152+
}
153+
if *self.max < *address {
154+
self.max = address;
155+
}
156+
}
157+
}
158+
127159
#[cfg(test)]
128160
pub mod tests {
129161
use super::*;
@@ -221,4 +253,47 @@ pub mod tests {
221253
);
222254
}
223255
}
256+
257+
#[test]
258+
fn test_pubkey_range_update_single() {
259+
let address = solana_sdk::pubkey::new_rand();
260+
let mut address_range = AccountAddressRange::default();
261+
262+
address_range.update(&address);
263+
// For a single update, the min and max should equal to the address
264+
assert_eq!(*address_range.min, address);
265+
assert_eq!(*address_range.max, address);
266+
}
267+
268+
#[test]
269+
fn test_pubkey_range_update_multiple() {
270+
const NUM_PUBKEYS: usize = 20;
271+
272+
let mut address_range = AccountAddressRange::default();
273+
let mut addresses = Vec::with_capacity(NUM_PUBKEYS);
274+
275+
let mut min_index = 0;
276+
let mut max_index = 0;
277+
278+
// Generate random addresses and track expected min and max indices
279+
for i in 0..NUM_PUBKEYS {
280+
let address = solana_sdk::pubkey::new_rand();
281+
addresses.push(address);
282+
283+
// Update expected min and max indices
284+
if address < addresses[min_index] {
285+
min_index = i;
286+
}
287+
if address > addresses[max_index] {
288+
max_index = i;
289+
}
290+
}
291+
292+
addresses
293+
.iter()
294+
.for_each(|address| address_range.update(address));
295+
296+
assert_eq!(*address_range.min, addresses[min_index]);
297+
assert_eq!(*address_range.max, addresses[max_index]);
298+
}
224299
}

accounts-db/src/tiered_storage/test_utils.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![cfg(test)]
22
//! Helper functions for TieredStorage tests
33
use {
4+
super::footer::TieredStorageFooter,
45
crate::{
56
account_storage::meta::{StoredAccountMeta, StoredMeta},
67
accounts_hash::AccountHash,
@@ -61,3 +62,14 @@ pub(super) fn verify_test_account(
6162
assert_eq!(stored_meta.pubkey(), address);
6263
assert_eq!(*stored_meta.hash(), AccountHash(Hash::default()));
6364
}
65+
66+
pub(super) fn verify_test_account_with_footer(
67+
stored_meta: &StoredAccountMeta<'_>,
68+
account: Option<&impl ReadableAccount>,
69+
address: &Pubkey,
70+
footer: &TieredStorageFooter,
71+
) {
72+
verify_test_account(stored_meta, account, address);
73+
assert!(footer.min_account_address <= *address);
74+
assert!(footer.max_account_address >= *address);
75+
}

0 commit comments

Comments
 (0)