88 "container/list"
99 "math/rand"
1010 "net"
11+ "sort"
1112 "sync"
1213 "sync/atomic"
1314 "time"
@@ -525,6 +526,13 @@ func (sm *SyncManager) handleCheckSyncPeer() {
525526 return
526527 }
527528
529+ // Check if a majority of our sync peer candidates are at a greater height than our current sync peer.
530+ // If they are, it is time to select a new peer, as ours is obviously behind.
531+ if sm .topBlock () < sm .medianSyncPeerCandidateBlockHeight () {
532+ sm .updateSyncPeer ()
533+ return
534+ }
535+
528536 // Update network stats at the end of this tick.
529537 defer sm .syncPeerState .updateNetwork (sm .syncPeer )
530538
@@ -537,7 +545,6 @@ func (sm *SyncManager) handleCheckSyncPeer() {
537545
538546 // Don't update sync peers if you have all the available
539547 // blocks.
540-
541548 best := sm .chain .BestSnapshot ()
542549
543550 if sm .topBlock () == best .Height || sm .chain .UtxoCacheFlushInProgress () || (sm .fastSyncMode && best .Height == sm .lastCheckpoint ().Height ) {
@@ -550,6 +557,40 @@ func (sm *SyncManager) handleCheckSyncPeer() {
550557 sm .updateSyncPeer ()
551558}
552559
560+ // medianSyncPeerCandidateBlockHeight returns the median block height of sync peer candidates.
561+ func (sm * SyncManager ) medianSyncPeerCandidateBlockHeight () int32 {
562+ heights := []int32 {}
563+
564+ for peer , state := range sm .peerStates {
565+ if ! state .syncCandidate {
566+ continue
567+ }
568+
569+ // Peer isn't connected, skip.
570+ if ! peer .Connected () {
571+ continue
572+ }
573+
574+ heights = append (heights , peer .LastBlock ())
575+ }
576+
577+ // If we don't have any sync peer candidate heights, return 0.
578+ // This is just to protect from a panic below.
579+ if len (heights ) < 1 {
580+ return 0
581+ }
582+
583+ sort .Slice (heights , func (i , j int ) bool { return heights [i ] < heights [j ] })
584+
585+ mNumber := len (heights ) / 2
586+
587+ if len (heights )% 2 != 0 {
588+ return heights [mNumber ]
589+ }
590+
591+ return (heights [mNumber - 1 ] + heights [mNumber ]) / 2
592+ }
593+
553594// topBlock returns the best chains top block height
554595func (sm * SyncManager ) topBlock () int32 {
555596 if sm .syncPeer .LastBlock () > sm .syncPeer .StartingHeight () {
0 commit comments