Skip to content

Commit

Permalink
basichost: ensure no duplicates in Addrs output (#2980)
Browse files Browse the repository at this point in the history
  • Loading branch information
sukunrt committed Oct 4, 2024
1 parent a074da0 commit 38cbcd0
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
6 changes: 5 additions & 1 deletion p2p/host/basic/basic_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,13 +500,17 @@ func (h *BasicHost) makeUpdatedAddrEvent(prev, current []ma.Multiaddr) *event.Ev
return nil
}
prevmap := make(map[string]ma.Multiaddr, len(prev))
currmap := make(map[string]ma.Multiaddr, len(current))
evt := &event.EvtLocalAddressesUpdated{Diffs: true}
addrsAdded := false

for _, addr := range prev {
prevmap[string(addr.Bytes())] = addr
}
for _, addr := range current {
currmap[string(addr.Bytes())] = addr
}
for _, addr := range currmap {
_, ok := prevmap[string(addr.Bytes())]
updated := event.UpdatedAddress{Address: addr}
if ok {
Expand Down Expand Up @@ -831,7 +835,7 @@ func (h *BasicHost) Addrs() []ma.Multiaddr {
// Make a copy. Consumers can modify the slice elements
res := make([]ma.Multiaddr, len(addrs))
copy(res, addrs)
return res
return ma.Unique(res)
}

// NormalizeMultiaddr returns a multiaddr suitable for equality checks.
Expand Down
58 changes: 58 additions & 0 deletions p2p/host/basic/basic_host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"
"time"

"github.com/libp2p/go-libp2p-testing/race"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
Expand Down Expand Up @@ -248,6 +249,63 @@ func TestAllAddrs(t *testing.T) {
require.True(t, ma.Contains(h.AllAddrs(), firstAddr), "should still contain the original addr")
}

func TestAllAddrsUnique(t *testing.T) {
if race.WithRace() {
t.Skip("updates addrChangeTickrInterval which might be racy")
}
oldInterval := addrChangeTickrInterval
addrChangeTickrInterval = 100 * time.Millisecond
defer func() {
addrChangeTickrInterval = oldInterval
}()
sendNewAddrs := make(chan struct{})
opts := HostOpts{
AddrsFactory: func(addrs []ma.Multiaddr) []ma.Multiaddr {
select {
case <-sendNewAddrs:
return []ma.Multiaddr{
ma.StringCast("/ip4/1.2.3.4/tcp/1"),
ma.StringCast("/ip4/1.2.3.4/tcp/1"),
ma.StringCast("/ip4/1.2.3.4/tcp/1"),
ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"),
ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"),
}
default:
return nil
}
},
}
// no listen addrs
h, err := NewHost(swarmt.GenSwarm(t, swarmt.OptDialOnly), &opts)
require.NoError(t, err)
defer h.Close()
h.Start()

sub, err := h.EventBus().Subscribe(&event.EvtLocalAddressesUpdated{})
require.NoError(t, err)
out := make(chan int)
done := make(chan struct{})
go func() {
cnt := 0
for {
select {
case <-sub.Out():
cnt++
case <-done:
out <- cnt
return
}
}
}()
close(sendNewAddrs)
require.Len(t, h.Addrs(), 2)
require.ElementsMatch(t, []ma.Multiaddr{ma.StringCast("/ip4/1.2.3.4/tcp/1"), ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1")}, h.Addrs())
time.Sleep(2*addrChangeTickrInterval + 1*time.Second) // the background loop runs every 5 seconds. Wait for 2x that time.
close(done)
cnt := <-out
require.Equal(t, 1, cnt)
}

// getHostPair gets a new pair of hosts.
// The first host initiates the connection to the second host.
func getHostPair(t *testing.T) (host.Host, host.Host) {
Expand Down

0 comments on commit 38cbcd0

Please sign in to comment.