Browse Source

Remove deprecated Memcmp filter symbols (#2050)

* Add test to demonstrate serialization and acceptable json inputs

* Remove custom serialization

* Unpub deprecated fields

* Remove deprecated, unused field

* Remove deprecated MemcmpEncodedBytes variant

* Remove deprecated error variants

* Add back custom deserialization to support missing 'encoding' field

* Update tests to demonstrate consistency and changes

* Add helper fns to use in rpc spl-token filter checks

* Update base64 syntax and remove allow-deprecated
Tyera 1 year ago
parent
commit
3b3ffbb6c9
4 changed files with 239 additions and 223 deletions
  1. 1 0
      Cargo.lock
  2. 1 0
      rpc-client-api/Cargo.toml
  3. 209 181
      rpc-client-api/src/filter.rs
  4. 28 42
      rpc/src/rpc.rs

+ 1 - 0
Cargo.lock

@@ -7090,6 +7090,7 @@ dependencies = [
  "anyhow",
  "base64 0.22.1",
  "bs58",
+ "const_format",
  "jsonrpc-core",
  "reqwest",
  "reqwest-middleware",

+ 1 - 0
rpc-client-api/Cargo.toml

@@ -28,6 +28,7 @@ solana-version = { workspace = true }
 thiserror = { workspace = true }
 
 [dev-dependencies]
+const_format = { workspace = true }
 
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]

+ 209 - 181
rpc-client-api/src/filter.rs

@@ -1,5 +1,6 @@
-#![allow(deprecated)]
 use {
+    base64::{prelude::BASE64_STANDARD, Engine},
+    serde::Deserialize,
     solana_inline_spl::{token::GenericTokenAccount, token_2022::Account},
     solana_sdk::account::{AccountSharedData, ReadableAccount},
     std::borrow::Cow,
@@ -23,55 +24,36 @@ impl RpcFilterType {
         match self {
             RpcFilterType::DataSize(_) => Ok(()),
             RpcFilterType::Memcmp(compare) => {
-                let encoding = compare.encoding.as_ref().unwrap_or(&MemcmpEncoding::Binary);
-                match encoding {
-                    MemcmpEncoding::Binary => {
-                        use MemcmpEncodedBytes::*;
-                        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)?;
-                                if bytes.len() > MAX_DATA_SIZE {
-                                    Err(RpcFilterError::Base58DataTooLarge)
-                                } else {
-                                    Ok(())
-                                }
-                            }
-                            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)
-                                } else {
-                                    Ok(())
-                                }
-                            }
-                            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)
-                                } else {
-                                    Ok(())
-                                }
-                            }
-                            Bytes(bytes) => {
-                                if bytes.len() > MAX_DATA_SIZE {
-                                    return Err(RpcFilterError::DataTooLarge);
-                                }
-                                Ok(())
-                            }
+                use MemcmpEncodedBytes::*;
+                match &compare.bytes {
+                    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)
+                        } else {
+                            Ok(())
+                        }
+                    }
+                    Base64(bytes) => {
+                        if bytes.len() > MAX_DATA_BASE64_SIZE {
+                            return Err(RpcFilterError::DataTooLarge);
+                        }
+                        let bytes = BASE64_STANDARD.decode(bytes)?;
+                        if bytes.len() > MAX_DATA_SIZE {
+                            Err(RpcFilterError::DataTooLarge)
+                        } else {
+                            Ok(())
                         }
                     }
+                    Bytes(bytes) => {
+                        if bytes.len() > MAX_DATA_SIZE {
+                            return Err(RpcFilterError::DataTooLarge);
+                        }
+                        Ok(())
+                    }
                 }
             }
             RpcFilterType::TokenAccountState => Ok(()),
@@ -95,65 +77,68 @@ impl RpcFilterType {
 pub enum RpcFilterError {
     #[error("encoded binary data should be less than 129 bytes")]
     DataTooLarge,
-    #[deprecated(
-        since = "1.8.1",
-        note = "Error for MemcmpEncodedBytes::Binary which is deprecated"
-    )]
-    #[error("encoded binary (base 58) data should be less than 129 bytes")]
-    Base58DataTooLarge,
-    #[deprecated(
-        since = "1.8.1",
-        note = "Error for MemcmpEncodedBytes::Binary which is deprecated"
-    )]
-    #[error("bs58 decode error")]
-    DecodeError(bs58::decode::Error),
     #[error("base58 decode error")]
     Base58DecodeError(#[from] bs58::decode::Error),
     #[error("base64 decode error")]
     Base64DecodeError(#[from] base64::DecodeError),
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub enum MemcmpEncoding {
-    Binary,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase", untagged)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
+#[serde(rename_all = "camelCase", tag = "encoding", content = "bytes")]
 pub enum MemcmpEncodedBytes {
-    #[deprecated(
-        since = "1.8.1",
-        note = "Please use MemcmpEncodedBytes::Base58 instead"
-    )]
-    Binary(String),
     Base58(String),
     Base64(String),
     Bytes(Vec<u8>),
 }
 
+impl<'de> Deserialize<'de> for MemcmpEncodedBytes {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        #[serde(untagged)]
+        enum DataType {
+            Encoded(String),
+            Raw(Vec<u8>),
+        }
+
+        #[derive(Deserialize)]
+        #[serde(rename_all = "camelCase")]
+        enum RpcMemcmpEncoding {
+            Base58,
+            Base64,
+            Bytes,
+        }
+
+        #[derive(Deserialize)]
+        struct RpcMemcmpInner {
+            bytes: DataType,
+            encoding: Option<RpcMemcmpEncoding>,
+        }
+
+        let data = RpcMemcmpInner::deserialize(deserializer)?;
+
+        let memcmp_encoded_bytes = match data.bytes {
+            DataType::Encoded(bytes) => match data.encoding.unwrap_or(RpcMemcmpEncoding::Base58) {
+                RpcMemcmpEncoding::Base58 => MemcmpEncodedBytes::Base58(bytes),
+                RpcMemcmpEncoding::Base64 => MemcmpEncodedBytes::Base64(bytes),
+                _ => unreachable!(),
+            },
+            DataType::Raw(bytes) => MemcmpEncodedBytes::Bytes(bytes),
+        };
+
+        Ok(memcmp_encoded_bytes)
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[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. \
-            Field will be made private in future. Please use a constructor method instead."
-    )]
-    pub encoding: Option<MemcmpEncoding>,
+    offset: usize,
+    /// Bytes, encoded with specified encoding
+    #[serde(flatten)]
+    bytes: MemcmpEncodedBytes,
 }
 
 impl Memcmp {
@@ -161,7 +146,6 @@ impl Memcmp {
         Self {
             offset,
             bytes: encoded_bytes,
-            encoding: None,
         }
     }
 
@@ -169,7 +153,6 @@ impl Memcmp {
         Self {
             offset,
             bytes: MemcmpEncodedBytes::Bytes(bytes),
-            encoding: None,
         }
     }
 
@@ -177,15 +160,18 @@ impl Memcmp {
         Self {
             offset,
             bytes: MemcmpEncodedBytes::Base58(bs58::encode(bytes).into_string()),
-            encoding: None,
         }
     }
 
+    pub fn offset(&self) -> usize {
+        self.offset
+    }
+
     pub fn bytes(&self) -> Option<Cow<Vec<u8>>> {
         use MemcmpEncodedBytes::*;
         match &self.bytes {
-            Binary(bytes) | Base58(bytes) => bs58::decode(bytes).into_vec().ok().map(Cow::Owned),
-            Base64(bytes) => base64::decode(bytes).ok().map(Cow::Owned),
+            Base58(bytes) => bs58::decode(bytes).into_vec().ok().map(Cow::Owned),
+            Base64(bytes) => BASE64_STANDARD.decode(bytes).ok().map(Cow::Owned),
             Bytes(bytes) => Some(Cow::Borrowed(bytes)),
         }
     }
@@ -193,13 +179,13 @@ impl Memcmp {
     pub fn convert_to_raw_bytes(&mut self) -> Result<(), RpcFilterError> {
         use MemcmpEncodedBytes::*;
         match &self.bytes {
-            Binary(bytes) | Base58(bytes) => {
+            Base58(bytes) => {
                 let bytes = bs58::decode(bytes).into_vec()?;
                 self.bytes = Bytes(bytes);
                 Ok(())
             }
             Base64(bytes) => {
-                let bytes = base64::decode(bytes)?;
+                let bytes = BASE64_STANDARD.decode(bytes)?;
                 self.bytes = Bytes(bytes);
                 Ok(())
             }
@@ -221,92 +207,34 @@ impl Memcmp {
             None => false,
         }
     }
-}
-
-// Internal struct to hold Memcmp filter data as either encoded String or raw Bytes
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[serde(untagged)]
-enum DataType {
-    Encoded(String),
-    Raw(Vec<u8>),
-}
-
-// Internal struct used to specify explicit Base58 and Base64 encoding
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-enum RpcMemcmpEncoding {
-    Base58,
-    Base64,
-    // This variant exists only to preserve backward compatibility with generic `Memcmp` serde
-    #[serde(other)]
-    Binary,
-}
-
-// Internal struct to enable Memcmp filters with explicit Base58 and Base64 encoding. The From
-// implementations emulate `#[serde(tag = "encoding", content = "bytes")]` for
-// `MemcmpEncodedBytes`. On the next major version, all these internal elements should be removed
-// and replaced with adjacent tagging of `MemcmpEncodedBytes`.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-struct RpcMemcmp {
-    offset: usize,
-    bytes: DataType,
-    encoding: Option<RpcMemcmpEncoding>,
-}
-
-impl From<Memcmp> for RpcMemcmp {
-    fn from(memcmp: Memcmp) -> RpcMemcmp {
-        let (bytes, encoding) = match memcmp.bytes {
-            MemcmpEncodedBytes::Binary(string) => {
-                (DataType::Encoded(string), Some(RpcMemcmpEncoding::Binary))
-            }
-            MemcmpEncodedBytes::Base58(string) => {
-                (DataType::Encoded(string), Some(RpcMemcmpEncoding::Base58))
-            }
-            MemcmpEncodedBytes::Base64(string) => {
-                (DataType::Encoded(string), Some(RpcMemcmpEncoding::Base64))
-            }
-            MemcmpEncodedBytes::Bytes(vector) => (DataType::Raw(vector), None),
-        };
-        RpcMemcmp {
-            offset: memcmp.offset,
-            bytes,
-            encoding,
-        }
-    }
-}
 
-impl From<RpcMemcmp> for Memcmp {
-    fn from(memcmp: RpcMemcmp) -> Memcmp {
-        let encoding = memcmp.encoding.unwrap_or(RpcMemcmpEncoding::Binary);
-        let bytes = match (encoding, memcmp.bytes) {
-            (RpcMemcmpEncoding::Binary, DataType::Encoded(string))
-            | (RpcMemcmpEncoding::Base58, DataType::Encoded(string)) => {
-                MemcmpEncodedBytes::Base58(string)
-            }
-            (RpcMemcmpEncoding::Binary, DataType::Raw(vector)) => MemcmpEncodedBytes::Bytes(vector),
-            (RpcMemcmpEncoding::Base64, DataType::Encoded(string)) => {
-                MemcmpEncodedBytes::Base64(string)
-            }
-            _ => unreachable!(),
-        };
-        Memcmp {
-            offset: memcmp.offset,
-            bytes,
-            encoding: None,
+    /// Returns reference to bytes if variant is MemcmpEncodedBytes::Bytes;
+    /// otherwise returns None. Used exclusively by solana-rpc to check
+    /// SPL-token filters.
+    pub fn raw_bytes_as_ref(&self) -> Option<&[u8]> {
+        use MemcmpEncodedBytes::*;
+        if let Bytes(bytes) = &self.bytes {
+            Some(bytes)
+        } else {
+            None
         }
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use super::*;
+    use {
+        super::*,
+        const_format::formatcp,
+        serde_json::{json, Value},
+    };
 
     #[test]
     fn test_worst_case_encoded_tx_goldens() {
         let ff_data = vec![0xffu8; MAX_DATA_SIZE];
         let data58 = bs58::encode(&ff_data).into_string();
         assert_eq!(data58.len(), MAX_DATA_BASE58_SIZE);
-        let data64 = base64::encode(&ff_data);
+        let data64 = BASE64_STANDARD.encode(&ff_data);
         assert_eq!(data64.len(), MAX_DATA_BASE64_SIZE);
     }
 
@@ -318,7 +246,6 @@ mod tests {
         assert!(Memcmp {
             offset: 0,
             bytes: MemcmpEncodedBytes::Base58(bs58::encode(vec![1, 2, 3, 4, 5]).into_string()),
-            encoding: None,
         }
         .bytes_match(&data));
 
@@ -326,7 +253,6 @@ mod tests {
         assert!(Memcmp {
             offset: 0,
             bytes: MemcmpEncodedBytes::Base58(bs58::encode(vec![1, 2]).into_string()),
-            encoding: None,
         }
         .bytes_match(&data));
 
@@ -334,7 +260,6 @@ mod tests {
         assert!(Memcmp {
             offset: 2,
             bytes: MemcmpEncodedBytes::Base58(bs58::encode(vec![3, 4]).into_string()),
-            encoding: None,
         }
         .bytes_match(&data));
 
@@ -342,7 +267,6 @@ mod tests {
         assert!(!Memcmp {
             offset: 0,
             bytes: MemcmpEncodedBytes::Base58(bs58::encode(vec![2]).into_string()),
-            encoding: None,
         }
         .bytes_match(&data));
 
@@ -350,7 +274,6 @@ mod tests {
         assert!(!Memcmp {
             offset: 2,
             bytes: MemcmpEncodedBytes::Base58(bs58::encode(vec![3, 4, 5, 6]).into_string()),
-            encoding: None,
         }
         .bytes_match(&data));
 
@@ -358,7 +281,6 @@ mod tests {
         assert!(!Memcmp {
             offset: 6,
             bytes: MemcmpEncodedBytes::Base58(bs58::encode(vec![5]).into_string()),
-            encoding: None,
         }
         .bytes_match(&data));
 
@@ -366,7 +288,6 @@ mod tests {
         assert!(!Memcmp {
             offset: 0,
             bytes: MemcmpEncodedBytes::Base58("III".to_string()),
-            encoding: None,
         }
         .bytes_match(&data));
     }
@@ -381,7 +302,6 @@ mod tests {
             RpcFilterType::Memcmp(Memcmp {
                 offset: 0,
                 bytes: MemcmpEncodedBytes::Base58(base58_bytes.to_string()),
-                encoding: None,
             })
             .verify(),
             Ok(())
@@ -396,10 +316,118 @@ mod tests {
             RpcFilterType::Memcmp(Memcmp {
                 offset: 0,
                 bytes: MemcmpEncodedBytes::Base58(base58_bytes.to_string()),
-                encoding: None,
             })
             .verify(),
             Err(RpcFilterError::DataTooLarge)
         );
     }
+
+    const BASE58_STR: &str = "Bpf4ERpEvSFmCSTNh1PzTWTkALrKXvMXEdthxHuwCQcf";
+    const BASE64_STR: &str = "oMoycDvJzrjQpCfukbO4VW/FLGLfnbqBEc9KUEVgj2g=";
+    const BYTES: [u8; 4] = [0, 1, 2, 3];
+    const OFFSET: usize = 42;
+    const DEFAULT_ENCODING_FILTER: &str =
+        formatcp!(r#"{{"bytes":"{BASE58_STR}","offset":{OFFSET}}}"#);
+    const BINARY_FILTER: &str =
+        formatcp!(r#"{{"bytes":"{BASE58_STR}","offset":{OFFSET},"encoding":"binary"}}"#);
+    const BASE58_FILTER: &str =
+        formatcp!(r#"{{"bytes":"{BASE58_STR}","offset":{OFFSET},"encoding":"base58"}}"#);
+    const BASE64_FILTER: &str =
+        formatcp!(r#"{{"bytes":"{BASE64_STR}","offset":{OFFSET},"encoding":"base64"}}"#);
+    const BYTES_FILTER: &str =
+        formatcp!(r#"{{"bytes":[0, 1, 2, 3],"offset":{OFFSET},"encoding":null}}"#);
+    const BYTES_FILTER_WITH_ENCODING: &str =
+        formatcp!(r#"{{"bytes":[0, 1, 2, 3],"offset":{OFFSET},"encoding":"bytes"}}"#);
+
+    #[test]
+    fn test_filter_deserialize() {
+        // Base58 is the default encoding
+        let default: Memcmp = serde_json::from_str(DEFAULT_ENCODING_FILTER).unwrap();
+        assert_eq!(
+            default,
+            Memcmp {
+                offset: OFFSET,
+                bytes: MemcmpEncodedBytes::Base58(BASE58_STR.to_string()),
+            }
+        );
+
+        // Binary input is no longer supported
+        let binary = serde_json::from_str::<Memcmp>(BINARY_FILTER);
+        assert!(binary.is_err());
+
+        // Base58 input
+        let base58_filter: Memcmp = serde_json::from_str(BASE58_FILTER).unwrap();
+        assert_eq!(
+            base58_filter,
+            Memcmp {
+                offset: OFFSET,
+                bytes: MemcmpEncodedBytes::Base58(BASE58_STR.to_string()),
+            }
+        );
+
+        // Base64 input
+        let base64_filter: Memcmp = serde_json::from_str(BASE64_FILTER).unwrap();
+        assert_eq!(
+            base64_filter,
+            Memcmp {
+                offset: OFFSET,
+                bytes: MemcmpEncodedBytes::Base64(BASE64_STR.to_string()),
+            }
+        );
+
+        // Raw bytes input
+        let bytes_filter: Memcmp = serde_json::from_str(BYTES_FILTER).unwrap();
+        assert_eq!(
+            bytes_filter,
+            Memcmp {
+                offset: OFFSET,
+                bytes: MemcmpEncodedBytes::Bytes(BYTES.to_vec()),
+            }
+        );
+
+        let bytes_filter: Memcmp = serde_json::from_str(BYTES_FILTER_WITH_ENCODING).unwrap();
+        assert_eq!(
+            bytes_filter,
+            Memcmp {
+                offset: OFFSET,
+                bytes: MemcmpEncodedBytes::Bytes(BYTES.to_vec()),
+            }
+        );
+    }
+
+    #[test]
+    fn test_filter_serialize() {
+        // Base58
+        let base58 = Memcmp {
+            offset: OFFSET,
+            bytes: MemcmpEncodedBytes::Base58(BASE58_STR.to_string()),
+        };
+        let serialized_json = json!(base58);
+        assert_eq!(
+            serialized_json,
+            serde_json::from_str::<Value>(BASE58_FILTER).unwrap()
+        );
+
+        // Base64
+        let base64 = Memcmp {
+            offset: OFFSET,
+            bytes: MemcmpEncodedBytes::Base64(BASE64_STR.to_string()),
+        };
+        let serialized_json = json!(base64);
+        assert_eq!(
+            serialized_json,
+            serde_json::from_str::<Value>(BASE64_FILTER).unwrap()
+        );
+
+        // Bytes
+        let bytes = Memcmp {
+            offset: OFFSET,
+            bytes: MemcmpEncodedBytes::Bytes(BYTES.to_vec()),
+        };
+        let serialized_json = json!(bytes);
+        assert_eq!(
+            serialized_json,
+            serde_json::from_str::<Value>(BYTES_FILTER_WITH_ENCODING).unwrap()
+        );
+    }
 }

+ 28 - 42
rpc/src/rpc.rs

@@ -39,7 +39,7 @@ use {
     solana_rpc_client_api::{
         config::*,
         custom_error::RpcCustomError,
-        filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
+        filter::{Memcmp, RpcFilterType},
         request::{
             TokenAccountsFilter, DELINQUENT_VALIDATOR_SLOT_DISTANCE,
             MAX_GET_CONFIRMED_BLOCKS_RANGE, MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT,
@@ -2379,7 +2379,7 @@ fn encode_account<T: ReadableAccount>(
 /// 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`.
+/// the requirement that `Memcmp::raw_bytes_as_ref().is_some()`.
 fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) -> Option<Pubkey> {
     if !is_known_spl_token_id(program_id) {
         return None;
@@ -2393,28 +2393,21 @@ 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),
-                ..
-            }) if *offset == account_packed_len && *program_id == token_2022::id() => {
-                memcmp_filter = Some(bytes)
-            }
-            #[allow(deprecated)]
-            RpcFilterType::Memcmp(Memcmp {
-                offset,
-                bytes: MemcmpEncodedBytes::Bytes(bytes),
-                ..
-            }) if *offset == SPL_TOKEN_ACCOUNT_OWNER_OFFSET => {
-                if bytes.len() == PUBKEY_BYTES {
-                    owner_key = Pubkey::try_from(&bytes[..]).ok();
-                } else {
-                    incorrect_owner_len = Some(bytes.len());
+            RpcFilterType::Memcmp(memcmp) => {
+                let offset = memcmp.offset();
+                if let Some(bytes) = memcmp.raw_bytes_as_ref() {
+                    if offset == account_packed_len && *program_id == token_2022::id() {
+                        memcmp_filter = Some(bytes);
+                    } else if offset == SPL_TOKEN_ACCOUNT_OWNER_OFFSET {
+                        if bytes.len() == PUBKEY_BYTES {
+                            owner_key = Pubkey::try_from(bytes).ok();
+                        } else {
+                            incorrect_owner_len = Some(bytes.len());
+                        }
+                    }
                 }
             }
             RpcFilterType::TokenAccountState => token_account_state_filter = true,
-            _ => {}
         }
     }
     if data_size_filter == Some(account_packed_len as u64)
@@ -2437,7 +2430,7 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
 /// 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`.
+/// the requirement that `Memcmp::raw_bytes_as_ref().is_some()`.
 fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) -> Option<Pubkey> {
     if !is_known_spl_token_id(program_id) {
         return None;
@@ -2451,28 +2444,21 @@ 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),
-                ..
-            }) if *offset == account_packed_len && *program_id == token_2022::id() => {
-                memcmp_filter = Some(bytes)
-            }
-            #[allow(deprecated)]
-            RpcFilterType::Memcmp(Memcmp {
-                offset,
-                bytes: MemcmpEncodedBytes::Bytes(bytes),
-                ..
-            }) if *offset == SPL_TOKEN_ACCOUNT_MINT_OFFSET => {
-                if bytes.len() == PUBKEY_BYTES {
-                    mint = Pubkey::try_from(&bytes[..]).ok();
-                } else {
-                    incorrect_mint_len = Some(bytes.len());
+            RpcFilterType::Memcmp(memcmp) => {
+                let offset = memcmp.offset();
+                if let Some(bytes) = memcmp.raw_bytes_as_ref() {
+                    if offset == account_packed_len && *program_id == token_2022::id() {
+                        memcmp_filter = Some(bytes);
+                    } else if offset == SPL_TOKEN_ACCOUNT_MINT_OFFSET {
+                        if bytes.len() == PUBKEY_BYTES {
+                            mint = Pubkey::try_from(bytes).ok();
+                        } else {
+                            incorrect_mint_len = Some(bytes.len());
+                        }
+                    }
                 }
             }
             RpcFilterType::TokenAccountState => token_account_state_filter = true,
-            _ => {}
         }
     }
     if data_size_filter == Some(account_packed_len as u64)
@@ -4344,7 +4330,7 @@ pub mod tests {
                 JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE,
                 JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION,
             },
-            filter::{Memcmp, MemcmpEncodedBytes},
+            filter::MemcmpEncodedBytes,
         },
         solana_runtime::{
             accounts_background_service::AbsRequestSender, bank::BankTestConfig,