func (sp *serverPeer) OnInv(_ *peer.Peer, msg *wire.MsgInv) {
	if !cfg.BlocksOnly {
		if len(msg.InvList) > 0 {
			sp.server.syncManager.QueueInv(msg, sp.Peer)
		}
		return
	}
	newInv := wire.NewMsgInvSizeHint(uint(len(msg.InvList)))
	for _, invVect := range msg.InvList {
		if invVect.Type == wire.InvTypeTx {
			peerLog.Tracef("Ignoring tx %v in inv from %v -- "+
				"blocksonly enabled", invVect.Hash, sp)
			if sp.ProtocolVersion() >= wire.BIP0037Version {
				peerLog.Infof("Peer %v is announcing "+
					"transactions -- disconnecting", sp)
				sp.Disconnect()
				return
			}
			continue
		}
		err := newInv.AddInvVect(invVect)
		if err != nil {
			peerLog.Errorf("Failed to add inventory vector: %v", err)
			break
		}
	}
	if len(newInv.InvList) > 0 {
		sp.server.syncManager.QueueInv(newInv, sp.Peer)
	}
}
OnInv is invoked when a peer receives an inv soter message and is
used to examine the inventory being advertised by the remote peer and react
accordingly.  We pass the message down to blockmanager which will call
QueueMessage with any appropriate responses.
package main
import (
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/soteria-dag/soterd/mining/cuckoo"
	"math"
	"net"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"github.com/soteria-dag/soterd/addrmgr"
	"github.com/soteria-dag/soterd/blockdag"
	"github.com/soteria-dag/soterd/blockdag/indexers"
	"github.com/soteria-dag/soterd/chaincfg"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/connmgr"
	"github.com/soteria-dag/soterd/database"
	"github.com/soteria-dag/soterd/mempool"
	"github.com/soteria-dag/soterd/metrics"
	"github.com/soteria-dag/soterd/mining/cpuminer"
	"github.com/soteria-dag/soterd/miningdag"
	"github.com/soteria-dag/soterd/netsync"
	"github.com/soteria-dag/soterd/peer"
	"github.com/soteria-dag/soterd/soterutil"
	"github.com/soteria-dag/soterd/soterutil/bloom"
	"github.com/soteria-dag/soterd/txscript"
	"github.com/soteria-dag/soterd/wire"
)
const (
	defaultServices = wire.SFNodeNetwork | wire.SFNodeBloom |
		wire.SFNodeWitness | wire.SFNodeCF
	defaultRequiredServices = wire.SFNodeNetwork
	defaultTargetOutbound = 8
	connectionRetryInterval = time.Second * 5
)
var (
	userAgentName = "soterd"
	userAgentVersion = version
)
var zeroHash chainhash.Hash
type onionAddr struct {
	addr string
}
func (oa *onionAddr) String() string {
	return oa.addr
}
func (oa *onionAddr) Network() string {
	return "onion"
}
var _ net.Addr = (*onionAddr)(nil)
type simpleAddr struct {
	net, addr string
}
func (a simpleAddr) String() string {
	return a.addr
}
func (a simpleAddr) Network() string {
	return a.net
}
var _ net.Addr = simpleAddr{}
type broadcastMsg struct {
	message      wire.Message
	excludePeers []*serverPeer
}
type broadcastInventoryAdd relayMsg
type broadcastInventoryDel *wire.InvVect
type relayMsg struct {
	invVect *wire.InvVect
	data    interface{}
}
type updatePeerHeightsMsg struct {
	newHash    *chainhash.Hash
	newHeight  int32
	originPeer *peer.Peer
}
type peerState struct {
	inboundPeers    map[int32]*serverPeer
	outboundPeers   map[int32]*serverPeer
	persistentPeers map[int32]*serverPeer
	banned          map[string]time.Time
	outboundGroups  map[string]int
}
func (ps *peerState) Count() int {
	return len(ps.inboundPeers) + len(ps.outboundPeers) +
		len(ps.persistentPeers)
}
func (ps *peerState) forAllOutboundPeers(closure func(sp *serverPeer)) {
	for _, e := range ps.outboundPeers {
		closure(e)
	}
	for _, e := range ps.persistentPeers {
		closure(e)
	}
}
func (ps *peerState) forAllPeers(closure func(sp *serverPeer)) {
	for _, e := range ps.inboundPeers {
		closure(e)
	}
	ps.forAllOutboundPeers(closure)
}
type cfHeaderKV struct {
	blockHash    chainhash.Hash
	filterHeader chainhash.Hash
}
type server struct {
	bytesReceived uint64  
	bytesSent     uint64  
	started       int32
	shutdown      int32
	shutdownSched int32
	startupTime   int64
	chainParams          *chaincfg.Params
	addrManager          *addrmgr.AddrManager
	connManager          *connmgr.ConnManager
	sigCache             *txscript.SigCache
	hashCache            *txscript.HashCache
	rpcServer            *rpcServer
	metricsManager       *metrics.MetricsManager
	syncManager          *netsync.SyncManager
	chain                *blockdag.BlockDAG
	txMemPool            *mempool.TxPool
	cpuMiner             *cpuminer.CPUMiner
	modifyRebroadcastInv chan interface{}
	newPeers             chan *serverPeer
	donePeers            chan *serverPeer
	banPeers             chan *serverPeer
	query                chan interface{}
	relayInv             chan relayMsg
	broadcast            chan broadcastMsg
	peerHeightsUpdate    chan updatePeerHeightsMsg
	wg                   sync.WaitGroup
	quit                 chan struct{}
	nat                  NAT
	db                   database.DB
	timeSource           blockdag.MedianTimeSource
	services             wire.ServiceFlag
	txIndex   *dagindexers.TxIndex
	addrIndex *dagindexers.AddrIndex
	cfIndex   *dagindexers.CfIndex
	feeEstimator *mempool.FeeEstimator
	cfCheckptCaches    map[wire.FilterType][]cfHeaderKV
	cfCheckptCachesMtx sync.RWMutex
}
type serverPeer struct {
	feeFilter int64
	*peer.Peer
	connReq        *connmgr.ConnReq
	server         *server
	persistent     bool
	continueHash   *chainhash.Hash
	relayMtx       sync.Mutex
	disableRelayTx bool
	sentAddrs      bool
	isWhitelisted  bool
	filter         *bloom.Filter
	knownAddresses map[string]struct{}
	addressMtx     sync.RWMutex
	banScore       connmgr.DynamicBanScore
	quit           chan struct{}
	txProcessed    chan struct{}
	blockProcessed chan struct{}
}
func newServerPeer(s *server, isPersistent bool) *serverPeer {
	return &serverPeer{
		server:         s,
		persistent:     isPersistent,
		filter:         bloom.LoadFilter(nil),
		knownAddresses: make(map[string]struct{}),
		quit:           make(chan struct{}),
		txProcessed:    make(chan struct{}, 1),
		blockProcessed: make(chan struct{}, 1),
	}
}
func (sp *serverPeer) newestBlock() (*chainhash.Hash, int32, error) {
	best := sp.server.chain.BestSnapshot()
	dagState := sp.server.chain.DAGSnapshot()
	return &best.Hash, dagState.MaxHeight, nil
}
func (sp *serverPeer) addKnownAddresses(addresses []*wire.NetAddress) {
	sp.addressMtx.Lock()
	defer sp.addressMtx.Unlock()
	for _, na := range addresses {
		sp.knownAddresses[addrmgr.NetAddressKey(na)] = struct{}{}
	}
}
func (sp *serverPeer) addressKnown(na *wire.NetAddress) bool {
	sp.addressMtx.RLock()
	defer sp.addressMtx.RUnlock()
	_, exists := sp.knownAddresses[addrmgr.NetAddressKey(na)]
	return exists
}
func (sp *serverPeer) setDisableRelayTx(disable bool) {
	sp.relayMtx.Lock()
	sp.disableRelayTx = disable
	sp.relayMtx.Unlock()
}
func (sp *serverPeer) relayTxDisabled() bool {
	sp.relayMtx.Lock()
	isDisabled := sp.disableRelayTx
	sp.relayMtx.Unlock()
	return isDisabled
}
func (sp *serverPeer) pushAddrMsg(addresses []*wire.NetAddress) {
	addrs := make([]*wire.NetAddress, 0, len(addresses))
	for _, addr := range addresses {
		if !sp.addressKnown(addr) {
			addrs = append(addrs, addr)
		}
	}
	known, err := sp.PushAddrMsg(addrs)
	if err != nil {
		peerLog.Errorf("Can't push address message to %s: %v", sp.Peer, err)
		sp.Disconnect()
		return
	}
	sp.addKnownAddresses(known)
}
func (sp *serverPeer) addBanScore(persistent, transient uint32, reason string) {
	if cfg.DisableBanning {
		return
	}
	if sp.isWhitelisted {
		peerLog.Debugf("Misbehaving whitelisted peer %s: %s", sp, reason)
		return
	}
	warnThreshold := cfg.BanThreshold >> 1
	if transient == 0 && persistent == 0 {
		score := sp.banScore.Int()
		if score > warnThreshold {
			peerLog.Warnf("Misbehaving peer %s: %s -- ban score is %d, "+
				"it was not increased this time", sp, reason, score)
		}
		return
	}
	score := sp.banScore.Increase(persistent, transient)
	if score > warnThreshold {
		peerLog.Warnf("Misbehaving peer %s: %s -- ban score increased to %d",
			sp, reason, score)
		if score > cfg.BanThreshold {
			peerLog.Warnf("Misbehaving peer %s -- banning and disconnecting",
				sp)
			sp.server.BanPeer(sp)
			sp.Disconnect()
		}
	}
}
func (sp *serverPeer) KnownAddresses() []string {
	sp.addressMtx.RLock()
	defer sp.addressMtx.RUnlock()
	addrs := make([]string, 0)
	for a := range sp.knownAddresses {
		addrs = append(addrs, a)
	}
	return addrs
}
func (sp *serverPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) *wire.MsgReject {
	if msg.ProtocolVersion < int32(peer.MinAcceptableProtocolVersion) {
		return nil
	}
	sp.server.timeSource.AddTimeSample(sp.Addr(), msg.Timestamp)
	sp.server.syncManager.NewPeer(sp.Peer)
	sp.setDisableRelayTx(msg.DisableRelayTx)
	if !cfg.SimNet {
		addrManager := sp.server.addrManager
		if !sp.Inbound() {
			chain := sp.server.chain
			segwitActive, err := chain.IsDeploymentActive(chaincfg.DeploymentSegwit)
			if err != nil {
				peerLog.Errorf("Unable to query for segwit "+
					"soft-fork state: %v", err)
				return nil
			}
			if segwitActive && !sp.IsWitnessEnabled() {
				peerLog.Infof("Disconnecting non-segwit "+
					"peer %v, isn't segwit enabled and "+
					"we need more segwit enabled peers", sp)
				sp.Disconnect()
				return nil
			}
			if !cfg.DisableListen   {
				lna := addrManager.GetBestLocalAddress(sp.NA())
				if addrmgr.IsRoutable(lna) {
					addresses := []*wire.NetAddress{lna}
					sp.pushAddrMsg(addresses)
				}
			}
			hasTimestamp := sp.ProtocolVersion() >=
				wire.NetAddressTimeVersion
			if addrManager.NeedMoreAddresses() && hasTimestamp {
				sp.QueueMessage(wire.NewMsgGetAddr(), nil)
			}
			addrManager.Good(sp.NA())
		}
	}
	sp.server.AddPeer(sp)
	return nil
}
func (sp *serverPeer) OnMemPool(_ *peer.Peer, msg *wire.MsgMemPool) {
	if sp.server.services&wire.SFNodeBloom != wire.SFNodeBloom {
		peerLog.Debugf("peer %v sent mempool request with bloom "+
			"filtering disabled -- disconnecting", sp)
		sp.Disconnect()
		return
	}
	sp.addBanScore(0, 33, "mempool")
	txMemPool := sp.server.txMemPool
	txDescs := txMemPool.TxDescs()
	invMsg := wire.NewMsgInvSizeHint(uint(len(txDescs)))
	for _, txDesc := range txDescs {
		if !sp.filter.IsLoaded() || sp.filter.MatchTxAndUpdate(txDesc.Tx) {
			iv := wire.NewInvVect(wire.InvTypeTx, txDesc.Tx.Hash(), -1)
			invMsg.AddInvVect(iv)
			if len(invMsg.InvList)+1 > wire.MaxInvPerMsg {
				break
			}
		}
	}
	if len(invMsg.InvList) > 0 {
		sp.QueueMessage(invMsg, nil)
	}
}
func (sp *serverPeer) OnTx(_ *peer.Peer, msg *wire.MsgTx) {
	if cfg.BlocksOnly {
		peerLog.Tracef("Ignoring tx %v from %v - blocksonly enabled",
			msg.TxHash(), sp)
		return
	}
	tx := soterutil.NewTx(msg)
	iv := wire.NewInvVect(wire.InvTypeTx, tx.Hash(), -1)
	sp.AddKnownInventory(iv)
	sp.server.syncManager.QueueTx(tx, sp.Peer, sp.txProcessed)
	<-sp.txProcessed
}
func (sp *serverPeer) OnBlock(_ *peer.Peer, msg *wire.MsgBlock, buf []byte) {
	block := soterutil.NewBlockFromBlockAndBytes(msg, buf)
	iv := wire.NewInvVect(wire.InvTypeBlock, block.Hash(), block.Height())
	sp.AddKnownInventory(iv)
	sp.server.syncManager.QueueBlock(block, sp.Peer, sp.blockProcessed)
	<-sp.blockProcessed
}