Handle removing slots during account scans (#17471)

This commit is contained in:
carllin
2021-06-14 21:04:01 -07:00
committed by GitHub
parent 471b34132e
commit ccc013e134
15 changed files with 934 additions and 319 deletions

View File

@ -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(

View File

@ -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!(
"{}",