Skip to content

fix(core/txpool): subscribe to head events in New and release on Init error #35048 - #2543

Open
gzliudan wants to merge 2 commits into
XinFinOrg:dev-upgradefrom
gzliudan:fix-txpool-head-events
Open

fix(core/txpool): subscribe to head events in New and release on Init error #35048#2543
gzliudan wants to merge 2 commits into
XinFinOrg:dev-upgradefrom
gzliudan:fix-txpool-head-events

Conversation

@gzliudan

@gzliudan gzliudan commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes lost chain head events in the txpool that left the pool resetting against a stale head, rejecting fresh transactions as ErrNonceTooHigh (this also caused sporadic TestResubmit/TestJournal flakes on CI).

Ref: ethereum#35048

Root cause

The pool subscribed to chain head events only after its loop goroutine started:

var (
    newHeadCh  = make(chan core.ChainHeadEvent)
    newHeadSub = p.chain.SubscribeChainHeadEvent(newHeadCh)
)

Because the subscription is established asynchronously, a head event emitted by InsertChain right after New could be missed. The pool then reset against a stale head, keeping pending nonces at genesis (nonce 0); transactions built on the new chain nonce were rejected with ErrNonceTooHigh.

Fix

  1. Subscribe synchronously in New (matching upstream geth): newHeadCh/newHeadSub become TxPool fields and chain.SubscribeChainHeadEvent is called before any block can be inserted, so head events are never lost.
  2. Release the subscription on Init failure: New subscribes before the fallible SubPool.Init calls; if Init fails, New returns without starting the loop, so the loop's deferred Unsubscribe never runs and the chain feed stays subscribed to an unconsumed, unbuffered channel — a later head publication can block until the chain is stopped. The error path now unsubscribes before returning.

Tests

  • TestHeadEventDeliveredAfterNew: inserts blocks right after New and waits for the pool's pending nonce to advance to the new head — it times out if the head event is lost.
  • TestNewUnsubscribesOnInitError: forces a SubPool.Init failure and asserts the head event subscription is released (fails if leaked).

Upstream reference

Aligns the head-event subscription with upstream geth commit b71f75091 (core, core/txpool, eth: move subscriptions to constructor, ethereum#35048; closes ethereum#20554). XDPoSChain was still on the pre-ethereum#35048 shape where the loop subscribed asynchronously inside its goroutine. The Init-failure release goes beyond upstream, fixing a leak also present in geth's current shape.

Verification

  • core/txpool: full package passes;
  • TestHeadEventDeliveredAfterNew and TestNewUnsubscribesOnInitError pass repeated runs under -cover and -race;
  • core/txpool/locals: 100 consecutive runs under -cover all pass (the TestResubmit/TestJournal flakes were rooted in this head-event loss).

Compatibility

Internal txpool concurrency control only; no protocol, RPC, or state-transition changes.

@gzliudan gzliudan changed the title fix(core/txpool): subscribe to head events in New to avoid loss fix(core/txpool): subscribe to head events in New to avoid loss #35048 Aug 26, 2026
@gzliudan
gzliudan force-pushed the fix-txpool-head-events branch from dad2f5f to 581cee2 Compare August 26, 2026 01:17
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 934bf47b-88c8-42fb-b2bd-3971b163b27e

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

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Moves txpool head-event subscription into construction to prevent missed events and stale nonce state.

Changes:

  • Subscribes synchronously in txpool.New.
  • Adds regression coverage for immediate block insertion.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
core/txpool/txpool.go Moves head subscription into the constructor.
core/txpool/txpool_head_event_test.go Tests immediate head-event delivery and transaction acceptance.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread core/txpool/txpool.go
@gzliudan gzliudan changed the title fix(core/txpool): subscribe to head events in New to avoid loss #35048 fix(core/txpool): subscribe to head events in New and release on Init error Aug 26, 2026
@gzliudan gzliudan changed the title fix(core/txpool): subscribe to head events in New and release on Init error fix(core/txpool): subscribe to head events in New and release on Init error #35048 Aug 26, 2026
@gzliudan
gzliudan requested a balanced review from Copilot August 26, 2026 01:33
@gzliudan
gzliudan force-pushed the fix-txpool-head-events branch from 26138cc to 9b5b77e Compare August 26, 2026 02:17
…eum#35048

The pool subscribed to chain head events only after its loop goroutine
started, so a head event emitted by InsertChain right after New could be
missed. The pool then reset against a stale head, keeping pending nonces
at genesis and rejecting fresh transactions as ErrNonceTooHigh (this also
caused the TestResubmit/TestJournal flakes).

Move the subscription into New so events are captured from the start, and
add TestHeadEventDeliveredAfterNew which waits for the pool to observe the
head inserted right after New.
@gzliudan
gzliudan force-pushed the fix-txpool-head-events branch from 9b5b77e to a445d13 Compare August 26, 2026 02:19
@gzliudan
gzliudan requested a balanced review from Copilot and removed request for Copilot August 26, 2026 02:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread core/txpool/txpool_head_event_test.go
New subscribes to chain head events before the fallible SubPool.Init calls.
When Init fails, New returns without starting the loop, so the loop's
deferred Unsubscribe never runs and the chain feed stays subscribed to an
unconsumed, unbuffered channel; a later head publication can block until
the whole blockchain is stopped.

Unsubscribe on this error path before returning, and add
TestNewUnsubscribesOnInitError which fails if the subscription is leaked.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

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.

2 participants