func (sm *SyncManager) startSync() {
	if sm.syncPeer != nil {
		return
	}
	segwitActive, err := sm.chain.IsDeploymentActive(chaincfg.DeploymentSegwit)
	if err != nil {
		log.Errorf("Unable to query for segwit soft-fork state: %v", err)
		return
	}
	dagState := sm.chain.DAGSnapshot()
	var equalPeers, higherPeers []*peerpkg.Peer
	for peer, state := range sm.peerStates {
		if !state.syncCandidate {
			continue
		}
		if segwitActive && !peer.IsWitnessEnabled() {
			log.Debugf("peer %v not witness enabled, skipping", peer)
			continue
		}
		if peer.MaxBlockHeight() < dagState.MaxHeight {
			state.syncCandidate = false
			continue
		}
		if peer.MaxBlockHeight() > dagState.MaxHeight {
			higherPeers = append(higherPeers, peer)
		} else if peer.MaxBlockHeight() == dagState.MaxHeight {
			equalPeers = append(equalPeers, peer)
		}
	}
	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))]
	}
	if bestPeer != nil {
		sm.requestedBlocks = make(map[chainhash.Hash]*requestExpiry)
		locator, err := sm.chain.LatestBlockLocator()
		if err != nil {
			log.Errorf("Failed to get block locator for the "+
				"latest block: %v", err)
			return
		}
		log.Infof("Syncing to block height %d from peer %v",
			bestPeer.MaxBlockHeight(), bestPeer.Addr())
		_ = bestPeer.PushGetBlocksMsg(locator, &zeroHash)
		sm.syncPeer = bestPeer
		sm.lastProgressTime = time.Now()
	} else {
		log.Warnf("No sync peer candidates available")
	}
}
NOTE(cedric): Commented out to disable checkpoint-related code (JIRA DAG-3)


findNextHeaderCheckpoint returns the next checkpoint after the passed height.
It returns nil when there is not one either because the height is already
later than the final checkpoint or some other reason such as disabled
checkpoints.
func (sm *SyncManager) findNextHeaderCheckpoint(height int32) *chaincfg.Checkpoint {
checkpoints := sm.chain.Checkpoints()
if len(checkpoints) == 0 {
return nil
}
// There is no next checkpoint if the height is already after the final
// checkpoint.
finalCheckpoint := &checkpoints[len(checkpoints)-1]
if height >= finalCheckpoint.Height {
return nil
}
// Find the next checkpoint.
nextCheckpoint := finalCheckpoint
for i := len(checkpoints) - 2; i >= 0; i-- {
if height >= checkpoints[i].Height {
break
}
nextCheckpoint = &checkpoints[i]
}
return nextCheckpoint
}
startSync will choose the best peer among the available candidate peers to
download/sync the blockchain from.  When syncing is already running, it
simply returns.  It also examines the candidates for any which are no longer
candidates and removes them as needed.
package netsync
import (
	"container/list"
	"math/rand"
	"net"
	"sync"
	"sync/atomic"
	"time"
	"github.com/soteria-dag/soterd/blockdag"
	"github.com/soteria-dag/soterd/chaincfg"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/database"
	"github.com/soteria-dag/soterd/mempool"
	peerpkg "github.com/soteria-dag/soterd/peer"
	"github.com/soteria-dag/soterd/soterutil"
	"github.com/soteria-dag/soterd/wire"
)
const (
	minInFlightBlocks = 10
	maxRejectedTxns = 1000
	maxRequestedBlocks = wire.MaxInvPerMsg
	maxRequestedTxns = wire.MaxInvPerMsg
	maxStallDuration = 3 * time.Minute
	stallSampleInterval = 30 * time.Second
)
var zeroHash chainhash.Hash
type newPeerMsg struct {
	peer *peerpkg.Peer
}
type blockMsg struct {
	block *soterutil.Block
	peer  *peerpkg.Peer
	reply chan struct{}
}
type invMsg struct {
	inv  *wire.MsgInv
	peer *peerpkg.Peer
}
type headersMsg struct {
	headers *wire.MsgHeaders
	peer    *peerpkg.Peer
}
type donePeerMsg struct {
	peer *peerpkg.Peer
}
type txMsg struct {
	tx    *soterutil.Tx
	peer  *peerpkg.Peer
	reply chan struct{}
}
type getSyncPeerMsg struct {
	reply chan int32
}
type processBlockResponse struct {
	isOrphan bool
	err      error
}
type processBlockMsg struct {
	block *soterutil.Block
	flags blockdag.BehaviorFlags
	reply chan processBlockResponse
}
type isCurrentMsg struct {
	reply chan bool
}
type pauseMsg struct {
	unpause <-chan struct{}
}
type headerNode struct {
	height int32
	hash   *chainhash.Hash
}
type peerSyncState struct {
	syncCandidate   bool
	requestQueue    []*wire.InvVect
	requestedTxns   map[chainhash.Hash]*requestExpiry
	requestedBlocks map[chainhash.Hash]*requestExpiry
}
type requestExpiry struct {
	reqTime time.Time
	attempts int
}
type SyncManager struct {
	peerNotifier   PeerNotifier
	started        int32
	shutdown       int32
	chain          *blockdag.BlockDAG
	txMemPool      *mempool.TxPool
	chainParams    *chaincfg.Params
	progressLogger *blockProgressLogger
	msgChan        chan interface{}
	wg             sync.WaitGroup
	quit           chan struct{}
	rejectedTxns    map[chainhash.Hash]struct{}
	requestedTxns   map[chainhash.Hash]*requestExpiry
	requestedBlocks map[chainhash.Hash]*requestExpiry
	syncPeer        *peerpkg.Peer
	peerStates      map[*peerpkg.Peer]*peerSyncState
	lastProgressTime time.Time
	headersFirstMode bool
	headerList       *list.List
	startHeader      *list.Element
	feeEstimator *mempool.FeeEstimator
}
func (e *requestExpiry) expired() bool {
	return time.Now().After(e.reqTime.Add(stallSampleInterval))
}
func (e *requestExpiry) reset() {
	e.reqTime = time.Now()
	e.attempts = 0
}
func NewRequestExpiry() *requestExpiry {
	return &requestExpiry{
		reqTime: time.Now(),
	}
}
func (sm *SyncManager) canReqBlock(state *peerSyncState, hash chainhash.Hash) bool {
	peerReqExp, peerExists := state.requestedBlocks[hash]
	if peerExists && !peerReqExp.expired() {
		return false
	}
	reqExp, exists := sm.requestedBlocks[hash]
	if exists && !reqExp.expired() {
		return false
	}
	return true
}
func (sm *SyncManager) canReqTxn(state *peerSyncState, hash chainhash.Hash) bool {
	peerReqExp, peerExists := state.requestedTxns[hash]
	if peerExists && !peerReqExp.expired() {
		return false
	}
	reqExp, exists := sm.requestedTxns[hash]
	if exists && !reqExp.expired() {
		return false
	}
	return true
}
func (sm *SyncManager) hasPendingBlocks(peer *peerpkg.Peer) bool {
	state, exists := sm.peerStates[peer]
	if !exists {
		return false
	}
	for _, req := range state.requestedBlocks {
		if !req.expired() {
			return true
		}
	}
	return false
}
func (sm *SyncManager) resetHeaderState(newestHash *chainhash.Hash, newestHeight int32) {
	sm.headersFirstMode = false
	sm.headerList.Init()
	sm.startHeader = nil
}