Skip to content

fix(mpool): MempoolFilter returns the pending transactions#7250

Open
akaladarshi wants to merge 4 commits into
mainfrom
akaladarshi/fix-mempool-filter
Open

fix(mpool): MempoolFilter returns the pending transactions#7250
akaladarshi wants to merge 4 commits into
mainfrom
akaladarshi/fix-mempool-filter

Conversation

@akaladarshi

@akaladarshi akaladarshi commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary of changes

Changes introduced in this pull request:

Reference issue to close (if applicable)

Closes

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

  • 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

    • Enhanced pending-transaction filter/subscription behavior so pending transaction hashes are delivered as they enter the mempool, with per-filter buffered results and proper incremental updates.
    • Updated Ethereum event handling to better reflect chain/network context and live message-pool changes.
  • Bug Fixes

    • eth_newPendingTransactionFilter now returns hashes for truly pending mempool transactions (not on-chain execution events).
    • eth_getFilterChanges now returns only newly observed pending transaction hashes per poll, avoiding duplicates across polls.

@akaladarshi akaladarshi requested a review from a team as a code owner June 29, 2026 10:03
@akaladarshi akaladarshi requested review from hanabi1224 and sudo-shashank and removed request for a team June 29, 2026 10:03
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f107041f-4d47-45a0-8d13-68fb39042940

📥 Commits

Reviewing files that changed from the base of the PR and between 11b230e and 45f7c4b.

📒 Files selected for processing (5)
  • src/message_pool/msgpool/events.rs
  • src/rpc/methods/eth/filter/mod.rs
  • src/tool/subcommands/api_cmd/generate_test_snapshot.rs
  • src/tool/subcommands/api_cmd/stateful_tests.rs
  • src/tool/subcommands/api_cmd/test_snapshot.rs
🔗 Linked repositories identified

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

  • filecoin-project/lotus (manual)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/message_pool/msgpool/events.rs
  • src/tool/subcommands/api_cmd/stateful_tests.rs
  • src/rpc/methods/eth/filter/mod.rs

Walkthrough

Pending-transaction filtering now uses a subscriber-backed mempool stream, buffers hashes per filter, and drains them through the Ethereum RPC path. Handler construction passes chain id and mempool subscriber through daemon and offline-server wiring. Pubsub and stateful tests are updated to match the new hash flow.

Changes

Pending transaction hash flow

Layer / File(s) Summary
Subscriber wrapper and API migration
src/message_pool/msgpool/events.rs, src/message_pool/msgpool/mod.rs, src/message_pool/msgpool/msg_pool.rs, src/message_pool/msgpool/pending_store.rs, src/message_pool/msgpool/selection.rs, src/utils/task/mod.rs
Adds MpoolSubscriber, re-exports it, changes message-pool subscription entry points to return the subscriber handle, and updates the related call sites and derives.
Mempool filter buffering and fan-out
src/rpc/methods/eth/filter/mempool.rs
Replaces the mempool filter with a bounded FIFO of hashes, adds the pending-transaction hash stream helper, redesigns the filter manager around a shared fan-out task, and rewrites the unit tests for the new behavior.
Ethereum event handler wiring
src/rpc/methods/eth/filter/mod.rs, src/daemon/mod.rs, src/tool/offline_server/server.rs, src/tool/subcommands/api_cmd/generate_test_snapshot.rs, src/tool/subcommands/api_cmd/test_snapshot.rs
Extends EthEventHandler construction to accept chain id and MpoolSubscriber, wires those inputs from daemon and offline server code, and updates the related ETH filter tests and snapshot builders.
RPC filter and pubsub hash paths
src/rpc/methods/eth.rs, src/rpc/methods/eth/pubsub.rs
Changes pending filter change handling to drain buffered hashes directly, updates pubsub to use the shared pending-transaction hash stream, and switches the Ethereum hash/result helpers to the new tipset-based paths.
Integration tests and changelog
src/tool/subcommands/api_cmd/stateful_tests.rs, CHANGELOG.md
Adds polling helpers and pending-transaction filter scenarios to the stateful test suite, and records the pending-filter behavior change in the changelog.

Sequence Diagram(s)

sequenceDiagram
  participant RPCClient
  participant MempoolFilterManager
  participant pending_tx_added_hashes
  participant MpoolSubscriber
  participant MempoolFilter

  RPCClient->>MempoolFilterManager: install()
  MempoolFilterManager->>pending_tx_added_hashes: start fan-out task(eth_chain_id, subscriber)
  pending_tx_added_hashes->>MpoolSubscriber: subscribe()
  MpoolSubscriber-->>pending_tx_added_hashes: MpoolUpdate::Add
  pending_tx_added_hashes-->>MempoolFilterManager: EthHash
  MempoolFilterManager->>MempoolFilter: push(hash)
  RPCClient->>MempoolFilterManager: remove()/eth_getFilterChanges
  MempoolFilterManager->>MempoolFilter: drain()
  MempoolFilter-->>RPCClient: Vec<EthHash>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ChainSafe/forest#5749: Adds the Filecoin.EthSubscribe pubsub framework with pending-transaction handling in src/rpc/methods/eth/pubsub.rs, which overlaps with the pubsub stream changes here.
  • ChainSafe/forest#6941: Implements pendingTransactions by mapping mempool Add updates to Ethereum tx hashes, directly matching the hash-stream logic introduced here.

Suggested reviewers

  • sudo-shashank
  • LesnyRumcajs
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing MempoolFilter to return pending transactions from the mempool.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch akaladarshi/fix-mempool-filter
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch akaladarshi/fix-mempool-filter

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

@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: 4

🤖 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/mempool.rs`:
- Around line 256-258: The async test in the mempool filter flow should not rely
on a single tokio::task::yield_now() to let the fan-out task deliver the
broadcast event. Update the test around the filter subscription/drain logic in
the mempool.rs path to poll with a small timeout until both filters have
received the hash, using the existing filter/broadcast setup instead of assuming
one scheduler yield is sufficient.
- Around line 119-128: The fan-out task startup in ensure_fanout_task currently
calls tokio::spawn unconditionally, which can panic if there is no active Tokio
runtime. Update the install path that reaches ensure_fanout_task to check for a
runtime first and return an installation error instead of spawning blindly, and
make sure the caller of ensure_fanout_task propagates that Result so the
existing error handling is preserved.

In `@src/rpc/methods/eth/filter/mod.rs`:
- Around line 142-146: `EthEventHandler::new()` is wiring pending-filter RPCs to
`MpoolSubscriber::dummy()`, so `eth_newPendingTransactionFilter` never receives
mempool adds in states built from it. Update the RPC state constructors that use
pending filters, especially the snapshot/test paths in `generate_test_snapshot`
and `test_snapshot`, to pass a real `MessagePool` subscriber
(`mpool.subscriber()`) into `EthEventHandler::from_config(...)` instead of
relying on the dummy subscriber. Make sure the `EthEventHandler` and related
`RPCState` setup still use the same `EventsConfig` and chain ID, but are
connected to the live mempool bus.

In `@src/tool/subcommands/api_cmd/stateful_tests.rs`:
- Around line 1041-1044: The pending-tx assertions are still happening after
chain inclusion because wait_pending_message() continues into StateWaitMsg, so
the tests do not actually verify pre-mining mempool behavior. Update the
stateful tests to inspect the filter immediately after the first MpoolPending
observation, or split wait_pending_message() into a helper that returns once the
CID appears so the test can stop before StateWaitMsg. Apply the same fix in both
affected test sections that use wait_pending_message() and
poll_pending_filter_until().
🪄 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: b1fab06a-d564-4511-ba0e-b6e9944153cd

📥 Commits

Reviewing files that changed from the base of the PR and between 28d3c1c and 11b230e.

📒 Files selected for processing (14)
  • CHANGELOG.md
  • src/daemon/mod.rs
  • src/message_pool/msgpool/events.rs
  • src/message_pool/msgpool/mod.rs
  • src/message_pool/msgpool/msg_pool.rs
  • src/message_pool/msgpool/pending_store.rs
  • src/message_pool/msgpool/selection.rs
  • src/rpc/methods/eth.rs
  • src/rpc/methods/eth/filter/mempool.rs
  • src/rpc/methods/eth/filter/mod.rs
  • src/rpc/methods/eth/pubsub.rs
  • src/tool/offline_server/server.rs
  • src/tool/subcommands/api_cmd/stateful_tests.rs
  • src/utils/task/mod.rs
🔗 Linked repositories identified

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

  • filecoin-project/lotus (manual)

Comment on lines +119 to +128
fn ensure_fanout_task(&self) {
self.fanout_task.get_or_init(|| {
let filters = self.filters.shallow_clone();
let mut hashes =
pending_tx_added_hashes(self.subscriber.subscribe(), self.eth_chain_id);
let task = tokio::spawn(async move {
while let Some(hash) = hashes.next().await {
fan_out(&filters.read(), hash);
}
});

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- mempool.rs outline ---'
ast-grep outline src/rpc/methods/eth/filter/mempool.rs --view expanded || true

echo '--- ensure_fanout_task occurrences ---'
rg -n "ensure_fanout_task|fn install|eth_new_pending_transaction_filter|tokio::spawn" src/rpc/methods/eth/filter -S || true

Repository: ChainSafe/forest

Length of output: 3074


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- mempool.rs relevant lines ---'
sed -n '110,150p' src/rpc/methods/eth/filter/mempool.rs | cat -n

echo '--- mod.rs relevant lines ---'
sed -n '210,340p' src/rpc/methods/eth/filter/mod.rs | cat -n

echo '--- tests around pending filter ---'
sed -n '1220,1285p' src/rpc/methods/eth/filter/mod.rs | cat -n

Repository: ChainSafe/forest

Length of output: 10232


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- install_filter call sites ---'
rg -n "install_filter\(" src/rpc/methods/eth -S || true

echo '--- eth_new_pending_transaction_filter implementation ---'
sed -n '230,275p' src/rpc/methods/eth/filter/mod.rs | cat -n

echo '--- FilterManager trait and implementations ---'
sed -n '70,110p' src/rpc/methods/eth/filter/mod.rs | cat -n

Repository: ChainSafe/forest

Length of output: 5330


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- install_filter call sites ---'
rg -n "install_filter\(" src/rpc/methods/eth -S || true

echo '--- mod.rs around install_filter and eth_new_pending_transaction_filter ---'
sed -n '220,270p' src/rpc/methods/eth/filter/mod.rs | cat -n

Repository: ChainSafe/forest

Length of output: 3372


Guard the fan-out task spawn with a runtime check
ensure_fanout_task calls tokio::spawn from a synchronous install path, so a caller without an active Tokio runtime will panic instead of getting the existing Result. Propagate an installation error here instead.

🤖 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/mempool.rs` around lines 119 - 128, The fan-out
task startup in ensure_fanout_task currently calls tokio::spawn unconditionally,
which can panic if there is no active Tokio runtime. Update the install path
that reaches ensure_fanout_task to check for a runtime first and return an
installation error instead of spawning blindly, and make sure the caller of
ensure_fanout_task propagates that Result so the existing error handling is
preserved.

Comment on lines +256 to +258
// The receiver is subscribed during install, so the event is already
// buffered; one yield lets the fan-out task drain it into both filters.
tokio::task::yield_now().await;

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

Avoid relying on a single scheduler yield in this async test.

One yield_now() does not guarantee the fan-out task has drained and pushed the broadcast event, so this can be flaky under load. Poll with a small timeout until both filters receive the hash.

🤖 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/mempool.rs` around lines 256 - 258, The async test
in the mempool filter flow should not rely on a single tokio::task::yield_now()
to let the fan-out task deliver the broadcast event. Update the test around the
filter subscription/drain logic in the mempool.rs path to poll with a small
timeout until both filters have received the hash, using the existing
filter/broadcast setup instead of assuming one scheduler yield is sufficient.

Comment thread src/rpc/methods/eth/filter/mod.rs
Comment thread src/tool/subcommands/api_cmd/stateful_tests.rs
@akaladarshi akaladarshi added the RPC requires calibnet RPC checks to run on CI label Jun 29, 2026
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.99526% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.22%. Comparing base (28d3c1c) to head (45f7c4b).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/rpc/methods/eth/filter/mempool.rs 96.73% 3 Missing and 2 partials ⚠️
...tool/subcommands/api_cmd/generate_test_snapshot.rs 0.00% 5 Missing ⚠️
src/daemon/mod.rs 0.00% 4 Missing ⚠️
src/rpc/methods/eth/pubsub.rs 0.00% 3 Missing ⚠️
src/rpc/methods/eth.rs 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/message_pool/msgpool/events.rs 100.00% <100.00%> (ø)
src/message_pool/msgpool/mod.rs 97.91% <ø> (ø)
src/message_pool/msgpool/msg_pool.rs 88.28% <100.00%> (+0.46%) ⬆️
src/message_pool/msgpool/pending_store.rs 82.85% <100.00%> (ø)
src/message_pool/msgpool/selection.rs 87.45% <100.00%> (ø)
src/rpc/methods/eth/filter/mod.rs 88.58% <100.00%> (+0.15%) ⬆️
src/tool/offline_server/server.rs 28.89% <100.00%> (+1.32%) ⬆️
src/tool/subcommands/api_cmd/test_snapshot.rs 82.63% <100.00%> (+0.42%) ⬆️
src/utils/task/mod.rs 100.00% <ø> (ø)
src/rpc/methods/eth.rs 66.10% <0.00%> (+1.27%) ⬆️
... and 4 more

... and 3 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 28d3c1c...45f7c4b. 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.

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.

2 participants