Rpc: filters performance improvement (#20185)

* Add Base58,Base64,Bytes to MemcmpEncodedBytes

* Rpc: decode memcmp before filtering accounts

* Add deprecated attribute

* Add Memcmp::bytes

* Fix clippy for deprecated

* Another clippy fix

* merge RpcFilterError::DataTooLarge

* add deprecation for Base58DataTooLarge

* change filter data size limit

* strict data size len for base58

* add magic numbers

* fix tests
This commit is contained in:
Kirill Fomichev
2021-10-14 21:43:27 +03:00
committed by GitHub
parent 4beabb3a43
commit e9a427b9c8
4 changed files with 147 additions and 53 deletions

View File

@ -1704,7 +1704,7 @@ impl JsonRpcRequestProcessor {
// Optional filter on Mint address
filters.push(RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary(mint.to_string()),
bytes: MemcmpEncodedBytes::Bytes(mint.to_bytes().into()),
encoding: None,
}));
}
@ -1748,15 +1748,13 @@ impl JsonRpcRequestProcessor {
// Filter on Delegate is_some()
RpcFilterType::Memcmp(Memcmp {
offset: 72,
bytes: MemcmpEncodedBytes::Binary(
bs58::encode(bincode::serialize(&1u32).unwrap()).into_string(),
),
bytes: MemcmpEncodedBytes::Bytes(bincode::serialize(&1u32).unwrap()),
encoding: None,
}),
// Filter on Delegate address
RpcFilterType::Memcmp(Memcmp {
offset: 76,
bytes: MemcmpEncodedBytes::Binary(delegate.to_string()),
bytes: MemcmpEncodedBytes::Bytes(delegate.to_bytes().into()),
encoding: None,
}),
];
@ -1795,8 +1793,9 @@ impl JsonRpcRequestProcessor {
&self,
bank: &Arc<Bank>,
program_id: &Pubkey,
filters: Vec<RpcFilterType>,
mut filters: Vec<RpcFilterType>,
) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
optimize_filters(&mut filters);
let filter_closure = |account: &AccountSharedData| {
filters.iter().all(|filter_type| match filter_type {
RpcFilterType::DataSize(size) => account.data().len() as u64 == *size,
@ -1853,7 +1852,7 @@ impl JsonRpcRequestProcessor {
// Filter on Owner address
filters.push(RpcFilterType::Memcmp(Memcmp {
offset: SPL_TOKEN_ACCOUNT_OWNER_OFFSET,
bytes: MemcmpEncodedBytes::Binary(owner_key.to_string()),
bytes: MemcmpEncodedBytes::Bytes(owner_key.to_bytes().into()),
encoding: None,
}));
@ -1867,6 +1866,7 @@ 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()
@ -1902,7 +1902,7 @@ impl JsonRpcRequestProcessor {
// Filter on Mint address
filters.push(RpcFilterType::Memcmp(Memcmp {
offset: SPL_TOKEN_ACCOUNT_MINT_OFFSET,
bytes: MemcmpEncodedBytes::Binary(mint_key.to_string()),
bytes: MemcmpEncodedBytes::Bytes(mint_key.to_bytes().into()),
encoding: None,
}));
if self
@ -1915,6 +1915,7 @@ 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()
@ -1970,6 +1971,24 @@ impl JsonRpcRequestProcessor {
}
}
fn optimize_filters(filters: &mut Vec<RpcFilterType>) {
filters.iter_mut().for_each(|filter_type| {
if let RpcFilterType::Memcmp(compare) = filter_type {
use MemcmpEncodedBytes::*;
match &compare.bytes {
#[allow(deprecated)]
Binary(bytes) | Base58(bytes) => {
compare.bytes = Bytes(bs58::decode(bytes).into_vec().unwrap());
}
Base64(bytes) => {
compare.bytes = Bytes(base64::decode(bytes).unwrap());
}
_ => {}
}
}
})
}
fn verify_transaction(
transaction: &SanitizedTransaction,
feature_set: &Arc<feature_set::FeatureSet>,
@ -2136,7 +2155,7 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
RpcFilterType::DataSize(size) => data_size_filter = Some(*size),
RpcFilterType::Memcmp(Memcmp {
offset: SPL_TOKEN_ACCOUNT_OWNER_OFFSET,
bytes: MemcmpEncodedBytes::Binary(bytes),
bytes: MemcmpEncodedBytes::Base58(bytes),
..
}) => {
if let Ok(key) = Pubkey::from_str(bytes) {
@ -2164,7 +2183,7 @@ fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
RpcFilterType::DataSize(size) => data_size_filter = Some(*size),
RpcFilterType::Memcmp(Memcmp {
offset: SPL_TOKEN_ACCOUNT_MINT_OFFSET,
bytes: MemcmpEncodedBytes::Binary(bytes),
bytes: MemcmpEncodedBytes::Base58(bytes),
..
}) => {
if let Ok(key) = Pubkey::from_str(bytes) {
@ -6132,7 +6151,7 @@ pub mod tests {
fn test_rpc_verify_filter() {
let filter = RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary(
bytes: MemcmpEncodedBytes::Base58(
"13LeFbG6m2EP1fqCj9k66fcXsoTHMMtgr7c78AivUrYD".to_string(),
),
encoding: None,
@ -6141,7 +6160,7 @@ pub mod tests {
// Invalid base-58
let filter = RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary("III".to_string()),
bytes: MemcmpEncodedBytes::Base58("III".to_string()),
encoding: None,
});
assert!(verify_filter(&filter).is_err());
@ -7646,7 +7665,7 @@ pub mod tests {
&[
RpcFilterType::Memcmp(Memcmp {
offset: 32,
bytes: MemcmpEncodedBytes::Binary(owner.to_string()),
bytes: MemcmpEncodedBytes::Base58(owner.to_string()),
encoding: None
}),
RpcFilterType::DataSize(165)
@ -7662,7 +7681,7 @@ pub mod tests {
&[
RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary(owner.to_string()),
bytes: MemcmpEncodedBytes::Base58(owner.to_string()),
encoding: None
}),
RpcFilterType::DataSize(165)
@ -7676,7 +7695,7 @@ pub mod tests {
&[
RpcFilterType::Memcmp(Memcmp {
offset: 32,
bytes: MemcmpEncodedBytes::Binary(owner.to_string()),
bytes: MemcmpEncodedBytes::Base58(owner.to_string()),
encoding: None
}),
RpcFilterType::DataSize(165)