@libp2p/circuit-relay-v2 2.1.4 → 2.1.5-3bc9769b8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. package/dist/index.min.js +4 -4
  2. package/dist/src/constants.d.ts +0 -5
  3. package/dist/src/constants.d.ts.map +1 -1
  4. package/dist/src/constants.js +0 -5
  5. package/dist/src/constants.js.map +1 -1
  6. package/dist/src/errors.d.ts +22 -0
  7. package/dist/src/errors.d.ts.map +1 -1
  8. package/dist/src/errors.js +22 -0
  9. package/dist/src/errors.js.map +1 -1
  10. package/dist/src/index.d.ts +16 -1
  11. package/dist/src/index.d.ts.map +1 -1
  12. package/dist/src/index.js.map +1 -1
  13. package/dist/src/pb/index.d.ts +12 -1
  14. package/dist/src/pb/index.d.ts.map +1 -1
  15. package/dist/src/pb/index.js +78 -2
  16. package/dist/src/pb/index.js.map +1 -1
  17. package/dist/src/server/index.d.ts.map +1 -1
  18. package/dist/src/server/index.js +19 -10
  19. package/dist/src/server/index.js.map +1 -1
  20. package/dist/src/server/reservation-store.d.ts +5 -9
  21. package/dist/src/server/reservation-store.d.ts.map +1 -1
  22. package/dist/src/server/reservation-store.js +32 -33
  23. package/dist/src/server/reservation-store.js.map +1 -1
  24. package/dist/src/server/reservation-voucher.d.ts +1 -1
  25. package/dist/src/transport/discovery.d.ts +1 -0
  26. package/dist/src/transport/discovery.d.ts.map +1 -1
  27. package/dist/src/transport/discovery.js +38 -8
  28. package/dist/src/transport/discovery.js.map +1 -1
  29. package/dist/src/transport/index.d.ts +0 -6
  30. package/dist/src/transport/index.d.ts.map +1 -1
  31. package/dist/src/transport/index.js.map +1 -1
  32. package/dist/src/transport/listener.d.ts +3 -0
  33. package/dist/src/transport/listener.d.ts.map +1 -1
  34. package/dist/src/transport/listener.js +57 -27
  35. package/dist/src/transport/listener.js.map +1 -1
  36. package/dist/src/transport/reservation-store.d.ts +37 -14
  37. package/dist/src/transport/reservation-store.d.ts.map +1 -1
  38. package/dist/src/transport/reservation-store.js +144 -74
  39. package/dist/src/transport/reservation-store.js.map +1 -1
  40. package/dist/src/transport/transport.d.ts +2 -13
  41. package/dist/src/transport/transport.d.ts.map +1 -1
  42. package/dist/src/transport/transport.js +30 -54
  43. package/dist/src/transport/transport.js.map +1 -1
  44. package/dist/src/utils.d.ts +10 -1
  45. package/dist/src/utils.d.ts.map +1 -1
  46. package/dist/src/utils.js +22 -8
  47. package/dist/src/utils.js.map +1 -1
  48. package/package.json +14 -12
  49. package/src/constants.ts +0 -7
  50. package/src/errors.ts +25 -0
  51. package/src/index.ts +19 -1
  52. package/src/pb/index.proto +20 -1
  53. package/src/pb/index.ts +99 -3
  54. package/src/server/index.ts +21 -11
  55. package/src/server/reservation-store.ts +38 -42
  56. package/src/server/reservation-voucher.ts +2 -2
  57. package/src/transport/discovery.ts +47 -9
  58. package/src/transport/index.ts +0 -7
  59. package/src/transport/listener.ts +75 -35
  60. package/src/transport/reservation-store.ts +209 -95
  61. package/src/transport/transport.ts +34 -76
  62. package/src/utils.ts +29 -8
  63. package/dist/typedoc-urls.json +0 -23
@@ -2,14 +2,14 @@ import { DialError, InvalidMessageError, serviceCapabilities, serviceDependencie
2
2
  import { peerFilter } from '@libp2p/peer-collections'
3
3
  import { peerIdFromMultihash, peerIdFromString } from '@libp2p/peer-id'
4
4
  import { streamToMaConnection } from '@libp2p/utils/stream-to-ma-conn'
5
- import * as mafmt from '@multiformats/mafmt'
6
5
  import { multiaddr } from '@multiformats/multiaddr'
6
+ import { Circuit } from '@multiformats/multiaddr-matcher'
7
7
  import { pbStream } from 'it-protobuf-stream'
8
8
  import * as Digest from 'multiformats/hashes/digest'
9
9
  import { CustomProgressEvent } from 'progress-events'
10
10
  import { CIRCUIT_PROTO_CODE, DEFAULT_DISCOVERY_FILTER_ERROR_RATE, DEFAULT_DISCOVERY_FILTER_SIZE, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js'
11
11
  import { StopMessage, HopMessage, Status } from '../pb/index.js'
12
- import { LimitTracker } from '../utils.js'
12
+ import { CircuitListen, CircuitSearch, LimitTracker } from '../utils.js'
13
13
  import { RelayDiscovery } from './discovery.js'
14
14
  import { createListener } from './listener.js'
15
15
  import { ReservationStore } from './reservation-store.js'
@@ -17,7 +17,7 @@ import type { CircuitRelayTransportComponents, CircuitRelayTransportInit } from
17
17
  import type { Transport, CreateListenerOptions, Listener, Upgrader, ComponentLogger, Logger, Connection, Stream, ConnectionGater, PeerId, PeerStore, OutboundConnectionUpgradeEvents, DialTransportOptions, OpenConnectionProgressEvents } from '@libp2p/interface'
18
18
  import type { AddressManager, ConnectionManager, IncomingStreamData, Registrar, TransportManager } from '@libp2p/interface-internal'
19
19
  import type { Multiaddr } from '@multiformats/multiaddr'
20
- import type { ProgressEvent, ProgressOptions } from 'progress-events'
20
+ import type { ProgressEvent } from 'progress-events'
21
21
 
22
22
  const isValidStop = (request: StopMessage): request is Required<StopMessage> => {
23
23
  if (request.peer == null) {
@@ -33,16 +33,6 @@ const isValidStop = (request: StopMessage): request is Required<StopMessage> =>
33
33
  return true
34
34
  }
35
35
 
36
- interface ConnectOptions extends ProgressOptions<CircuitRelayDialEvents> {
37
- stream: Stream
38
- connection: Connection
39
- destinationPeer: PeerId
40
- destinationAddr: Multiaddr
41
- relayAddr: Multiaddr
42
- ma: Multiaddr
43
- disconnectOnFailure: boolean
44
- }
45
-
46
36
  const defaults = {
47
37
  maxInboundStopStreams: MAX_CONNECTIONS,
48
38
  maxOutboundStopStreams: MAX_CONNECTIONS,
@@ -91,28 +81,23 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
91
81
  this.maxOutboundStopStreams = init.maxOutboundStopStreams ?? defaults.maxOutboundStopStreams
92
82
  this.stopTimeout = init.stopTimeout ?? defaults.stopTimeout
93
83
 
94
- const discoverRelays = init.discoverRelays ?? 0
95
-
96
- if (discoverRelays > 0) {
97
- this.discovery = new RelayDiscovery(components, {
98
- filter: init.discoveryFilter ?? peerFilter(DEFAULT_DISCOVERY_FILTER_SIZE, DEFAULT_DISCOVERY_FILTER_ERROR_RATE)
99
- })
100
- this.discovery.addEventListener('relay:discover', (evt) => {
101
- this.reservationStore.addRelay(evt.detail, 'discovered')
102
- .catch(err => {
84
+ this.discovery = new RelayDiscovery(components, {
85
+ filter: init.discoveryFilter ?? peerFilter(DEFAULT_DISCOVERY_FILTER_SIZE, DEFAULT_DISCOVERY_FILTER_ERROR_RATE)
86
+ })
87
+ this.discovery.addEventListener('relay:discover', (evt) => {
88
+ this.reservationStore.addRelay(evt.detail, 'discovered')
89
+ .catch(err => {
90
+ if (err.name !== 'HadEnoughRelaysError' && err.name !== 'RelayQueueFullError') {
103
91
  this.log.error('could not add discovered relay %p', evt.detail, err)
104
- })
105
- })
106
- }
107
-
92
+ }
93
+ })
94
+ })
108
95
  this.reservationStore = new ReservationStore(components, init)
109
96
  this.reservationStore.addEventListener('relay:not-enough-relays', () => {
110
97
  this.discovery?.startDiscovery()
111
98
  })
112
- this.reservationStore.addEventListener('relay:created-reservation', () => {
113
- if (this.reservationStore.reservationCount() >= discoverRelays) {
114
- this.discovery?.stopDiscovery()
115
- }
99
+ this.reservationStore.addEventListener('relay:found-enough-relays', () => {
100
+ this.discovery?.stopDiscovery()
116
101
  })
117
102
 
118
103
  this.started = false
@@ -184,15 +169,14 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
184
169
  const destinationId = destinationAddr.getPeerId()
185
170
 
186
171
  if (relayId == null || destinationId == null) {
187
- const errMsg = `Circuit relay dial to ${ma.toString()} failed as address did not have peer ids`
188
- this.log.error(errMsg)
189
- throw new DialError(errMsg)
172
+ const errMsg = `ircuit relay dial to ${ma.toString()} failed as address did not have both relay and destination PeerIDs`
173
+ this.log.error(`c${errMsg}`)
174
+ throw new DialError(`C${errMsg}`)
190
175
  }
191
176
 
192
177
  const relayPeer = peerIdFromString(relayId)
193
178
  const destinationPeer = peerIdFromString(destinationId)
194
179
 
195
- let disconnectOnFailure = false
196
180
  const relayConnections = this.connectionManager.getConnections(relayPeer)
197
181
  let relayConnection = relayConnections[0]
198
182
 
@@ -203,7 +187,6 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
203
187
 
204
188
  options.onProgress?.(new CustomProgressEvent('circuit-relay:open-connection'))
205
189
  relayConnection = await this.connectionManager.openConnection(relayPeer, options)
206
- disconnectOnFailure = true
207
190
  } else {
208
191
  options.onProgress?.(new CustomProgressEvent('circuit-relay:reuse-connection'))
209
192
  }
@@ -212,52 +195,22 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
212
195
 
213
196
  try {
214
197
  options.onProgress?.(new CustomProgressEvent('circuit-relay:open-hop-stream'))
215
- stream = await relayConnection.newStream(RELAY_V2_HOP_CODEC)
216
-
217
- return await this.connectV2({
218
- stream,
219
- connection: relayConnection,
220
- destinationPeer,
221
- destinationAddr,
222
- relayAddr,
223
- ma,
224
- disconnectOnFailure,
225
- onProgress: options.onProgress
226
- })
227
- } catch (err: any) {
228
- this.log.error('circuit relay dial to destination %p via relay %p failed', destinationPeer, relayPeer, err)
198
+ stream = await relayConnection.newStream(RELAY_V2_HOP_CODEC, options)
229
199
 
230
- if (stream != null) {
231
- stream.abort(err)
232
- }
233
- disconnectOnFailure && await relayConnection.close()
234
- throw err
235
- }
236
- }
237
-
238
- async connectV2 (
239
- {
240
- stream, connection, destinationPeer,
241
- destinationAddr, relayAddr, ma,
242
- disconnectOnFailure,
243
- onProgress
244
- }: ConnectOptions
245
- ): Promise<Connection> {
246
- try {
247
200
  const pbstr = pbStream(stream)
248
201
  const hopstr = pbstr.pb(HopMessage)
249
202
 
250
- onProgress?.(new CustomProgressEvent('circuit-relay:write-connect-message'))
203
+ options.onProgress?.(new CustomProgressEvent('circuit-relay:write-connect-message'))
251
204
  await hopstr.write({
252
205
  type: HopMessage.Type.CONNECT,
253
206
  peer: {
254
207
  id: destinationPeer.toMultihash().bytes,
255
208
  addrs: [multiaddr(destinationAddr).bytes]
256
209
  }
257
- })
210
+ }, options)
258
211
 
259
- onProgress?.(new CustomProgressEvent('circuit-relay:read-connect-response'))
260
- const status = await hopstr.read()
212
+ options.onProgress?.(new CustomProgressEvent('circuit-relay:read-connect-response'))
213
+ const status = await hopstr.read(options)
261
214
 
262
215
  if (status.status !== Status.OK) {
263
216
  throw new InvalidMessageError(`failed to connect via relay with status ${status?.status?.toString() ?? 'undefined'}`)
@@ -277,12 +230,13 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
277
230
  this.log('new outbound relayed connection %a', maConn.remoteAddr)
278
231
 
279
232
  return await this.upgrader.upgradeOutbound(maConn, {
280
- limits: limits.getLimits(),
281
- onProgress
233
+ ...options,
234
+ limits: limits.getLimits()
282
235
  })
283
236
  } catch (err: any) {
284
- this.log.error(`Circuit relay dial to destination ${destinationPeer.toString()} via relay ${connection.remotePeer.toString()} failed`, err)
285
- disconnectOnFailure && await connection.close()
237
+ this.log.error('circuit relay dial to destination %p via relay %p failed', destinationPeer, relayPeer, err)
238
+ stream?.abort(err)
239
+
286
240
  throw err
287
241
  }
288
242
  }
@@ -305,7 +259,7 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
305
259
  multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
306
260
 
307
261
  return multiaddrs.filter((ma) => {
308
- return mafmt.Circuit.matches(ma)
262
+ return CircuitListen.exactMatch(ma) || CircuitSearch.exactMatch(ma)
309
263
  })
310
264
  }
311
265
 
@@ -313,7 +267,11 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
313
267
  * Filter check for all Multiaddrs that this transport can dial
314
268
  */
315
269
  dialFilter (multiaddrs: Multiaddr[]): Multiaddr[] {
316
- return this.listenFilter(multiaddrs)
270
+ multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
271
+
272
+ return multiaddrs.filter((ma) => {
273
+ return Circuit.exactMatch(ma)
274
+ })
317
275
  }
318
276
 
319
277
  /**
package/src/utils.ts CHANGED
@@ -1,7 +1,10 @@
1
+ import { P2P } from '@multiformats/multiaddr-matcher'
2
+ import { fmt, literal, and } from '@multiformats/multiaddr-matcher/utils'
1
3
  import { anySignal } from 'any-signal'
2
4
  import { CID } from 'multiformats/cid'
3
5
  import { sha256 } from 'multiformats/hashes/sha2'
4
6
  import { DurationLimitError, TransferLimitError } from './errors.js'
7
+ import type { RelayReservation } from './index.js'
5
8
  import type { Limit } from './pb/index.js'
6
9
  import type { ConnectionLimits, LoggerOptions, Stream } from '@libp2p/interface'
7
10
  import type { Source } from 'it-stream-types'
@@ -34,16 +37,18 @@ async function * countStreamBytes (source: Source<Uint8Array | Uint8ArrayList>,
34
37
  }
35
38
  }
36
39
 
37
- export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: AbortSignal, limit: Limit | undefined, options: LoggerOptions): void {
40
+ export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: AbortSignal, reservation: RelayReservation, options: LoggerOptions): void {
38
41
  function abortStreams (err: Error): void {
39
42
  src.abort(err)
40
43
  dst.abort(err)
41
44
  }
42
45
 
43
- const signals = [abortSignal]
46
+ // combine shutdown signal and reservation expiry signal
47
+ const signals = [abortSignal, reservation.signal]
44
48
 
45
- if (limit?.duration != null) {
46
- signals.push(AbortSignal.timeout(limit.duration))
49
+ if (reservation.limit?.duration != null) {
50
+ options.log('limiting relayed connection duration to %dms', reservation.limit.duration)
51
+ signals.push(AbortSignal.timeout(reservation.limit.duration))
47
52
  }
48
53
 
49
54
  const signal = anySignal(signals)
@@ -53,15 +58,16 @@ export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: Abort
53
58
 
54
59
  let dataLimit: { remaining: bigint } | undefined
55
60
 
56
- if (limit?.data != null) {
61
+ if (reservation.limit?.data != null) {
57
62
  dataLimit = {
58
- remaining: limit.data
63
+ remaining: reservation.limit.data
59
64
  }
60
65
  }
61
66
 
62
67
  queueMicrotask(() => {
63
68
  const onAbort = (): void => {
64
- dst.abort(new DurationLimitError(`duration limit of ${limit?.duration} ms exceeded`))
69
+ options.log('relayed connection reached time limit')
70
+ dst.abort(new DurationLimitError(`duration limit of ${reservation.limit?.duration} ms exceeded`))
65
71
  }
66
72
 
67
73
  signal.addEventListener('abort', onAbort, { once: true })
@@ -83,7 +89,8 @@ export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: Abort
83
89
 
84
90
  queueMicrotask(() => {
85
91
  const onAbort = (): void => {
86
- src.abort(new DurationLimitError(`duration limit of ${limit?.duration} ms exceeded`))
92
+ options.log('relayed connection reached time limit')
93
+ src.abort(new DurationLimitError(`duration limit of ${reservation.limit?.duration} ms exceeded`))
87
94
  }
88
95
 
89
96
  signal.addEventListener('abort', onAbort, { once: true })
@@ -185,3 +192,17 @@ export class LimitTracker {
185
192
  return output
186
193
  }
187
194
  }
195
+
196
+ /**
197
+ * A custom matcher that tells us to listen on a particular relay
198
+ */
199
+ export const CircuitListen = fmt(
200
+ and(P2P.matchers[0], literal('p2p-circuit'))
201
+ )
202
+
203
+ /**
204
+ * A custom matcher that tells us to discover available relays
205
+ */
206
+ export const CircuitSearch = fmt(
207
+ literal('p2p-circuit')
208
+ )
@@ -1,23 +0,0 @@
1
- {
2
- "codec": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.Limit.codec.html",
3
- "decode": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.Limit.decode.html",
4
- "encode": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.Limit.encode.html",
5
- "CircuitRelayServerComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServerComponents.html",
6
- "CircuitRelayServerInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServerInit.html",
7
- "CircuitRelayService": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayService.html",
8
- ".:CircuitRelayService": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayService.html",
9
- "CircuitRelayServiceEvents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServiceEvents.html",
10
- ".:CircuitRelayServiceEvents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServiceEvents.html",
11
- "CircuitRelayTransportComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayTransportComponents.html",
12
- "CircuitRelayTransportInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayTransportInit.html",
13
- "Limit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.Limit-1.html",
14
- "RelayDiscoveryComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.RelayDiscoveryComponents.html",
15
- "RelayReservation": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.RelayReservation.html",
16
- ".:RelayReservation": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.RelayReservation.html",
17
- "ServerReservationStoreInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.ServerReservationStoreInit.html",
18
- "TransportReservationStoreInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.TransportReservationStoreInit.html",
19
- "RELAY_V2_HOP_CODEC": "https://libp2p.github.io/js-libp2p/variables/_libp2p_circuit_relay_v2.RELAY_V2_HOP_CODEC.html",
20
- "RELAY_V2_STOP_CODEC": "https://libp2p.github.io/js-libp2p/variables/_libp2p_circuit_relay_v2.RELAY_V2_STOP_CODEC.html",
21
- "circuitRelayServer": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.circuitRelayServer.html",
22
- "circuitRelayTransport": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.circuitRelayTransport.html"
23
- }