Skip to content

Commit 6dffa1a

Browse files
MarcoPoloarajasek
andauthored
Release v0.27.5 (#2324)
* swarm: Dedup addresses to dial (#2322) * Dedup addresses to dial Co-authored-by: Aayush Rajasekaran <[email protected]> * Move DedupAddrs test * Typo --------- Co-authored-by: Aayush Rajasekaran <[email protected]> * Release version v0.27.5 --------- Co-authored-by: Aayush Rajasekaran <[email protected]>
1 parent fc89448 commit 6dffa1a

File tree

8 files changed

+119
-53
lines changed

8 files changed

+119
-53
lines changed

core/network/network.go

+22
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
package network
77

88
import (
9+
"bytes"
910
"context"
1011
"io"
12+
"sort"
1113
"time"
1214

1315
"github.com/libp2p/go-libp2p/core/peer"
@@ -184,3 +186,23 @@ type Dialer interface {
184186
Notify(Notifiee)
185187
StopNotify(Notifiee)
186188
}
189+
190+
// DedupAddrs deduplicates addresses in place, leave only unique addresses.
191+
// It doesn't allocate.
192+
func DedupAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
193+
if len(addrs) == 0 {
194+
return addrs
195+
}
196+
sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i].Bytes(), addrs[j].Bytes()) < 0 })
197+
idx := 1
198+
for i := 1; i < len(addrs); i++ {
199+
if !addrs[i-1].Equal(addrs[i]) {
200+
addrs[idx] = addrs[i]
201+
idx++
202+
}
203+
}
204+
for i := idx; i < len(addrs); i++ {
205+
addrs[i] = nil
206+
}
207+
return addrs[:idx]
208+
}

core/network/network_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package network
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
ma "github.com/multiformats/go-multiaddr"
8+
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestDedupAddrs(t *testing.T) {
13+
tcpAddr := ma.StringCast("/ip4/127.0.0.1/tcp/1234")
14+
quicAddr := ma.StringCast("/ip4/127.0.0.1/udp/1234/quic-v1")
15+
wsAddr := ma.StringCast("/ip4/127.0.0.1/tcp/1234/ws")
16+
17+
type testcase struct {
18+
in, out []ma.Multiaddr
19+
}
20+
21+
for i, tc := range []testcase{
22+
{in: nil, out: nil},
23+
{in: []ma.Multiaddr{tcpAddr}, out: []ma.Multiaddr{tcpAddr}},
24+
{in: []ma.Multiaddr{tcpAddr, tcpAddr, tcpAddr}, out: []ma.Multiaddr{tcpAddr}},
25+
{in: []ma.Multiaddr{tcpAddr, quicAddr, tcpAddr}, out: []ma.Multiaddr{tcpAddr, quicAddr}},
26+
{in: []ma.Multiaddr{tcpAddr, quicAddr, wsAddr}, out: []ma.Multiaddr{tcpAddr, quicAddr, wsAddr}},
27+
} {
28+
tc := tc
29+
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
30+
deduped := DedupAddrs(tc.in)
31+
for _, a := range tc.out {
32+
require.Contains(t, deduped, a)
33+
}
34+
})
35+
}
36+
}

p2p/host/basic/basic_host.go

+2-24
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package basichost
22

33
import (
4-
"bytes"
54
"context"
65
"errors"
76
"fmt"
87
"io"
98
"net"
10-
"sort"
119
"sync"
1210
"time"
1311

@@ -816,26 +814,6 @@ func (h *BasicHost) NormalizeMultiaddr(addr ma.Multiaddr) ma.Multiaddr {
816814
return addr
817815
}
818816

819-
// dedupAddrs deduplicates addresses in place, leave only unique addresses.
820-
// It doesn't allocate.
821-
func dedupAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
822-
if len(addrs) == 0 {
823-
return addrs
824-
}
825-
sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i].Bytes(), addrs[j].Bytes()) < 0 })
826-
idx := 1
827-
for i := 1; i < len(addrs); i++ {
828-
if !addrs[i-1].Equal(addrs[i]) {
829-
addrs[idx] = addrs[i]
830-
idx++
831-
}
832-
}
833-
for i := idx; i < len(addrs); i++ {
834-
addrs[i] = nil
835-
}
836-
return addrs[:idx]
837-
}
838-
839817
// AllAddrs returns all the addresses of BasicHost at this moment in time.
840818
// It's ok to not include addresses if they're not available to be used now.
841819
func (h *BasicHost) AllAddrs() []ma.Multiaddr {
@@ -860,7 +838,7 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
860838
finalAddrs = append(finalAddrs, resolved...)
861839
}
862840

863-
finalAddrs = dedupAddrs(finalAddrs)
841+
finalAddrs = network.DedupAddrs(finalAddrs)
864842

865843
var natMappings []inat.Mapping
866844

@@ -1010,7 +988,7 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
1010988
}
1011989
finalAddrs = append(finalAddrs, observedAddrs...)
1012990
}
1013-
finalAddrs = dedupAddrs(finalAddrs)
991+
finalAddrs = network.DedupAddrs(finalAddrs)
1014992
finalAddrs = inferWebtransportAddrsFromQuic(finalAddrs)
1015993

1016994
return finalAddrs

p2p/host/basic/basic_host_test.go

-26
Original file line numberDiff line numberDiff line change
@@ -825,32 +825,6 @@ func TestNormalizeMultiaddr(t *testing.T) {
825825
require.Equal(t, "/ip4/1.2.3.4/udp/9999/quic-v1/webtransport", h1.NormalizeMultiaddr(ma.StringCast("/ip4/1.2.3.4/udp/9999/quic-v1/webtransport/certhash/uEgNmb28")).String())
826826
}
827827

828-
func TestDedupAddrs(t *testing.T) {
829-
tcpAddr := ma.StringCast("/ip4/127.0.0.1/tcp/1234")
830-
quicAddr := ma.StringCast("/ip4/127.0.0.1/udp/1234/quic-v1")
831-
wsAddr := ma.StringCast("/ip4/127.0.0.1/tcp/1234/ws")
832-
833-
type testcase struct {
834-
in, out []ma.Multiaddr
835-
}
836-
837-
for i, tc := range []testcase{
838-
{in: nil, out: nil},
839-
{in: []ma.Multiaddr{tcpAddr}, out: []ma.Multiaddr{tcpAddr}},
840-
{in: []ma.Multiaddr{tcpAddr, tcpAddr, tcpAddr}, out: []ma.Multiaddr{tcpAddr}},
841-
{in: []ma.Multiaddr{tcpAddr, quicAddr, tcpAddr}, out: []ma.Multiaddr{tcpAddr, quicAddr}},
842-
{in: []ma.Multiaddr{tcpAddr, quicAddr, wsAddr}, out: []ma.Multiaddr{tcpAddr, quicAddr, wsAddr}},
843-
} {
844-
tc := tc
845-
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
846-
deduped := dedupAddrs(tc.in)
847-
for _, a := range tc.out {
848-
require.Contains(t, deduped, a)
849-
}
850-
})
851-
}
852-
}
853-
854828
func TestInferWebtransportAddrsFromQuic(t *testing.T) {
855829
type testCase struct {
856830
name string

p2p/net/swarm/dial_worker.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,12 @@ loop:
180180
case <-w.triggerDial:
181181
for _, addr := range w.nextDial {
182182
// spawn the dial
183-
ad := w.pending[string(addr.Bytes())]
183+
ad, ok := w.pending[string(addr.Bytes())]
184+
if !ok {
185+
log.Warn("unexpectedly missing pending addrDial for addr")
186+
// Assume nothing to dial here
187+
continue
188+
}
184189
err := w.s.dialNextAddr(ad.ctx, w.peer, addr, w.resch)
185190
if err != nil {
186191
w.dispatchError(ad, err)
@@ -195,7 +200,12 @@ loop:
195200
w.connected = true
196201
}
197202

198-
ad := w.pending[string(res.Addr.Bytes())]
203+
ad, ok := w.pending[string(res.Addr.Bytes())]
204+
if !ok {
205+
log.Warn("unexpectedly missing pending addrDial res")
206+
// Assume nothing to do here
207+
continue
208+
}
199209

200210
if res.Conn != nil {
201211
// we got a connection, add it to the swarm

p2p/net/swarm/swarm_dial.go

+1
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ func (s *Swarm) addrsForDial(ctx context.Context, p peer.ID) ([]ma.Multiaddr, er
334334
if forceDirect, _ := network.GetForceDirectDial(ctx); forceDirect {
335335
goodAddrs = ma.FilterAddrs(goodAddrs, s.nonProxyAddr)
336336
}
337+
goodAddrs = network.DedupAddrs(goodAddrs)
337338

338339
if len(goodAddrs) == 0 {
339340
return nil, ErrNoGoodAddresses

p2p/net/swarm/swarm_dial_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,51 @@ func TestAddrsForDial(t *testing.T) {
6565
require.NotZero(t, len(mas))
6666
}
6767

68+
func TestDedupAddrsForDial(t *testing.T) {
69+
mockResolver := madns.MockResolver{IP: make(map[string][]net.IPAddr)}
70+
ipaddr, err := net.ResolveIPAddr("ip4", "1.2.3.4")
71+
if err != nil {
72+
t.Fatal(err)
73+
}
74+
mockResolver.IP["example.com"] = []net.IPAddr{*ipaddr}
75+
76+
resolver, err := madns.NewResolver(madns.WithDomainResolver("example.com", &mockResolver))
77+
if err != nil {
78+
t.Fatal(err)
79+
}
80+
81+
priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
82+
require.NoError(t, err)
83+
id, err := peer.IDFromPrivateKey(priv)
84+
require.NoError(t, err)
85+
86+
ps, err := pstoremem.NewPeerstore()
87+
require.NoError(t, err)
88+
ps.AddPubKey(id, priv.GetPublic())
89+
ps.AddPrivKey(id, priv)
90+
t.Cleanup(func() { ps.Close() })
91+
92+
s, err := NewSwarm(id, ps, eventbus.NewBus(), WithMultiaddrResolver(resolver))
93+
require.NoError(t, err)
94+
defer s.Close()
95+
96+
tpt, err := tcp.NewTCPTransport(nil, &network.NullResourceManager{})
97+
require.NoError(t, err)
98+
err = s.AddTransport(tpt)
99+
require.NoError(t, err)
100+
101+
otherPeer := test.RandPeerIDFatal(t)
102+
103+
ps.AddAddr(otherPeer, ma.StringCast("/dns4/example.com/tcp/1234"), time.Hour)
104+
ps.AddAddr(otherPeer, ma.StringCast("/ip4/1.2.3.4/tcp/1234"), time.Hour)
105+
106+
ctx := context.Background()
107+
mas, err := s.addrsForDial(ctx, otherPeer)
108+
require.NoError(t, err)
109+
110+
require.Equal(t, 1, len(mas))
111+
}
112+
68113
func newTestSwarmWithResolver(t *testing.T, resolver *madns.Resolver) *Swarm {
69114
priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
70115
require.NoError(t, err)

version.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "v0.27.4"
2+
"version": "v0.27.5"
33
}

0 commit comments

Comments
 (0)