Skip to content

Commit e45fe9e

Browse files
committed
add tests for present behavior
1 parent fd76100 commit e45fe9e

File tree

3 files changed

+229
-60
lines changed

3 files changed

+229
-60
lines changed

p2p/host/basic/address_service.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/libp2p/go-libp2p/core/event"
1111
"github.com/libp2p/go-libp2p/core/network"
12-
"github.com/libp2p/go-libp2p/core/record"
1312
"github.com/libp2p/go-libp2p/core/transport"
1413
"github.com/libp2p/go-libp2p/p2p/host/basic/internal/backoff"
1514
libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc"
@@ -19,8 +18,6 @@ import (
1918
manet "github.com/multiformats/go-multiaddr/net"
2019
)
2120

22-
type peerRecordFunc func([]ma.Multiaddr) (*record.Envelope, error)
23-
2421
type observedAddrsService interface {
2522
OwnObservedAddrs() []ma.Multiaddr
2623
ObservedAddrsFor(local ma.Multiaddr) []ma.Multiaddr
@@ -34,12 +31,13 @@ type addressService struct {
3431
addrsChangeChan chan struct{}
3532
addrsUpdated chan struct{}
3633
autoRelayAddrsSub event.Subscription
37-
autoRelayAddrs func() []ma.Multiaddr
38-
reachability func() network.Reachability
39-
ifaceAddrs *interfaceAddrsCache
40-
wg sync.WaitGroup
41-
ctx context.Context
42-
ctxCancel context.CancelFunc
34+
// There are wrapped in to functions for mocking
35+
autoRelayAddrs func() []ma.Multiaddr
36+
reachability func() network.Reachability
37+
ifaceAddrs *interfaceAddrsCache
38+
wg sync.WaitGroup
39+
ctx context.Context
40+
ctxCancel context.CancelFunc
4341
}
4442

4543
func NewAddressService(h *BasicHost, natmgr func(network.Network) NATManager,

p2p/host/basic/address_service_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package basichost
22

33
import (
44
"testing"
5+
"time"
56

7+
"github.com/libp2p/go-libp2p/core/network"
8+
swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing"
69
ma "github.com/multiformats/go-multiaddr"
710
manet "github.com/multiformats/go-multiaddr/net"
811
"github.com/stretchr/testify/require"
@@ -96,3 +99,174 @@ func TestAppendNATAddrs(t *testing.T) {
9699
})
97100
}
98101
}
102+
103+
type mockNatManager struct {
104+
GetMappingFunc func(addr ma.Multiaddr) ma.Multiaddr
105+
HasDiscoveredNATFunc func() bool
106+
}
107+
108+
func (m *mockNatManager) Close() error {
109+
return nil
110+
}
111+
112+
func (m *mockNatManager) GetMapping(addr ma.Multiaddr) ma.Multiaddr {
113+
return m.GetMappingFunc(addr)
114+
}
115+
116+
func (m *mockNatManager) HasDiscoveredNAT() bool {
117+
return m.HasDiscoveredNATFunc()
118+
}
119+
120+
var _ NATManager = &mockNatManager{}
121+
122+
type mockObservedAddrs struct {
123+
OwnObservedAddrsFunc func() []ma.Multiaddr
124+
ObservedAddrsForFunc func(ma.Multiaddr) []ma.Multiaddr
125+
}
126+
127+
func (m *mockObservedAddrs) OwnObservedAddrs() []ma.Multiaddr {
128+
return m.OwnObservedAddrsFunc()
129+
}
130+
131+
func (m *mockObservedAddrs) ObservedAddrsFor(local ma.Multiaddr) []ma.Multiaddr {
132+
return m.ObservedAddrsForFunc(local)
133+
}
134+
135+
func TestAddressService(t *testing.T) {
136+
getAddrService := func() *addressService {
137+
h, err := NewHost(swarmt.GenSwarm(t), &HostOpts{DisableIdentifyAddressDiscovery: true})
138+
require.NoError(t, err)
139+
t.Cleanup(func() { h.Close() })
140+
141+
as := h.addressService
142+
return as
143+
}
144+
145+
t.Run("NAT Address", func(t *testing.T) {
146+
as := getAddrService()
147+
as.natmgr = &mockNatManager{
148+
HasDiscoveredNATFunc: func() bool { return true },
149+
GetMappingFunc: func(addr ma.Multiaddr) ma.Multiaddr {
150+
if _, err := addr.ValueForProtocol(ma.P_UDP); err == nil {
151+
return ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1")
152+
}
153+
return nil
154+
},
155+
}
156+
require.Contains(t, as.Addrs(), ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"))
157+
})
158+
159+
t.Run("NAT And Observed Address", func(t *testing.T) {
160+
as := getAddrService()
161+
as.natmgr = &mockNatManager{
162+
HasDiscoveredNATFunc: func() bool { return true },
163+
GetMappingFunc: func(addr ma.Multiaddr) ma.Multiaddr {
164+
if _, err := addr.ValueForProtocol(ma.P_UDP); err == nil {
165+
return ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1")
166+
}
167+
return nil
168+
},
169+
}
170+
as.observedAddrsService = &mockObservedAddrs{
171+
ObservedAddrsForFunc: func(addr ma.Multiaddr) []ma.Multiaddr {
172+
if _, err := addr.ValueForProtocol(ma.P_TCP); err == nil {
173+
return []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/tcp/1")}
174+
}
175+
return nil
176+
},
177+
}
178+
require.Contains(t, as.Addrs(), ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"))
179+
require.Contains(t, as.Addrs(), ma.StringCast("/ip4/2.2.2.2/tcp/1"))
180+
})
181+
t.Run("Only Observed Address", func(t *testing.T) {
182+
as := getAddrService()
183+
as.natmgr = nil
184+
as.observedAddrsService = &mockObservedAddrs{
185+
ObservedAddrsForFunc: func(addr ma.Multiaddr) []ma.Multiaddr {
186+
if _, err := addr.ValueForProtocol(ma.P_TCP); err == nil {
187+
return []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/tcp/1")}
188+
}
189+
return nil
190+
},
191+
OwnObservedAddrsFunc: func() []ma.Multiaddr {
192+
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1")}
193+
},
194+
}
195+
require.NotContains(t, as.Addrs(), ma.StringCast("/ip4/2.2.2.2/tcp/1"))
196+
require.Contains(t, as.Addrs(), ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1"))
197+
})
198+
t.Run("Public Addrs Removed When Private", func(t *testing.T) {
199+
as := getAddrService()
200+
as.natmgr = nil
201+
as.observedAddrsService = &mockObservedAddrs{
202+
OwnObservedAddrsFunc: func() []ma.Multiaddr {
203+
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1")}
204+
},
205+
}
206+
as.reachability = func() network.Reachability {
207+
return network.ReachabilityPrivate
208+
}
209+
relayAddr := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/p2p/QmdXGaeGiVA745XorV1jr11RHxB9z4fqykm6xCUPX1aTJo/p2p-circuit")
210+
as.autoRelayAddrs = func() []ma.Multiaddr {
211+
return []ma.Multiaddr{relayAddr}
212+
}
213+
require.NotContains(t, as.Addrs(), ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1"))
214+
require.Contains(t, as.Addrs(), relayAddr)
215+
require.Contains(t, as.AllAddrs(), ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1"))
216+
})
217+
218+
t.Run("AddressFactory gets relay addresses", func(t *testing.T) {
219+
as := getAddrService()
220+
as.natmgr = nil
221+
as.observedAddrsService = &mockObservedAddrs{
222+
OwnObservedAddrsFunc: func() []ma.Multiaddr {
223+
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1")}
224+
},
225+
}
226+
as.reachability = func() network.Reachability {
227+
return network.ReachabilityPrivate
228+
}
229+
relayAddr := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/p2p/QmdXGaeGiVA745XorV1jr11RHxB9z4fqykm6xCUPX1aTJo/p2p-circuit")
230+
as.autoRelayAddrs = func() []ma.Multiaddr {
231+
return []ma.Multiaddr{relayAddr}
232+
}
233+
as.addrsFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr {
234+
for _, a := range addrs {
235+
if a.Equal(relayAddr) {
236+
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1")}
237+
}
238+
}
239+
return nil
240+
}
241+
require.Contains(t, as.Addrs(), ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1"))
242+
require.NotContains(t, as.Addrs(), relayAddr)
243+
})
244+
245+
t.Run("updates addresses on signaling", func(t *testing.T) {
246+
as := getAddrService()
247+
as.natmgr = nil
248+
updateChan := make(chan struct{})
249+
a1 := ma.StringCast("/ip4/1.1.1.1/udp/1/quic-v1")
250+
a2 := ma.StringCast("/ip4/1.1.1.1/tcp/1")
251+
as.addrsFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr {
252+
select {
253+
case <-updateChan:
254+
return []ma.Multiaddr{a2}
255+
default:
256+
return []ma.Multiaddr{a1}
257+
}
258+
}
259+
as.Start()
260+
require.Contains(t, as.Addrs(), a1)
261+
require.NotContains(t, as.Addrs(), a2)
262+
close(updateChan)
263+
as.SignalAddressChange()
264+
select {
265+
case <-as.AddrsUpdated():
266+
require.Contains(t, as.Addrs(), a2)
267+
require.NotContains(t, as.Addrs(), a1)
268+
case <-time.After(2 * time.Second):
269+
t.Fatal("expected addrs to be updated")
270+
}
271+
})
272+
}

p2p/host/basic/basic_host.go

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type BasicHost struct {
9090

9191
disableSignedPeerRecord bool
9292
signKey crypto.PrivKey
93+
caBook peerstore.CertifiedAddrBook
9394

9495
autoNATMx sync.RWMutex
9596
autoNat autonat.AutoNAT
@@ -309,11 +310,12 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
309310
if !ok {
310311
return nil, errors.New("peerstore should also be a certified address book")
311312
}
313+
h.caBook = cab
312314
rec, err := h.makeSignedPeerRecord(h.addressService.Addrs())
313315
if err != nil {
314316
return nil, fmt.Errorf("failed to create signed record for self: %w", err)
315317
}
316-
if _, err := cab.ConsumePeerRecord(rec, peerstore.PermanentAddrTTL); err != nil {
318+
if _, err := h.caBook.ConsumePeerRecord(rec, peerstore.PermanentAddrTTL); err != nil {
317319
return nil, fmt.Errorf("failed to persist signed record to peerstore: %w", err)
318320
}
319321
}
@@ -398,56 +400,6 @@ func (h *BasicHost) newStreamHandler(s network.Stream) {
398400
handle(protoID, s)
399401
}
400402

401-
func (h *BasicHost) background() {
402-
defer h.refCount.Done()
403-
var lastAddrs []ma.Multiaddr
404-
405-
// TODO: Deprecate this event and logic
406-
emitAddrChange := func(currentAddrs []ma.Multiaddr, lastAddrs []ma.Multiaddr) {
407-
changeEvt := h.makeUpdatedAddrEvent(lastAddrs, currentAddrs)
408-
if changeEvt == nil {
409-
return
410-
}
411-
// Our addresses have changed.
412-
// store the signed peer record in the peer store.
413-
if !h.disableSignedPeerRecord {
414-
cabook, ok := peerstore.GetCertifiedAddrBook(h.Peerstore())
415-
if !ok {
416-
log.Errorf("peerstore doesn't implement certified address book")
417-
return
418-
}
419-
if _, err := cabook.ConsumePeerRecord(changeEvt.SignedPeerRecord, peerstore.PermanentAddrTTL); err != nil {
420-
log.Errorf("failed to persist signed peer record in peer store, err=%s", err)
421-
return
422-
}
423-
}
424-
// update host addresses in the peer store
425-
removedAddrs := make([]ma.Multiaddr, 0, len(changeEvt.Removed))
426-
for _, ua := range changeEvt.Removed {
427-
removedAddrs = append(removedAddrs, ua.Address)
428-
}
429-
h.Peerstore().SetAddrs(h.ID(), currentAddrs, peerstore.PermanentAddrTTL)
430-
h.Peerstore().SetAddrs(h.ID(), removedAddrs, 0)
431-
432-
// emit addr change event
433-
if err := h.emitters.evtLocalAddrsUpdated.Emit(*changeEvt); err != nil {
434-
log.Warnf("error emitting event for updated addrs: %s", err)
435-
}
436-
}
437-
438-
for {
439-
curr := h.Addrs()
440-
emitAddrChange(curr, lastAddrs)
441-
lastAddrs = curr
442-
443-
select {
444-
case <-h.addressService.AddrsUpdated():
445-
case <-h.ctx.Done():
446-
return
447-
}
448-
}
449-
}
450-
451403
func (h *BasicHost) makeUpdatedAddrEvent(prev, current []ma.Multiaddr) *event.EvtLocalAddressesUpdated {
452404
if prev == nil && current == nil {
453405
return nil
@@ -515,6 +467,51 @@ func (h *BasicHost) makeSignedPeerRecord(addrs []ma.Multiaddr) (*record.Envelope
515467
return record.Seal(rec, h.signKey)
516468
}
517469

470+
func (h *BasicHost) background() {
471+
defer h.refCount.Done()
472+
var lastAddrs []ma.Multiaddr
473+
474+
// TODO: Deprecate this event and logic
475+
emitAddrChange := func(currentAddrs []ma.Multiaddr, lastAddrs []ma.Multiaddr) {
476+
changeEvt := h.makeUpdatedAddrEvent(lastAddrs, currentAddrs)
477+
if changeEvt == nil {
478+
return
479+
}
480+
// Our addresses have changed.
481+
// store the signed peer record in the peer store.
482+
if !h.disableSignedPeerRecord {
483+
if _, err := h.caBook.ConsumePeerRecord(changeEvt.SignedPeerRecord, peerstore.PermanentAddrTTL); err != nil {
484+
log.Errorf("failed to persist signed peer record in peer store, err=%s", err)
485+
return
486+
}
487+
}
488+
// update host addresses in the peer store
489+
removedAddrs := make([]ma.Multiaddr, 0, len(changeEvt.Removed))
490+
for _, ua := range changeEvt.Removed {
491+
removedAddrs = append(removedAddrs, ua.Address)
492+
}
493+
h.Peerstore().SetAddrs(h.ID(), currentAddrs, peerstore.PermanentAddrTTL)
494+
h.Peerstore().SetAddrs(h.ID(), removedAddrs, 0)
495+
496+
// emit addr change event
497+
if err := h.emitters.evtLocalAddrsUpdated.Emit(*changeEvt); err != nil {
498+
log.Warnf("error emitting event for updated addrs: %s", err)
499+
}
500+
}
501+
502+
for {
503+
curr := h.Addrs()
504+
emitAddrChange(curr, lastAddrs)
505+
lastAddrs = curr
506+
507+
select {
508+
case <-h.addressService.AddrsUpdated():
509+
case <-h.ctx.Done():
510+
return
511+
}
512+
}
513+
}
514+
518515
// ID returns the (local) peer.ID associated with this Host
519516
func (h *BasicHost) ID() peer.ID {
520517
return h.Network().LocalPeer()

0 commit comments

Comments
 (0)