mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-29 12:41:44 +00:00
p2p: Integrate new Transport
We are swapping the exisiting listener implementation with the newly introduced Transport and its default implementation MultiplexTransport, removing a large chunk of old connection setup and handling scattered over the Peer and Switch code. The Switch requires a Transport now and handles externally passed Peer filters.
This commit is contained in:
282
node/node.go
282
node/node.go
@ -126,9 +126,12 @@ type Node struct {
|
||||
privValidator types.PrivValidator // local node's validator key
|
||||
|
||||
// network
|
||||
sw *p2p.Switch // p2p connections
|
||||
addrBook pex.AddrBook // known peers
|
||||
nodeKey *p2p.NodeKey // our node privkey
|
||||
transport *p2p.MultiplexTransport
|
||||
sw *p2p.Switch // p2p connections
|
||||
addrBook pex.AddrBook // known peers
|
||||
nodeInfo p2p.NodeInfo
|
||||
nodeKey *p2p.NodeKey // our node privkey
|
||||
isListening bool
|
||||
|
||||
// services
|
||||
eventBus *types.EventBus // pub/sub for services
|
||||
@ -301,70 +304,6 @@ func NewNode(config *cfg.Config,
|
||||
consensusReactor := cs.NewConsensusReactor(consensusState, fastSync)
|
||||
consensusReactor.SetLogger(consensusLogger)
|
||||
|
||||
p2pLogger := logger.With("module", "p2p")
|
||||
|
||||
sw := p2p.NewSwitch(config.P2P, p2p.WithMetrics(p2pMetrics))
|
||||
sw.SetLogger(p2pLogger)
|
||||
sw.AddReactor("MEMPOOL", mempoolReactor)
|
||||
sw.AddReactor("BLOCKCHAIN", bcReactor)
|
||||
sw.AddReactor("CONSENSUS", consensusReactor)
|
||||
sw.AddReactor("EVIDENCE", evidenceReactor)
|
||||
p2pLogger.Info("P2P Node ID", "ID", nodeKey.ID(), "file", config.NodeKeyFile())
|
||||
|
||||
// Optionally, start the pex reactor
|
||||
//
|
||||
// TODO:
|
||||
//
|
||||
// We need to set Seeds and PersistentPeers on the switch,
|
||||
// since it needs to be able to use these (and their DNS names)
|
||||
// even if the PEX is off. We can include the DNS name in the NetAddress,
|
||||
// but it would still be nice to have a clear list of the current "PersistentPeers"
|
||||
// somewhere that we can return with net_info.
|
||||
//
|
||||
// If PEX is on, it should handle dialing the seeds. Otherwise the switch does it.
|
||||
// Note we currently use the addrBook regardless at least for AddOurAddress
|
||||
addrBook := pex.NewAddrBook(config.P2P.AddrBookFile(), config.P2P.AddrBookStrict)
|
||||
addrBook.SetLogger(p2pLogger.With("book", config.P2P.AddrBookFile()))
|
||||
if config.P2P.PexReactor {
|
||||
// TODO persistent peers ? so we can have their DNS addrs saved
|
||||
pexReactor := pex.NewPEXReactor(addrBook,
|
||||
&pex.PEXReactorConfig{
|
||||
Seeds: splitAndTrimEmpty(config.P2P.Seeds, ",", " "),
|
||||
SeedMode: config.P2P.SeedMode,
|
||||
})
|
||||
pexReactor.SetLogger(p2pLogger)
|
||||
sw.AddReactor("PEX", pexReactor)
|
||||
}
|
||||
|
||||
sw.SetAddrBook(addrBook)
|
||||
|
||||
// Filter peers by addr or pubkey with an ABCI query.
|
||||
// If the query return code is OK, add peer.
|
||||
// XXX: Query format subject to change
|
||||
if config.FilterPeers {
|
||||
// NOTE: addr is ip:port
|
||||
sw.SetAddrFilter(func(addr net.Addr) error {
|
||||
resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: fmt.Sprintf("/p2p/filter/addr/%s", addr.String())})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resQuery.IsErr() {
|
||||
return fmt.Errorf("Error querying abci app: %v", resQuery)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
sw.SetIDFilter(func(id p2p.ID) error {
|
||||
resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: fmt.Sprintf("/p2p/filter/id/%s", id)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resQuery.IsErr() {
|
||||
return fmt.Errorf("Error querying abci app: %v", resQuery)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
eventBus := types.NewEventBus()
|
||||
eventBus.SetLogger(logger.With("module", "events"))
|
||||
|
||||
@ -394,6 +333,113 @@ func NewNode(config *cfg.Config,
|
||||
indexerService := txindex.NewIndexerService(txIndexer, eventBus)
|
||||
indexerService.SetLogger(logger.With("module", "txindex"))
|
||||
|
||||
var (
|
||||
p2pLogger = logger.With("module", "p2p")
|
||||
nodeInfo = makeNodeInfo(config, nodeKey.ID(), txIndexer, genDoc.ChainID)
|
||||
)
|
||||
|
||||
// Setup Transport.
|
||||
var (
|
||||
transport = p2p.NewMultiplexTransport(nodeInfo, *nodeKey)
|
||||
connFilters = []p2p.ConnFilterFunc{}
|
||||
peerFilters = []p2p.PeerFilterFunc{}
|
||||
)
|
||||
|
||||
if !config.P2P.AllowDuplicateIP {
|
||||
connFilters = append(connFilters, p2p.ConnDuplicateIPFilter())
|
||||
}
|
||||
|
||||
// Filter peers by addr or pubkey with an ABCI query.
|
||||
// If the query return code is OK, add peer.
|
||||
// XXX: Query format subject to change
|
||||
if config.FilterPeers {
|
||||
connFilters = append(
|
||||
connFilters,
|
||||
// ABCI query for address filtering.
|
||||
func(_ p2p.ConnSet, c net.Conn, _ []net.IP) error {
|
||||
res, err := proxyApp.Query().QuerySync(abci.RequestQuery{
|
||||
Path: fmt.Sprintf("/p2p/filter/addr/%s", c.RemoteAddr().String()),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.IsErr() {
|
||||
return fmt.Errorf("Error querying abci app: %v", res)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
peerFilters = append(
|
||||
peerFilters,
|
||||
// ABCI query for ID filtering.
|
||||
func(_ p2p.IPeerSet, p p2p.Peer) error {
|
||||
res, err := proxyApp.Query().QuerySync(abci.RequestQuery{
|
||||
Path: fmt.Sprintf("/p2p/filter/id/%s", p.ID()),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.IsErr() {
|
||||
return fmt.Errorf("Error querying abci app: %v", res)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
p2p.MultiplexTransportConnFilters(connFilters...)(transport)
|
||||
|
||||
// Setup Switch.
|
||||
sw := p2p.NewSwitch(
|
||||
config.P2P,
|
||||
transport,
|
||||
p2p.WithMetrics(p2pMetrics),
|
||||
p2p.SwitchPeerFilters(peerFilters...),
|
||||
)
|
||||
sw.SetLogger(p2pLogger)
|
||||
sw.AddReactor("MEMPOOL", mempoolReactor)
|
||||
sw.AddReactor("BLOCKCHAIN", bcReactor)
|
||||
sw.AddReactor("CONSENSUS", consensusReactor)
|
||||
sw.AddReactor("EVIDENCE", evidenceReactor)
|
||||
sw.SetNodeInfo(nodeInfo)
|
||||
sw.SetNodeKey(nodeKey)
|
||||
|
||||
p2pLogger.Info("P2P Node ID", "ID", nodeKey.ID(), "file", config.NodeKeyFile())
|
||||
|
||||
// Optionally, start the pex reactor
|
||||
//
|
||||
// TODO:
|
||||
//
|
||||
// We need to set Seeds and PersistentPeers on the switch,
|
||||
// since it needs to be able to use these (and their DNS names)
|
||||
// even if the PEX is off. We can include the DNS name in the NetAddress,
|
||||
// but it would still be nice to have a clear list of the current "PersistentPeers"
|
||||
// somewhere that we can return with net_info.
|
||||
//
|
||||
// If PEX is on, it should handle dialing the seeds. Otherwise the switch does it.
|
||||
// Note we currently use the addrBook regardless at least for AddOurAddress
|
||||
addrBook := pex.NewAddrBook(config.P2P.AddrBookFile(), config.P2P.AddrBookStrict)
|
||||
|
||||
// Add ourselves to addrbook to prevent dialing ourselves
|
||||
addrBook.AddOurAddress(nodeInfo.NetAddress())
|
||||
|
||||
addrBook.SetLogger(p2pLogger.With("book", config.P2P.AddrBookFile()))
|
||||
if config.P2P.PexReactor {
|
||||
// TODO persistent peers ? so we can have their DNS addrs saved
|
||||
pexReactor := pex.NewPEXReactor(addrBook,
|
||||
&pex.PEXReactorConfig{
|
||||
Seeds: splitAndTrimEmpty(config.P2P.Seeds, ",", " "),
|
||||
SeedMode: config.P2P.SeedMode,
|
||||
})
|
||||
pexReactor.SetLogger(p2pLogger)
|
||||
sw.AddReactor("PEX", pexReactor)
|
||||
}
|
||||
|
||||
sw.SetAddrBook(addrBook)
|
||||
|
||||
// run the profile server
|
||||
profileHost := config.ProfListenAddress
|
||||
if profileHost != "" {
|
||||
@ -407,9 +453,11 @@ func NewNode(config *cfg.Config,
|
||||
genesisDoc: genDoc,
|
||||
privValidator: privValidator,
|
||||
|
||||
sw: sw,
|
||||
addrBook: addrBook,
|
||||
nodeKey: nodeKey,
|
||||
transport: transport,
|
||||
sw: sw,
|
||||
addrBook: addrBook,
|
||||
nodeInfo: nodeInfo,
|
||||
nodeKey: nodeKey,
|
||||
|
||||
stateDB: stateDB,
|
||||
blockStore: blockStore,
|
||||
@ -441,21 +489,6 @@ func (n *Node) OnStart() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create & add listener
|
||||
l := p2p.NewDefaultListener(
|
||||
n.config.P2P.ListenAddress,
|
||||
n.config.P2P.ExternalAddress,
|
||||
n.config.P2P.UPNP,
|
||||
n.Logger.With("module", "p2p"))
|
||||
n.sw.AddListener(l)
|
||||
|
||||
nodeInfo := n.makeNodeInfo(n.nodeKey.ID())
|
||||
n.sw.SetNodeInfo(nodeInfo)
|
||||
n.sw.SetNodeKey(n.nodeKey)
|
||||
|
||||
// Add ourselves to addrbook to prevent dialing ourselves
|
||||
n.addrBook.AddOurAddress(nodeInfo.NetAddress())
|
||||
|
||||
// Add private IDs to addrbook to block those peers being added
|
||||
n.addrBook.AddPrivateIDs(splitAndTrimEmpty(n.config.P2P.PrivatePeerIDs, ",", " "))
|
||||
|
||||
@ -474,6 +507,17 @@ func (n *Node) OnStart() error {
|
||||
n.prometheusSrv = n.startPrometheusServer(n.config.Instrumentation.PrometheusListenAddr)
|
||||
}
|
||||
|
||||
// Start the transport.
|
||||
addr, err := p2p.NewNetAddressStringWithOptionalID(n.config.P2P.ListenAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := n.transport.Listen(*addr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.isListening = true
|
||||
|
||||
// Start the switch (the P2P server).
|
||||
err = n.sw.Start()
|
||||
if err != nil {
|
||||
@ -506,6 +550,12 @@ func (n *Node) OnStop() {
|
||||
// TODO: gracefully disconnect from peers.
|
||||
n.sw.Stop()
|
||||
|
||||
if err := n.transport.Close(); err != nil {
|
||||
n.Logger.Error("Error closing transport", "err", err)
|
||||
}
|
||||
|
||||
n.isListening = false
|
||||
|
||||
// finally stop the listeners / external services
|
||||
for _, l := range n.rpcListeners {
|
||||
n.Logger.Info("Closing rpc listener", "listener", l)
|
||||
@ -536,13 +586,6 @@ func (n *Node) RunForever() {
|
||||
})
|
||||
}
|
||||
|
||||
// AddListener adds a listener to accept inbound peer connections.
|
||||
// It should be called before starting the Node.
|
||||
// The first listener is the primary listener (in NodeInfo)
|
||||
func (n *Node) AddListener(l p2p.Listener) {
|
||||
n.sw.AddListener(l)
|
||||
}
|
||||
|
||||
// ConfigureRPC sets all variables in rpccore so they will serve
|
||||
// rpc calls from this node
|
||||
func (n *Node) ConfigureRPC() {
|
||||
@ -551,7 +594,8 @@ func (n *Node) ConfigureRPC() {
|
||||
rpccore.SetConsensusState(n.consensusState)
|
||||
rpccore.SetMempool(n.mempoolReactor.Mempool)
|
||||
rpccore.SetEvidencePool(n.evidencePool)
|
||||
rpccore.SetSwitch(n.sw)
|
||||
rpccore.SetP2PPeers(n.sw)
|
||||
rpccore.SetP2PTransport(n)
|
||||
rpccore.SetPubKey(n.privValidator.GetPubKey())
|
||||
rpccore.SetGenesisDoc(n.genesisDoc)
|
||||
rpccore.SetAddrBook(n.addrBook)
|
||||
@ -683,14 +727,36 @@ func (n *Node) ProxyApp() proxy.AppConns {
|
||||
return n.proxyApp
|
||||
}
|
||||
|
||||
func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (n *Node) Listeners() []string {
|
||||
return []string{
|
||||
fmt.Sprintf("Listener(@%v)", n.config.P2P.ExternalAddress),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) IsListening() bool {
|
||||
return n.isListening
|
||||
}
|
||||
|
||||
// NodeInfo returns the Node's Info from the Switch.
|
||||
func (n *Node) NodeInfo() p2p.NodeInfo {
|
||||
return n.nodeInfo
|
||||
}
|
||||
|
||||
func makeNodeInfo(
|
||||
config *cfg.Config,
|
||||
nodeID p2p.ID,
|
||||
txIndexer txindex.TxIndexer,
|
||||
chainID string,
|
||||
) p2p.NodeInfo {
|
||||
txIndexerStatus := "on"
|
||||
if _, ok := n.txIndexer.(*null.TxIndex); ok {
|
||||
if _, ok := txIndexer.(*null.TxIndex); ok {
|
||||
txIndexerStatus = "off"
|
||||
}
|
||||
nodeInfo := p2p.NodeInfo{
|
||||
ID: nodeID,
|
||||
Network: n.genesisDoc.ChainID,
|
||||
Network: chainID,
|
||||
Version: version.Version,
|
||||
Channels: []byte{
|
||||
bc.BlockchainChannel,
|
||||
@ -698,7 +764,7 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo {
|
||||
mempl.MempoolChannel,
|
||||
evidence.EvidenceChannel,
|
||||
},
|
||||
Moniker: n.config.Moniker,
|
||||
Moniker: config.Moniker,
|
||||
Other: p2p.NodeInfoOther{
|
||||
AminoVersion: amino.Version,
|
||||
P2PVersion: p2p.Version,
|
||||
@ -708,34 +774,26 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo {
|
||||
},
|
||||
}
|
||||
|
||||
if n.config.P2P.PexReactor {
|
||||
if config.P2P.PexReactor {
|
||||
nodeInfo.Channels = append(nodeInfo.Channels, pex.PexChannel)
|
||||
}
|
||||
|
||||
rpcListenAddr := n.config.RPC.ListenAddress
|
||||
rpcListenAddr := config.RPC.ListenAddress
|
||||
nodeInfo.Other.RPCAddress = rpcListenAddr
|
||||
|
||||
if !n.sw.IsListening() {
|
||||
return nodeInfo
|
||||
lAddr := config.P2P.ExternalAddress
|
||||
|
||||
if lAddr == "" {
|
||||
lAddr = config.P2P.ListenAddress
|
||||
}
|
||||
|
||||
p2pListener := n.sw.Listeners()[0]
|
||||
p2pHost := p2pListener.ExternalAddressHost()
|
||||
p2pPort := p2pListener.ExternalAddress().Port
|
||||
nodeInfo.ListenAddr = fmt.Sprintf("%v:%v", p2pHost, p2pPort)
|
||||
nodeInfo.ListenAddr = lAddr
|
||||
|
||||
return nodeInfo
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// NodeInfo returns the Node's Info from the Switch.
|
||||
func (n *Node) NodeInfo() p2p.NodeInfo {
|
||||
return n.sw.NodeInfo()
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var (
|
||||
genesisDocKey = []byte("genesisDoc")
|
||||
)
|
||||
|
Reference in New Issue
Block a user