Skip to content

Commit 195b2d5

Browse files
committed
p2p: speed up startup and initial peer connection
1 parent 639a7b5 commit 195b2d5

4 files changed

Lines changed: 64 additions & 40 deletions

File tree

application.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ func New() *Application {
9191
}
9292

9393
func (a *Application) Init(ctx context.Context, tunDevice tun.Device) error {
94+
a.logger.Info("Application initialization started")
95+
9496
a.ctx, a.ctxCancel = context.WithCancel(ctx)
9597
a.P2p = p2p.NewP2p(a.ctx)
9698
p2pHost, err := a.P2p.InitHost(a.makeP2pHostConfig())
@@ -100,8 +102,8 @@ func (a *Application) Init(ctx context.Context, tunDevice tun.Device) error {
100102

101103
privKey := p2pHost.Peerstore().PrivKey(p2pHost.ID())
102104
a.Conf.SetIdentity(privKey, p2pHost.ID())
103-
a.logger.Infof("Host created. We are: %s", p2pHost.ID().String())
104-
a.logger.Infof("Listen interfaces: %v", p2pHost.Addrs())
105+
a.logger.Infof("P2P host initialized. My peer_id: %s", p2pHost.ID().String())
106+
a.logger.Infof("P2P listening on addresses: %v", p2pHost.Addrs())
105107

106108
localIP, netMask := a.Conf.VPNLocalIPMask()
107109
interfaceName := a.Conf.VPNConfig.InterfaceName
@@ -110,12 +112,9 @@ func (a *Application) Init(ctx context.Context, tunDevice tun.Device) error {
110112
return fmt.Errorf("failed to init vpn: %v", err)
111113
}
112114
a.vpnDevice = vpnDevice
113-
a.logger.Infof("Created vpn interface %s: %s", interfaceName, &net.IPNet{IP: localIP, Mask: netMask})
115+
a.logger.Infof("VPN interface created. Name: %s CIDR: %s", interfaceName, &net.IPNet{IP: localIP, Mask: netMask})
114116

115-
err = a.P2p.Bootstrap()
116-
if err != nil {
117-
return err
118-
}
117+
a.P2p.Bootstrap()
119118

120119
a.Dns = NewDNSService(a.Conf, a.Eventbus, a.ctx, a.logger)
121120
a.AuthStatus = service.NewAuthStatus(a.P2p, a.Conf, a.Eventbus)
@@ -151,11 +150,13 @@ func (a *Application) Init(ctx context.Context, tunDevice tun.Device) error {
151150
interfaceName, err := a.vpnDevice.InterfaceName()
152151
if err != nil {
153152
a.logger.Errorf("failed to get TUN interface name: %v", err)
154-
return nil
153+
} else {
154+
a.Dns.initDNS(interfaceName)
155155
}
156-
a.Dns.initDNS(interfaceName)
157156
}
158157

158+
a.logger.Info("Application initialized successfully")
159+
159160
return nil
160161
}
161162

@@ -176,7 +177,7 @@ func (a *Application) SetupLoggerAndConfig() *log.ZapEventLogger {
176177

177178
encoderConfig := zap.NewDevelopmentEncoderConfig()
178179
encoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
179-
enc.AppendString(t.Format("2006-01-02 15:04:05"))
180+
enc.AppendString(t.Format("2006-01-02 15:04:05.99"))
180181
}
181182
consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
182183
zapCore := zapcore.NewCore(consoleEncoder, syncer, zapcore.InfoLevel)

p2p/p2p.go

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ type P2p struct {
9595
bootstrapPeers []peer.AddrInfo
9696
startedAt time.Time
9797
bootstrapsInfo atomic.Pointer[map[string]BootstrapPeerDebugInfo]
98+
99+
dhtBootstrapFinishedChan chan struct{}
98100
}
99101

100102
func NewP2p(ctx context.Context) *P2p {
@@ -103,6 +105,8 @@ func NewP2p(ctx context.Context) *P2p {
103105
ctx: newCtx,
104106
ctxCancel: ctxCancel,
105107
logger: log.Logger("awl/p2p"),
108+
109+
dhtBootstrapFinishedChan: make(chan struct{}),
106110
}
107111
}
108112

@@ -300,45 +304,68 @@ func (p *P2p) SubscribeConnectionEvents(onConnected, onDisconnected func(network
300304
p.host.Network().Notify(notifyBundle)
301305
}
302306

303-
func (p *P2p) Bootstrap() error {
304-
p.logger.Debug("Bootstrapping the DHT")
305-
// connect to the bootstrap nodes first
306-
ctx, cancel := context.WithTimeout(p.ctx, 2*time.Second)
307-
defer cancel()
307+
func (p *P2p) Bootstrap() {
308+
ctx, cancel := context.WithTimeout(p.ctx, 3*time.Second)
308309
var wg sync.WaitGroup
310+
successfulConnectionsCh := make(chan struct{}, len(p.bootstrapPeers))
309311

312+
p.logger.Debug("Start bootstrapping the DHT")
310313
for _, peerAddr := range p.bootstrapPeers {
311314
wg.Add(1)
312-
p.host.ConnManager().Protect(peerAddr.ID, protectedBootstrapPeerTag)
313-
314315
go func() {
315316
defer wg.Done()
316317
if err := p.host.Connect(ctx, peerAddr); err != nil && !errors.Is(err, context.Canceled) {
317318
p.logger.Warnf("Failed to connect to bootstrap node %s: %v", peerAddr.ID, err)
318319
} else if err == nil {
319320
p.logger.Infof("Connection established with bootstrap node: %s", peerAddr.ID)
321+
successfulConnectionsCh <- struct{}{}
320322
}
321323
}()
322324
}
323-
wg.Wait()
324-
p.logger.Info("Connection established with all bootstrap nodes")
325325

326-
if err := p.dht.Bootstrap(p.ctx); err != nil {
327-
return fmt.Errorf("bootstrap dht: %v", err)
328-
}
326+
go func() {
327+
defer cancel()
329328

330-
return nil
329+
// wait for at least 2 bootstrap nodes
330+
for range min(2, len(p.bootstrapPeers)) {
331+
select {
332+
case <-ctx.Done():
333+
case <-successfulConnectionsCh:
334+
}
335+
}
336+
337+
p.logger.Info("Bootstrapping the DHT")
338+
if err := p.dht.Bootstrap(p.ctx); err != nil {
339+
// from the code err is always nil for now
340+
p.logger.Warnf("Failed to bootstrap DHT: %v", err)
341+
}
342+
close(p.dhtBootstrapFinishedChan)
343+
344+
wg.Wait()
345+
p.logger.Info("Finished connecting to all bootstrap nodes")
346+
}()
331347
}
332348

333349
func (p *P2p) MaintainBackgroundConnections(ctx context.Context, interval time.Duration, knownPeersIdsFunc func() []peer.ID) {
334-
const firstTryInterval = 5 * time.Second
335-
p.connectToKnownPeers(ctx, firstTryInterval, knownPeersIdsFunc())
350+
const timeout = 5 * time.Second
351+
const firstRetryDelay = 5 * time.Second
352+
353+
// wait for bootstrapping
354+
select {
355+
case <-ctx.Done():
356+
return
357+
case <-p.dhtBootstrapFinishedChan:
358+
}
359+
360+
p.connectToKnownPeers(ctx, timeout, knownPeersIdsFunc())
361+
362+
// retry once after a short delay in case of network instability
336363
select {
337364
case <-ctx.Done():
338365
return
339-
case <-time.After(firstTryInterval):
366+
case <-time.After(firstRetryDelay):
340367
}
341-
p.connectToKnownPeers(ctx, interval, knownPeersIdsFunc())
368+
p.connectToKnownPeers(ctx, timeout, knownPeersIdsFunc())
342369

343370
ticker := time.NewTicker(interval)
344371
defer ticker.Stop()
@@ -350,7 +377,7 @@ func (p *P2p) MaintainBackgroundConnections(ctx context.Context, interval time.D
350377
case <-ticker.C:
351378
}
352379

353-
p.connectToKnownPeers(ctx, interval, knownPeersIdsFunc())
380+
p.connectToKnownPeers(ctx, timeout, knownPeersIdsFunc())
354381
ticker.Reset(interval)
355382
}
356383
}
@@ -380,6 +407,8 @@ func (p *P2p) connectToKnownPeers(ctx context.Context, timeout time.Duration, pe
380407

381408
for _, peerAddr := range p.bootstrapPeers {
382409
wg.Add(1)
410+
p.host.ConnManager().Protect(peerAddr.ID, protectedBootstrapPeerTag)
411+
383412
go func() {
384413
defer wg.Done()
385414

service/auth_status.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ type P2p interface {
3030
NewStream(ctx context.Context, id peer.ID, proto libp2pProtocol.ID) (network.Stream, error)
3131
NewStreamWithDedicatedConn(ctx context.Context, id peer.ID, proto libp2pProtocol.ID) (network.Stream, error)
3232
SubscribeConnectionEvents(onConnected, onDisconnected func(network.Network, network.Conn))
33-
ProtectPeer(id peer.ID)
3433
RecordPeerLatency(id peer.ID, rtt time.Duration)
3534
}
3635

@@ -338,7 +337,6 @@ func (s *AuthStatus) AddPeer(ctx context.Context, peerID peer.ID, name, alias st
338337
newPeerConfig.DomainName = awldns.TrimDomainName(newPeerConfig.DisplayName())
339338
s.conf.RemoveBlockedPeer(peerIDStr)
340339
s.conf.UpsertPeer(newPeerConfig)
341-
s.p2p.ProtectPeer(peerID)
342340

343341
go func() {
344342
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)

test_suite_test.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,7 @@ func (ts *TestSuite) initBootstrapNode() {
204204
p2pSrv := p2p.NewP2p(context.Background())
205205
p2pHost, err := p2pSrv.InitHost(hostConfig)
206206
ts.NoError(err)
207-
err = p2pSrv.Bootstrap()
208-
ts.NoError(err)
207+
p2pSrv.Bootstrap()
209208

210209
peerInfo := peer.AddrInfo{ID: p2pHost.ID(), Addrs: p2pHost.Addrs()}
211210
ts.bootstrapAddrs = append(ts.bootstrapAddrs, peerInfo)
@@ -221,15 +220,12 @@ func (ts *TestSuite) initBootstrapNode() {
221220
}
222221

223222
func (ts *TestSuite) ensurePeersAvailableInDHT(peer1, peer2 TestPeer) {
224-
ts.Eventually(func() bool {
225-
err1 := peer1.app.P2p.Bootstrap()
226-
err2 := peer2.app.P2p.Bootstrap()
227-
if err1 != nil || err2 != nil {
228-
return false
229-
}
223+
peer1.app.P2p.Bootstrap()
224+
peer2.app.P2p.Bootstrap()
230225

231-
_, err1 = peer1.app.P2p.FindPeer(context.Background(), peer2.app.P2p.PeerID())
232-
_, err2 = peer2.app.P2p.FindPeer(context.Background(), peer1.app.P2p.PeerID())
226+
ts.Eventually(func() bool {
227+
_, err1 := peer1.app.P2p.FindPeer(context.Background(), peer2.app.P2p.PeerID())
228+
_, err2 := peer2.app.P2p.FindPeer(context.Background(), peer1.app.P2p.PeerID())
233229

234230
return err1 == nil && err2 == nil
235231
}, 20*time.Second, 100*time.Millisecond)

0 commit comments

Comments
 (0)