Add Memcmp filter constructor and deprecate fields (#29923)

* Deprecate Memcmp inner fields

* Add Memcmp::new

* Replace some literal construction

* Add convert_to_raw_bytes method and use

* Make convert_to_raw_bytes fallible

* Allow literal matches for complex cases
This commit is contained in:
Tyera 2023-01-26 14:50:15 -07:00 committed by GitHub
parent d6fbf3fb17
commit e39153df51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 39 deletions

View File

@ -133,18 +133,35 @@ pub enum MemcmpEncodedBytes {
#[serde(into = "RpcMemcmp", from = "RpcMemcmp")]
pub struct Memcmp {
/// Data offset to begin match
#[deprecated(
since = "1.15.0",
note = "Field will be made private in future. Please use a constructor method instead."
)]
pub offset: usize,
/// Bytes, encoded with specified encoding, or default Binary
#[deprecated(
since = "1.15.0",
note = "Field will be made private in future. Please use a constructor method instead."
)]
pub bytes: MemcmpEncodedBytes,
/// Optional encoding specification
#[deprecated(
since = "1.11.2",
note = "Field has no server-side effect. Specify encoding with `MemcmpEncodedBytes` variant instead."
note = "Field has no server-side effect. Specify encoding with `MemcmpEncodedBytes` variant instead. \
Field will be made private in future. Please use a constructor method instead."
)]
pub encoding: Option<MemcmpEncoding>,
}
impl Memcmp {
pub fn new(offset: usize, encoded_bytes: MemcmpEncodedBytes) -> Self {
Self {
offset,
bytes: encoded_bytes,
encoding: None,
}
}
pub fn new_raw_bytes(offset: usize, bytes: Vec<u8>) -> Self {
Self {
offset,
@ -170,6 +187,23 @@ impl Memcmp {
}
}
pub fn convert_to_raw_bytes(&mut self) -> Result<(), RpcFilterError> {
use MemcmpEncodedBytes::*;
match &self.bytes {
Binary(bytes) | Base58(bytes) => {
let bytes = bs58::decode(bytes).into_vec()?;
self.bytes = Bytes(bytes);
Ok(())
}
Base64(bytes) => {
let bytes = base64::decode(bytes)?;
self.bytes = Bytes(bytes);
Ok(())
}
_ => Ok(()),
}
}
pub fn bytes_match(&self, data: &[u8]) -> bool {
match self.bytes() {
Some(bytes) => {

View File

@ -4421,11 +4421,10 @@ impl RpcClient {
/// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
/// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
/// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
/// let memcmp = RpcFilterType::Memcmp(Memcmp {
/// offset: 0,
/// bytes: MemcmpEncodedBytes::Base64(base64_bytes.to_string()),
/// encoding: None,
/// });
/// let memcmp = RpcFilterType::Memcmp(Memcmp::new(
/// 0, // offset
/// MemcmpEncodedBytes::Base64(base64_bytes.to_string()), // encoded bytes
/// ));
/// let config = RpcProgramAccountsConfig {
/// filters: Some(vec![
/// RpcFilterType::DataSize(128),

View File

@ -3600,11 +3600,10 @@ impl RpcClient {
/// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
/// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
/// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
/// let memcmp = RpcFilterType::Memcmp(Memcmp {
/// offset: 0,
/// bytes: MemcmpEncodedBytes::Base64(base64_bytes.to_string()),
/// encoding: None,
/// });
/// let memcmp = RpcFilterType::Memcmp(Memcmp::new(
/// 0, // offset
/// MemcmpEncodedBytes::Base64(base64_bytes.to_string()), // encoded bytes
/// ));
/// let config = RpcProgramAccountsConfig {
/// filters: Some(vec![
/// RpcFilterType::DataSize(128),

View File

@ -2174,20 +2174,9 @@ impl JsonRpcRequestProcessor {
fn optimize_filters(filters: &mut [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) => {
if let Ok(bytes) = bs58::decode(bytes).into_vec() {
compare.bytes = Bytes(bytes);
}
}
Base64(bytes) => {
if let Ok(bytes) = base64::decode(bytes) {
compare.bytes = Bytes(bytes);
}
}
_ => {}
if let Err(err) = compare.convert_to_raw_bytes() {
// All filters should have been previously verified
warn!("Invalid filter: bytes could not be decoded, {err}");
}
}
})
@ -2338,6 +2327,7 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
for filter in filters {
match filter {
RpcFilterType::DataSize(size) => data_size_filter = Some(*size),
#[allow(deprecated)]
RpcFilterType::Memcmp(Memcmp {
offset,
bytes: MemcmpEncodedBytes::Bytes(bytes),
@ -2345,6 +2335,7 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
}) if *offset == account_packed_len && *program_id == inline_spl_token_2022::id() => {
memcmp_filter = Some(bytes)
}
#[allow(deprecated)]
RpcFilterType::Memcmp(Memcmp {
offset,
bytes: MemcmpEncodedBytes::Bytes(bytes),
@ -2394,6 +2385,7 @@ fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
for filter in filters {
match filter {
RpcFilterType::DataSize(size) => data_size_filter = Some(*size),
#[allow(deprecated)]
RpcFilterType::Memcmp(Memcmp {
offset,
bytes: MemcmpEncodedBytes::Bytes(bytes),
@ -2401,6 +2393,7 @@ fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
}) if *offset == account_packed_len && *program_id == inline_spl_token_2022::id() => {
memcmp_filter = Some(bytes)
}
#[allow(deprecated)]
RpcFilterType::Memcmp(Memcmp {
offset,
bytes: MemcmpEncodedBytes::Bytes(bytes),
@ -6531,22 +6524,16 @@ pub mod tests {
#[test]
fn test_rpc_verify_filter() {
#[allow(deprecated)]
let filter = RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Base58(
"13LeFbG6m2EP1fqCj9k66fcXsoTHMMtgr7c78AivUrYD".to_string(),
),
encoding: None,
});
let filter = RpcFilterType::Memcmp(Memcmp::new(
0, // offset
MemcmpEncodedBytes::Base58("13LeFbG6m2EP1fqCj9k66fcXsoTHMMtgr7c78AivUrYD".to_string()), // encoded bytes
));
assert_eq!(verify_filter(&filter), Ok(()));
// Invalid base-58
#[allow(deprecated)]
let filter = RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Base58("III".to_string()),
encoding: None,
});
let filter = RpcFilterType::Memcmp(Memcmp::new(
0, // offset
MemcmpEncodedBytes::Base58("III".to_string()), // encoded bytes
));
assert!(verify_filter(&filter).is_err());
}