@@ -572,11 +572,17 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
572
572
if head > height {
573
573
head = height
574
574
}
575
- from := int64 (head ) - int64 (MaxHeaderFetch ) + 1
575
+ from := int64 (head ) - int64 (MaxHeaderFetch )
576
576
if from < 0 {
577
577
from = 0
578
578
}
579
- go p .getAbsHeaders (uint64 (from ), MaxHeaderFetch , 0 , false )
579
+ // Span out with 15 block gaps into the future to catch bad head reports
580
+ limit := 2 * MaxHeaderFetch / 16
581
+ count := 1 + int ((int64 (ceil )- from )/ 16 )
582
+ if count > limit {
583
+ count = limit
584
+ }
585
+ go p .getAbsHeaders (uint64 (from ), count , 15 , false )
580
586
581
587
// Wait for the remote response to the head fetch
582
588
number , hash := uint64 (0 ), common.Hash {}
@@ -601,25 +607,27 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
601
607
}
602
608
// Make sure the peer's reply conforms to the request
603
609
for i := 0 ; i < len (headers ); i ++ {
604
- if number := headers [i ].Number .Int64 (); number != from + int64 (i ) {
605
- glog .V (logger .Warn ).Infof ("%v: head header set (item %d) broke chain ordering: requested %d, got %d" , p , i , from + int64 (i ), number )
606
- return 0 , errInvalidChain
607
- }
608
- if i > 0 && headers [i - 1 ].Hash () != headers [i ].ParentHash {
609
- glog .V (logger .Warn ).Infof ("%v: head header set (item %d) broke chain ancestry: expected [%x], got [%x]" , p , i , headers [i - 1 ].Hash ().Bytes ()[:4 ], headers [i ].ParentHash [:4 ])
610
+ if number := headers [i ].Number .Int64 (); number != from + int64 (i )* 16 {
611
+ glog .V (logger .Warn ).Infof ("%v: head header set (item %d) broke chain ordering: requested %d, got %d" , p , i , from + int64 (i )* 16 , number )
610
612
return 0 , errInvalidChain
611
613
}
612
614
}
613
615
// Check if a common ancestor was found
614
616
finished = true
615
617
for i := len (headers ) - 1 ; i >= 0 ; i -- {
616
618
// Skip any headers that underflow/overflow our requested set
617
- if headers [i ].Number .Int64 () < from || headers [i ].Number .Uint64 () > head {
619
+ if headers [i ].Number .Int64 () < from || headers [i ].Number .Uint64 () > ceil {
618
620
continue
619
621
}
620
622
// Otherwise check if we already know the header or not
621
623
if (d .mode == FullSync && d .hasBlockAndState (headers [i ].Hash ())) || (d .mode != FullSync && d .hasHeader (headers [i ].Hash ())) {
622
624
number , hash = headers [i ].Number .Uint64 (), headers [i ].Hash ()
625
+
626
+ // If every header is known, even future ones, the peer straight out lied about its head
627
+ if number > height && i == limit - 1 {
628
+ glog .V (logger .Warn ).Infof ("%v: lied about chain head: reported %d, found above %d" , p , height , number )
629
+ return 0 , errStallingPeer
630
+ }
623
631
break
624
632
}
625
633
}
0 commit comments