Prepare RPC subsystem for multiple SPL Token program ids
This commit is contained in:
@ -11,7 +11,7 @@ use {
|
||||
jsonrpc_derive::rpc,
|
||||
serde::{Deserialize, Serialize},
|
||||
solana_account_decoder::{
|
||||
parse_token::{spl_token_id, token_amount_to_ui_amount, UiTokenAmount},
|
||||
parse_token::{is_known_spl_token_id, token_amount_to_ui_amount, UiTokenAmount},
|
||||
UiAccount, UiAccountEncoding, UiDataSliceConfig, MAX_BASE58_BYTES,
|
||||
},
|
||||
solana_client::{
|
||||
@ -405,14 +405,15 @@ impl JsonRpcRequestProcessor {
|
||||
optimize_filters(&mut filters);
|
||||
let keyed_accounts = {
|
||||
if let Some(owner) = get_spl_token_owner_filter(program_id, &filters) {
|
||||
self.get_filtered_spl_token_accounts_by_owner(&bank, &owner, filters)?
|
||||
self.get_filtered_spl_token_accounts_by_owner(&bank, program_id, &owner, filters)?
|
||||
} else if let Some(mint) = get_spl_token_mint_filter(program_id, &filters) {
|
||||
self.get_filtered_spl_token_accounts_by_mint(&bank, &mint, filters)?
|
||||
self.get_filtered_spl_token_accounts_by_mint(&bank, program_id, &mint, filters)?
|
||||
} else {
|
||||
self.get_filtered_program_accounts(&bank, program_id, filters)?
|
||||
}
|
||||
};
|
||||
let accounts = if program_id == &spl_token_id() && encoding == UiAccountEncoding::JsonParsed
|
||||
let accounts = if is_known_spl_token_id(program_id)
|
||||
&& encoding == UiAccountEncoding::JsonParsed
|
||||
{
|
||||
get_parsed_token_accounts(bank.clone(), keyed_accounts.into_iter()).collect()
|
||||
} else {
|
||||
@ -1709,7 +1710,7 @@ impl JsonRpcRequestProcessor {
|
||||
Error::invalid_params("Invalid param: could not find account".to_string())
|
||||
})?;
|
||||
|
||||
if account.owner() != &spl_token_id() {
|
||||
if !is_known_spl_token_id(account.owner()) {
|
||||
return Err(Error::invalid_params(
|
||||
"Invalid param: not a Token account".to_string(),
|
||||
));
|
||||
@ -1732,7 +1733,7 @@ impl JsonRpcRequestProcessor {
|
||||
let mint_account = bank.get_account(mint).ok_or_else(|| {
|
||||
Error::invalid_params("Invalid param: could not find account".to_string())
|
||||
})?;
|
||||
if mint_account.owner() != &spl_token_id() {
|
||||
if !is_known_spl_token_id(mint_account.owner()) {
|
||||
return Err(Error::invalid_params(
|
||||
"Invalid param: not a Token mint".to_string(),
|
||||
));
|
||||
@ -1752,13 +1753,13 @@ impl JsonRpcRequestProcessor {
|
||||
) -> Result<RpcResponse<Vec<RpcTokenAccountBalance>>> {
|
||||
let bank = self.bank(commitment);
|
||||
let (mint_owner, decimals) = get_mint_owner_and_decimals(&bank, mint)?;
|
||||
if mint_owner != spl_token_id() {
|
||||
if !is_known_spl_token_id(&mint_owner) {
|
||||
return Err(Error::invalid_params(
|
||||
"Invalid param: not a Token mint".to_string(),
|
||||
));
|
||||
}
|
||||
let mut token_balances: Vec<RpcTokenAccountBalance> = self
|
||||
.get_filtered_spl_token_accounts_by_mint(&bank, mint, vec![])?
|
||||
.get_filtered_spl_token_accounts_by_mint(&bank, &mint_owner, mint, vec![])?
|
||||
.into_iter()
|
||||
.map(|(address, account)| {
|
||||
let amount = TokenAccount::unpack(account.data())
|
||||
@ -1794,7 +1795,7 @@ impl JsonRpcRequestProcessor {
|
||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||
let data_slice_config = config.data_slice;
|
||||
check_slice_and_encoding(&encoding, data_slice_config.is_some())?;
|
||||
let (_, mint) = get_token_program_id_and_mint(&bank, token_account_filter)?;
|
||||
let (token_program_id, mint) = get_token_program_id_and_mint(&bank, token_account_filter)?;
|
||||
|
||||
let mut filters = vec![];
|
||||
if let Some(mint) = mint {
|
||||
@ -1806,8 +1807,12 @@ impl JsonRpcRequestProcessor {
|
||||
}));
|
||||
}
|
||||
|
||||
let keyed_accounts =
|
||||
self.get_filtered_spl_token_accounts_by_owner(&bank, owner, filters)?;
|
||||
let keyed_accounts = self.get_filtered_spl_token_accounts_by_owner(
|
||||
&bank,
|
||||
&token_program_id,
|
||||
owner,
|
||||
filters,
|
||||
)?;
|
||||
let accounts = if encoding == UiAccountEncoding::JsonParsed {
|
||||
get_parsed_token_accounts(bank.clone(), keyed_accounts.into_iter()).collect()
|
||||
} else {
|
||||
@ -1853,7 +1858,7 @@ impl JsonRpcRequestProcessor {
|
||||
];
|
||||
// Optional filter on Mint address, uses mint account index for scan
|
||||
let keyed_accounts = if let Some(mint) = mint {
|
||||
self.get_filtered_spl_token_accounts_by_mint(&bank, &mint, filters)?
|
||||
self.get_filtered_spl_token_accounts_by_mint(&bank, &token_program_id, &mint, filters)?
|
||||
} else {
|
||||
// Filter on Token Account state
|
||||
filters.push(RpcFilterType::DataSize(
|
||||
@ -1932,6 +1937,7 @@ impl JsonRpcRequestProcessor {
|
||||
fn get_filtered_spl_token_accounts_by_owner(
|
||||
&self,
|
||||
bank: &Arc<Bank>,
|
||||
program_id: &Pubkey,
|
||||
owner_key: &Pubkey,
|
||||
mut filters: Vec<RpcFilterType>,
|
||||
) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
@ -1965,7 +1971,7 @@ impl JsonRpcRequestProcessor {
|
||||
.get_filtered_indexed_accounts(
|
||||
&IndexKey::SplTokenOwner(*owner_key),
|
||||
|account| {
|
||||
account.owner() == &spl_token_id()
|
||||
account.owner() == program_id
|
||||
&& filters.iter().all(|filter_type| match filter_type {
|
||||
RpcFilterType::DataSize(size) => {
|
||||
account.data().len() as u64 == *size
|
||||
@ -1982,7 +1988,7 @@ impl JsonRpcRequestProcessor {
|
||||
message: e.to_string(),
|
||||
})?)
|
||||
} else {
|
||||
self.get_filtered_program_accounts(bank, &spl_token_id(), filters)
|
||||
self.get_filtered_program_accounts(bank, program_id, filters)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1990,6 +1996,7 @@ impl JsonRpcRequestProcessor {
|
||||
fn get_filtered_spl_token_accounts_by_mint(
|
||||
&self,
|
||||
bank: &Arc<Bank>,
|
||||
program_id: &Pubkey,
|
||||
mint_key: &Pubkey,
|
||||
mut filters: Vec<RpcFilterType>,
|
||||
) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
@ -2022,7 +2029,7 @@ impl JsonRpcRequestProcessor {
|
||||
.get_filtered_indexed_accounts(
|
||||
&IndexKey::SplTokenMint(*mint_key),
|
||||
|account| {
|
||||
account.owner() == &spl_token_id()
|
||||
account.owner() == program_id
|
||||
&& filters.iter().all(|filter_type| match filter_type {
|
||||
RpcFilterType::DataSize(size) => {
|
||||
account.data().len() as u64 == *size
|
||||
@ -2039,7 +2046,7 @@ impl JsonRpcRequestProcessor {
|
||||
message: e.to_string(),
|
||||
})?)
|
||||
} else {
|
||||
self.get_filtered_program_accounts(bank, &spl_token_id(), filters)
|
||||
self.get_filtered_program_accounts(bank, program_id, filters)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2217,7 +2224,7 @@ fn get_encoded_account(
|
||||
) -> Result<Option<UiAccount>> {
|
||||
match bank.get_account(pubkey) {
|
||||
Some(account) => {
|
||||
let response = if account.owner() == &spl_token_id()
|
||||
let response = if is_known_spl_token_id(account.owner())
|
||||
&& encoding == UiAccountEncoding::JsonParsed
|
||||
{
|
||||
get_parsed_token_account(bank.clone(), pubkey, account)
|
||||
@ -2257,7 +2264,7 @@ fn encode_account<T: ReadableAccount>(
|
||||
/// NOTE: `optimize_filters()` should almost always be called before using this method because of
|
||||
/// the strict match on `MemcmpEncodedBytes::Bytes`.
|
||||
fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) -> Option<Pubkey> {
|
||||
if program_id != &spl_token_id() {
|
||||
if !is_known_spl_token_id(program_id) {
|
||||
return None;
|
||||
}
|
||||
let mut data_size_filter: Option<u64> = None;
|
||||
@ -2299,7 +2306,7 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
|
||||
/// NOTE: `optimize_filters()` should almost always be called before using this method because of
|
||||
/// the strict match on `MemcmpEncodedBytes::Bytes`.
|
||||
fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) -> Option<Pubkey> {
|
||||
if program_id != &spl_token_id() {
|
||||
if !is_known_spl_token_id(program_id) {
|
||||
return None;
|
||||
}
|
||||
let mut data_size_filter: Option<u64> = None;
|
||||
@ -2345,7 +2352,7 @@ fn get_token_program_id_and_mint(
|
||||
match token_account_filter {
|
||||
TokenAccountsFilter::Mint(mint) => {
|
||||
let (mint_owner, _) = get_mint_owner_and_decimals(bank, &mint)?;
|
||||
if mint_owner != spl_token_id() {
|
||||
if !is_known_spl_token_id(&mint_owner) {
|
||||
return Err(Error::invalid_params(
|
||||
"Invalid param: not a Token mint".to_string(),
|
||||
));
|
||||
@ -2353,7 +2360,7 @@ fn get_token_program_id_and_mint(
|
||||
Ok((mint_owner, Some(mint)))
|
||||
}
|
||||
TokenAccountsFilter::ProgramId(program_id) => {
|
||||
if program_id == spl_token_id() {
|
||||
if is_known_spl_token_id(&program_id) {
|
||||
Ok((program_id, None))
|
||||
} else {
|
||||
Err(Error::invalid_params(
|
||||
@ -4422,6 +4429,10 @@ pub mod tests {
|
||||
std::collections::HashMap,
|
||||
};
|
||||
|
||||
fn spl_token_id() -> Pubkey {
|
||||
solana_account_decoder::parse_token::spl_token_ids()[0]
|
||||
}
|
||||
|
||||
const TEST_MINT_LAMPORTS: u64 = 1_000_000;
|
||||
const TEST_SLOTS_PER_EPOCH: u64 = DELINQUENT_VALIDATOR_SLOT_DISTANCE + 1;
|
||||
|
||||
|
Reference in New Issue
Block a user