@libp2p/circuit-relay-v2 3.2.23-cf9aab5c8 → 3.2.24-a02cb0461

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/index.min.js +1 -1
  2. package/dist/index.min.js.map +4 -4
  3. package/dist/src/index.d.ts +170 -7
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +12 -2
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/server/index.d.ts +41 -45
  8. package/dist/src/server/index.d.ts.map +1 -1
  9. package/dist/src/server/index.js +26 -43
  10. package/dist/src/server/index.js.map +1 -1
  11. package/dist/src/server/reservation-store.d.ts +2 -36
  12. package/dist/src/server/reservation-store.d.ts.map +1 -1
  13. package/dist/src/server/reservation-store.js.map +1 -1
  14. package/dist/src/transport/discovery.d.ts +2 -17
  15. package/dist/src/transport/discovery.d.ts.map +1 -1
  16. package/dist/src/transport/discovery.js +2 -2
  17. package/dist/src/transport/discovery.js.map +1 -1
  18. package/dist/src/transport/index.d.ts +34 -42
  19. package/dist/src/transport/index.d.ts.map +1 -1
  20. package/dist/src/transport/index.js +296 -5
  21. package/dist/src/transport/index.js.map +1 -1
  22. package/dist/src/transport/reservation-store.d.ts +3 -37
  23. package/dist/src/transport/reservation-store.d.ts.map +1 -1
  24. package/dist/src/transport/reservation-store.js +2 -4
  25. package/dist/src/transport/reservation-store.js.map +1 -1
  26. package/dist/src/transport/stream-to-conn.d.ts +19 -0
  27. package/dist/src/transport/stream-to-conn.d.ts.map +1 -0
  28. package/dist/src/transport/stream-to-conn.js +60 -0
  29. package/dist/src/transport/stream-to-conn.js.map +1 -0
  30. package/dist/src/utils.d.ts.map +1 -1
  31. package/dist/src/utils.js +36 -59
  32. package/dist/src/utils.js.map +1 -1
  33. package/package.json +19 -24
  34. package/src/index.ts +207 -8
  35. package/src/server/index.ts +32 -94
  36. package/src/server/reservation-store.ts +2 -42
  37. package/src/transport/discovery.ts +4 -22
  38. package/src/transport/index.ts +344 -46
  39. package/src/transport/reservation-store.ts +6 -44
  40. package/src/transport/stream-to-conn.ts +91 -0
  41. package/src/utils.ts +37 -66
  42. package/dist/src/transport/transport.d.ts +0 -54
  43. package/dist/src/transport/transport.d.ts.map +0 -1
  44. package/dist/src/transport/transport.js +0 -314
  45. package/dist/src/transport/transport.js.map +0 -1
  46. package/src/transport/transport.ts +0 -380
@@ -1,8 +1,8 @@
1
1
  import { publicKeyToProtobuf } from '@libp2p/crypto/keys'
2
2
  import { peerIdFromMultihash } from '@libp2p/peer-id'
3
3
  import { RecordEnvelope } from '@libp2p/peer-record'
4
+ import { pbStream } from '@libp2p/utils'
4
5
  import { multiaddr } from '@multiformats/multiaddr'
5
- import { pbStream } from 'it-protobuf-stream'
6
6
  import { TypedEventEmitter, setMaxListeners } from 'main-event'
7
7
  import * as Digest from 'multiformats/hashes/digest'
8
8
  import {
@@ -18,50 +18,15 @@ import { HopMessage, Status, StopMessage } from '../pb/index.js'
18
18
  import { createLimitedRelay } from '../utils.js'
19
19
  import { ReservationStore } from './reservation-store.js'
20
20
  import { ReservationVoucherRecord } from './reservation-voucher.js'
21
- import type { ReservationStoreInit } from './reservation-store.js'
22
- import type { CircuitRelayService, RelayReservation } from '../index.js'
21
+ import type { CircuitRelayServerComponents, CircuitRelayServerInit, CircuitRelayService, RelayReservation } from '../index.js'
23
22
  import type { Reservation } from '../pb/index.js'
24
- import type { ComponentLogger, Logger, Connection, Stream, ConnectionGater, PeerId, PeerStore, Startable, PrivateKey, Metrics, AbortOptions, IncomingStreamData } from '@libp2p/interface'
25
- import type { AddressManager, ConnectionManager, Registrar } from '@libp2p/interface-internal'
23
+ import type { Logger, Connection, Stream, PeerId, Startable, AbortOptions } from '@libp2p/interface'
26
24
  import type { PeerMap } from '@libp2p/peer-collections'
25
+ import type { ProtobufStream } from '@libp2p/utils'
27
26
  import type { Multiaddr } from '@multiformats/multiaddr'
28
- import type { ProtobufStream } from 'it-protobuf-stream'
29
27
 
30
28
  const isRelayAddr = (ma: Multiaddr): boolean => ma.protoCodes().includes(CIRCUIT_PROTO_CODE)
31
29
 
32
- export interface CircuitRelayServerInit {
33
- /**
34
- * Incoming hop requests must complete within this time in ms otherwise
35
- * the stream will be reset
36
- *
37
- * @default 30000
38
- */
39
- hopTimeout?: number
40
-
41
- /**
42
- * Configuration of reservations
43
- */
44
- reservations?: ReservationStoreInit
45
-
46
- /**
47
- * The maximum number of simultaneous HOP inbound streams that can be open at once
48
- */
49
- maxInboundHopStreams?: number
50
-
51
- /**
52
- * The maximum number of simultaneous HOP outbound streams that can be open at once
53
- */
54
- maxOutboundHopStreams?: number
55
-
56
- /**
57
- * The maximum number of simultaneous STOP outbound streams that can be open at
58
- * once.
59
- *
60
- * @default 300
61
- */
62
- maxOutboundStopStreams?: number
63
- }
64
-
65
30
  export interface HopProtocolOptions {
66
31
  connection: Connection
67
32
  request: HopMessage
@@ -73,18 +38,6 @@ export interface StopOptions {
73
38
  request: StopMessage
74
39
  }
75
40
 
76
- export interface CircuitRelayServerComponents {
77
- registrar: Registrar
78
- peerStore: PeerStore
79
- addressManager: AddressManager
80
- peerId: PeerId
81
- privateKey: PrivateKey
82
- connectionManager: ConnectionManager
83
- connectionGater: ConnectionGater
84
- logger: ComponentLogger
85
- metrics?: Metrics
86
- }
87
-
88
41
  export interface RelayServerEvents {
89
42
  'relay:reservation': CustomEvent<RelayReservation>
90
43
  'relay:advert:success': CustomEvent<unknown>
@@ -95,14 +48,8 @@ const defaults = {
95
48
  maxOutboundStopStreams: MAX_CONNECTIONS
96
49
  }
97
50
 
98
- class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements Startable, CircuitRelayService {
99
- private readonly registrar: Registrar
100
- private readonly peerStore: PeerStore
101
- private readonly addressManager: AddressManager
102
- private readonly peerId: PeerId
103
- private readonly privateKey: PrivateKey
104
- private readonly connectionManager: ConnectionManager
105
- private readonly connectionGater: ConnectionGater
51
+ export class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements Startable, CircuitRelayService {
52
+ private readonly components: CircuitRelayServerComponents
106
53
  private readonly reservationStore: ReservationStore
107
54
  private started: boolean
108
55
  private readonly hopTimeout: number
@@ -119,13 +66,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
119
66
  super()
120
67
 
121
68
  this.log = components.logger.forComponent('libp2p:circuit-relay:server')
122
- this.registrar = components.registrar
123
- this.peerStore = components.peerStore
124
- this.addressManager = components.addressManager
125
- this.peerId = components.peerId
126
- this.privateKey = components.privateKey
127
- this.connectionManager = components.connectionManager
128
- this.connectionGater = components.connectionGater
69
+ this.components = components
129
70
  this.started = false
130
71
  this.hopTimeout = init?.hopTimeout ?? DEFAULT_HOP_TIMEOUT
131
72
  this.maxInboundHopStreams = init.maxInboundHopStreams
@@ -135,6 +76,8 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
135
76
 
136
77
  this.shutdownController = new AbortController()
137
78
  setMaxListeners(Infinity, this.shutdownController.signal)
79
+
80
+ this.onHop = this.onHop.bind(this)
138
81
  }
139
82
 
140
83
  readonly [Symbol.toStringTag] = '@libp2p/circuit-relay-v2-server'
@@ -151,11 +94,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
151
94
  return
152
95
  }
153
96
 
154
- await this.registrar.handle(RELAY_V2_HOP_CODEC, (data) => {
155
- void this.onHop(data).catch(err => {
156
- this.log.error(err)
157
- })
158
- }, {
97
+ await this.components.registrar.handle(RELAY_V2_HOP_CODEC, this.onHop, {
159
98
  maxInboundStreams: this.maxInboundHopStreams,
160
99
  maxOutboundStreams: this.maxOutboundHopStreams,
161
100
  runOnLimitedConnection: true
@@ -170,16 +109,19 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
170
109
  async stop (): Promise<void> {
171
110
  this.reservationStore.clear()
172
111
  this.shutdownController.abort()
173
- await this.registrar.unhandle(RELAY_V2_HOP_CODEC)
112
+ await this.components.registrar.unhandle(RELAY_V2_HOP_CODEC)
174
113
 
175
114
  this.started = false
176
115
  }
177
116
 
178
- async onHop ({ connection, stream }: IncomingStreamData): Promise<void> {
117
+ async onHop (stream: Stream, connection: Connection): Promise<void> {
179
118
  this.log('received circuit v2 hop protocol stream from %p', connection.remotePeer)
180
119
 
120
+ const signal = AbortSignal.timeout(this.hopTimeout)
121
+ setMaxListeners(Infinity, signal)
122
+
181
123
  const options = {
182
- signal: AbortSignal.timeout(this.hopTimeout)
124
+ signal
183
125
  }
184
126
  const pbstr = pbStream(stream)
185
127
 
@@ -229,7 +171,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
229
171
  return
230
172
  }
231
173
 
232
- if ((await this.connectionGater.denyInboundRelayReservation?.(connection.remotePeer)) === true) {
174
+ if ((await this.components.connectionGater.denyInboundRelayReservation?.(connection.remotePeer)) === true) {
233
175
  this.log.error('reservation for %p denied by connection gater', connection.remotePeer)
234
176
  await hopstr.write({ type: HopMessage.Type.STATUS, status: Status.PERMISSION_DENIED }, options)
235
177
  return
@@ -247,12 +189,12 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
247
189
  // result.expire is non-null if `ReservationStore.reserve` returns with status == OK
248
190
  if (result.expire != null) {
249
191
  const ttl = (result.expire * 1000) - Date.now()
250
- await this.peerStore.merge(connection.remotePeer, {
192
+ await this.components.peerStore.merge(connection.remotePeer, {
251
193
  tags: {
252
194
  [RELAY_SOURCE_TAG]: { value: 1, ttl },
253
195
  [KEEP_ALIVE_SOURCE_TAG]: { value: 1, ttl }
254
196
  }
255
- })
197
+ }, options)
256
198
  }
257
199
 
258
200
  await hopstr.write({
@@ -262,17 +204,20 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
262
204
  limit: this.reservationStore.get(connection.remotePeer)?.limit
263
205
  }, options)
264
206
  this.log('sent confirmation response to %s', connection.remotePeer)
207
+
208
+ // close writable end of stream
209
+ await hopstr.unwrap().unwrap().close(options)
265
210
  } catch (err) {
266
211
  this.log.error('failed to send confirmation response to %p - %e', connection.remotePeer, err)
267
212
  this.reservationStore.removeReservation(connection.remotePeer)
268
213
 
269
214
  try {
270
- await this.peerStore.merge(connection.remotePeer, {
215
+ await this.components.peerStore.merge(connection.remotePeer, {
271
216
  tags: {
272
217
  [RELAY_SOURCE_TAG]: undefined,
273
218
  [KEEP_ALIVE_SOURCE_TAG]: undefined
274
219
  }
275
- })
220
+ }, options)
276
221
  } catch (err) {
277
222
  this.log.error('failed to untag relay source peer %p - %e', connection.remotePeer, err)
278
223
  }
@@ -285,7 +230,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
285
230
  ): Promise<Reservation> {
286
231
  const addrs = []
287
232
 
288
- for (const relayAddr of this.addressManager.getAddresses()) {
233
+ for (const relayAddr of this.components.addressManager.getAddresses()) {
289
234
  if (relayAddr.toString().includes('/p2p-circuit')) {
290
235
  continue
291
236
  }
@@ -295,9 +240,9 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
295
240
 
296
241
  const envelope = await RecordEnvelope.seal(new ReservationVoucherRecord({
297
242
  peer: remotePeer,
298
- relay: this.peerId,
243
+ relay: this.components.peerId,
299
244
  expiration: expire
300
- }), this.privateKey)
245
+ }), this.components.privateKey)
301
246
 
302
247
  return {
303
248
  addrs,
@@ -307,7 +252,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
307
252
  payloadType: envelope.payloadType,
308
253
  payload: {
309
254
  peer: remotePeer.toMultihash().bytes,
310
- relay: this.peerId.toMultihash().bytes,
255
+ relay: this.components.peerId.toMultihash().bytes,
311
256
  expiration: expire
312
257
  },
313
258
  signature: envelope.signature
@@ -350,13 +295,13 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
350
295
  return
351
296
  }
352
297
 
353
- if ((await this.connectionGater.denyOutboundRelayedConnection?.(connection.remotePeer, dstPeer)) === true) {
298
+ if ((await this.components.connectionGater.denyOutboundRelayedConnection?.(connection.remotePeer, dstPeer)) === true) {
354
299
  this.log.error('hop connect for %p to %p denied by connection gater', connection.remotePeer, dstPeer)
355
300
  await hopstr.write({ type: HopMessage.Type.STATUS, status: Status.PERMISSION_DENIED }, options)
356
301
  return
357
302
  }
358
303
 
359
- const connections = this.connectionManager.getConnections(dstPeer)
304
+ const connections = this.components.connectionManager.getConnections(dstPeer)
360
305
 
361
306
  if (connections.length === 0) {
362
307
  this.log('hop connect denied for destination peer %p not having a connection for %p as there is no destination connection', dstPeer, connection.remotePeer)
@@ -389,12 +334,11 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
389
334
  status: Status.OK,
390
335
  limit: reservation?.limit
391
336
  }, options)
392
- const sourceStream = stream.unwrap()
393
337
 
394
338
  this.log('connection from %p to %p established - merging streams', connection.remotePeer, dstPeer)
395
339
 
396
340
  // Short circuit the two streams to create the relayed connection
397
- createLimitedRelay(sourceStream, destinationStream, this.shutdownController.signal, reservation, {
341
+ createLimitedRelay(stream.unwrap(), destinationStream, this.shutdownController.signal, reservation, {
398
342
  log: this.log
399
343
  })
400
344
  }
@@ -404,7 +348,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
404
348
  */
405
349
  async stopHop ({ connection, request }: StopOptions, options: AbortOptions): Promise<Stream | undefined> {
406
350
  this.log('starting circuit relay v2 stop request to %s', connection.remotePeer)
407
- const stream = await connection.newStream([RELAY_V2_STOP_CODEC], {
351
+ const stream = await connection.newStream(RELAY_V2_STOP_CODEC, {
408
352
  maxOutboundStreams: this.maxOutboundStopStreams,
409
353
  runOnLimitedConnection: true,
410
354
  ...options
@@ -439,9 +383,3 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
439
383
  return this.reservationStore.reservations
440
384
  }
441
385
  }
442
-
443
- export function circuitRelayServer (init: CircuitRelayServerInit = {}): (components: CircuitRelayServerComponents) => CircuitRelayService {
444
- return (components) => {
445
- return new CircuitRelayServer(components, init)
446
- }
447
- }
@@ -2,7 +2,7 @@ import { trackedPeerMap } from '@libp2p/peer-collections'
2
2
  import { retimeableSignal } from 'retimeable-signal'
3
3
  import { DEFAULT_DATA_LIMIT, DEFAULT_DURATION_LIMIT, DEFAULT_MAX_RESERVATION_STORE_SIZE, DEFAULT_MAX_RESERVATION_TTL } from '../constants.js'
4
4
  import { Status } from '../pb/index.js'
5
- import type { RelayReservation } from '../index.js'
5
+ import type { RelayReservation, ServerReservationStoreInit } from '../index.js'
6
6
  import type { Limit } from '../pb/index.js'
7
7
  import type { ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
8
8
  import type { PeerMap } from '@libp2p/peer-collections'
@@ -15,46 +15,6 @@ export interface ReservationStoreComponents {
15
15
  metrics?: Metrics
16
16
  }
17
17
 
18
- export interface ReservationStoreInit {
19
- /**
20
- * maximum number of reservations allowed
21
- *
22
- * @default 15
23
- */
24
- maxReservations?: number
25
-
26
- /**
27
- * interval after which stale reservations are cleared
28
- *
29
- * @default 300000
30
- */
31
- reservationClearInterval?: number
32
-
33
- /**
34
- * apply default relay limits to a new reservation
35
- *
36
- * @default true
37
- */
38
- applyDefaultLimit?: boolean
39
-
40
- /**
41
- * reservation ttl
42
- *
43
- * @default 7200000
44
- */
45
- reservationTtl?: number
46
-
47
- /**
48
- * The maximum time a relayed connection can be open for
49
- */
50
- defaultDurationLimit?: number
51
-
52
- /**
53
- * The maximum amount of data allowed to be transferred over a relayed connection
54
- */
55
- defaultDataLimit?: bigint
56
- }
57
-
58
18
  export class ReservationStore {
59
19
  public readonly reservations: PeerMap<RelayReservation>
60
20
  private readonly maxReservations: number
@@ -64,7 +24,7 @@ export class ReservationStore {
64
24
  private readonly defaultDataLimit: bigint
65
25
  private readonly log: Logger
66
26
 
67
- constructor (components: ReservationStoreComponents, init: ReservationStoreInit = {}) {
27
+ constructor (components: ReservationStoreComponents, init: ServerReservationStoreInit = {}) {
68
28
  this.log = components.logger.forComponent('libp2p:circuit-relay:server:reservation-store')
69
29
  this.maxReservations = init.maxReservations ?? DEFAULT_MAX_RESERVATION_STORE_SIZE
70
30
  this.applyDefaultLimit = init.applyDefaultLimit !== false
@@ -1,30 +1,12 @@
1
- import { PeerQueue } from '@libp2p/utils/peer-queue'
1
+ import { PeerQueue } from '@libp2p/utils'
2
2
  import { anySignal } from 'any-signal'
3
3
  import { TypedEventEmitter, setMaxListeners } from 'main-event'
4
4
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
5
5
  import {
6
6
  RELAY_V2_HOP_CODEC
7
7
  } from '../constants.js'
8
- import type { ComponentLogger, Libp2pEvents, Logger, Peer, PeerId, PeerInfo, PeerStore, Startable, TopologyFilter, TypedEventTarget } from '@libp2p/interface'
9
- import type { ConnectionManager, RandomWalk, Registrar, TransportManager } from '@libp2p/interface-internal'
10
-
11
- export interface RelayDiscoveryEvents {
12
- 'relay:discover': CustomEvent<PeerId>
13
- }
14
-
15
- export interface RelayDiscoveryComponents {
16
- peerStore: PeerStore
17
- connectionManager: ConnectionManager
18
- transportManager: TransportManager
19
- registrar: Registrar
20
- logger: ComponentLogger
21
- randomWalk: RandomWalk
22
- events: TypedEventTarget<Libp2pEvents>
23
- }
24
-
25
- export interface RelayDiscoveryInit {
26
- filter?: TopologyFilter
27
- }
8
+ import type { RelayDiscoveryComponents, RelayDiscoveryEvents, RelayDiscoveryInit } from '../index.ts'
9
+ import type { Logger, Peer, PeerId, PeerInfo, Startable, TopologyFilter } from '@libp2p/interface'
28
10
 
29
11
  /**
30
12
  * ReservationManager automatically makes a circuit v2 reservation on any connected
@@ -221,7 +203,7 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
221
203
  }
222
204
 
223
205
  onPeer (evt: CustomEvent<PeerInfo>): void {
224
- this.log.trace('maybe dialing discovered peer %p - %e', evt.detail.id)
206
+ this.log.trace('maybe dialing discovered peer %p', evt.detail.id)
225
207
 
226
208
  this.maybeDialPeer(evt)
227
209
  .catch(err => {