mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 16:01:36 +00:00
The second state sync (pivot→HEAD) determines its target using CurrentSnapBlock(), which may equal CurrentBlock() if no afterP blocks were processed before the queue drained. This is a timing-dependent race: with rate-limited pivot advances, the pivot ends up close to the CL head, so the final batch may contain zero afterP blocks, causing CurrentSnapBlock == CurrentBlock. The check `snapHead.Hash() != currentHead.Hash()` then fails and the second sync is skipped entirely. Without the second sync, disableSnap() is never called, ConfigSyncMode() stays SnapSync, and ALL subsequent newPayload calls are delayed forever. Fix: use the skeleton head (beacon chain tip) as the second sync target instead of CurrentSnapBlock(). The skeleton head is always available and correctly reflects the CL's latest finalized target, independent of queue draining timing. Also removes the fragile "snap head too old" and "snap head too far behind" guards which could abort the second sync prematurely. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| api.go | ||
| beacondevsync.go | ||
| beaconsync.go | ||
| downloader.go | ||
| downloader_test.go | ||
| events.go | ||
| fetchers.go | ||
| fetchers_concurrent.go | ||
| fetchers_concurrent_bodies.go | ||
| fetchers_concurrent_receipts.go | ||
| metrics.go | ||
| peer.go | ||
| queue.go | ||
| queue_test.go | ||
| resultstore.go | ||
| skeleton.go | ||
| skeleton_test.go | ||
| statesync.go | ||
| syncmode.go | ||
| testchain_test.go | ||