func (sw *Switch) SetNodeKey(nodeKey *NodeKey) {
	sw.nodeKey = nodeKey
}
SetNodeKey sets the switch's private key for authenticated encryption.
NOTE: Not goroutine safe.
package p2p
import (
	"fmt"
	"math"
	"net"
	"sync"
	"time"
	"github.com/tendermint/tendermint/config"
	cmn "github.com/tendermint/tendermint/libs/common"
	"github.com/tendermint/tendermint/p2p/conn"
)
const (
	dialRandomizerIntervalMilliseconds = 3000
	reconnectAttempts = 20
	reconnectInterval = 5 * time.Second
	reconnectBackOffAttempts    = 10
	reconnectBackOffBaseSeconds = 3
	DefaultMinNumOutboundPeers = 10
)
type AddrBook interface {
	AddAddress(addr *NetAddress, src *NetAddress) error
	AddOurAddress(*NetAddress)
	OurAddress(*NetAddress) bool
	MarkGood(*NetAddress)
	RemoveAddress(*NetAddress)
	HasAddress(*NetAddress) bool
	Save()
}
type Switch struct {
	cmn.BaseService
	config       *config.P2PConfig
	listeners    []Listener
	reactors     map[string]Reactor
	chDescs      []*conn.ChannelDescriptor
	reactorsByCh map[byte]Reactor
	peers        *PeerSet
	dialing      *cmn.CMap
	reconnecting *cmn.CMap
	nodeInfo     NodeInfo  
	nodeKey      *NodeKey  
	addrBook     AddrBook
	filterConnByAddr func(net.Addr) error
	filterConnByID   func(ID) error
	mConfig conn.MConnConfig
	rng *cmn.Rand  
	metrics *Metrics
}
type SwitchOption func(*Switch)
func NewSwitch(cfg *config.P2PConfig, options ...SwitchOption) *Switch {
	sw := &Switch{
		config:       cfg,
		reactors:     make(map[string]Reactor),
		chDescs:      make([]*conn.ChannelDescriptor, 0),
		reactorsByCh: make(map[byte]Reactor),
		peers:        NewPeerSet(),
		dialing:      cmn.NewCMap(),
		reconnecting: cmn.NewCMap(),
		metrics:      NopMetrics(),
	}
	sw.rng = cmn.NewRand()
	mConfig := conn.DefaultMConnConfig()
	mConfig.FlushThrottle = time.Duration(cfg.FlushThrottleTimeout) * time.Millisecond
	mConfig.SendRate = cfg.SendRate
	mConfig.RecvRate = cfg.RecvRate
	mConfig.MaxPacketMsgPayloadSize = cfg.MaxPacketMsgPayloadSize
	sw.mConfig = mConfig
	sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw)
	for _, option := range options {
		option(sw)
	}
	return sw
}
func WithMetrics(metrics *Metrics) SwitchOption {
	return func(sw *Switch) { sw.metrics = metrics }
}
func (sw *Switch) AddReactor(name string, reactor Reactor) Reactor {
	reactorChannels := reactor.GetChannels()
	for _, chDesc := range reactorChannels {
		chID := chDesc.ID
		if sw.reactorsByCh[chID] != nil {
			cmn.PanicSanity(fmt.Sprintf("Channel %X has multiple reactors %v & %v", chID, sw.reactorsByCh[chID], reactor))
		}
		sw.chDescs = append(sw.chDescs, chDesc)
		sw.reactorsByCh[chID] = reactor
	}
	sw.reactors[name] = reactor
	reactor.SetSwitch(sw)
	return reactor
}
func (sw *Switch) Reactors() map[string]Reactor {
	return sw.reactors
}
func (sw *Switch) Reactor(name string) Reactor {
	return sw.reactors[name]
}
func (sw *Switch) AddListener(l Listener) {
	sw.listeners = append(sw.listeners, l)
}
func (sw *Switch) Listeners() []Listener {
	return sw.listeners
}
func (sw *Switch) IsListening() bool {
	return len(sw.listeners) > 0
}
func (sw *Switch) SetNodeInfo(nodeInfo NodeInfo) {
	sw.nodeInfo = nodeInfo
}
func (sw *Switch) NodeInfo() NodeInfo {
	return sw.nodeInfo
}