some more optimizations and bugfix on gPA

This commit is contained in:
godmodegalactus 2024-04-11 17:30:21 +02:00
parent de5362d4bb
commit ada5796e7e
No known key found for this signature in database
GPG Key ID: 22DA4A30887FDA3C
6 changed files with 185 additions and 14 deletions

View File

@ -1079,11 +1079,14 @@ impl Accounts {
|some_account_tuple| {
Self::load_while_filtering(&mut collector, some_account_tuple, |account| {
if just_get_program_ids {
Self::accumulate_and_check_scan_result_size(
if Self::accumulate_and_check_scan_result_size(
&sum,
account,
&byte_limit_for_scan,
)
) {
config.abort();
}
true
} else {
let use_account = filter(account);
if use_account

View File

@ -82,7 +82,7 @@ use {
solana_measure::{measure::Measure, measure_us},
solana_rayon_threadlimit::get_thread_count,
solana_sdk::{
account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
account::{Account, AccountMetaData, AccountSharedData, ReadableAccount, WritableAccount},
clock::{BankId, Epoch, Slot},
epoch_schedule::EpochSchedule,
genesis_config::{ClusterType, GenesisConfig},
@ -849,6 +849,33 @@ impl<'a> LoadedAccountAccessor<'a> {
}
}
pub fn get_account_meta(&mut self) -> Option<AccountMetaData> {
match self {
LoadedAccountAccessor::Cached(cached_account) => {
let cached_account: Cow<'a, CachedAccount> = cached_account.take().expect(
"Cache flushed/purged should be handled before trying to fetch account",
);
Some(AccountMetaData {
lamports: cached_account.account.lamports(),
owner: *cached_account.account.owner(),
executable: cached_account.account.executable(),
rent_epoch: cached_account.account.rent_epoch(),
space: cached_account.account.data().len(),
})
}
LoadedAccountAccessor::Stored(maybe_storage_entry) => {
// storage entry may not be present if slot was cleaned up in
// between reading the accounts index and calling this function to
// get account meta from the storage entry here
maybe_storage_entry
.as_ref()
.and_then(|(storage_entry, offset)| {
storage_entry.get_stored_account_meta_data(*offset)
})
}
}
}
fn account_matches_owners(&self, owners: &[Pubkey]) -> Result<usize, MatchAccountOwnerError> {
match self {
LoadedAccountAccessor::Cached(cached_account) => cached_account
@ -1141,6 +1168,10 @@ impl AccountStorageEntry {
Some(self.accounts.get_account(offset)?.0)
}
fn get_stored_account_meta_data(&self, offset: usize) -> Option<AccountMetaData> {
self.accounts.get_account_meta(offset)
}
fn add_account(&self, num_bytes: usize) {
let mut count_and_status = self.count_and_status.write().unwrap();
*count_and_status = (count_and_status.0 + 1, count_and_status.1);
@ -4970,8 +5001,17 @@ impl AccountsDb {
index_key,
|pubkey, (account_info, slot)| {
if just_get_program_ids {
let dummy_shared_data = AccountSharedData::new(0, 0, key);
scan_func(Some((pubkey, dummy_shared_data, slot)))
let account_slot = self
.get_account_accessor(slot, pubkey, &account_info.storage_location())
.get_account_meta()
.map(|x| {
(
pubkey,
AccountSharedData::new(x.lamports, x.space, &x.owner),
slot,
)
});
scan_func(account_slot)
} else {
let account_slot = self
.get_account_accessor(slot, pubkey, &account_info.storage_location())
@ -12175,6 +12215,7 @@ pub mod tests {
found_accounts.insert(*account.unwrap().0);
},
&ScanConfig::default(),
false,
)
.unwrap();
assert!(!used_index);
@ -12195,6 +12236,7 @@ pub mod tests {
found_accounts.insert(*account.unwrap().0);
},
&ScanConfig::default(),
false,
)
.unwrap();
assert!(used_index);

View File

@ -7,7 +7,12 @@ use {
storable_accounts::StorableAccounts,
tiered_storage::error::TieredStorageError,
},
solana_sdk::{account::ReadableAccount, clock::Slot, hash::Hash, pubkey::Pubkey},
solana_sdk::{
account::{AccountMetaData, ReadableAccount},
clock::Slot,
hash::Hash,
pubkey::Pubkey,
},
std::{
borrow::Borrow,
mem,
@ -113,6 +118,12 @@ impl AccountsFile {
}
}
pub fn get_account_meta(&self, index: usize) -> Option<AccountMetaData> {
match self {
Self::AppendVec(av) => av.get_account_meta_data(index),
}
}
pub fn account_matches_owners(
&self,
offset: usize,

View File

@ -17,7 +17,7 @@ use {
log::*,
memmap2::MmapMut,
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
account::{AccountMetaData, AccountSharedData, ReadableAccount},
clock::Slot,
hash::Hash,
pubkey::Pubkey,
@ -503,7 +503,7 @@ impl AppendVec {
))
}
fn get_account_meta(&self, offset: usize) -> Option<&AccountMeta> {
pub fn get_account_meta(&self, offset: usize) -> Option<&AccountMeta> {
// Skip over StoredMeta data in the account
let offset = offset.checked_add(mem::size_of::<StoredMeta>())?;
// u64_align! does an unchecked add for alignment. Check that it won't cause an overflow.
@ -512,6 +512,18 @@ impl AppendVec {
Some(account_meta)
}
pub fn get_account_meta_data(&self, offset: usize) -> Option<AccountMetaData> {
let (meta, next): (&StoredMeta, _) = self.get_type(offset)?;
let (account_meta, _): (&AccountMeta, _) = self.get_type(next)?;
Some(AccountMetaData {
lamports: account_meta.lamports,
owner: account_meta.owner,
executable: account_meta.executable,
rent_epoch: account_meta.rent_epoch,
space: meta.data_len as usize,
})
}
/// Return Ok(index_of_matching_owner) if the account owner at `offset` is one of the pubkeys in `owners`.
/// Return Err(MatchAccountOwnerError::NoMatch) if the account has 0 lamports or the owner is not one of
/// the pubkeys in `owners`.

View File

@ -7,6 +7,7 @@ use {
base64::{prelude::BASE64_STANDARD, Engine},
bincode::{config::Options, serialize},
crossbeam_channel::{unbounded, Receiver, Sender},
itertools::Itertools,
jsonrpc_core::{futures::future, types::error, BoxFuture, Error, Metadata, Result},
jsonrpc_derive::rpc,
solana_account_decoder::{
@ -486,11 +487,8 @@ impl JsonRpcRequestProcessor {
min_context_slot,
})?;
let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
let just_get_program_ids = data_slice_config
.clone()
.map(|x| x.length == 0)
.unwrap_or_default()
&& filters.len() == 0;
let just_get_program_ids =
data_slice_config.map(|x| x.length == 0).unwrap_or_default() && filters.is_empty();
optimize_filters(&mut filters);
let keyed_accounts = {
@ -528,6 +526,19 @@ impl JsonRpcRequestProcessor {
})
}
pub fn get_program_addresses(
&self,
program_id: &Pubkey,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Pubkey>> {
let bank = self.get_bank_with_config(RpcContextConfig {
commitment,
min_context_slot: None,
})?;
Ok(self.get_program_addresses_for_bank(&bank, program_id)?)
}
pub async fn get_inflation_reward(
&self,
addresses: Vec<Pubkey>,
@ -2031,7 +2042,11 @@ impl JsonRpcRequestProcessor {
// zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
// updates. We include the redundant filters here to avoid returning these
// accounts.
account.owner() == program_id && filter_closure(account)
if just_get_program_ids {
true
} else {
account.owner() == program_id && filter_closure(account)
}
},
&ScanConfig::default(),
bank.byte_limit_for_scans(),
@ -2050,6 +2065,48 @@ impl JsonRpcRequestProcessor {
}
}
fn get_program_addresses_for_bank(
&self,
bank: &Bank,
program_id: &Pubkey,
) -> RpcCustomResult<Vec<Pubkey>> {
if self
.config
.account_indexes
.contains(&AccountIndex::ProgramId)
{
if !self.config.account_indexes.include_key(program_id) {
return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
index_key: program_id.to_string(),
});
}
Ok(bank
.get_filtered_indexed_accounts(
&IndexKey::ProgramId(*program_id),
|account| {
// The program-id account index checks for Account owner on inclusion. However, due
// to the current AccountsDb implementation, an account may remain in storage as a
// zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
// updates. We include the redundant filters here to avoid returning these
// accounts.
account.owner() == program_id
},
&ScanConfig::default(),
bank.byte_limit_for_scans(),
true,
)
.map(|x| x.iter().map(|y| y.0).collect_vec())
.map_err(|e| RpcCustomError::ScanError {
message: e.to_string(),
})?)
} else {
// this path does not need to provide a mb limit because we only want to support secondary indexes
Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
index_key: program_id.to_string(),
})
}
}
/// Get an iterator of spl-token accounts by owner address
fn get_filtered_spl_token_accounts_by_owner(
&self,
@ -3133,6 +3190,14 @@ pub mod rpc_accounts_scan {
config: Option<RpcProgramAccountsConfig>,
) -> Result<OptionalContext<Vec<RpcKeyedAccount>>>;
#[rpc(meta, name = "getProgramAddresses")]
fn get_program_addresses(
&self,
meta: Self::Metadata,
program_id_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Pubkey>>;
#[rpc(meta, name = "getLargestAccounts")]
fn get_largest_accounts(
&self,
@ -3213,6 +3278,20 @@ pub mod rpc_accounts_scan {
meta.get_program_accounts(&program_id, config, filters, with_context)
}
fn get_program_addresses(
&self,
meta: Self::Metadata,
program_id_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Pubkey>> {
debug!(
"get_program_accounts rpc request received: {:?}",
program_id_str
);
let program_id = verify_pubkey(&program_id_str)?;
meta.get_program_addresses(&program_id, commitment)
}
fn get_largest_accounts(
&self,
meta: Self::Metadata,

View File

@ -118,6 +118,20 @@ pub struct AccountSharedData {
rent_epoch: Epoch,
}
#[derive(PartialEq, Eq, Clone, Default, AbiExample, Deserialize)]
#[serde(from = "AccountMetaData")]
pub struct AccountMetaData {
/// lamports in the account
pub lamports: u64,
/// the program that owns this account. If executable, the program that loads this account.
pub owner: Pubkey,
/// this account's data contains a loaded program (and is now read-only)
pub executable: bool,
/// the epoch at which this account will next owe rent
pub rent_epoch: Epoch,
pub space: usize,
}
/// Compares two ReadableAccounts
///
/// Returns true if accounts are essentially equivalent as in all fields are equivalent.
@ -207,6 +221,16 @@ pub trait ReadableAccount: Sized {
self.rent_epoch(),
)
}
fn to_account_meta(&self) -> AccountMetaData {
AccountMetaData {
lamports: self.lamports(),
owner: self.owner().clone(),
rent_epoch: self.rent_epoch(),
executable: self.executable(),
space: self.data().len(),
}
}
}
impl ReadableAccount for Account {