Skip to content

fix MempoolFilter returning pending transactions#7109

Open
Fraccaman wants to merge 6 commits into
ChainSafe:mainfrom
Fraccaman:fix-mempool-filters
Open

fix MempoolFilter returning pending transactions#7109
Fraccaman wants to merge 6 commits into
ChainSafe:mainfrom
Fraccaman:fix-mempool-filters

Conversation

@Fraccaman

@Fraccaman Fraccaman commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary of changes

MempoolFilter was returning hashes of already-mined transactions instead of pending ones. This PR fixes it by subscribing each mempool filter to the mempool's Add/Remove broadcast channel, so it reports only transactions still in the pool.

Changes introduced in this pull request:

  • MempoolFilterManager::install now create a Receiver on install
  • Added method drain to MempoolFilter to add/remove pending tx hashes
  • Call drain in EthGetFilterChanges::handle method
  • fix eth_new_pending_transaction_filter test + minor unit

Reference issue to close (if applicable)

Closes #7091

Other information and links

  • The implementation uses channels, no background tasks are spawned. I think having channels is easier and less error prone.
  • Claude Opus 4.7 was used to help navigate the codebase and implement the necessary changes.

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

  • Bug Fixes

    • Fixed pending transaction filter updates to consume mempool events directly instead of tipset-based tracking.
    • Simplified transaction hash derivation and removed redundant code paths.
    • Enhanced filter result generation accuracy by removing indirect message resolution.
  • Tests

    • Expanded test coverage for pending transaction filters including multi-poll mempool scenarios.

@Fraccaman Fraccaman requested a review from a team as a code owner May 26, 2026 21:59
@Fraccaman Fraccaman requested review from akaladarshi and hanabi1224 and removed request for a team May 26, 2026 21:59
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

MempoolFilter is refactored to own a per-filter broadcast::Receiver<MpoolUpdate> instead of epoch-based collection. A new MpoolSubscriber factory type threads from service initialization through EthEventHandler::from_config to MempoolFilterManager. EthGetFilterChanges now drains the broadcast receiver directly, and two old message-CID hash helpers are removed.

Changes

Mempool broadcast-driven pending transaction filter

Layer / File(s) Summary
MempoolFilter: broadcast receiver, drain, and manager
src/rpc/methods/eth/filter/mempool.rs
Introduces MpoolSubscriber type; replaces epoch/collected field with broadcast::Receiver<MpoolUpdate>; rewrites drain() to non-blockingly consume Add/Remove into a deduplicated IndexSet truncated to max_results; adds hash_or_log helper; updates MempoolFilterManager::new to accept MpoolSubscriber and use it on install(); replaces unit tests for broadcast-driven semantics including Add+Remove cancellation, truncation, lag, and multi-filter receiver independence.
EthEventHandler wiring for MpoolSubscriber
src/rpc/methods/eth/filter/mod.rs
EthEventHandler::new() creates a dummy broadcast channel as MpoolSubscriber; from_config signature extended to accept mpool_subscriber: MpoolSubscriber and passes it to MempoolFilterManager::new.
Daemon and offline server subscriber wiring
src/daemon/mod.rs, src/tool/offline_server/server.rs
Both call sites clone the message pool, construct an MpoolSubscriber from mp.subscribe_to_updates(), and pass it to EthEventHandler::from_config, replacing the previous single-argument call.
RPC method simplifications
src/rpc/methods/eth.rs
EthGetTransactionHashByCid delegates to eth_tx_hash_from_signed_message; eth_filter_logs_from_messages and eth_filter_result_from_messages (message-CID hash paths) are deleted; EthGetFilterChanges MempoolFilter branch replaced with direct mempool_filter.drain(chain_id).
Stateful mempool filter tests
src/tool/subcommands/api_cmd/stateful_tests.rs
Adds wait_in_mempool helper polling MpoolPending without chain confirmation; updates existing filter test to use it; adds eth_new_pending_transaction_filter_multi_poll asserting per-poll hash isolation; registers new scenario in create_tests.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RPC as Eth RPC
  participant EthEventHandler
  participant MempoolFilterManager
  participant MempoolFilter
  participant MessagePool

  Note over EthEventHandler,MessagePool: Service startup
  MessagePool->>EthEventHandler: subscribe_to_updates() → MpoolSubscriber
  EthEventHandler->>MempoolFilterManager: new(max_results, mpool_subscriber)

  Note over Client,MempoolFilter: eth_newPendingTransactionFilter
  Client->>RPC: eth_newPendingTransactionFilter
  RPC->>MempoolFilterManager: install()
  MempoolFilterManager->>MempoolFilter: new(max_results, subscriber())

  Note over Client,MempoolFilter: eth_getFilterChanges (pending txs)
  MessagePool->>MempoolFilter: broadcast MpoolUpdate::Add(msg)
  Client->>RPC: eth_getFilterChanges(filter_id)
  RPC->>MempoolFilter: drain(chain_id)
  MempoolFilter->>MempoolFilter: try_recv() → IndexSet<EthHash>
  MempoolFilter-->>RPC: Vec<EthHash>
  RPC-->>Client: EthFilterResult::Hashes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ChainSafe/forest#6965: Introduced MpoolUpdate enum and MessagePool::subscribe_to_updates() broadcast source that this PR's MpoolSubscriber and broadcast::Receiver<MpoolUpdate> depend on directly.
  • ChainSafe/forest#6361: Modifies the same eth_new_pending_transaction_filter stateful test flow (message submission and mempool drain waiting) that this PR refactors with wait_in_mempool and the multi-poll scenario.
  • ChainSafe/forest#6493: Modifies maybe_start_rpc_service in src/daemon/mod.rs to thread a stop handle, the same function this PR changes to wire the mempool subscriber into EthEventHandler.

Suggested reviewers

  • hanabi1224
  • akaladarshi
  • sudo-shashank
🚥 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 directly describes the primary change: fixing MempoolFilter to return pending transactions instead of chain-included ones.
Linked Issues check ✅ Passed The PR comprehensively addresses #7091 by implementing mempool subscriptions to track pending transactions and filtering out already-mined messages from results.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objective of 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%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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

🧹 Nitpick comments (1)
src/rpc/methods/eth.rs (1)

1106-1120: ⚡ Quick win

Consolidate the signed-message hash derivation into one helper.

eth_tx_hash_from_signed_message below still reimplements the same delegated/secp/BLS branches, so this extraction can drift from the event/log path. Please make one helper delegate to the other and keep the hash rules in one place.

♻️ Minimal consolidation
 fn eth_tx_hash_from_signed_message(
     message: &SignedMessage,
     eth_chain_id: EthChainIdType,
 ) -> anyhow::Result<EthHash> {
-    if message.is_delegated() {
-        let (_, tx) = eth_tx_from_signed_eth_message(message, eth_chain_id)?;
-        Ok(tx.eth_hash()?.into())
-    } else if message.is_secp256k1() {
-        Ok(message.cid().into())
-    } else {
-        Ok(message.message().cid().into())
-    }
+    eth_hash_from_signed_message(message, eth_chain_id)
 }
🤖 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.rs` around lines 1106 - 1120, The logic that derives an
Ethereum-style hash from a SignedMessage has been factored into
eth_hash_from_signed_message but eth_tx_hash_from_signed_message still
duplicates the delegated/secp256k1/BLS branching; consolidate by making
eth_tx_hash_from_signed_message call eth_hash_from_signed_message (or
vice‑versa) so the hash rules live in one place. Update
eth_tx_hash_from_signed_message to remove its own branching and delegate to
eth_hash_from_signed_message (passing the same SignedMessage and chain_id),
ensuring all callers use the single helper to avoid drift between paths.
🤖 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`:
- Line 67: The current drain uses
pending.into_iter().take(self.max_results).collect() which returns an empty vec
when self.max_results == 0; change the logic so a zero max_results means “no
cap”: check self.max_results and if it is 0 collect the full pending.into_iter()
otherwise collect after take(self.max_results). Use the existing pending
iterator and self.max_results symbol to implement the conditional branch so the
returned collection contains all items when max_results == 0.

In `@src/tool/subcommands/api_cmd/stateful_tests.rs`:
- Around line 300-311: The mempool polling in wait_in_mempool has a very short
timeout (retries = 100 with 10ms sleeps); increase the retry budget or
per-iteration sleep to reduce flakiness in CI by changing the retries or
Duration::from_millis call in the wait_in_mempool function (e.g., bump retries
to a larger value like 1000 or increase the sleep to 50–100ms) so the loop has a
longer total wait before the ensure! triggers; update the retries initialization
and/or the tokio::time::sleep(Duration::from_millis(...)).

---

Nitpick comments:
In `@src/rpc/methods/eth.rs`:
- Around line 1106-1120: The logic that derives an Ethereum-style hash from a
SignedMessage has been factored into eth_hash_from_signed_message but
eth_tx_hash_from_signed_message still duplicates the delegated/secp256k1/BLS
branching; consolidate by making eth_tx_hash_from_signed_message call
eth_hash_from_signed_message (or vice‑versa) so the hash rules live in one
place. Update eth_tx_hash_from_signed_message to remove its own branching and
delegate to eth_hash_from_signed_message (passing the same SignedMessage and
chain_id), ensuring all callers use the single helper to avoid drift between
paths.
🪄 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: 15f882bf-4135-452b-b120-7f6d544dc8b8

📥 Commits

Reviewing files that changed from the base of the PR and between a3caf3e and 0f8af7d.

📒 Files selected for processing (8)
  • src/daemon/mod.rs
  • src/message_pool/msgpool/msg_pool.rs
  • src/message_pool/msgpool/pending_store.rs
  • src/rpc/methods/eth.rs
  • src/rpc/methods/eth/filter/mempool.rs
  • src/rpc/methods/eth/filter/mod.rs
  • src/tool/offline_server/server.rs
  • src/tool/subcommands/api_cmd/stateful_tests.rs

}
}
}
pending.into_iter().take(self.max_results).collect()

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle max_results == 0 as “no cap” in drain output.

Line 67 currently truncates with take(0), which returns an empty vector when max_results is zero; this conflicts with the filter subsystem’s “0 disables cap” convention.

Proposed fix
-        pending.into_iter().take(self.max_results).collect()
+        if self.max_results == 0 {
+            return pending.into_iter().collect();
+        }
+        pending.into_iter().take(self.max_results).collect()
📝 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
pending.into_iter().take(self.max_results).collect()
if self.max_results == 0 {
return pending.into_iter().collect();
}
pending.into_iter().take(self.max_results).collect()
🤖 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` at line 67, The current drain uses
pending.into_iter().take(self.max_results).collect() which returns an empty vec
when self.max_results == 0; change the logic so a zero max_results means “no
cap”: check self.max_results and if it is 0 collect the full pending.into_iter()
otherwise collect after take(self.max_results). Use the existing pending
iterator and self.max_results symbol to implement the conditional branch so the
returned collection contains all items when max_results == 0.

Comment thread src/tool/subcommands/api_cmd/stateful_tests.rs
@Fraccaman Fraccaman force-pushed the fix-mempool-filters branch from 0f8af7d to 4f45897 Compare May 26, 2026 22:13
@Fraccaman Fraccaman changed the title refactor(eth-rpc): extract eth_hash_from_signed_message helper fix MempoolFilter returning pending transactions May 27, 2026
@akaladarshi akaladarshi added the RPC requires calibnet RPC checks to run on CI label May 27, 2026
@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.28125% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.41%. Comparing base (39a6969) to head (5464537).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/rpc/methods/eth.rs 62.50% 3 Missing and 3 partials ⚠️
src/rpc/methods/eth/filter/mempool.rs 93.25% 3 Missing and 3 partials ⚠️
src/daemon/mod.rs 0.00% 3 Missing ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/message_pool/msgpool/msg_pool.rs 87.96% <100.00%> (+0.21%) ⬆️
src/message_pool/msgpool/pending_store.rs 97.12% <100.00%> (+0.04%) ⬆️
src/rpc/methods/eth/filter/mod.rs 89.19% <100.00%> (+0.05%) ⬆️
src/tool/offline_server/server.rs 28.24% <100.00%> (+1.01%) ⬆️
src/daemon/mod.rs 24.81% <0.00%> (-0.08%) ⬇️
src/rpc/methods/eth.rs 66.60% <62.50%> (+1.33%) ⬆️
src/rpc/methods/eth/filter/mempool.rs 93.75% <93.25%> (-2.17%) ⬇️

... and 19 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 39a6969...5464537. 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

Copy link
Copy Markdown
Collaborator

@Fraccaman CI linter seems to be failing please fix it, you can use mise run lint locally to verify as well.

Also all the commits needs to signed, so please do that as well.

@Fraccaman Fraccaman force-pushed the fix-mempool-filters branch 2 times, most recently from 53c3804 to e39aa6f Compare May 27, 2026 10:41
@Fraccaman

Fraccaman commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

@akaladarshi I signed the commits and ran cargo fmt. I couldn't get mise to work:

mise run lint                                                     ok  at 13:49:43
mise config files in ~/forest are not trusted. Trust them? Yes
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: keydb_get_keyblock failed: Value not found
gpg: error writing keyring '[keyboxd]': SQL library used incorrectly
gpg: error reading '[stdin]': SQL library used incorrectly
gpg: import from '[stdin]' failed: SQL library used incorrectly
mise ERROR gpg failed
mise 2026.5.13 by @jdx                                                                                              [4/4]
go@1.26.3       go version go1.26.3 darwin/arm64                                                                        ✔
pnpm@11.3.0     extract pnpm-darwin-arm64.tar.gz                                                                        ✔
node@24.16.0    download node-v24.16.0-darwin-arm64.tar.gz                             119 B 5m18s [>                 ] ◠
cargo-binstall@1.17.9 extract cargo-binstall-aarch64-apple-darwin.zip                                                   ✔
mise ERROR Failed to install core:node@24: gpg exited with non-zero status: exit code 2
mise ERROR Run with --verbose or MISE_VERBOSE=1 for more information

@akaladarshi

Copy link
Copy Markdown
Collaborator

@akaladarshi I signed the commits and ran cargo fmt. I couldn't get mise to work:

mise run lint                                                     ok  at 13:49:43
mise config files in ~/forest are not trusted. Trust them? Yes
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: Note: database_open 134217901 waiting for lock (held by 32019) ...
gpg: keydb_get_keyblock failed: Value not found
gpg: error writing keyring '[keyboxd]': SQL library used incorrectly
gpg: error reading '[stdin]': SQL library used incorrectly
gpg: import from '[stdin]' failed: SQL library used incorrectly
mise ERROR gpg failed
mise 2026.5.13 by @jdx                                                                                              [4/4]
go@1.26.3       go version go1.26.3 darwin/arm64                                                                        ✔
pnpm@11.3.0     extract pnpm-darwin-arm64.tar.gz                                                                        ✔
node@24.16.0    download node-v24.16.0-darwin-arm64.tar.gz                             119 B 5m18s [>                 ] ◠
cargo-binstall@1.17.9 extract cargo-binstall-aarch64-apple-darwin.zip                                                   ✔
mise ERROR Failed to install core:node@24: gpg exited with non-zero status: exit code 2
mise ERROR Run with --verbose or MISE_VERBOSE=1 for more information

Hey @Fraccaman, Sorry for delayed response.
There was another PR related to PendingTransactions that was being worked on and now that is merged can you please rebase those changes and resolve the conflicts. So we can have proper review.
Thanks.

Also you need to first run the mise run install-lint-tools to download all the required tools.

@Fraccaman Fraccaman force-pushed the fix-mempool-filters branch from e39aa6f to 5464537 Compare June 2, 2026 19:48
@Fraccaman

Fraccaman commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

I rebased but mise run install-lint-tools is failing for me.

@akaladarshi akaladarshi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We also need to add tests for the EthGetFilterChanges where we call it multiple times and see if each call returns the new pending transaction since the last poll.


/// Clone of the [`MpoolUpdate`] broadcast sender. New independent
/// receivers can be derived by calling `subscribe()` on the clone.
pub(in crate::message_pool) fn event_sender(&self) -> broadcast::Sender<MpoolUpdate> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We made the events private for a specific reason, events should only be sent by the message pool module and every other module will read the data through subscribe method receiver.
This breaks the encapsulation.

Comment thread src/message_pool/msgpool/msg_pool.rs Outdated

/// Clone of the [`MpoolUpdate`] sender. Each call to `subscribe()` on
/// the returned sender yields an independent receiver.
pub fn mpool_event_sender(&self) -> broadcast::Sender<MpoolUpdate> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same here this breaks the encapsulation, event sender is send only should not shared.

Comment thread src/rpc/methods/eth.rs Outdated
}

/// Derive the Ethereum-style hash for a `SignedMessage`.
pub fn eth_hash_from_signed_message(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We already have similar fn eth_tx_hash_from_signed_message, please reuse it.

Comment on lines +56 to +58
Ok(MpoolUpdate::Remove(m)) => {
if let Some(h) = hash_or_log(&m, chain_id) {
pending.shift_remove(&h);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What is the actual purpose doing this ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

as far as I understand ::Remove is triggered when the mempool drops a pending tx (i.e in this case only when a tx is mined). The cancel in drain removes the hash that would otherwise surface as still-pending

@Fraccaman

Copy link
Copy Markdown
Contributor Author

hey @akaladarshi im on vacation, ill fix this as soon as im back

@akaladarshi

Copy link
Copy Markdown
Collaborator

Hi @Fraccaman
Any update on this?

Fraccaman added a commit to Fraccaman/forest that referenced this pull request Jun 21, 2026
…er poll

Adds eth_new_pending_transaction_filter_multi_poll: installs a pending-tx
filter, submits tx A, polls (asserts hash A returned), submits tx B,
polls (asserts hash B returned and hash A absent). Confirms each
eth_getFilterChanges call surfaces only the delta since the previous
poll, addressing review feedback on PR ChainSafe#7109.
@Fraccaman

Fraccaman commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Hi @Fraccaman Any update on this?

Hey @akaladarshi sorry for the delay, I got back from vacation this week and got busy. Fixed your code review suggestions! thanks

@Fraccaman Fraccaman requested a review from akaladarshi June 21, 2026 20:15
- Encapsulation: drop the public Sender accessor on PendingStore /
  MessagePool. MempoolFilterManager now holds an `MpoolSubscriber`
  closure (`Arc<dyn Fn() -> broadcast::Receiver<MpoolUpdate>>`); each
  install() calls it to obtain a fresh independent receiver via
  `MessagePool::subscribe_to_updates()`. Filter layer never touches the
  send side. Daemon and offline server wrap a shallow-cloned MessagePool
  in the closure; `EthEventHandler::new()` builds a dummy closure for
  standalone contexts.
- Helper reuse: drop the new `eth_hash_from_signed_message` helper and
  reuse the existing `eth_tx_hash_from_signed_message`. Both
  `EthGetTransactionHashByCid::run` and `MempoolFilter::drain` now call
  the single implementation.
- Docs: document why `MpoolUpdate::Remove` is processed inside `drain`
  (cancels a buffered `Add` for a tx that left the mempool between
  client polls, e.g. mined into a tipset).

Adds two unit tests for the new manager wiring:
manager_subscribes_each_filter_to_independent_receiver and
manager_with_dummy_subscriber_yields_empty.
…er poll

Adds eth_new_pending_transaction_filter_multi_poll: installs a pending-tx
filter, submits tx A, polls (asserts hash A returned), submits tx B,
polls (asserts hash B returned and hash A absent). Confirms each
eth_getFilterChanges call surfaces only the delta since the previous
poll, addressing review feedback on PR ChainSafe#7109.
@Fraccaman Fraccaman force-pushed the fix-mempool-filters branch from 2594346 to 0b66f95 Compare June 21, 2026 20:17
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.

MempoolFilter should collect pending transaction data

2 participants