Handle removing slots during account scans (#17471)
This commit is contained in:
@ -92,6 +92,8 @@ use {
|
||||
tokio::runtime::Runtime,
|
||||
};
|
||||
|
||||
type RpcCustomResult<T> = std::result::Result<T, RpcCustomError>;
|
||||
|
||||
pub const MAX_REQUEST_PAYLOAD_SIZE: usize = 50 * (1 << 10); // 50kB
|
||||
pub const PERFORMANCE_SAMPLES_LIMIT: usize = 720;
|
||||
|
||||
@ -705,18 +707,23 @@ impl JsonRpcRequestProcessor {
|
||||
fn get_largest_accounts(
|
||||
&self,
|
||||
config: Option<RpcLargestAccountsConfig>,
|
||||
) -> RpcResponse<Vec<RpcAccountBalance>> {
|
||||
) -> RpcCustomResult<RpcResponse<Vec<RpcAccountBalance>>> {
|
||||
let config = config.unwrap_or_default();
|
||||
let bank = self.bank(config.commitment);
|
||||
|
||||
if let Some((slot, accounts)) = self.get_cached_largest_accounts(&config.filter) {
|
||||
Response {
|
||||
Ok(Response {
|
||||
context: RpcResponseContext { slot },
|
||||
value: accounts,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let (addresses, address_filter) = if let Some(filter) = config.clone().filter {
|
||||
let non_circulating_supply = calculate_non_circulating_supply(&bank);
|
||||
let non_circulating_supply =
|
||||
calculate_non_circulating_supply(&bank).map_err(|e| {
|
||||
RpcCustomError::ScanError {
|
||||
message: e.to_string(),
|
||||
}
|
||||
})?;
|
||||
let addresses = non_circulating_supply.accounts.into_iter().collect();
|
||||
let address_filter = match filter {
|
||||
RpcLargestAccountsFilter::Circulating => AccountAddressFilter::Exclude,
|
||||
@ -728,6 +735,9 @@ impl JsonRpcRequestProcessor {
|
||||
};
|
||||
let accounts = bank
|
||||
.get_largest_accounts(NUM_LARGEST_ACCOUNTS, &addresses, address_filter)
|
||||
.map_err(|e| RpcCustomError::ScanError {
|
||||
message: e.to_string(),
|
||||
})?
|
||||
.into_iter()
|
||||
.map(|(address, lamports)| RpcAccountBalance {
|
||||
address: address.to_string(),
|
||||
@ -736,15 +746,21 @@ impl JsonRpcRequestProcessor {
|
||||
.collect::<Vec<RpcAccountBalance>>();
|
||||
|
||||
self.set_cached_largest_accounts(&config.filter, bank.slot(), &accounts);
|
||||
new_response(&bank, accounts)
|
||||
Ok(new_response(&bank, accounts))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_supply(&self, commitment: Option<CommitmentConfig>) -> RpcResponse<RpcSupply> {
|
||||
fn get_supply(
|
||||
&self,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> RpcCustomResult<RpcResponse<RpcSupply>> {
|
||||
let bank = self.bank(commitment);
|
||||
let non_circulating_supply = calculate_non_circulating_supply(&bank);
|
||||
let non_circulating_supply =
|
||||
calculate_non_circulating_supply(&bank).map_err(|e| RpcCustomError::ScanError {
|
||||
message: e.to_string(),
|
||||
})?;
|
||||
let total_supply = bank.capitalization();
|
||||
new_response(
|
||||
Ok(new_response(
|
||||
&bank,
|
||||
RpcSupply {
|
||||
total: total_supply,
|
||||
@ -756,7 +772,7 @@ impl JsonRpcRequestProcessor {
|
||||
.map(|pubkey| pubkey.to_string())
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn get_vote_accounts(
|
||||
@ -1738,7 +1754,7 @@ impl JsonRpcRequestProcessor {
|
||||
bank: &Arc<Bank>,
|
||||
program_id: &Pubkey,
|
||||
filters: Vec<RpcFilterType>,
|
||||
) -> Result<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
let filter_closure = |account: &AccountSharedData| {
|
||||
filters.iter().all(|filter_type| match filter_type {
|
||||
RpcFilterType::DataSize(size) => account.data().len() as u64 == *size,
|
||||
@ -1753,21 +1769,26 @@ impl JsonRpcRequestProcessor {
|
||||
if !self.config.account_indexes.include_key(program_id) {
|
||||
return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
|
||||
index_key: program_id.to_string(),
|
||||
}
|
||||
.into());
|
||||
});
|
||||
}
|
||||
Ok(
|
||||
bank.get_filtered_indexed_accounts(&IndexKey::ProgramId(*program_id), |account| {
|
||||
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 && filter_closure(account)
|
||||
}),
|
||||
)
|
||||
})
|
||||
.map_err(|e| RpcCustomError::ScanError {
|
||||
message: e.to_string(),
|
||||
})?)
|
||||
} else {
|
||||
Ok(bank.get_filtered_program_accounts(program_id, filter_closure))
|
||||
Ok(bank
|
||||
.get_filtered_program_accounts(program_id, filter_closure)
|
||||
.map_err(|e| RpcCustomError::ScanError {
|
||||
message: e.to_string(),
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1777,7 +1798,7 @@ impl JsonRpcRequestProcessor {
|
||||
bank: &Arc<Bank>,
|
||||
owner_key: &Pubkey,
|
||||
mut filters: Vec<RpcFilterType>,
|
||||
) -> Result<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
// The by-owner accounts index checks for Token Account state and Owner address 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
|
||||
@ -1802,19 +1823,19 @@ impl JsonRpcRequestProcessor {
|
||||
if !self.config.account_indexes.include_key(owner_key) {
|
||||
return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
|
||||
index_key: owner_key.to_string(),
|
||||
}
|
||||
.into());
|
||||
});
|
||||
}
|
||||
Ok(bank.get_filtered_indexed_accounts(
|
||||
&IndexKey::SplTokenOwner(*owner_key),
|
||||
|account| {
|
||||
Ok(bank
|
||||
.get_filtered_indexed_accounts(&IndexKey::SplTokenOwner(*owner_key), |account| {
|
||||
account.owner() == &spl_token_id_v2_0()
|
||||
&& filters.iter().all(|filter_type| match filter_type {
|
||||
RpcFilterType::DataSize(size) => account.data().len() as u64 == *size,
|
||||
RpcFilterType::Memcmp(compare) => compare.bytes_match(&account.data()),
|
||||
})
|
||||
},
|
||||
))
|
||||
})
|
||||
.map_err(|e| RpcCustomError::ScanError {
|
||||
message: e.to_string(),
|
||||
})?)
|
||||
} else {
|
||||
self.get_filtered_program_accounts(bank, &spl_token_id_v2_0(), filters)
|
||||
}
|
||||
@ -1826,7 +1847,7 @@ impl JsonRpcRequestProcessor {
|
||||
bank: &Arc<Bank>,
|
||||
mint_key: &Pubkey,
|
||||
mut filters: Vec<RpcFilterType>,
|
||||
) -> Result<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
// The by-mint accounts index checks for Token Account state and Mint address on inclusion.
|
||||
// However, due to the current AccountsDb implementation, an account may remain in storage
|
||||
// as be zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
|
||||
@ -1850,18 +1871,19 @@ impl JsonRpcRequestProcessor {
|
||||
if !self.config.account_indexes.include_key(mint_key) {
|
||||
return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
|
||||
index_key: mint_key.to_string(),
|
||||
}
|
||||
.into());
|
||||
});
|
||||
}
|
||||
Ok(
|
||||
bank.get_filtered_indexed_accounts(&IndexKey::SplTokenMint(*mint_key), |account| {
|
||||
Ok(bank
|
||||
.get_filtered_indexed_accounts(&IndexKey::SplTokenMint(*mint_key), |account| {
|
||||
account.owner() == &spl_token_id_v2_0()
|
||||
&& filters.iter().all(|filter_type| match filter_type {
|
||||
RpcFilterType::DataSize(size) => account.data().len() as u64 == *size,
|
||||
RpcFilterType::Memcmp(compare) => compare.bytes_match(&account.data()),
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
.map_err(|e| RpcCustomError::ScanError {
|
||||
message: e.to_string(),
|
||||
})?)
|
||||
} else {
|
||||
self.get_filtered_program_accounts(bank, &spl_token_id_v2_0(), filters)
|
||||
}
|
||||
@ -2872,7 +2894,7 @@ pub mod rpc_full {
|
||||
config: Option<RpcLargestAccountsConfig>,
|
||||
) -> Result<RpcResponse<Vec<RpcAccountBalance>>> {
|
||||
debug!("get_largest_accounts rpc request received");
|
||||
Ok(meta.get_largest_accounts(config))
|
||||
Ok(meta.get_largest_accounts(config)?)
|
||||
}
|
||||
|
||||
fn get_supply(
|
||||
@ -2881,7 +2903,7 @@ pub mod rpc_full {
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<RpcResponse<RpcSupply>> {
|
||||
debug!("get_supply rpc request received");
|
||||
Ok(meta.get_supply(commitment))
|
||||
Ok(meta.get_supply(commitment)?)
|
||||
}
|
||||
|
||||
fn request_airdrop(
|
||||
|
@ -246,6 +246,7 @@ fn process_rest(bank_forks: &Arc<RwLock<BankForks>>, path: &str) -> Option<Strin
|
||||
let total_supply = bank.capitalization();
|
||||
let non_circulating_supply =
|
||||
solana_runtime::non_circulating_supply::calculate_non_circulating_supply(&bank)
|
||||
.expect("Scan should not error on root banks")
|
||||
.lamports;
|
||||
Some(format!(
|
||||
"{}",
|
||||
|
Reference in New Issue
Block a user