From 138cfd781bef400750d931b2db7db5439a710d38 Mon Sep 17 00:00:00 2001
From: jeffhelius <jeff@helius.xyz>
Date: Tue, 31 Dec 2024 11:53:41 -0800
Subject: [PATCH 1/2] add filter that returns an error for the rpc is the
 filter is malformed

---
 rpc/src/rpc.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs
index 29cce7b1a74680..fdebbf7e8bf3c6 100644
--- a/rpc/src/rpc.rs
+++ b/rpc/src/rpc.rs
@@ -500,6 +500,10 @@ impl JsonRpcRequestProcessor {
             min_context_slot,
         })?;
         let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
+
+        // Early filter verification
+        verify_spl_token_owner_filters(program_id, &filters)?;
+
         optimize_filters(&mut filters);
         let keyed_accounts = {
             if let Some(owner) = get_spl_token_owner_filter(program_id, &filters) {
@@ -2394,6 +2398,46 @@ fn encode_account<T: ReadableAccount>(
     }
 }
 
+fn verify_spl_token_owner_filters(
+    program_id: &Pubkey,
+    filters: &[RpcFilterType],
+) -> std::result::Result<(), Error> {
+    if !is_known_spl_token_id(program_id) {
+        return Ok(()); // Not an SPL Token program, so skip
+    }
+
+    let account_packed_len = TokenAccount::get_packed_len();
+    for filter in filters {
+        match filter {
+            RpcFilterType::DataSize(size) => {
+                // Validate the DataSize if you want to require a certain size here
+                if *size != account_packed_len as u64 {
+                    return Err(Error::invalid_params(format!(
+                        "Invalid SPL token data size filter. Expected {}, got {}",
+                        account_packed_len, size
+                    )));
+                }
+            }
+            RpcFilterType::Memcmp(memcmp) => {
+                let offset = memcmp.offset();
+                if let Some(bytes) = memcmp.raw_bytes_as_ref() {
+                    // If the filter references the owner offset, ensure it’s 32 bytes long
+                    if offset == SPL_TOKEN_ACCOUNT_OWNER_OFFSET && bytes.len() != PUBKEY_BYTES {
+                        return Err(Error::invalid_params(format!(
+                            "Incorrect byte length {} for SPL token owner filter, expected {}",
+                            bytes.len(),
+                            PUBKEY_BYTES
+                        )));
+                    }
+                }
+            }
+            RpcFilterType::TokenAccountState => (),
+        }
+    }
+
+    Ok(())
+}
+
 /// 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

From d7bc400a0d420a2df51832f3aed701d82cedb8e9 Mon Sep 17 00:00:00 2001
From: jeffhelius <jeff@helius.xyz>
Date: Thu, 2 Jan 2025 04:08:08 -0800
Subject: [PATCH 2/2] address nicks comments on pr

---
 rpc/src/rpc.rs | 95 ++++++++++++++------------------------------------
 1 file changed, 26 insertions(+), 69 deletions(-)

diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs
index fdebbf7e8bf3c6..b8038f70e1f936 100644
--- a/rpc/src/rpc.rs
+++ b/rpc/src/rpc.rs
@@ -501,12 +501,9 @@ impl JsonRpcRequestProcessor {
         })?;
         let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
 
-        // Early filter verification
-        verify_spl_token_owner_filters(program_id, &filters)?;
-
         optimize_filters(&mut filters);
         let keyed_accounts = {
-            if let Some(owner) = get_spl_token_owner_filter(program_id, &filters) {
+            if let Some(owner) = get_spl_token_owner_filter(program_id, &filters)? {
                 self.get_filtered_spl_token_accounts_by_owner(
                     &bank,
                     program_id,
@@ -514,7 +511,7 @@ impl JsonRpcRequestProcessor {
                     filters,
                     sort_results,
                 )?
-            } else if let Some(mint) = get_spl_token_mint_filter(program_id, &filters) {
+            } else if let Some(mint) = get_spl_token_mint_filter(program_id, &filters)? {
                 self.get_filtered_spl_token_accounts_by_mint(
                     &bank,
                     program_id,
@@ -2398,58 +2395,20 @@ fn encode_account<T: ReadableAccount>(
     }
 }
 
-fn verify_spl_token_owner_filters(
-    program_id: &Pubkey,
-    filters: &[RpcFilterType],
-) -> std::result::Result<(), Error> {
-    if !is_known_spl_token_id(program_id) {
-        return Ok(()); // Not an SPL Token program, so skip
-    }
-
-    let account_packed_len = TokenAccount::get_packed_len();
-    for filter in filters {
-        match filter {
-            RpcFilterType::DataSize(size) => {
-                // Validate the DataSize if you want to require a certain size here
-                if *size != account_packed_len as u64 {
-                    return Err(Error::invalid_params(format!(
-                        "Invalid SPL token data size filter. Expected {}, got {}",
-                        account_packed_len, size
-                    )));
-                }
-            }
-            RpcFilterType::Memcmp(memcmp) => {
-                let offset = memcmp.offset();
-                if let Some(bytes) = memcmp.raw_bytes_as_ref() {
-                    // If the filter references the owner offset, ensure it’s 32 bytes long
-                    if offset == SPL_TOKEN_ACCOUNT_OWNER_OFFSET && bytes.len() != PUBKEY_BYTES {
-                        return Err(Error::invalid_params(format!(
-                            "Incorrect byte length {} for SPL token owner filter, expected {}",
-                            bytes.len(),
-                            PUBKEY_BYTES
-                        )));
-                    }
-                }
-            }
-            RpcFilterType::TokenAccountState => (),
-        }
-    }
-
-    Ok(())
-}
-
 /// 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 requirement that `Memcmp::raw_bytes_as_ref().is_some()`.
-fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) -> Option<Pubkey> {
+fn get_spl_token_owner_filter(
+    program_id: &Pubkey,
+    filters: &[RpcFilterType],
+) -> Result<Option<Pubkey>> {
     if !is_known_spl_token_id(program_id) {
-        return None;
+        return Ok(None);
     }
     let mut data_size_filter: Option<u64> = None;
     let mut memcmp_filter: Option<&[u8]> = None;
     let mut owner_key: Option<Pubkey> = None;
-    let mut incorrect_owner_len: Option<usize> = None;
     let mut token_account_state_filter = false;
     let account_packed_len = TokenAccount::get_packed_len();
     for filter in filters {
@@ -2464,7 +2423,11 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
                         if bytes.len() == PUBKEY_BYTES {
                             owner_key = Pubkey::try_from(bytes).ok();
                         } else {
-                            incorrect_owner_len = Some(bytes.len());
+                            return Err(Error::invalid_params(format!(
+                                "Incorrect byte length {} for SPL token owner filter, expected {}",
+                                bytes.len(),
+                                PUBKEY_BYTES
+                            )));
                         }
                     }
                 }
@@ -2476,16 +2439,10 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
         || memcmp_filter == Some(&[ACCOUNTTYPE_ACCOUNT])
         || token_account_state_filter
     {
-        if let Some(incorrect_owner_len) = incorrect_owner_len {
-            info!(
-                "Incorrect num bytes ({:?}) provided for spl_token_owner_filter",
-                incorrect_owner_len
-            );
-        }
-        owner_key
+        Ok(owner_key)
     } else {
         debug!("spl_token program filters do not match by-owner index requisites");
-        None
+        Ok(None)
     }
 }
 
@@ -2493,14 +2450,16 @@ fn get_spl_token_owner_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
 /// mint.
 /// NOTE: `optimize_filters()` should almost always be called before using this method because of
 /// the requirement that `Memcmp::raw_bytes_as_ref().is_some()`.
-fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) -> Option<Pubkey> {
+fn get_spl_token_mint_filter(
+    program_id: &Pubkey,
+    filters: &[RpcFilterType],
+) -> Result<Option<Pubkey>> {
     if !is_known_spl_token_id(program_id) {
-        return None;
+        return Ok(None);
     }
     let mut data_size_filter: Option<u64> = None;
     let mut memcmp_filter: Option<&[u8]> = None;
     let mut mint: Option<Pubkey> = None;
-    let mut incorrect_mint_len: Option<usize> = None;
     let mut token_account_state_filter = false;
     let account_packed_len = TokenAccount::get_packed_len();
     for filter in filters {
@@ -2515,7 +2474,11 @@ fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
                         if bytes.len() == PUBKEY_BYTES {
                             mint = Pubkey::try_from(bytes).ok();
                         } else {
-                            incorrect_mint_len = Some(bytes.len());
+                            return Err(Error::invalid_params(format!(
+                                "Incorrect byte length {} for SPL token mint filter, expected {}",
+                                bytes.len(),
+                                PUBKEY_BYTES
+                            )));
                         }
                     }
                 }
@@ -2527,16 +2490,10 @@ fn get_spl_token_mint_filter(program_id: &Pubkey, filters: &[RpcFilterType]) ->
         || memcmp_filter == Some(&[ACCOUNTTYPE_ACCOUNT])
         || token_account_state_filter
     {
-        if let Some(incorrect_mint_len) = incorrect_mint_len {
-            info!(
-                "Incorrect num bytes ({:?}) provided for spl_token_mint_filter",
-                incorrect_mint_len
-            );
-        }
-        mint
+        Ok(mint)
     } else {
         debug!("spl_token program filters do not match by-mint index requisites");
-        None
+        Ok(None)
     }
 }