mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
downloader: refactor common ancestor algos and logic
This breaks the common ancestor search functions into SpanSearch and BinarySearch functions, ensuring that a negotiated common ancestor is never above our local head. It makes switch cases conditional on sync mode use LightSync explicitly, which makes the code more readable (instead of relying on LightSync as tacit default). Signed-off-by: meows <b5c6@protonmail.com>
This commit is contained in:
parent
069a7e1f8a
commit
12f6c7642c
1 changed files with 44 additions and 4 deletions
|
|
@ -81,6 +81,7 @@ var (
|
|||
errTimeout = errors.New("timeout")
|
||||
errEmptyHeaderSet = errors.New("empty header set by peer")
|
||||
errPeersUnavailable = errors.New("no peers available or all tried for download")
|
||||
errNoAncestor = errors.New("no common ancestor")
|
||||
errInvalidAncestor = errors.New("retrieved ancestor is invalid")
|
||||
errInvalidChain = errors.New("retrieved hash chain is invalid")
|
||||
errInvalidBody = errors.New("retrieved block body is invalid")
|
||||
|
|
@ -711,8 +712,10 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||
localHeight = d.blockchain.CurrentBlock().NumberU64()
|
||||
case FastSync:
|
||||
localHeight = d.blockchain.CurrentFastBlock().NumberU64()
|
||||
default:
|
||||
case LightSync:
|
||||
localHeight = d.lightchain.CurrentHeader().Number.Uint64()
|
||||
default:
|
||||
log.Crit("unknown sync mode", "mode", d.mode)
|
||||
}
|
||||
p.log.Debug("Looking for common ancestor", "local", localHeight, "remote", remoteHeight)
|
||||
|
||||
|
|
@ -741,9 +744,36 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||
}
|
||||
}
|
||||
|
||||
// Only attempt span search if local head is "close" to reported remote
|
||||
if remoteHeight-localHeight < uint64(MaxHeaderFetch) {
|
||||
a, err := d.findAncestorSpanSearch(p, remoteHeight, localHeight, floor)
|
||||
if err == nil {
|
||||
if a > localHeight {
|
||||
a = localHeight
|
||||
}
|
||||
return a, nil
|
||||
} else if err != errNoAncestor {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// Ancestor not found, we need to binary search over our chain
|
||||
a, err := d.findAncestorBinarySearch(p, remoteHeight, floor)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if a > localHeight {
|
||||
a = localHeight
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// findAncestorSpanSearch looks for a common ancestor by requesting a spaced set of headers between ours and theirs.
|
||||
func (d *Downloader) findAncestorSpanSearch(p *peerConnection, remoteHeight, localHeight uint64, floor int64) (uint64, error) {
|
||||
from, count, skip, max := calculateRequestSpan(remoteHeight, localHeight)
|
||||
|
||||
p.log.Trace("Span searching for common ancestor", "count", count, "from", from, "skip", skip)
|
||||
|
||||
go p.peer.RequestHeadersByNumber(uint64(from), count, skip, false)
|
||||
|
||||
// Wait for the remote response to the head fetch
|
||||
|
|
@ -794,8 +824,10 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||
known = d.blockchain.HasBlock(h, n)
|
||||
case FastSync:
|
||||
known = d.blockchain.HasFastBlock(h, n)
|
||||
default:
|
||||
case LightSync:
|
||||
known = d.lightchain.HasHeader(h, n)
|
||||
default:
|
||||
log.Crit("unknown sync mode", "mode", d.mode)
|
||||
}
|
||||
if known {
|
||||
number, hash = n, h
|
||||
|
|
@ -821,13 +853,19 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||
p.log.Debug("Found common ancestor", "number", number, "hash", hash)
|
||||
return number, nil
|
||||
}
|
||||
// Ancestor not found, we need to binary search over our chain
|
||||
return 0, errNoAncestor
|
||||
}
|
||||
|
||||
// findAncestorBinarySearch negotiates a binary search using their reported chain.
|
||||
func (d *Downloader) findAncestorBinarySearch(p *peerConnection, remoteHeight uint64, floor int64) (uint64, error) {
|
||||
start, end := uint64(0), remoteHeight
|
||||
if floor > 0 {
|
||||
start = uint64(floor)
|
||||
}
|
||||
p.log.Trace("Binary searching for common ancestor", "start", start, "end", end)
|
||||
|
||||
// Wait for the remote response to the head fetch
|
||||
hash := common.Hash{}
|
||||
for start+1 < end {
|
||||
// Split our chain interval in two, and request the hash to cross check
|
||||
check := (start + end) / 2
|
||||
|
|
@ -867,8 +905,10 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||
known = d.blockchain.HasBlock(h, n)
|
||||
case FastSync:
|
||||
known = d.blockchain.HasFastBlock(h, n)
|
||||
default:
|
||||
case LightSync:
|
||||
known = d.lightchain.HasHeader(h, n)
|
||||
default:
|
||||
log.Crit("unknown sync mode", "mode", d.mode)
|
||||
}
|
||||
if !known {
|
||||
end = check
|
||||
|
|
|
|||
Loading…
Reference in a new issue