From ebbc3f02f5e770027b656637f4b1b74cb6ce6149 Mon Sep 17 00:00:00 2001 From: Gui Date: Wed, 19 Jan 2022 22:39:59 +0100 Subject: [PATCH] p2p: always advertise self, to enable mutual address discovery (#7594) Fixes #7593 --- CHANGELOG_PENDING.md | 1 + internal/p2p/peermanager.go | 11 +++++++++++ internal/p2p/peermanager_test.go | 17 +++++++++++++++++ node/setup.go | 6 ++++++ 4 files changed, 35 insertions(+) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 7a9c98700..02eef13f7 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -25,6 +25,7 @@ Special thanks to external contributors on this release: - [p2p] \#7035 Remove legacy P2P routing implementation and associated configuration options. (@tychoish) - [p2p] \#7265 Peer manager reduces peer score for each failed dial attempts for peers that have not successfully dialed. (@tychoish) + - [p2p] [\#7594](https://github.com/tendermint/tendermint/pull/7594) always advertise self, to enable mutual address discovery. (@altergui) - Go API diff --git a/internal/p2p/peermanager.go b/internal/p2p/peermanager.go index f7e4fb730..2edc5b3b6 100644 --- a/internal/p2p/peermanager.go +++ b/internal/p2p/peermanager.go @@ -136,6 +136,10 @@ type PeerManagerOptions struct { // consider private and never gossip. PrivatePeers map[types.NodeID]struct{} + // SelfAddress is the address that will be advertised to peers for them to dial back to us. + // If Hostname and Port are unset, Advertise() will include no self-announcement + SelfAddress NodeAddress + // persistentPeers provides fast PersistentPeers lookups. It is built // by optimize(). persistentPeers map[types.NodeID]bool @@ -791,6 +795,13 @@ func (m *PeerManager) Advertise(peerID types.NodeID, limit uint16) []NodeAddress defer m.mtx.Unlock() addresses := make([]NodeAddress, 0, limit) + + // advertise ourselves, to let everyone know how to dial us back + // and enable mutual address discovery + if m.options.SelfAddress.Hostname != "" && m.options.SelfAddress.Port != 0 { + addresses = append(addresses, m.options.SelfAddress) + } + for _, peer := range m.store.Ranked() { if peer.ID == peerID { continue diff --git a/internal/p2p/peermanager_test.go b/internal/p2p/peermanager_test.go index 2999e8d6d..17d04bac2 100644 --- a/internal/p2p/peermanager_test.go +++ b/internal/p2p/peermanager_test.go @@ -1828,6 +1828,23 @@ func TestPeerManager_Advertise(t *testing.T) { }, peerManager.Advertise(dID, 2)) } +func TestPeerManager_Advertise_Self(t *testing.T) { + dID := types.NodeID(strings.Repeat("d", 40)) + + self := p2p.NodeAddress{Protocol: "tcp", NodeID: selfID, Hostname: "2001:db8::1", Port: 26657} + + // Create a peer manager with SelfAddress defined. + peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{ + SelfAddress: self, + }) + require.NoError(t, err) + + // peer manager should always advertise its SelfAddress. + require.ElementsMatch(t, []p2p.NodeAddress{ + self, + }, peerManager.Advertise(dID, 100)) +} + func TestPeerManager_SetHeight_GetHeight(t *testing.T) { a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))} b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))} diff --git a/node/setup.go b/node/setup.go index 6f3b3245a..68371c45a 100644 --- a/node/setup.go +++ b/node/setup.go @@ -305,6 +305,11 @@ func createPeerManager( nodeID types.NodeID, ) (*p2p.PeerManager, closer, error) { + selfAddr, err := p2p.ParseNodeAddress(nodeID.AddressString(cfg.P2P.ExternalAddress)) + if err != nil { + return nil, func() error { return nil }, fmt.Errorf("couldn't parse ExternalAddress %q: %w", cfg.P2P.ExternalAddress, err) + } + privatePeerIDs := make(map[types.NodeID]struct{}) for _, id := range tmstrings.SplitAndTrimEmpty(cfg.P2P.PrivatePeerIDs, ",", " ") { privatePeerIDs[types.NodeID(id)] = struct{}{} @@ -320,6 +325,7 @@ func createPeerManager( } options := p2p.PeerManagerOptions{ + SelfAddress: selfAddr, MaxConnected: maxConns, MaxConnectedUpgrade: 4, MaxPeers: 1000,