From a9f23321d9561b0cebaa52d964b555bc61634500 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 15 Apr 2019 18:25:37 -0700 Subject: [PATCH] netsync/manager: prioritize higher height peers for sync peer This commit modifies the sync peer selection to prefer peers with a higher advertised height than our currently known best height. If no peers are known with a higher height, we will fall back to selecting a random peer with the same best height as our own. The current algorithm currently selects a random peer from the union of these two sets, while this approach will favor trying to make progress. This will likely help in selecting a good peer once already at tip, such as after a restart. Backport of https://github.com/gcash/bchd/pull/96 --- netsync/manager.go | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/netsync/manager.go b/netsync/manager.go index 2a940edb..8444c898 100644 --- a/netsync/manager.go +++ b/netsync/manager.go @@ -6,6 +6,7 @@ package netsync import ( "container/list" + "math/rand" "net" "sync" "sync/atomic" @@ -236,7 +237,7 @@ func (sm *SyncManager) startSync() { } best := sm.chain.BestSnapshot() - var bestPeer *peerpkg.Peer + var higherPeers, equalPeers []*peerpkg.Peer for peer, state := range sm.peerStates { if !state.syncCandidate { continue @@ -258,9 +259,33 @@ func (sm *SyncManager) startSync() { continue } - // TODO(davec): Use a better algorithm to choose the best peer. - // For now, just pick the first available candidate. - bestPeer = peer + // If the peer is at the same height as us, we'll add it a set + // of backup peers in case we do not find one with a higher + // height. If we are synced up with all of our peers, all of + // them will be in this set. + if peer.LastBlock() == best.Height { + equalPeers = append(equalPeers, peer) + continue + } + + // This peer has a height greater than our own, we'll consider + // it in the set of better peers from which we'll randomly + // select. + higherPeers = append(higherPeers, peer) + } + + // Pick randomly from the set of peers greater than our block height, + // falling back to a random peer of the same height if none are greater. + // + // TODO(conner): Use a better algorithm to ranking peers based on + // observed metrics and/or sync in parallel. + var bestPeer *peerpkg.Peer + switch { + case len(higherPeers) > 0: + bestPeer = higherPeers[rand.Intn(len(higherPeers))] + + case len(equalPeers) > 0: + bestPeer = equalPeers[rand.Intn(len(equalPeers))] } // Start syncing from the best peer if one was selected.