diff --git a/client/src/rpc_filter.rs b/client/src/rpc_filter.rs index 0944c24c56..a23bf9221b 100644 --- a/client/src/rpc_filter.rs +++ b/client/src/rpc_filter.rs @@ -22,22 +22,11 @@ impl RpcFilterType { MemcmpEncoding::Binary => { use MemcmpEncodedBytes::*; match &compare.bytes { - Binary(bytes) if bytes.len() > MAX_DATA_BASE58_SIZE => { - Err(RpcFilterError::Base58DataTooLarge) - } - Base58(bytes) if bytes.len() > MAX_DATA_BASE58_SIZE => { - Err(RpcFilterError::DataTooLarge) - } - Base64(bytes) if bytes.len() > MAX_DATA_BASE64_SIZE => { - Err(RpcFilterError::DataTooLarge) - } - Bytes(bytes) if bytes.len() > MAX_DATA_SIZE => { - Err(RpcFilterError::DataTooLarge) - } - _ => Ok(()), - }?; - match &compare.bytes { + // DEPRECATED Binary(bytes) => { + if bytes.len() > MAX_DATA_BASE58_SIZE { + return Err(RpcFilterError::Base58DataTooLarge); + } let bytes = bs58::decode(&bytes) .into_vec() .map_err(RpcFilterError::DecodeError)?; @@ -48,6 +37,9 @@ impl RpcFilterType { } } Base58(bytes) => { + if bytes.len() > MAX_DATA_BASE58_SIZE { + return Err(RpcFilterError::DataTooLarge); + } let bytes = bs58::decode(&bytes).into_vec()?; if bytes.len() > MAX_DATA_SIZE { Err(RpcFilterError::DataTooLarge) @@ -56,6 +48,9 @@ impl RpcFilterType { } } Base64(bytes) => { + if bytes.len() > MAX_DATA_BASE64_SIZE { + return Err(RpcFilterError::DataTooLarge); + } let bytes = base64::decode(&bytes)?; if bytes.len() > MAX_DATA_SIZE { Err(RpcFilterError::DataTooLarge) @@ -63,7 +58,12 @@ impl RpcFilterType { Ok(()) } } - Bytes(_) => Ok(()), + Bytes(bytes) => { + if bytes.len() > MAX_DATA_SIZE { + return Err(RpcFilterError::DataTooLarge); + } + Ok(()) + } } } } diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 07b49b2bdf..f01707b582 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -60,7 +60,7 @@ use { fee_calculator::FeeCalculator, hash::Hash, message::{Message, SanitizedMessage}, - pubkey::Pubkey, + pubkey::{Pubkey, PUBKEY_BYTES}, signature::{Keypair, Signature, Signer}, stake::state::{StakeActivationStatus, StakeState}, stake_history::StakeHistory, @@ -377,7 +377,7 @@ impl JsonRpcRequestProcessor { &self, program_id: &Pubkey, config: Option, - filters: Vec, + mut filters: Vec, with_context: bool, ) -> Result>> { let config = config.unwrap_or_default(); @@ -385,6 +385,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())?; + 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)? @@ -1872,7 +1873,6 @@ impl JsonRpcRequestProcessor { index_key: owner_key.to_string(), }); } - optimize_filters(&mut filters); Ok(bank .get_filtered_indexed_accounts(&IndexKey::SplTokenOwner(*owner_key), |account| { account.owner() == &spl_token_id_v2_0() @@ -1921,7 +1921,6 @@ impl JsonRpcRequestProcessor { index_key: mint_key.to_string(), }); } - optimize_filters(&mut filters); Ok(bank .get_filtered_indexed_accounts(&IndexKey::SplTokenMint(*mint_key), |account| { account.owner() == &spl_token_id_v2_0() @@ -2151,58 +2150,86 @@ fn encode_account( } } +/// Analyze custom filters to determine if the result will be a subset of spl-token accounts by +/// owner. +/// 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 { if program_id != &spl_token_id_v2_0() { return None; } let mut data_size_filter: Option = None; let mut owner_key: Option = None; + let mut incorrect_owner_len: Option = None; for filter in filters { match filter { RpcFilterType::DataSize(size) => data_size_filter = Some(*size), RpcFilterType::Memcmp(Memcmp { offset: SPL_TOKEN_ACCOUNT_OWNER_OFFSET, - bytes: MemcmpEncodedBytes::Base58(bytes), + bytes: MemcmpEncodedBytes::Bytes(bytes), .. }) => { - if let Ok(key) = Pubkey::from_str(bytes) { - owner_key = Some(key) + if bytes.len() == PUBKEY_BYTES { + owner_key = Some(Pubkey::new(bytes)); + } else { + incorrect_owner_len = Some(bytes.len()); } } _ => {} } } if data_size_filter == Some(TokenAccount::get_packed_len() as u64) { + if let Some(incorrect_owner_len) = incorrect_owner_len { + info!( + "Incorrect num bytes ({:?}) provided for spl_token_owner_filter", + incorrect_owner_len + ); + } owner_key } else { + debug!("spl_token program filters do not match by-owner index requisites"); None } } +/// Analyze custom filters to determine if the result will be a subset of spl-token accounts by +/// mint. +/// 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 { if program_id != &spl_token_id_v2_0() { return None; } let mut data_size_filter: Option = None; let mut mint: Option = None; + let mut incorrect_mint_len: Option = None; for filter in filters { match filter { RpcFilterType::DataSize(size) => data_size_filter = Some(*size), RpcFilterType::Memcmp(Memcmp { offset: SPL_TOKEN_ACCOUNT_MINT_OFFSET, - bytes: MemcmpEncodedBytes::Base58(bytes), + bytes: MemcmpEncodedBytes::Bytes(bytes), .. }) => { - if let Ok(key) = Pubkey::from_str(bytes) { - mint = Some(key) + if bytes.len() == PUBKEY_BYTES { + mint = Some(Pubkey::new(bytes)); + } else { + incorrect_mint_len = Some(bytes.len()); } } _ => {} } } if data_size_filter == Some(TokenAccount::get_packed_len() as u64) { + if let Some(incorrect_mint_len) = incorrect_mint_len { + info!( + "Incorrect num bytes ({:?}) provided for spl_token_mint_filter", + incorrect_mint_len + ); + } mint } else { + debug!("spl_token program filters do not match by-mint index requisites"); None } } @@ -7673,7 +7700,7 @@ pub mod tests { &[ RpcFilterType::Memcmp(Memcmp { offset: 32, - bytes: MemcmpEncodedBytes::Base58(owner.to_string()), + bytes: MemcmpEncodedBytes::Bytes(owner.to_bytes().to_vec()), encoding: None }), RpcFilterType::DataSize(165) @@ -7689,7 +7716,7 @@ pub mod tests { &[ RpcFilterType::Memcmp(Memcmp { offset: 0, - bytes: MemcmpEncodedBytes::Base58(owner.to_string()), + bytes: MemcmpEncodedBytes::Bytes(owner.to_bytes().to_vec()), encoding: None }), RpcFilterType::DataSize(165) @@ -7703,7 +7730,7 @@ pub mod tests { &[ RpcFilterType::Memcmp(Memcmp { offset: 32, - bytes: MemcmpEncodedBytes::Base58(owner.to_string()), + bytes: MemcmpEncodedBytes::Bytes(owner.to_bytes().to_vec()), encoding: None }), RpcFilterType::DataSize(165)