mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
Fix several interacting issues that prevented partial state nodes from syncing and following the chain on bal-devnet-2: 1. Stale pivot deadlock: Replace unconditional pivot suppression with rate-limited advances (2-minute cooldown). This prevents the restart loop bug while allowing recovery when the initial pivot is too stale for peers to serve. 2. Storage root resolution: Add snap-based resolver that queries peers for untracked contracts' storage roots during BAL processing. This lets the computed state root converge toward the header root. 3. SetCanonical for partial state: When the computed root differs from the header root (expected when untracked contracts have unresolved storage roots), check HasState(partialState.Root()) instead of only HasState(block.Root()). Guard against zero root during snap sync. 4. Canonical hash backfill: AdvancePartialHead now writes canonical hashes for all blocks between the pivot and snap head, fixing the "final block not in canonical chain" error caused by InsertReceiptChain skipping blocks whose bodies already exist. 5. Gap block processing: After snap sync completes, process accumulated blocks between the sync head and chain tip using their persisted BALs before entering steady-state chain following. 6. Computed root chaining: Use partialState.Root() (actual computed root) as parentRoot for subsequent blocks, not the header root. This ensures correct trie chaining when computed != header root. Tested end-to-end on bal-devnet-2: snap sync completes, gap blocks processed, canonical head advances at chain tip (~1 block/12s). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
57 lines
2.1 KiB
Go
57 lines
2.1 KiB
Go
// Copyright 2020 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package eth
|
|
|
|
import (
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
)
|
|
|
|
// snapHandler implements the snap.Backend interface to handle the various network
|
|
// packets that are sent as replies or broadcasts.
|
|
type snapHandler handler
|
|
|
|
func (h *snapHandler) Chain() *core.BlockChain { return h.chain }
|
|
|
|
// RunPeer is invoked when a peer joins on the `snap` protocol.
|
|
func (h *snapHandler) RunPeer(peer *snap.Peer, hand snap.Handler) error {
|
|
return (*handler)(h).runSnapExtension(peer, hand)
|
|
}
|
|
|
|
// PeerInfo retrieves all known `snap` information about a peer.
|
|
func (h *snapHandler) PeerInfo(id enode.ID) interface{} {
|
|
if p := h.peers.peer(id.String()); p != nil {
|
|
if p.snapExt != nil {
|
|
return p.snapExt.info()
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Handle is invoked from a peer's message handler when it receives a new remote
|
|
// message that the handler couldn't consume and serve itself.
|
|
func (h *snapHandler) Handle(peer *snap.Peer, packet snap.Packet) error {
|
|
// Check if this is a response to a one-off storage root query from partial state
|
|
if resp, ok := packet.(*snap.AccountRangePacket); ok {
|
|
if ch, loaded := (*handler)(h).pendingSnapQueries.LoadAndDelete(resp.ID); loaded {
|
|
ch.(chan *snap.AccountRangePacket) <- resp
|
|
return nil
|
|
}
|
|
}
|
|
return h.downloader.DeliverSnapPacket(peer, packet)
|
|
}
|