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.
- package/README.md +20 -63
- package/dist/index.min.js +29 -29
- package/dist/src/autonat/index.d.ts.map +1 -1
- package/dist/src/autonat/index.js +3 -11
- package/dist/src/autonat/index.js.map +1 -1
- package/dist/src/circuit-relay/server/index.d.ts.map +1 -1
- package/dist/src/circuit-relay/server/index.js +2 -7
- package/dist/src/circuit-relay/server/index.js.map +1 -1
- package/dist/src/circuit-relay/transport/discovery.d.ts.map +1 -1
- package/dist/src/circuit-relay/transport/discovery.js +1 -0
- package/dist/src/circuit-relay/transport/discovery.js.map +1 -1
- package/dist/src/circuit-relay/transport/listener.d.ts.map +1 -1
- package/dist/src/circuit-relay/transport/listener.js +3 -17
- package/dist/src/circuit-relay/transport/listener.js.map +1 -1
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/index.js +5 -6
- package/dist/src/connection/index.js.map +1 -1
- package/dist/src/connection-manager/dial-queue.d.ts +4 -0
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
- package/dist/src/connection-manager/dial-queue.js +37 -7
- package/dist/src/connection-manager/dial-queue.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +7 -5
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/connection-manager/utils.d.ts.map +1 -1
- package/dist/src/connection-manager/utils.js +3 -11
- package/dist/src/connection-manager/utils.js.map +1 -1
- package/dist/src/dcutr/dcutr.d.ts +0 -5
- package/dist/src/dcutr/dcutr.d.ts.map +1 -1
- package/dist/src/dcutr/dcutr.js +4 -28
- package/dist/src/dcutr/dcutr.js.map +1 -1
- package/dist/src/dcutr/utils.d.ts +8 -0
- package/dist/src/dcutr/utils.d.ts.map +1 -0
- package/dist/src/dcutr/utils.js +27 -0
- package/dist/src/dcutr/utils.js.map +1 -0
- package/dist/src/fetch/index.d.ts.map +1 -1
- package/dist/src/fetch/index.js +2 -6
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/identify/consts.d.ts +1 -1
- package/dist/src/identify/identify.d.ts.map +1 -1
- package/dist/src/identify/identify.js +55 -47
- package/dist/src/identify/identify.js.map +1 -1
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +3 -7
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/registrar.d.ts +7 -6
- package/dist/src/registrar.d.ts.map +1 -1
- package/dist/src/registrar.js +16 -41
- package/dist/src/registrar.js.map +1 -1
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +3 -11
- package/dist/src/upgrader.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +23 -24
- package/src/autonat/index.ts +3 -9
- package/src/circuit-relay/server/index.ts +2 -6
- package/src/circuit-relay/transport/discovery.ts +1 -0
- package/src/circuit-relay/transport/listener.ts +3 -21
- package/src/connection/index.ts +6 -5
- package/src/connection-manager/dial-queue.ts +46 -6
- package/src/connection-manager/index.ts +7 -5
- package/src/connection-manager/utils.ts +3 -9
- package/src/dcutr/dcutr.ts +4 -35
- package/src/dcutr/utils.ts +33 -0
- package/src/fetch/index.ts +2 -5
- package/src/identify/identify.ts +63 -47
- package/src/libp2p.ts +3 -6
- package/src/pnet/README.md +0 -4
- package/src/registrar.ts +19 -50
- package/src/upgrader.ts +3 -9
- package/src/version.ts +1 -1
package/src/connection/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
509
|
+
const existingConnection = this.getConnections(peerId)
|
|
510
|
+
.find(conn => !conn.transient)
|
|
509
511
|
|
|
510
|
-
if (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
// fails on node < 15.4
|
|
71
|
-
setMaxListeners?.(Infinity, signal)
|
|
72
|
-
} catch {}
|
|
66
|
+
setMaxListeners(Infinity, signal)
|
|
73
67
|
|
|
74
68
|
return signal
|
|
75
69
|
}
|
package/src/dcutr/dcutr.ts
CHANGED
|
@@ -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
|
|
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 (!
|
|
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
|
+
}
|
package/src/fetch/index.ts
CHANGED
|
@@ -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
|
-
|
|
150
|
-
// fails on node < 15.4
|
|
151
|
-
setMaxListeners?.(Infinity, signal)
|
|
152
|
-
} catch {}
|
|
149
|
+
setMaxListeners(Infinity, signal)
|
|
153
150
|
}
|
|
154
151
|
|
|
155
152
|
try {
|
package/src/identify/identify.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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
|
|
407
|
+
throw new CodeError('message was null or undefined', 'ERR_INVALID_MESSAGE')
|
|
429
408
|
}
|
|
430
409
|
|
|
431
|
-
const peer = {
|
|
432
|
-
|
|
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
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
507
|
-
|
|
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
|
-
|
|
511
|
-
|
|
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
|
-
|
|
530
|
+
this.events.safeDispatchEvent('peer:identify', { detail: result })
|
|
515
531
|
|
|
516
|
-
return
|
|
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
|
-
|
|
74
|
-
|
|
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
|
package/src/pnet/README.md
CHANGED
|
@@ -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.
|
|
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
|
-
*
|
|
187
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
if (connection == null) {
|
|
225
|
+
if (connection.transient && topology.notifyOnTransient !== true) {
|
|
258
226
|
continue
|
|
259
227
|
}
|
|
260
|
-
|
|
228
|
+
|
|
229
|
+
topology.onConnect?.(peerId, connection)
|
|
261
230
|
}
|
|
262
231
|
}
|
|
263
232
|
}
|