Skip to content

eth/filters: fix flaky TestPendingTxFilterDeadlock#35334

Open
posidoni wants to merge 1 commit into
ethereum:masterfrom
posidoni:fix-flaky-pendingtx-filter-deadlock
Open

eth/filters: fix flaky TestPendingTxFilterDeadlock#35334
posidoni wants to merge 1 commit into
ethereum:masterfrom
posidoni:fix-flaky-pendingtx-filter-deadlock

Conversation

@posidoni

@posidoni posidoni commented Jul 10, 2026

Copy link
Copy Markdown

TestPendingTxFilterDeadlock fails intermittently under the race detector:

--- FAIL: TestPendingTxFilterDeadlock (0.86s)
    filter_system_test.go:767: Filter should exist: filter not found

Cause

The test sets a 100ms filter timeout and polls GetFilterChanges until each filter has seen a transaction. Every successful poll resets the filter deadline. On a loaded system (race detector, t.Parallel, low GOMAXPROCS) a single gap longer than 100ms between two polls lets timeoutLoop uninstall the filter, so the next poll returns errFilterNotFound and the test fails.

This early timeout is not the deadlock the test guards against (#22131). That deadlock froze filtersMu, so GetFilterChanges would block on the lock instead of returning errFilterNotFound.

This is the only test in the package that configures a non-default filter timeout, so no other test is exposed to this race.

Fix

  • Treat errFilterNotFound during the setup poll as a benign early timeout. The tolerance only applies once the filter has lived at least the configured timeout, so a regression that uninstalls filters before their deadline still fails the test. The uninstall itself is still verified by the sub.Err() wait at the end.
  • Close the done channel on test exit. The tx-sending goroutine was never stopped and kept spinning for the rest of the test binary, adding load to subsequent tests.

Verification

Before (M-series Mac):

  • go test -race -count=20 ./eth/filters/: 3 failures in 20 runs
  • go test -race -count=30 -cpu=1,2 -run 'TestPendingTxFilterDeadlock$' ./eth/filters/: 9+ failures

After:

  • -count=100 and -count=100 -cpu=1,2 (300 executions): all pass
  • full go test -race ./eth/filters/: pass

The test polls GetFilterChanges with a 100ms filter timeout. On a loaded
system a >100ms gap between two polls lets the timeout loop uninstall
the filter, so the next poll returns errFilterNotFound and the test
fails. Treat that as a benign early timeout, gated on the deadline
having actually elapsed; the uninstall is still verified through the
sub.Err() wait at the end of the test. Also close the done channel so
the tx-sending goroutine exits when the test finishes instead of
spinning for the remainder of the test binary.

Signed-off-by: Mikhail Kuznetsov <mikhail.n.kuznetsov@gmail.com>
@posidoni posidoni requested a review from rjl493456442 as a code owner July 10, 2026 05:39
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant