Skip to content

eth/downloader: stop snap sync when the result queue closes empty - #2477

Open
Amirhosein wants to merge 1 commit into
0xPolygon:developfrom
Amirhosein:fix/snap-sync-downloader-empty-results-panic-2441
Open

Amirhosein wants to merge 1 commit into
0xPolygon:developfrom
Amirhosein:fix/snap-sync-downloader-empty-results-panic-2441

Conversation

@Amirhosein

Copy link
Copy Markdown

Summary

Fixes an index out of range [-1] panic in processSnapSyncContent when the result queue closes before a pivot block has been committed or held (oldPivot == nil).

When queue.Close() is called while pivotHeader is still uncommitted and cancelCh is open:

  • d.queue.Results(true) unblocks and returns an empty slice ([]*fetchResult{}).
  • The downloader loop proceeded directly to evaluate latest := results[len(results)-1].Header, indexing into -1 and panicking.

With this change, when len(results) == 0 and oldPivot == nil:

  • sync.Cancel() is invoked. If state sync failed for a real reason (e.g. queue closed by closeOnErr), that underlying non-cancellation error is returned.
  • Otherwise, errCanceled is returned so that caller routines (such as spawnSync) can prioritize fetcher errors (such as errNoPeers).

Note: This PR addresses observation A reported in #2441 (the empty results queue panic during snap sync). Protocol receipt size limits (>10 MiB) are out of scope.

Executed tests

  • Added unit test TestProcessSnapSyncContentEmptyQueue covering:
    • BareQueueShutdown: clean queue closure with healthy state sync returns errCanceled.
    • StateSyncFailure: queue closure triggered by a state sync failure returns the underlying error.
    • CommittedWithEmptyQueue: empty queue when already committed preserves the normal exit path.
  • Verified with the Go race detector: go test -v -race ./eth/downloader -run TestProcessSnapSyncContentEmptyQueue (passed, 0 race warnings).
  • Ran package test suite: go test -short ./eth/downloader (all passed).

Rollout notes

Non-breaking bug fix, backwards-compatible, not consensus-affecting.

When the result queue closes before a pivot block is committed or held
(oldPivot == nil), Results(true) returns an empty slice. Previously,
the loop proceeded to evaluate results[len(results)-1].Header, causing
an index out of range [-1] panic.

Cancel state sync and return early when results is empty and oldPivot is nil:
if sync.Cancel() returns a non-cancellation error (e.g. from closeOnErr),
surface that error; otherwise return errCanceled so callers can surface
fetcher errors.

@claude claude Bot 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.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

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