Skip to content

feat(filters): add ttl in eth filters#7386

Draft
akaladarshi wants to merge 2 commits into
mainfrom
akaladarshi/add-ttl-filters
Draft

feat(filters): add ttl in eth filters#7386
akaladarshi wants to merge 2 commits into
mainfrom
akaladarshi/add-ttl-filters

Conversation

@akaladarshi

@akaladarshi akaladarshi commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Summary of changes

Changes introduced in this pull request:

  • Introduced the FOREST_FILTER_TTL_SECS which make sure the filter expires if remained idle after the ttl time limit (3600 seconds)

Reference issue to close (if applicable)

Closes #7265

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Outside contributions

  • This pull request is based on an issue that a maintainer has accepted (see Before Opening a Pull Request).
  • I have read and agree to the CONTRIBUTING document.
  • I have read and agree to the AI Policy document. I understand that failure to comply with the guidelines will lead to rejection of the pull request.

Summary by CodeRabbit

  • New Features

    • Added configurable expiration for idle Ethereum event, block, and pending-transaction filters.
    • Filters now expire after one hour by default; expiration can be disabled by setting the duration to zero.
    • Polling a filter refreshes its idle timer, keeping actively used filters available.
  • Bug Fixes

    • Improved filter cleanup and uninstallation behavior to prevent stale filters from remaining registered.

@akaladarshi akaladarshi added the RPC requires calibnet RPC checks to run on CI label Jul 20, 2026
@akaladarshi
akaladarshi marked this pull request as ready for review July 20, 2026 12:31
@akaladarshi
akaladarshi requested a review from a team as a code owner July 20, 2026 12:31
@akaladarshi
akaladarshi requested review from LesnyRumcajs and hanabi1224 and removed request for a team July 20, 2026 12:31
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bb71a41a-66d6-4d6e-9f3f-fb13835bca57

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds configurable idle TTL expiry for Ethereum filters. Filter activity is tracked on polling, expired entries are removed from the store and type-specific managers, and filter registration/uninstallation paths share centralized lifecycle handling.

Changes

Ethereum filter TTL

Layer / File(s) Summary
TTL configuration contract
src/cli_shared/cli/config.rs
EventsConfig now supports serde defaults and defines filter_ttl_secs, defaulting to 3600 seconds.
Filter activity tracking and expiry
src/rpc/methods/eth/filter/store.rs
The in-memory store records last_used, refreshes it on lookup, and extracts filters idle beyond the configured TTL.
Handler registration and cleanup
src/rpc/methods/eth/filter/mod.rs
EthEventHandler reads the TTL environment variable, sweeps expired filters, centralizes registration rollback, and unregisters removed filters from managers. Async tests cover expiry and polling behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant EthEventHandler
  participant MemFilterStore
  participant TypeSpecificManagers
  EthEventHandler->>MemFilterStore: sweep_expired()
  MemFilterStore-->>EthEventHandler: expired filters
  EthEventHandler->>TypeSpecificManagers: remove_from_manager(filter)
Loading

Possibly related PRs

  • ChainSafe/forest#7250: Touches Ethereum filter installation and uninstallation wiring, which overlaps with this PR’s filter lifecycle changes.

Suggested reviewers: hanabi1224, lesnyrumcajs, sudo-shashank

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds TTL expiry and last-used tracking, but the summary shows a 3600s default and no configurable sweep interval, which misses the issue requirements. Set the default TTL near 5 minutes and add a configurable sweep interval in EventsConfig/env vars, or document why the linked issue's defaults were changed.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly describes the main change: adding TTL support to Ethereum filters.
Out of Scope Changes check ✅ Passed The changes stay focused on filter TTL expiry, config, store refactoring, and related tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch akaladarshi/add-ttl-filters
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch akaladarshi/add-ttl-filters

Comment @coderabbitai help to get the list of available commands.

@akaladarshi
akaladarshi marked this pull request as draft July 20, 2026 12:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/rpc/methods/eth/filter/mod.rs`:
- Around line 307-317: Update eth_uninstall_filter and uninstall_filter so
filter removal is atomic: remove the entry directly by its ID via
filter_store.remove(id), rather than first fetching a Filter and then removing
by filter.id(). Preserve the existing graceful Ok(false) behavior when no entry
exists, and continue removing the successfully removed filter from the manager
using the returned filter value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6c9011be-78b4-46fb-a760-97adc6357384

📥 Commits

Reviewing files that changed from the base of the PR and between d44ecc7 and a5900e6.

📒 Files selected for processing (3)
  • src/cli_shared/cli/config.rs
  • src/rpc/methods/eth/filter/mod.rs
  • src/rpc/methods/eth/filter/store.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • filecoin-project/lotus (manual)

Comment thread src/rpc/methods/eth/filter/mod.rs Outdated
Comment on lines +307 to +317
Ok(())
}

fn uninstall_filter(&self, filter: Arc<dyn Filter>) -> Result<(), Error> {
self.filter_store
.as_ref()
.context("Filter store is missing")?
.remove(id)
.remove(filter.id())
.context("Failed to remove filter from store")?;

Ok(())
self.remove_from_manager(filter.as_ref())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

TOCTOU: concurrent uninstall/expiry can turn an idempotent uninstall into an error.

eth_uninstall_filter (lines 320-332, unchanged) does store.get(id) — which succeeds and bumps last_used — then calls uninstall_filter(filter), which does store.remove(filter.id()) again. If the entry is removed between those two calls (e.g. a second concurrent eth_uninstall_filter for the same id, or a future periodic sweep), remove returns None and .context("Failed to remove filter from store")? propagates an Err all the way to the RPC caller, instead of the graceful Ok(false) this function clearly wants to return for "no such filter."

Removing directly via store.remove(id) (fetch-and-remove atomic) avoids both the race and the redundant last_used bump on the entry about to be deleted.

🔒 Proposed fix to make uninstall atomic
-    fn uninstall_filter(&self, filter: Arc<dyn Filter>) -> Result<(), Error> {
-        self.filter_store
-            .as_ref()
-            .context("Filter store is missing")?
-            .remove(filter.id())
-            .context("Failed to remove filter from store")?;
-
-        self.remove_from_manager(filter.as_ref())
-    }
+    fn uninstall_filter(&self, filter: &dyn Filter) -> Result<(), Error> {
+        self.remove_from_manager(filter)
+    }

     pub fn eth_uninstall_filter(&self, id: &FilterID) -> Result<bool, Error> {
         let store = self
             .filter_store
             .as_ref()
             .context("Filter store is not supported")?;

-        if let Ok(filter) = store.get(id) {
-            self.uninstall_filter(filter)?;
+        if let Some(filter) = store.remove(id) {
+            self.uninstall_filter(filter.as_ref())?;
             Ok(true)
         } else {
             Ok(false)
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Ok(())
}
fn uninstall_filter(&self, filter: Arc<dyn Filter>) -> Result<(), Error> {
self.filter_store
.as_ref()
.context("Filter store is missing")?
.remove(id)
.remove(filter.id())
.context("Failed to remove filter from store")?;
Ok(())
self.remove_from_manager(filter.as_ref())
Ok(())
}
fn uninstall_filter(&self, filter: &dyn Filter) -> Result<(), Error> {
self.remove_from_manager(filter)
}
pub fn eth_uninstall_filter(&self, id: &FilterID) -> Result<bool, Error> {
let store = self
.filter_store
.as_ref()
.context("Filter store is not supported")?;
if let Some(filter) = store.remove(id) {
self.uninstall_filter(filter.as_ref())?;
Ok(true)
} else {
Ok(false)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/rpc/methods/eth/filter/mod.rs` around lines 307 - 317, Update
eth_uninstall_filter and uninstall_filter so filter removal is atomic: remove
the entry directly by its ID via filter_store.remove(id), rather than first
fetching a Filter and then removing by filter.id(). Preserve the existing
graceful Ok(false) behavior when no entry exists, and continue removing the
successfully removed filter from the manager using the returned filter value.

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.75362% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.10%. Comparing base (a6f303b) to head (a5900e6).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/rpc/methods/eth/filter/mod.rs 87.34% 7 Missing and 3 partials ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/cli_shared/cli/config.rs 100.00% <100.00%> (ø)
src/rpc/methods/eth/filter/store.rs 96.66% <100.00%> (+2.54%) ⬆️
src/rpc/methods/eth/filter/mod.rs 89.00% <87.34%> (+0.36%) ⬆️

... and 4 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d44ecc7...a5900e6. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@akaladarshi
akaladarshi force-pushed the akaladarshi/add-ttl-filters branch from a5900e6 to 3073e4b Compare July 21, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RPC requires calibnet RPC checks to run on CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Periodically expire idle eth filters on a TTL

1 participant