Skip to content

Commit

Permalink
fix: emit 'listening' when relays change (#2758)
Browse files Browse the repository at this point in the history
To signal to the rest of libp2p that our addresses are changing, emit the `listening` event when relays go away or our reservation expires.

Also remove the old tags on startup to ensure we don't reconnect to old relays as the spec says the reservation is only valid while we are connected.
  • Loading branch information
achingbrain authored Oct 9, 2024
1 parent 29b47ad commit 0d326d1
Show file tree
Hide file tree
Showing 13 changed files with 298 additions and 143 deletions.
9 changes: 5 additions & 4 deletions packages/integration-tests/test/circuit-relay.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,15 +624,16 @@ describe('circuit-relay', () => {
return circuitMultiaddrs.length > 0
})

expect(circuitListener[0].relayStore.listenerCount('relay:removed')).to.equal(2)
expect(circuitListener[0].reservationStore.listenerCount('relay:removed')).to.equal(2)

// remove one listener
await local.hangUp(relay1.peerId)
// stop the listener
await circuitListener[0].close()

// not using the relay any more
await notUsingAsRelay(local, relay1)

// expect 1 listener
expect(circuitListener[0].relayStore.listenerCount('relay:removed')).to.equal(1)
expect(circuitListener[0].reservationStore.listenerCount('relay:removed')).to.equal(1)
})

it('should mark an outgoing relayed connection as limited', async () => {
Expand Down
30 changes: 24 additions & 6 deletions packages/interface/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,10 @@ export interface Libp2pEvents<T extends ServiceMap = ServiceMap> {
'peer:connect': CustomEvent<PeerId>

/**
* This event will be triggered any time we are disconnected from another peer, regardless of
* the circumstances of that disconnection. If we happen to have multiple connections to a
* peer, this event will **only** be triggered when the last connection is closed.
* This event will be triggered any time we are disconnected from another
* peer, regardless of the circumstances of that disconnection. If we happen
* to have multiple connections to a peer, this event will **only** be
* triggered when the last connection is closed.
*
* @example
*
Expand All @@ -177,9 +178,26 @@ export interface Libp2pEvents<T extends ServiceMap = ServiceMap> {
'peer:disconnect': CustomEvent<PeerId>

/**
* This event is dispatched after a remote peer has successfully responded to the identify
* protocol. Note that for this to be emitted, both peers must have an identify service
* configured.
* When a peer tagged with `keep-alive` disconnects, we will make multiple
* attempts to reconnect to it with a backoff factor (see the connection
* manager settings for details). If these all fail, the `keep-alive` tag will
* be removed and this event will be emitted.
*
* @example
*
* ```TypeScript
* libp2p.addEventListener('peer:reconnect-failure', (event) => {
* const peerId = event.detail
* // ...
* })
* ```
*/
'peer:reconnect-failure': CustomEvent<PeerId>

/**
* This event is dispatched after a remote peer has successfully responded to
* the identify protocol. Note that for this to be emitted, both peers must
* have an identify service configured.
*
* @example
*
Expand Down
10 changes: 8 additions & 2 deletions packages/libp2p/src/connection-manager/reconnect-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class ReconnectQueue implements Startable {
private readonly retryInterval?: number
private readonly backoffFactor?: number
private readonly connectionManager: ConnectionManager
private readonly events: TypedEventTarget<Libp2pEvents>

constructor (components: ReconnectQueueComponents, init: ReconnectQueueInit = {}) {
this.log = components.logger.forComponent('libp2p:reconnect-queue')
Expand All @@ -47,11 +48,12 @@ export class ReconnectQueue implements Startable {
this.retries = init.retries ?? 5
this.backoffFactor = init.backoffFactor
this.retryInterval = init.retryInterval
this.events = components.events

components.events.addEventListener('peer:disconnect', (evt) => {
this.maybeReconnect(evt.detail)
.catch(err => {
this.log.error('failed to maybe reconnect to %p', evt.detail, err)
this.log.error('failed to maybe reconnect to %p - %e', evt.detail, err)
})
})
}
Expand Down Expand Up @@ -82,7 +84,7 @@ export class ReconnectQueue implements Startable {
signal: options?.signal
})
} catch (err) {
this.log('reconnecting to %p attempt %d of %d failed', peerId, attempt, this.retries, err)
this.log('reconnecting to %p attempt %d of %d failed - %e', peerId, attempt, this.retries, err)
throw err
}
}, {
Expand All @@ -108,6 +110,10 @@ export class ReconnectQueue implements Startable {
await this.peerStore.merge(peerId, {
tags
})

this.events.safeDispatchEvent('peer:reconnect-failure', {
detail: peerId
})
})
.catch(async err => {
this.log.error('failed to remove keep-alive tag from %p - %e', peerId, err)
Expand Down
1 change: 0 additions & 1 deletion packages/transport-circuit-relay-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
"it-protobuf-stream": "^1.1.3",
"it-stream-types": "^2.0.1",
"multiformats": "^13.1.0",
"p-defer": "^4.0.1",
"progress-events": "^1.0.0",
"protons-runtime": "^5.4.0",
"race-signal": "^1.0.2",
Expand Down
5 changes: 3 additions & 2 deletions packages/transport-circuit-relay-v2/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export const DEFAULT_MAX_RESERVATION_TTL = 2 * 60 * minute
export const DEFAULT_RESERVATION_CONCURRENCY = 1

/**
* How long to wait for a reservation attempt to finsih
* How long to wait for a reservation attempt to finish
*/
export const DEFAULT_RESERVATION_COMPLETION_TIMEOUT = 1000
export const DEFAULT_RESERVATION_COMPLETION_TIMEOUT = 2000

/**
* How long to let the reservation attempt queue to grow
Expand All @@ -43,6 +43,7 @@ export const RELAY_SOURCE_TAG = 'circuit-relay-source'
export const RELAY_TAG = 'circuit-relay-relay'

export const KEEP_ALIVE_TAG = `${KEEP_ALIVE}-circuit-relay`
export const KEEP_ALIVE_SOURCE_TAG = `${KEEP_ALIVE}-circuit-relay-source`

// circuit v2 connection limits
// https://github.com/libp2p/go-libp2p/blob/master/p2p/protocol/circuitv2/relay/resources.go#L61-L66
Expand Down
4 changes: 2 additions & 2 deletions packages/transport-circuit-relay-v2/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ export interface CircuitRelayService extends TypedEventEmitter<CircuitRelayServi

export { circuitRelayServer } from './server/index.js'
export type { CircuitRelayServerInit, CircuitRelayServerComponents } from './server/index.js'
export type { ReservationStoreInit } from './server/reservation-store.js'
export type { ReservationStoreInit as ServerReservationStoreInit } from './server/reservation-store.js'
export { circuitRelayTransport } from './transport/index.js'
export type { RelayDiscoveryComponents } from './transport/discovery.js'
export type { RelayStoreInit } from './transport/reservation-store.js'
export type { ReservationStoreInit as TransportReservationStoreInit } from './transport/reservation-store.js'
export type { CircuitRelayTransportInit, CircuitRelayTransportComponents } from './transport/index.js'

export {
Expand Down
Loading

0 comments on commit 0d326d1

Please sign in to comment.