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
This commit is contained in:
Conner Fromknecht 2019-04-15 18:25:37 -07:00
parent 9bfb2ca034
commit a9f23321d9
No known key found for this signature in database
GPG key ID: E7D737B67FA592C7

View file

@ -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.