Skip to content

Commit 914331b

Browse files
authored
autorelay: send addresses on eventbus; dont wrap address factory (#3071)
1 parent fe11448 commit 914331b

File tree

9 files changed

+224
-132
lines changed

9 files changed

+224
-132
lines changed

config/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ func (cfg *Config) NewNode() (host.Host, error) {
532532
}
533533
fxopts = append(fxopts, transportOpts...)
534534

535-
// Configure routing and autorelay
535+
// Configure routing
536536
if cfg.Routing != nil {
537537
fxopts = append(fxopts,
538538
fx.Provide(cfg.Routing),

core/event/addrs.go

+5
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,8 @@ type EvtLocalAddressesUpdated struct {
8181
// wrapped in a record.Envelope and signed by the Host's private key.
8282
SignedPeerRecord *record.Envelope
8383
}
84+
85+
// EvtAutoRelayAddrsUpdated is sent by the autorelay when the node's relay addresses are updated
86+
type EvtAutoRelayAddrsUpdated struct {
87+
RelayAddrs []ma.Multiaddr
88+
}

libp2p_test.go

-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,6 @@ func TestDialCircuitAddrWithWrappedResourceManager(t *testing.T) {
466466
),
467467
peerstore.TempAddrTTL,
468468
)
469-
require.NoError(t, err)
470469

471470
require.Eventually(t, func() bool {
472471
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)

p2p/host/autorelay/addrsplosion.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import (
99

1010
// This function cleans up a relay's address set to remove private addresses and curtail
1111
// addrsplosion.
12+
// TODO: Remove this, we don't need this. The current method tries to select the
13+
// best address for the relay. Instead we should rely on the addresses provided by the
14+
// relay in response to the reservation request.
1215
func cleanupAddressSet(addrs []ma.Multiaddr) []ma.Multiaddr {
1316
var public, private []ma.Multiaddr
1417

@@ -17,7 +20,7 @@ func cleanupAddressSet(addrs []ma.Multiaddr) []ma.Multiaddr {
1720
continue
1821
}
1922

20-
if manet.IsPublicAddr(a) || isDNSAddr(a) {
23+
if manet.IsPublicAddr(a) {
2124
public = append(public, a)
2225
continue
2326
}
@@ -51,16 +54,6 @@ func isRelayAddr(a ma.Multiaddr) bool {
5154
return isRelay
5255
}
5356

54-
func isDNSAddr(a ma.Multiaddr) bool {
55-
if first, _ := ma.SplitFirst(a); first != nil {
56-
switch first.Protocol().Code {
57-
case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR:
58-
return true
59-
}
60-
}
61-
return false
62-
}
63-
6457
// we have addrsplosion if for some protocol we advertise multiple ports on
6558
// the same base address.
6659
func hasAddrsplosion(addrs []ma.Multiaddr) bool {

p2p/host/autorelay/autorelay.go

+8-25
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ package autorelay
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"sync"
78

89
"github.com/libp2p/go-libp2p/core/event"
910
"github.com/libp2p/go-libp2p/core/host"
1011
"github.com/libp2p/go-libp2p/core/network"
11-
basic "github.com/libp2p/go-libp2p/p2p/host/basic"
1212
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
1313

1414
logging "github.com/ipfs/go-log/v2"
15-
ma "github.com/multiformats/go-multiaddr"
1615
)
1716

1817
var log = logging.Logger("autorelay")
@@ -22,8 +21,6 @@ type AutoRelay struct {
2221
ctx context.Context
2322
ctxCancel context.CancelFunc
2423

25-
conf *config
26-
2724
mx sync.Mutex
2825
status network.Reachability
2926

@@ -34,9 +31,9 @@ type AutoRelay struct {
3431
metricsTracer MetricsTracer
3532
}
3633

37-
func NewAutoRelay(bhost *basic.BasicHost, opts ...Option) (*AutoRelay, error) {
34+
func NewAutoRelay(host host.Host, opts ...Option) (*AutoRelay, error) {
3835
r := &AutoRelay{
39-
host: bhost,
36+
host: host,
4037
status: network.ReachabilityUnknown,
4138
}
4239
conf := defaultConfig
@@ -46,25 +43,12 @@ func NewAutoRelay(bhost *basic.BasicHost, opts ...Option) (*AutoRelay, error) {
4643
}
4744
}
4845
r.ctx, r.ctxCancel = context.WithCancel(context.Background())
49-
r.conf = &conf
50-
r.relayFinder = newRelayFinder(bhost, conf.peerSource, &conf)
51-
r.metricsTracer = &wrappedMetricsTracer{conf.metricsTracer}
52-
53-
// Update the host address factory to use autorelay addresses if we're private
54-
//
55-
// TODO: Don't update host address factory. Instead send our relay addresses on the eventbus.
56-
// The host can decide how to handle those.
57-
addrF := bhost.AddrsFactory
58-
bhost.AddrsFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr {
59-
addrs = addrF(addrs)
60-
r.mx.Lock()
61-
defer r.mx.Unlock()
62-
63-
if r.status != network.ReachabilityPrivate {
64-
return addrs
65-
}
66-
return r.relayFinder.relayAddrs(addrs)
46+
rf, err := newRelayFinder(host, &conf)
47+
if err != nil {
48+
return nil, fmt.Errorf("failed to create autorelay: %w", err)
6749
}
50+
r.relayFinder = rf
51+
r.metricsTracer = &wrappedMetricsTracer{conf.metricsTracer}
6852

6953
return r, nil
7054
}
@@ -93,7 +77,6 @@ func (r *AutoRelay) background() {
9377
if !ok {
9478
return
9579
}
96-
// TODO: push changed addresses
9780
evt := ev.(event.EvtLocalReachabilityChanged)
9881
switch evt.Reachability {
9982
case network.ReachabilityPrivate, network.ReachabilityUnknown:

p2p/host/autorelay/autorelay_test.go

+85-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ package autorelay_test
33
import (
44
"context"
55
"fmt"
6+
"slices"
67
"strings"
78
"sync/atomic"
89
"testing"
910
"time"
1011

1112
"github.com/libp2p/go-libp2p"
13+
"github.com/libp2p/go-libp2p/core/event"
1214
"github.com/libp2p/go-libp2p/core/host"
1315
"github.com/libp2p/go-libp2p/core/network"
1416
"github.com/libp2p/go-libp2p/core/peer"
@@ -17,6 +19,7 @@ import (
1719
circuitv2_proto "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto"
1820

1921
ma "github.com/multiformats/go-multiaddr"
22+
"github.com/stretchr/testify/assert"
2023
"github.com/stretchr/testify/require"
2124
)
2225

@@ -96,7 +99,10 @@ func newRelay(t *testing.T) host.Host {
9699
saddr := addr.String()
97100
if strings.HasPrefix(saddr, "/ip4/127.0.0.1/") {
98101
addrNoIP := strings.TrimPrefix(saddr, "/ip4/127.0.0.1")
99-
addrs[i] = ma.StringCast("/dns4/localhost" + addrNoIP)
102+
// .internal is classified as a public address as users
103+
// are free to map this dns to a public ip address for
104+
// use within a LAN
105+
addrs[i] = ma.StringCast("/dns/libp2p.internal" + addrNoIP)
100106
}
101107
}
102108
return addrs
@@ -517,3 +523,81 @@ func TestNoBusyLoop0MinInterval(t *testing.T) {
517523
val := atomic.LoadUint64(&calledTimes)
518524
require.Less(t, val, uint64(2))
519525
}
526+
func TestAutoRelayAddrsEvent(t *testing.T) {
527+
cl := newMockClock()
528+
relays := []host.Host{newRelay(t), newRelay(t), newRelay(t), newRelay(t), newRelay(t)}
529+
t.Cleanup(func() {
530+
for _, r := range relays {
531+
r.Close()
532+
}
533+
})
534+
535+
relayIDFromP2PAddr := func(a ma.Multiaddr) peer.ID {
536+
r, c := ma.SplitLast(a)
537+
if c.Protocol().Code != ma.P_CIRCUIT {
538+
return ""
539+
}
540+
if id, err := peer.IDFromP2PAddr(r); err == nil {
541+
return id
542+
}
543+
return ""
544+
}
545+
546+
checkAddrsContainsPeersAsRelay := func(addrs []ma.Multiaddr, peers ...peer.ID) bool {
547+
for _, p := range peers {
548+
if !slices.ContainsFunc(addrs, func(a ma.Multiaddr) bool { return relayIDFromP2PAddr(a) == p }) {
549+
return false
550+
}
551+
}
552+
return true
553+
}
554+
peerChan := make(chan peer.AddrInfo, 5)
555+
h := newPrivateNode(t,
556+
func(context.Context, int) <-chan peer.AddrInfo {
557+
return peerChan
558+
},
559+
autorelay.WithClock(cl),
560+
autorelay.WithMinCandidates(1),
561+
autorelay.WithMaxCandidates(10),
562+
autorelay.WithNumRelays(5),
563+
autorelay.WithBootDelay(1*time.Second),
564+
autorelay.WithMinInterval(time.Hour),
565+
)
566+
defer h.Close()
567+
568+
sub, err := h.EventBus().Subscribe(new(event.EvtAutoRelayAddrsUpdated))
569+
require.NoError(t, err)
570+
571+
peerChan <- peer.AddrInfo{ID: relays[0].ID(), Addrs: relays[0].Addrs()}
572+
cl.AdvanceBy(time.Second)
573+
574+
require.EventuallyWithT(t, func(collect *assert.CollectT) {
575+
e := <-sub.Out()
576+
evt := e.(event.EvtAutoRelayAddrsUpdated)
577+
if !checkAddrsContainsPeersAsRelay(evt.RelayAddrs, relays[0].ID()) {
578+
collect.Errorf("expected %s to be in %v", relays[0].ID(), evt.RelayAddrs)
579+
}
580+
if checkAddrsContainsPeersAsRelay(evt.RelayAddrs, relays[1].ID()) {
581+
collect.Errorf("expected %s to not be in %v", relays[1].ID(), evt.RelayAddrs)
582+
}
583+
}, 5*time.Second, 50*time.Millisecond)
584+
for _, r := range relays[1:] {
585+
peerChan <- peer.AddrInfo{ID: r.ID(), Addrs: r.Addrs()}
586+
}
587+
require.EventuallyWithT(t, func(c *assert.CollectT) {
588+
e := <-sub.Out()
589+
evt := e.(event.EvtAutoRelayAddrsUpdated)
590+
relayIds := []peer.ID{}
591+
for _, r := range relays[1:] {
592+
relayIds = append(relayIds, r.ID())
593+
}
594+
if !checkAddrsContainsPeersAsRelay(evt.RelayAddrs, relayIds...) {
595+
c.Errorf("expected %s to be in %v", relayIds, evt.RelayAddrs)
596+
}
597+
}, 5*time.Second, 50*time.Millisecond)
598+
select {
599+
case e := <-sub.Out():
600+
t.Fatal("expected no more events after all reservations obtained; got: ", e.(event.EvtAutoRelayAddrsUpdated))
601+
case <-time.After(1 * time.Second):
602+
}
603+
}

p2p/host/autorelay/relay.go

-19
This file was deleted.

0 commit comments

Comments
 (0)