Skip to content

Commit a6a8b05

Browse files
rjl493456442jagdeep sidhu
authored andcommitted
eth/downloader: resolve local header by hash for beacon sync (ethereum#24691)
* eth/downlaoder: resolve local header by hash for beacon sync * eth/downloader: fix error message * eth/downloader: cap the reverse header resolving * eth/downloader: re-enable tests * eth/downloader: add warning logs
1 parent ec21c26 commit a6a8b05

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

eth/downloader/beaconsync.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,23 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
263263
// fetchBeaconHeaders feeds skeleton headers to the downloader queue for scheduling
264264
// until sync errors or is finished.
265265
func (d *Downloader) fetchBeaconHeaders(from uint64) error {
266-
head, _, err := d.skeleton.Bounds()
266+
head, tail, err := d.skeleton.Bounds()
267267
if err != nil {
268268
return err
269269
}
270+
// A part of headers are not in the skeleton space, try to resolve
271+
// them from the local chain. Note the range should be very short
272+
// and it should only happen when there are less than 64 post-merge
273+
// blocks in the network.
274+
var localHeaders []*types.Header
275+
if from < tail.Number.Uint64() {
276+
count := tail.Number.Uint64() - from
277+
if count > uint64(fsMinFullBlocks) {
278+
return fmt.Errorf("invalid origin (%d) of beacon sync (%d)", from, tail.Number)
279+
}
280+
localHeaders = d.readHeaderRange(tail, int(count))
281+
log.Warn("Retrieved beacon headers from local", "from", from, "count", count)
282+
}
270283
for {
271284
// Retrieve a batch of headers and feed it to the header processor
272285
var (
@@ -275,8 +288,18 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error {
275288
)
276289
for i := 0; i < maxHeadersProcess && from <= head.Number.Uint64(); i++ {
277290
header := d.skeleton.Header(from)
291+
292+
// The header is not found in skeleton space, try to find it in local chain.
293+
if header == nil && from < tail.Number.Uint64() {
294+
dist := tail.Number.Uint64() - from
295+
if len(localHeaders) >= int(dist) {
296+
header = localHeaders[dist-1]
297+
}
298+
}
299+
// The header is still missing, the beacon sync is corrupted and bail out
300+
// the error here.
278301
if header == nil {
279-
header = d.lightchain.GetHeaderByNumber(from)
302+
return fmt.Errorf("missing beacon header %d", from)
280303
}
281304
headers = append(headers, header)
282305
hashes = append(hashes, headers[i].Hash())

eth/downloader/downloader.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,6 @@ type LightChain interface {
160160
// GetHeaderByHash retrieves a header from the local chain.
161161
GetHeaderByHash(common.Hash) *types.Header
162162

163-
// GetHeaderByNumber retrieves a block header from the local chain by number.
164-
GetHeaderByNumber(number uint64) *types.Header
165-
166163
// CurrentHeader retrieves the head header from the local chain.
167164
CurrentHeader() *types.Header
168165

@@ -493,7 +490,15 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
493490
// Retrieve the pivot header from the skeleton chain segment but
494491
// fallback to local chain if it's not found in skeleton space.
495492
if pivot = d.skeleton.Header(number); pivot == nil {
496-
pivot = d.lightchain.GetHeaderByNumber(number)
493+
_, oldest, _ := d.skeleton.Bounds() // error is already checked
494+
if number < oldest.Number.Uint64() {
495+
count := int(oldest.Number.Uint64() - number) // it's capped by fsMinFullBlocks
496+
headers := d.readHeaderRange(oldest, count)
497+
if len(headers) == count {
498+
pivot = headers[len(headers)-1]
499+
log.Warn("Retrieved pivot header from local", "number", pivot.Number, "hash", pivot.Hash(), "latest", latest.Number, "oldest", oldest.Number)
500+
}
501+
}
497502
}
498503
// Print an error log and return directly in case the pivot header
499504
// is still not found. It means the skeleton chain is not linked
@@ -1779,3 +1784,25 @@ func (d *Downloader) DeliverSnapPacket(peer *snap.Peer, packet snap.Packet) erro
17791784
return fmt.Errorf("unexpected snap packet type: %T", packet)
17801785
}
17811786
}
1787+
1788+
// readHeaderRange returns a list of headers, using the given last header as the base,
1789+
// and going backwards towards genesis. This method assumes that the caller already has
1790+
// placed a reasonable cap on count.
1791+
func (d *Downloader) readHeaderRange(last *types.Header, count int) []*types.Header {
1792+
var (
1793+
current = last
1794+
headers []*types.Header
1795+
)
1796+
for {
1797+
parent := d.lightchain.GetHeaderByHash(current.ParentHash)
1798+
if parent == nil {
1799+
break // The chain is not continuous, or the chain is exhausted
1800+
}
1801+
headers = append(headers, parent)
1802+
if len(headers) >= count {
1803+
break
1804+
}
1805+
current = parent
1806+
}
1807+
return headers
1808+
}

0 commit comments

Comments
 (0)