Skip to content

Commit 40978ee

Browse files
sukunrtmarten-seemann
authored andcommitted
swarm: change maps with multiaddress keys to use strings (#2284)
* swarm: change maps with multiaddress keys to use strings * fix test * fix more flakiness
1 parent 6926113 commit 40978ee

File tree

3 files changed

+83
-17
lines changed

3 files changed

+83
-17
lines changed

p2p/host/routed/routed.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,16 @@ func (rh *RoutedHost) Connect(ctx context.Context, pi peer.AddrInfo) error {
119119
}
120120

121121
// Build lookup map
122-
lookup := make(map[ma.Multiaddr]struct{}, len(addrs))
122+
lookup := make(map[string]struct{}, len(addrs))
123123
for _, addr := range addrs {
124-
lookup[addr] = struct{}{}
124+
lookup[string(addr.Bytes())] = struct{}{}
125125
}
126126

127127
// if there's any address that's not in the previous set
128128
// of addresses, try to connect again. If all addresses
129129
// where known previously we return the original error.
130130
for _, newAddr := range newAddrs {
131-
if _, found := lookup[newAddr]; found {
131+
if _, found := lookup[string(newAddr.Bytes())]; found {
132132
continue
133133
}
134134

p2p/net/swarm/dial_worker.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ type dialResponse struct {
2727
}
2828

2929
type pendRequest struct {
30-
req dialRequest // the original request
31-
err *DialError // dial error accumulator
32-
addrs map[ma.Multiaddr]struct{} // pending addr dials
30+
req dialRequest // the original request
31+
err *DialError // dial error accumulator
32+
addrs map[string]struct{} // pending address to dial. The key is a multiaddr
3333
}
3434

3535
type addrDial struct {
@@ -47,7 +47,7 @@ type dialWorker struct {
4747
reqch <-chan dialRequest
4848
reqno int
4949
requests map[int]*pendRequest
50-
pending map[ma.Multiaddr]*addrDial
50+
pending map[string]*addrDial // pending addresses to dial. The key is a multiaddr
5151
resch chan dialResult
5252

5353
connected bool // true when a connection has been successfully established
@@ -67,7 +67,7 @@ func newDialWorker(s *Swarm, p peer.ID, reqch <-chan dialRequest) *dialWorker {
6767
peer: p,
6868
reqch: reqch,
6969
requests: make(map[int]*pendRequest),
70-
pending: make(map[ma.Multiaddr]*addrDial),
70+
pending: make(map[string]*addrDial),
7171
resch: make(chan dialResult),
7272
}
7373
}
@@ -109,10 +109,10 @@ loop:
109109
pr := &pendRequest{
110110
req: req,
111111
err: &DialError{Peer: w.peer},
112-
addrs: make(map[ma.Multiaddr]struct{}),
112+
addrs: make(map[string]struct{}),
113113
}
114114
for _, a := range addrs {
115-
pr.addrs[a] = struct{}{}
115+
pr.addrs[string(a.Bytes())] = struct{}{}
116116
}
117117

118118
// check if any of the addrs has been successfully dialed and accumulate
@@ -121,7 +121,7 @@ loop:
121121
var tojoin []*addrDial
122122

123123
for _, a := range addrs {
124-
ad, ok := w.pending[a]
124+
ad, ok := w.pending[string(a.Bytes())]
125125
if !ok {
126126
todial = append(todial, a)
127127
continue
@@ -136,7 +136,7 @@ loop:
136136
if ad.err != nil {
137137
// dial to this addr errored, accumulate the error
138138
pr.err.recordErr(a, ad.err)
139-
delete(pr.addrs, a)
139+
delete(pr.addrs, string(a.Bytes()))
140140
continue
141141
}
142142

@@ -167,7 +167,7 @@ loop:
167167

168168
if len(todial) > 0 {
169169
for _, a := range todial {
170-
w.pending[a] = &addrDial{addr: a, ctx: req.ctx, requests: []int{w.reqno}}
170+
w.pending[string(a.Bytes())] = &addrDial{addr: a, ctx: req.ctx, requests: []int{w.reqno}}
171171
}
172172

173173
w.nextDial = append(w.nextDial, todial...)
@@ -180,7 +180,7 @@ loop:
180180
case <-w.triggerDial:
181181
for _, addr := range w.nextDial {
182182
// spawn the dial
183-
ad := w.pending[addr]
183+
ad := w.pending[string(addr.Bytes())]
184184
err := w.s.dialNextAddr(ad.ctx, w.peer, addr, w.resch)
185185
if err != nil {
186186
w.dispatchError(ad, err)
@@ -195,7 +195,7 @@ loop:
195195
w.connected = true
196196
}
197197

198-
ad := w.pending[res.Addr]
198+
ad := w.pending[string(res.Addr.Bytes())]
199199

200200
if res.Conn != nil {
201201
// we got a connection, add it to the swarm
@@ -250,7 +250,7 @@ func (w *dialWorker) dispatchError(ad *addrDial, err error) {
250250
// accumulate the error
251251
pr.err.recordErr(ad.addr, err)
252252

253-
delete(pr.addrs, ad.addr)
253+
delete(pr.addrs, string(ad.addr.Bytes()))
254254
if len(pr.addrs) == 0 {
255255
// all addrs have erred, dispatch dial error
256256
// but first do a last one check in case an acceptable connection has landed from
@@ -274,7 +274,7 @@ func (w *dialWorker) dispatchError(ad *addrDial, err error) {
274274
// it is also necessary to preserve consisent behaviour with the old dialer -- TestDialBackoff
275275
// regresses without this.
276276
if err == ErrDialBackoff {
277-
delete(w.pending, ad.addr)
277+
delete(w.pending, string(ad.addr.Bytes()))
278278
}
279279
}
280280

p2p/net/swarm/dial_worker_test.go

+66
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
2525

2626
ma "github.com/multiformats/go-multiaddr"
27+
manet "github.com/multiformats/go-multiaddr/net"
2728
"github.com/stretchr/testify/require"
2829
)
2930

@@ -342,3 +343,68 @@ func TestDialWorkerLoopConcurrentFailureStress(t *testing.T) {
342343
close(reqch)
343344
worker.wg.Wait()
344345
}
346+
347+
func TestDialWorkerLoopAddrDedup(t *testing.T) {
348+
s1 := makeSwarm(t)
349+
s2 := makeSwarm(t)
350+
defer s1.Close()
351+
defer s2.Close()
352+
t1 := ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 10000))
353+
t2 := ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 10000))
354+
355+
// acceptAndClose accepts a connection and closes it
356+
acceptAndClose := func(a ma.Multiaddr, ch chan struct{}, closech chan struct{}) {
357+
list, err := manet.Listen(a)
358+
if err != nil {
359+
t.Error(err)
360+
return
361+
}
362+
go func() {
363+
ch <- struct{}{}
364+
for {
365+
conn, err := list.Accept()
366+
if err != nil {
367+
return
368+
}
369+
ch <- struct{}{}
370+
conn.Close()
371+
}
372+
}()
373+
<-closech
374+
list.Close()
375+
}
376+
ch := make(chan struct{}, 1)
377+
closeCh := make(chan struct{})
378+
go acceptAndClose(t1, ch, closeCh)
379+
defer close(closeCh)
380+
<-ch // the routine has started listening on addr
381+
382+
s1.Peerstore().AddAddrs(s2.LocalPeer(), []ma.Multiaddr{t1}, peerstore.PermanentAddrTTL)
383+
384+
reqch := make(chan dialRequest)
385+
resch := make(chan dialResponse, 2)
386+
387+
worker := newDialWorker(s1, s2.LocalPeer(), reqch)
388+
go worker.loop()
389+
defer worker.wg.Wait()
390+
defer close(reqch)
391+
392+
reqch <- dialRequest{ctx: context.Background(), resch: resch}
393+
<-ch
394+
<-resch
395+
// Need to clear backoff otherwise the dial attempt would not be made
396+
s1.Backoff().Clear(s2.LocalPeer())
397+
398+
s1.Peerstore().ClearAddrs(s2.LocalPeer())
399+
s1.Peerstore().AddAddrs(s2.LocalPeer(), []ma.Multiaddr{t2}, peerstore.PermanentAddrTTL)
400+
401+
reqch <- dialRequest{ctx: context.Background(), resch: resch}
402+
select {
403+
case r := <-resch:
404+
require.Error(t, r.err)
405+
case <-ch:
406+
t.Errorf("didn't expect a connection attempt")
407+
case <-time.After(5 * time.Second):
408+
t.Errorf("expected a fail response")
409+
}
410+
}

0 commit comments

Comments
 (0)