libp2p 0.46.16 → 0.46.17

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 (72) hide show
  1. package/README.md +20 -63
  2. package/dist/index.min.js +29 -29
  3. package/dist/src/autonat/index.d.ts.map +1 -1
  4. package/dist/src/autonat/index.js +3 -11
  5. package/dist/src/autonat/index.js.map +1 -1
  6. package/dist/src/circuit-relay/server/index.d.ts.map +1 -1
  7. package/dist/src/circuit-relay/server/index.js +2 -7
  8. package/dist/src/circuit-relay/server/index.js.map +1 -1
  9. package/dist/src/circuit-relay/transport/discovery.d.ts.map +1 -1
  10. package/dist/src/circuit-relay/transport/discovery.js +1 -0
  11. package/dist/src/circuit-relay/transport/discovery.js.map +1 -1
  12. package/dist/src/circuit-relay/transport/listener.d.ts.map +1 -1
  13. package/dist/src/circuit-relay/transport/listener.js +3 -17
  14. package/dist/src/circuit-relay/transport/listener.js.map +1 -1
  15. package/dist/src/connection/index.d.ts.map +1 -1
  16. package/dist/src/connection/index.js +5 -6
  17. package/dist/src/connection/index.js.map +1 -1
  18. package/dist/src/connection-manager/dial-queue.d.ts +4 -0
  19. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
  20. package/dist/src/connection-manager/dial-queue.js +37 -7
  21. package/dist/src/connection-manager/dial-queue.js.map +1 -1
  22. package/dist/src/connection-manager/index.d.ts.map +1 -1
  23. package/dist/src/connection-manager/index.js +7 -5
  24. package/dist/src/connection-manager/index.js.map +1 -1
  25. package/dist/src/connection-manager/utils.d.ts.map +1 -1
  26. package/dist/src/connection-manager/utils.js +3 -11
  27. package/dist/src/connection-manager/utils.js.map +1 -1
  28. package/dist/src/dcutr/dcutr.d.ts +0 -5
  29. package/dist/src/dcutr/dcutr.d.ts.map +1 -1
  30. package/dist/src/dcutr/dcutr.js +4 -28
  31. package/dist/src/dcutr/dcutr.js.map +1 -1
  32. package/dist/src/dcutr/utils.d.ts +8 -0
  33. package/dist/src/dcutr/utils.d.ts.map +1 -0
  34. package/dist/src/dcutr/utils.js +27 -0
  35. package/dist/src/dcutr/utils.js.map +1 -0
  36. package/dist/src/fetch/index.d.ts.map +1 -1
  37. package/dist/src/fetch/index.js +2 -6
  38. package/dist/src/fetch/index.js.map +1 -1
  39. package/dist/src/identify/consts.d.ts +1 -1
  40. package/dist/src/identify/identify.d.ts.map +1 -1
  41. package/dist/src/identify/identify.js +55 -47
  42. package/dist/src/identify/identify.js.map +1 -1
  43. package/dist/src/libp2p.d.ts.map +1 -1
  44. package/dist/src/libp2p.js +3 -7
  45. package/dist/src/libp2p.js.map +1 -1
  46. package/dist/src/registrar.d.ts +7 -6
  47. package/dist/src/registrar.d.ts.map +1 -1
  48. package/dist/src/registrar.js +16 -41
  49. package/dist/src/registrar.js.map +1 -1
  50. package/dist/src/upgrader.d.ts.map +1 -1
  51. package/dist/src/upgrader.js +3 -11
  52. package/dist/src/upgrader.js.map +1 -1
  53. package/dist/src/version.d.ts +1 -1
  54. package/dist/src/version.js +1 -1
  55. package/package.json +23 -24
  56. package/src/autonat/index.ts +3 -9
  57. package/src/circuit-relay/server/index.ts +2 -6
  58. package/src/circuit-relay/transport/discovery.ts +1 -0
  59. package/src/circuit-relay/transport/listener.ts +3 -21
  60. package/src/connection/index.ts +6 -5
  61. package/src/connection-manager/dial-queue.ts +46 -6
  62. package/src/connection-manager/index.ts +7 -5
  63. package/src/connection-manager/utils.ts +3 -9
  64. package/src/dcutr/dcutr.ts +4 -35
  65. package/src/dcutr/utils.ts +33 -0
  66. package/src/fetch/index.ts +2 -5
  67. package/src/identify/identify.ts +63 -47
  68. package/src/libp2p.ts +3 -6
  69. package/src/pnet/README.md +0 -4
  70. package/src/registrar.ts +19 -50
  71. package/src/upgrader.ts +3 -9
  72. package/src/version.ts +1 -1
@@ -1,6 +1,6 @@
1
- import { setMaxListeners } from 'events'
2
1
  import { symbol } from '@libp2p/interface/connection'
3
2
  import { CodeError } from '@libp2p/interface/errors'
3
+ import { setMaxListeners } from '@libp2p/interface/events'
4
4
  import { logger } from '@libp2p/logger'
5
5
  import type { AbortOptions } from '@libp2p/interface'
6
6
  import type { Direction, Connection, Stream, ConnectionTimeline, ConnectionStatus, NewStreamOptions } from '@libp2p/interface/connection'
@@ -93,6 +93,10 @@ export class ConnectionImpl implements Connection {
93
93
  this.encryption = init.encryption
94
94
  this.transient = init.transient ?? false
95
95
 
96
+ if (this.remoteAddr.getPeerId() == null) {
97
+ this.remoteAddr = this.remoteAddr.encapsulate(`/p2p/${this.remotePeer}`)
98
+ }
99
+
96
100
  this._newStream = newStream
97
101
  this._close = close
98
102
  this._abort = abort
@@ -152,10 +156,7 @@ export class ConnectionImpl implements Connection {
152
156
 
153
157
  options.signal = options?.signal ?? AbortSignal.timeout(CLOSE_TIMEOUT)
154
158
 
155
- try {
156
- // fails on node < 15.4
157
- setMaxListeners?.(Infinity, options.signal)
158
- } catch { }
159
+ setMaxListeners(Infinity, options.signal)
159
160
 
160
161
  try {
161
162
  log.trace('closing all streams')
@@ -1,6 +1,7 @@
1
- import { setMaxListeners } from 'events'
2
1
  import { AbortError, CodeError } from '@libp2p/interface/errors'
2
+ import { setMaxListeners } from '@libp2p/interface/events'
3
3
  import { logger } from '@libp2p/logger'
4
+ import { PeerMap } from '@libp2p/peer-collections'
4
5
  import { defaultAddressSort } from '@libp2p/utils/address-sort'
5
6
  import { type Multiaddr, type Resolver, resolvers } from '@multiformats/multiaddr'
6
7
  import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
@@ -35,6 +36,7 @@ export interface PendingDialTarget {
35
36
 
36
37
  export interface DialOptions extends AbortOptions {
37
38
  priority?: number
39
+ force?: boolean
38
40
  }
39
41
 
40
42
  interface PendingDialInternal extends PendingDial {
@@ -48,6 +50,7 @@ interface DialerInit {
48
50
  maxParallelDialsPerPeer?: number
49
51
  dialTimeout?: number
50
52
  resolvers?: Record<string, Resolver>
53
+ connections?: PeerMap<Connection[]>
51
54
  }
52
55
 
53
56
  const defaultOptions = {
@@ -83,12 +86,14 @@ export class DialQueue {
83
86
  private readonly inProgressDialCount?: Metric
84
87
  private readonly pendingDialCount?: Metric
85
88
  private readonly shutDownController: AbortController
89
+ private readonly connections: PeerMap<Connection[]>
86
90
 
87
91
  constructor (components: DialQueueComponents, init: DialerInit = {}) {
88
92
  this.addressSorter = init.addressSorter ?? defaultOptions.addressSorter
89
93
  this.maxPeerAddrsToDial = init.maxPeerAddrsToDial ?? defaultOptions.maxPeerAddrsToDial
90
94
  this.maxParallelDialsPerPeer = init.maxParallelDialsPerPeer ?? defaultOptions.maxParallelDialsPerPeer
91
95
  this.dialTimeout = init.dialTimeout ?? defaultOptions.dialTimeout
96
+ this.connections = init.connections ?? new PeerMap()
92
97
 
93
98
  this.peerId = components.peerId
94
99
  this.peerStore = components.peerStore
@@ -96,10 +101,7 @@ export class DialQueue {
96
101
  this.transportManager = components.transportManager
97
102
  this.shutDownController = new AbortController()
98
103
 
99
- try {
100
- // This emitter gets listened to a lot
101
- setMaxListeners?.(Infinity, this.shutDownController.signal)
102
- } catch {}
104
+ setMaxListeners(Infinity, this.shutDownController.signal)
103
105
 
104
106
  this.pendingDialCount = components.metrics?.registerMetric('libp2p_dialler_pending_dials')
105
107
  this.inProgressDialCount = components.metrics?.registerMetric('libp2p_dialler_in_progress_dials')
@@ -190,6 +192,23 @@ export class DialQueue {
190
192
  throw err
191
193
  }
192
194
 
195
+ // make sure we don't have an existing connection to any of the addresses we
196
+ // are about to dial
197
+ let existingConnection = Array.from(this.connections.values()).flat().find(conn => {
198
+ if (options.force === true) {
199
+ return false
200
+ }
201
+
202
+ return addrsToDial.find(addr => {
203
+ return addr.multiaddr.equals(conn.remoteAddr)
204
+ })
205
+ })
206
+
207
+ if (existingConnection != null) {
208
+ log('already connected to %a', existingConnection.remoteAddr)
209
+ return existingConnection
210
+ }
211
+
193
212
  // ready to dial, all async work finished - make sure we don't have any
194
213
  // pending dials in progress for this peer or set of multiaddrs
195
214
  const existingDial = this.pendingDials.find(dial => {
@@ -260,7 +279,28 @@ export class DialQueue {
260
279
  // let other dials join this one
261
280
  this.pendingDials.push(pendingDial)
262
281
 
263
- return pendingDial.promise
282
+ const connection = await pendingDial.promise
283
+
284
+ // we may have been dialing a multiaddr without a peer id attached but by
285
+ // this point we have upgraded the connection so the remote peer information
286
+ // should be available - check again that we don't already have a connection
287
+ // to the remote multiaddr
288
+ existingConnection = Array.from(this.connections.values()).flat().find(conn => {
289
+ if (options.force === true) {
290
+ return false
291
+ }
292
+
293
+ return conn.id !== connection.id && conn.remoteAddr.equals(connection.remoteAddr)
294
+ })
295
+
296
+ if (existingConnection != null) {
297
+ log('already connected to %a', existingConnection.remoteAddr)
298
+ await connection.close()
299
+ return existingConnection
300
+ }
301
+
302
+ log('connection opened to %a', connection.remoteAddr)
303
+ return connection
264
304
  }
265
305
 
266
306
  private createDialAbortControllers (userSignal?: AbortSignal): ClearableSignal {
@@ -261,7 +261,8 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
261
261
  dialTimeout: init.dialTimeout ?? DIAL_TIMEOUT,
262
262
  resolvers: init.resolvers ?? {
263
263
  dnsaddr: dnsaddrResolver
264
- }
264
+ },
265
+ connections: this.connections
265
266
  })
266
267
  }
267
268
 
@@ -505,12 +506,13 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
505
506
 
506
507
  if (peerId != null && options.force !== true) {
507
508
  log('dial %p', peerId)
508
- const existingConnections = this.getConnections(peerId)
509
+ const existingConnection = this.getConnections(peerId)
510
+ .find(conn => !conn.transient)
509
511
 
510
- if (existingConnections.length > 0) {
511
- log('had an existing connection to %p', peerId)
512
+ if (existingConnection != null) {
513
+ log('had an existing non-transient connection to %p', peerId)
512
514
 
513
- return existingConnections[0]
515
+ return existingConnection
514
516
  }
515
517
  }
516
518
 
@@ -1,4 +1,4 @@
1
- import { setMaxListeners } from 'events'
1
+ import { setMaxListeners } from '@libp2p/interface/events'
2
2
  import { logger } from '@libp2p/logger'
3
3
  import { type AbortOptions, multiaddr, type Multiaddr } from '@multiformats/multiaddr'
4
4
  import { type ClearableSignal, anySignal } from 'any-signal'
@@ -55,10 +55,7 @@ export function combineSignals (...signals: Array<AbortSignal | undefined>): Cle
55
55
 
56
56
  for (const sig of signals) {
57
57
  if (sig != null) {
58
- try {
59
- // fails on node < 15.4
60
- setMaxListeners?.(Infinity, sig)
61
- } catch { }
58
+ setMaxListeners(Infinity, sig)
62
59
  sigs.push(sig)
63
60
  }
64
61
  }
@@ -66,10 +63,7 @@ export function combineSignals (...signals: Array<AbortSignal | undefined>): Cle
66
63
  // let any signal abort the dial
67
64
  const signal = anySignal(sigs)
68
65
 
69
- try {
70
- // fails on node < 15.4
71
- setMaxListeners?.(Infinity, signal)
72
- } catch {}
66
+ setMaxListeners(Infinity, signal)
73
67
 
74
68
  return signal
75
69
  }
@@ -1,12 +1,11 @@
1
1
  import { CodeError } from '@libp2p/interface/errors'
2
2
  import { logger } from '@libp2p/logger'
3
3
  import { type Multiaddr, multiaddr } from '@multiformats/multiaddr'
4
- import { Circuit, IP, DNS } from '@multiformats/multiaddr-matcher'
5
4
  import delay from 'delay'
6
5
  import { pbStream } from 'it-protobuf-stream'
7
- import isPrivate from 'private-ip'
8
6
  import { codes } from '../errors.js'
9
7
  import { HolePunch } from './pb/message.js'
8
+ import { isPublicAndDialable } from './utils.js'
10
9
  import { multicodec } from './index.js'
11
10
  import type { DCUtRServiceComponents, DCUtRServiceInit } from './index.js'
12
11
  import type { Connection, Stream } from '@libp2p/interface/connection'
@@ -72,6 +71,7 @@ export class DefaultDCUtRService implements Startable {
72
71
  // register for notifications of when peers that support DCUtR connect
73
72
  // nb. requires the identify service to be enabled
74
73
  this.topologyId = await this.registrar.register(multicodec, {
74
+ notifyOnTransient: true,
75
75
  onConnect: (peerId, connection) => {
76
76
  if (!connection.transient) {
77
77
  // the connection is already direct, no upgrade is required
@@ -241,7 +241,7 @@ export class DefaultDCUtRService implements Startable {
241
241
  return ma
242
242
  })
243
243
  .filter(ma => {
244
- return this.isPublicAndDialable(ma)
244
+ return isPublicAndDialable(ma, this.transportManager)
245
245
  })
246
246
 
247
247
  if (publicAddresses.length > 0) {
@@ -365,7 +365,7 @@ export class DefaultDCUtRService implements Startable {
365
365
  try {
366
366
  const ma = multiaddr(addr)
367
367
 
368
- if (!this.isPublicAndDialable(ma)) {
368
+ if (!isPublicAndDialable(ma, this.transportManager)) {
369
369
  continue
370
370
  }
371
371
 
@@ -375,35 +375,4 @@ export class DefaultDCUtRService implements Startable {
375
375
 
376
376
  return output
377
377
  }
378
-
379
- /**
380
- * Returns true if the passed multiaddr is public, not relayed and we have a
381
- * transport that can dial it
382
- */
383
- isPublicAndDialable (ma: Multiaddr): boolean {
384
- // ignore circuit relay
385
- if (Circuit.matches(ma)) {
386
- return false
387
- }
388
-
389
- // dns addresses are probably public?
390
- if (DNS.matches(ma)) {
391
- return true
392
- }
393
-
394
- // ensure we have only IPv4/IPv6 addresses
395
- if (!IP.matches(ma)) {
396
- return false
397
- }
398
-
399
- const transport = this.transportManager.transportForMultiaddr(ma)
400
-
401
- if (transport == null) {
402
- return false
403
- }
404
-
405
- const options = ma.toOptions()
406
-
407
- return isPrivate(options.host) === false
408
- }
409
378
  }
@@ -0,0 +1,33 @@
1
+ import { type Multiaddr } from '@multiformats/multiaddr'
2
+ import { Circuit, IP, DNS } from '@multiformats/multiaddr-matcher'
3
+ import isPrivate from 'private-ip'
4
+ import type { TransportManager } from '@libp2p/interface-internal/src/transport-manager'
5
+
6
+ /**
7
+ * Returns true if the passed multiaddr is public, not relayed and we have a
8
+ * transport that can dial it
9
+ */
10
+ export function isPublicAndDialable (ma: Multiaddr, transportManager: TransportManager): boolean {
11
+ // ignore circuit relay
12
+ if (Circuit.matches(ma)) {
13
+ return false
14
+ }
15
+
16
+ const transport = transportManager.transportForMultiaddr(ma)
17
+
18
+ if (transport == null) {
19
+ return false
20
+ }
21
+
22
+ // dns addresses are probably public?
23
+ if (DNS.matches(ma)) {
24
+ return true
25
+ }
26
+
27
+ // ensure we have only IPv4/IPv6 addresses
28
+ if (!IP.matches(ma)) {
29
+ return false
30
+ }
31
+
32
+ return isPrivate(ma.toOptions().host) === false
33
+ }
@@ -1,5 +1,5 @@
1
- import { setMaxListeners } from 'events'
2
1
  import { CodeError } from '@libp2p/interface/errors'
2
+ import { setMaxListeners } from '@libp2p/interface/events'
3
3
  import { logger } from '@libp2p/logger'
4
4
  import first from 'it-first'
5
5
  import * as lp from 'it-length-prefixed'
@@ -146,10 +146,7 @@ class DefaultFetchService implements Startable, FetchService {
146
146
  log('using default timeout of %d ms', this.init.timeout)
147
147
  signal = AbortSignal.timeout(this.init.timeout ?? DEFAULT_TIMEOUT)
148
148
 
149
- try {
150
- // fails on node < 15.4
151
- setMaxListeners?.(Infinity, signal)
152
- } catch {}
149
+ setMaxListeners(Infinity, signal)
153
150
  }
154
151
 
155
152
  try {
@@ -1,5 +1,5 @@
1
- import { setMaxListeners } from 'events'
2
1
  import { CodeError } from '@libp2p/interface/errors'
2
+ import { setMaxListeners } from '@libp2p/interface/events'
3
3
  import { logger } from '@libp2p/logger'
4
4
  import { peerIdFromKeys } from '@libp2p/peer-id'
5
5
  import { RecordEnvelope, PeerRecord } from '@libp2p/peer-record'
@@ -23,7 +23,7 @@ import type { Libp2pEvents, IdentifyResult, SignedPeerRecord, AbortOptions } fro
23
23
  import type { Connection, Stream } from '@libp2p/interface/connection'
24
24
  import type { TypedEventTarget } from '@libp2p/interface/events'
25
25
  import type { PeerId } from '@libp2p/interface/peer-id'
26
- import type { Peer, PeerStore } from '@libp2p/interface/peer-store'
26
+ import type { Peer, PeerData, PeerStore } from '@libp2p/interface/peer-store'
27
27
  import type { Startable } from '@libp2p/interface/startable'
28
28
  import type { AddressManager } from '@libp2p/interface-internal/address-manager'
29
29
  import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
@@ -187,10 +187,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService {
187
187
 
188
188
  const signal = AbortSignal.timeout(this.timeout)
189
189
 
190
- try {
191
- // fails on node < 15.4
192
- setMaxListeners?.(Infinity, signal)
193
- } catch {}
190
+ setMaxListeners(Infinity, signal)
194
191
 
195
192
  try {
196
193
  stream = await connection.newStream([this.identifyPushProtocolStr], {
@@ -318,22 +315,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService {
318
315
  this.addressManager.addObservedAddr(cleanObservedAddr)
319
316
  }
320
317
 
321
- const signedPeerRecord = await this.#consumeIdentifyMessage(connection.remotePeer, message)
322
-
323
- const result: IdentifyResult = {
324
- peerId: id,
325
- protocolVersion: message.protocolVersion,
326
- agentVersion: message.agentVersion,
327
- publicKey: message.publicKey,
328
- listenAddrs: message.listenAddrs.map(buf => multiaddr(buf)),
329
- observedAddr: message.observedAddr == null ? undefined : multiaddr(message.observedAddr),
330
- protocols: message.protocols,
331
- signedPeerRecord
332
- }
333
-
334
- this.events.safeDispatchEvent('peer:identify', { detail: result })
335
-
336
- return result
318
+ return this.#consumeIdentifyMessage(connection, message)
337
319
  }
338
320
 
339
321
  /**
@@ -345,10 +327,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService {
345
327
 
346
328
  const signal = AbortSignal.timeout(this.timeout)
347
329
 
348
- try {
349
- // fails on node < 15.4
350
- setMaxListeners?.(Infinity, signal)
351
- } catch {}
330
+ setMaxListeners(Infinity, signal)
352
331
 
353
332
  try {
354
333
  const publicKey = this.peerId.publicKey ?? new Uint8Array(0)
@@ -411,7 +390,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService {
411
390
  const message = await pb.read(options)
412
391
  await stream.close(options)
413
392
 
414
- await this.#consumeIdentifyMessage(connection.remotePeer, message)
393
+ await this.#consumeIdentifyMessage(connection, message)
415
394
  } catch (err: any) {
416
395
  log.error('received invalid message', err)
417
396
  stream.abort(err)
@@ -421,28 +400,41 @@ export class DefaultIdentifyService implements Startable, IdentifyService {
421
400
  log('handled push from %p', connection.remotePeer)
422
401
  }
423
402
 
424
- async #consumeIdentifyMessage (remotePeer: PeerId, message: Identify): Promise<SignedPeerRecord | undefined> {
425
- log('received identify from %p', remotePeer)
403
+ async #consumeIdentifyMessage (connection: Connection, message: Identify): Promise<IdentifyResult> {
404
+ log('received identify from %p', connection.remotePeer)
426
405
 
427
406
  if (message == null) {
428
- throw new Error('Message was null or undefined')
407
+ throw new CodeError('message was null or undefined', 'ERR_INVALID_MESSAGE')
429
408
  }
430
409
 
431
- const peer = {
432
- addresses: message.listenAddrs.map(buf => ({
410
+ const peer: PeerData = {}
411
+
412
+ if (message.listenAddrs.length > 0) {
413
+ peer.addresses = message.listenAddrs.map(buf => ({
433
414
  isCertified: false,
434
415
  multiaddr: multiaddr(buf)
435
- })),
436
- protocols: message.protocols,
437
- metadata: new Map(),
438
- peerRecordEnvelope: message.signedPeerRecord
416
+ }))
417
+ }
418
+
419
+ if (message.protocols.length > 0) {
420
+ peer.protocols = message.protocols
421
+ }
422
+
423
+ if (message.publicKey != null) {
424
+ peer.publicKey = message.publicKey
425
+
426
+ const peerId = await peerIdFromKeys(message.publicKey)
427
+
428
+ if (!peerId.equals(connection.remotePeer)) {
429
+ throw new CodeError('public key did not match remote PeerId', 'ERR_INVALID_PUBLIC_KEY')
430
+ }
439
431
  }
440
432
 
441
433
  let output: SignedPeerRecord | undefined
442
434
 
443
435
  // if the peer record has been sent, prefer the addresses in the record as they are signed by the remote peer
444
436
  if (message.signedPeerRecord != null) {
445
- log('received signedPeerRecord in push from %p', remotePeer)
437
+ log('received signedPeerRecord in push from %p', connection.remotePeer)
446
438
 
447
439
  let peerRecordEnvelope = message.signedPeerRecord
448
440
  const envelope = await RecordEnvelope.openAndCertify(peerRecordEnvelope, PeerRecord.DOMAIN)
@@ -450,12 +442,12 @@ export class DefaultIdentifyService implements Startable, IdentifyService {
450
442
 
451
443
  // Verify peerId
452
444
  if (!peerRecord.peerId.equals(envelope.peerId)) {
453
- throw new Error('signing key does not match PeerId in the PeerRecord')
445
+ throw new CodeError('signing key does not match PeerId in the PeerRecord', 'ERR_INVALID_SIGNING_KEY')
454
446
  }
455
447
 
456
448
  // Make sure remote peer is the one sending the record
457
- if (!remotePeer.equals(peerRecord.peerId)) {
458
- throw new Error('signing key does not match remote PeerId')
449
+ if (!connection.remotePeer.equals(peerRecord.peerId)) {
450
+ throw new CodeError('signing key does not match remote PeerId', 'ERR_INVALID_PEER_RECORD_KEY')
459
451
  }
460
452
 
461
453
  let existingPeer: Peer | undefined
@@ -500,20 +492,44 @@ export class DefaultIdentifyService implements Startable, IdentifyService {
500
492
  addresses: peerRecord.multiaddrs
501
493
  }
502
494
  } else {
503
- log('%p did not send a signed peer record', remotePeer)
495
+ log('%p did not send a signed peer record', connection.remotePeer)
504
496
  }
505
497
 
506
- if (message.agentVersion != null) {
507
- peer.metadata.set('AgentVersion', uint8ArrayFromString(message.agentVersion))
498
+ log('patching %p with', peer)
499
+ await this.peerStore.patch(connection.remotePeer, peer)
500
+
501
+ if (message.agentVersion != null || message.protocolVersion != null) {
502
+ const metadata: Record<string, Uint8Array> = {}
503
+
504
+ if (message.agentVersion != null) {
505
+ metadata.AgentVersion = uint8ArrayFromString(message.agentVersion)
506
+ }
507
+
508
+ if (message.protocolVersion != null) {
509
+ metadata.ProtocolVersion = uint8ArrayFromString(message.protocolVersion)
510
+ }
511
+
512
+ log('updating %p metadata', peer)
513
+ await this.peerStore.merge(connection.remotePeer, {
514
+ metadata
515
+ })
508
516
  }
509
517
 
510
- if (message.protocolVersion != null) {
511
- peer.metadata.set('ProtocolVersion', uint8ArrayFromString(message.protocolVersion))
518
+ const result: IdentifyResult = {
519
+ peerId: connection.remotePeer,
520
+ protocolVersion: message.protocolVersion,
521
+ agentVersion: message.agentVersion,
522
+ publicKey: message.publicKey,
523
+ listenAddrs: message.listenAddrs.map(buf => multiaddr(buf)),
524
+ observedAddr: message.observedAddr == null ? undefined : multiaddr(message.observedAddr),
525
+ protocols: message.protocols,
526
+ signedPeerRecord: output,
527
+ connection
512
528
  }
513
529
 
514
- await this.peerStore.patch(remotePeer, peer)
530
+ this.events.safeDispatchEvent('peer:identify', { detail: result })
515
531
 
516
- return output
532
+ return result
517
533
  }
518
534
  }
519
535
 
package/src/libp2p.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { setMaxListeners } from 'events'
2
1
  import { unmarshalPublicKey } from '@libp2p/crypto/keys'
3
2
  import { type ContentRouting, contentRouting } from '@libp2p/interface/content-routing'
4
3
  import { CodeError } from '@libp2p/interface/errors'
5
- import { TypedEventEmitter, CustomEvent } from '@libp2p/interface/events'
4
+ import { TypedEventEmitter, CustomEvent, setMaxListeners } from '@libp2p/interface/events'
6
5
  import { peerDiscovery } from '@libp2p/interface/peer-discovery'
7
6
  import { type PeerRouting, peerRouting } from '@libp2p/interface/peer-routing'
8
7
  import { DefaultKeyChain } from '@libp2p/keychain'
@@ -70,10 +69,8 @@ export class Libp2pNode<T extends ServiceMap = Record<string, unknown>> extends
70
69
  return internalResult || externalResult
71
70
  }
72
71
 
73
- try {
74
- // This emitter gets listened to a lot
75
- setMaxListeners?.(Infinity, events)
76
- } catch {}
72
+ // This emitter gets listened to a lot
73
+ setMaxListeners(Infinity, events)
77
74
 
78
75
  this.#started = false
79
76
  this.peerId = init.peerId
@@ -8,7 +8,6 @@ js-libp2p-pnet <!-- omit in toc -->
8
8
  ## Table of Contents <!-- omit in toc -->
9
9
 
10
10
  - [Usage](#usage)
11
- - [Examples](#examples)
12
11
  - [Private Shared Keys](#private-shared-keys)
13
12
  - [PSK Generation](#psk-generation)
14
13
  - [From a module using libp2p](#from-a-module-using-libp2p)
@@ -32,9 +31,6 @@ const node = await createLibp2p({
32
31
  })
33
32
  ```
34
33
 
35
- ## Examples
36
- [Private Networks with IPFS](../../examples/pnet-ipfs)
37
-
38
34
  ## Private Shared Keys
39
35
 
40
36
  Private Shared Keys are expected to be in the following format:
package/src/registrar.ts CHANGED
@@ -2,7 +2,7 @@ import { CodeError } from '@libp2p/interface/errors'
2
2
  import { logger } from '@libp2p/logger'
3
3
  import merge from 'merge-options'
4
4
  import { codes } from './errors.js'
5
- import type { Libp2pEvents, PeerUpdate } from '@libp2p/interface'
5
+ import type { IdentifyResult, Libp2pEvents, PeerUpdate } from '@libp2p/interface'
6
6
  import type { TypedEventTarget } from '@libp2p/interface/events'
7
7
  import type { PeerId } from '@libp2p/interface/peer-id'
8
8
  import type { PeerStore } from '@libp2p/interface/peer-store'
@@ -37,11 +37,11 @@ export class DefaultRegistrar implements Registrar {
37
37
 
38
38
  this._onDisconnect = this._onDisconnect.bind(this)
39
39
  this._onPeerUpdate = this._onPeerUpdate.bind(this)
40
- this._onConnect = this._onConnect.bind(this)
40
+ this._onPeerIdentify = this._onPeerIdentify.bind(this)
41
41
 
42
42
  this.components.events.addEventListener('peer:disconnect', this._onDisconnect)
43
- this.components.events.addEventListener('peer:connect', this._onConnect)
44
43
  this.components.events.addEventListener('peer:update', this._onPeerUpdate)
44
+ this.components.events.addEventListener('peer:identify', this._onPeerIdentify)
45
45
  }
46
46
 
47
47
  getProtocols (): string[] {
@@ -183,52 +183,12 @@ export class DefaultRegistrar implements Registrar {
183
183
  }
184
184
 
185
185
  /**
186
- * On peer connected if we already have their protocols. Usually used for reconnects
187
- * as change:protocols event won't be emitted due to identical protocols.
188
- */
189
- _onConnect (evt: CustomEvent<PeerId>): void {
190
- const remotePeer = evt.detail
191
-
192
- void this.components.peerStore.get(remotePeer)
193
- .then(peer => {
194
- const connection = this.components.connectionManager.getConnections(peer.id)[0]
195
-
196
- if (connection == null) {
197
- log('peer %p connected but the connection manager did not have a connection', peer)
198
- // peer disconnected while we were loading their details from the peer store
199
- return
200
- }
201
-
202
- for (const protocol of peer.protocols) {
203
- const topologies = this.topologies.get(protocol)
204
-
205
- if (topologies == null) {
206
- // no topologies are interested in this protocol
207
- continue
208
- }
209
-
210
- for (const topology of topologies.values()) {
211
- topology.onConnect?.(remotePeer, connection)
212
- }
213
- }
214
- })
215
- .catch(err => {
216
- if (err.code === codes.ERR_NOT_FOUND) {
217
- // peer has not completed identify so they are not in the peer store
218
- return
219
- }
220
-
221
- log.error('could not inform topologies of connecting peer %p', remotePeer, err)
222
- })
223
- }
224
-
225
- /**
226
- * Check if a new peer support the multicodecs for this topology
186
+ * When a peer is updated, if they have removed supported protocols notify any
187
+ * topologies interested in the removed protocols.
227
188
  */
228
189
  _onPeerUpdate (evt: CustomEvent<PeerUpdate>): void {
229
190
  const { peer, previous } = evt.detail
230
191
  const removed = (previous?.protocols ?? []).filter(protocol => !peer.protocols.includes(protocol))
231
- const added = peer.protocols.filter(protocol => !(previous?.protocols ?? []).includes(protocol))
232
192
 
233
193
  for (const protocol of removed) {
234
194
  const topologies = this.topologies.get(protocol)
@@ -242,8 +202,18 @@ export class DefaultRegistrar implements Registrar {
242
202
  topology.onDisconnect?.(peer.id)
243
203
  }
244
204
  }
205
+ }
245
206
 
246
- for (const protocol of added) {
207
+ /**
208
+ * After identify has completed and we have received the list of supported
209
+ * protocols, notify any topologies interested in those protocols.
210
+ */
211
+ _onPeerIdentify (evt: CustomEvent<IdentifyResult>): void {
212
+ const protocols = evt.detail.protocols
213
+ const connection = evt.detail.connection
214
+ const peerId = evt.detail.peerId
215
+
216
+ for (const protocol of protocols) {
247
217
  const topologies = this.topologies.get(protocol)
248
218
 
249
219
  if (topologies == null) {
@@ -252,12 +222,11 @@ export class DefaultRegistrar implements Registrar {
252
222
  }
253
223
 
254
224
  for (const topology of topologies.values()) {
255
- const connection = this.components.connectionManager.getConnections(peer.id)[0]
256
-
257
- if (connection == null) {
225
+ if (connection.transient && topology.notifyOnTransient !== true) {
258
226
  continue
259
227
  }
260
- topology.onConnect?.(peer.id, connection)
228
+
229
+ topology.onConnect?.(peerId, connection)
261
230
  }
262
231
  }
263
232
  }