From 4b565fe58a65f044a32ec23c225d0c4c7bd36467 Mon Sep 17 00:00:00 2001 From: Gui Date: Wed, 19 Jan 2022 19:46:30 +0100 Subject: [PATCH] p2p: always advertise self, to enable mutual address discovery (#7620) Fixes #7593 --- CHANGELOG_PENDING.md | 1 + internal/p2p/peermanager.go | 11 +++++++++++ internal/p2p/peermanager_test.go | 18 ++++++++++++++++++ node/setup.go | 6 ++++++ 4 files changed, 36 insertions(+) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 88a36d2c5..7349128be 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -19,6 +19,7 @@ Special thanks to external contributors on this release: - P2P Protocol - [p2p] [\#7265](https://github.com/tendermint/tendermint/pull/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 397b16941..99ea85692 100644 --- a/internal/p2p/peermanager.go +++ b/internal/p2p/peermanager.go @@ -154,6 +154,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 @@ -814,6 +818,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 69c798d2d..f1dda6543 100644 --- a/internal/p2p/peermanager_test.go +++ b/internal/p2p/peermanager_test.go @@ -1760,6 +1760,24 @@ 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) + defer peerManager.Close() + + // 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 f1ee533ac..e36fe6522 100644 --- a/node/setup.go +++ b/node/setup.go @@ -423,6 +423,11 @@ func createPeerManager( nodeID types.NodeID, ) (*p2p.PeerManager, error) { + selfAddr, err := p2p.ParseNodeAddress(nodeID.AddressString(cfg.P2P.ExternalAddress)) + if err != nil { + return nil, fmt.Errorf("couldn't parse ExternalAddress %q: %w", cfg.P2P.ExternalAddress, err) + } + var maxConns uint16 switch { @@ -452,6 +457,7 @@ func createPeerManager( } options := p2p.PeerManagerOptions{ + SelfAddress: selfAddr, MaxConnected: maxConns, MaxConnectedUpgrade: 4, MaxPeers: 1000,