some more optimizations and bugfix on gPA
This commit is contained in:
parent
de5362d4bb
commit
ada5796e7e
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue