@libp2p/pubsub 1.2.1 → 1.2.5
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/dist/src/errors.d.ts +4 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +4 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +28 -29
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +104 -85
- package/dist/src/index.js.map +1 -1
- package/dist/src/message/sign.d.ts +1 -1
- package/dist/src/message/sign.d.ts.map +1 -1
- package/dist/src/message/sign.js +6 -8
- package/dist/src/message/sign.js.map +1 -1
- package/dist/src/peer-streams.d.ts +5 -5
- package/dist/src/peer-streams.d.ts.map +1 -1
- package/dist/src/peer-streams.js +1 -0
- package/dist/src/peer-streams.js.map +1 -1
- package/dist/src/utils.d.ts +6 -5
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +36 -28
- package/dist/src/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/errors.ts +4 -0
- package/src/index.ts +128 -100
- package/src/message/sign.ts +7 -9
- package/src/peer-streams.ts +6 -4
- package/src/utils.ts +39 -29
package/src/index.ts
CHANGED
@@ -3,22 +3,25 @@ import { EventEmitter, CustomEvent } from '@libp2p/interfaces'
|
|
3
3
|
import errcode from 'err-code'
|
4
4
|
import { pipe } from 'it-pipe'
|
5
5
|
import Queue from 'p-queue'
|
6
|
-
import {
|
6
|
+
import { Topology } from '@libp2p/topology'
|
7
7
|
import { codes } from './errors.js'
|
8
|
-
import {
|
9
|
-
import {
|
10
|
-
import * as utils from './utils.js'
|
8
|
+
import { PeerStreams as PeerStreamsImpl } from './peer-streams.js'
|
9
|
+
import { toRpcMessage, toMessage, ensureArray, randomSeqno, noSignMsgId, msgId } from './utils.js'
|
11
10
|
import {
|
12
11
|
signMessage,
|
13
12
|
verifySignature
|
14
13
|
} from './message/sign.js'
|
15
14
|
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
16
|
-
import type { Registrar,
|
15
|
+
import type { Registrar, IncomingStreamData } from '@libp2p/interfaces/registrar'
|
17
16
|
import type { Connection } from '@libp2p/interfaces/connection'
|
18
|
-
import type
|
19
|
-
import type { PubSub, Message, StrictNoSign, StrictSign, PubsubOptions, PubsubEvents } from '@libp2p/interfaces/pubsub'
|
20
|
-
import type { Startable } from '@libp2p/interfaces'
|
17
|
+
import type { PubSub, Message, StrictNoSign, StrictSign, PubSubOptions, PubSubEvents, RPCMessage, RPC, PeerStreams, RPCSubscription } from '@libp2p/interfaces/pubsub'
|
21
18
|
import type { Logger } from '@libp2p/logger'
|
19
|
+
import { base58btc } from 'multiformats/bases/base58'
|
20
|
+
import { peerMap } from '@libp2p/peer-map'
|
21
|
+
import type { PeerMap } from '@libp2p/peer-map'
|
22
|
+
import { peerIdFromString } from '@libp2p/peer-id'
|
23
|
+
import type { IRPC } from './message/rpc.js'
|
24
|
+
import { RPC as RPCProto } from './message/rpc.js'
|
22
25
|
|
23
26
|
export interface TopicValidator { (topic: string, message: Message): Promise<void> }
|
24
27
|
|
@@ -26,7 +29,7 @@ export interface TopicValidator { (topic: string, message: Message): Promise<voi
|
|
26
29
|
* PubsubBaseProtocol handles the peers and connections logic for pubsub routers
|
27
30
|
* and specifies the API that pubsub routers should have.
|
28
31
|
*/
|
29
|
-
export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap &
|
32
|
+
export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap & PubSubEvents> implements PubSub<EventMap & PubSubEvents> {
|
30
33
|
public peerId: PeerId
|
31
34
|
public started: boolean
|
32
35
|
/**
|
@@ -40,11 +43,11 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
40
43
|
/**
|
41
44
|
* Map of peer streams
|
42
45
|
*/
|
43
|
-
public peers:
|
46
|
+
public peers: PeerMap<PeerStreams>
|
44
47
|
/**
|
45
48
|
* The signature policy to follow by default
|
46
49
|
*/
|
47
|
-
public globalSignaturePolicy: StrictNoSign | StrictSign
|
50
|
+
public globalSignaturePolicy: typeof StrictNoSign | typeof StrictSign
|
48
51
|
/**
|
49
52
|
* If router can relay received messages, even if not subscribed
|
50
53
|
*/
|
@@ -62,19 +65,21 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
62
65
|
public topicValidators: Map<string, TopicValidator>
|
63
66
|
public queue: Queue
|
64
67
|
public registrar: Registrar
|
68
|
+
public multicodecs: string[]
|
65
69
|
|
66
70
|
protected log: Logger
|
67
|
-
protected multicodecs: string[]
|
68
71
|
protected _libp2p: any
|
69
|
-
private
|
72
|
+
private _registrarHandlerId: string | undefined
|
73
|
+
private _registrarTopologyId: string | undefined
|
70
74
|
|
71
|
-
constructor (props:
|
75
|
+
constructor (props: PubSubOptions) {
|
72
76
|
super()
|
73
77
|
|
74
78
|
const {
|
75
79
|
debugName = 'libp2p:pubsub',
|
76
80
|
multicodecs = [],
|
77
|
-
|
81
|
+
peerId,
|
82
|
+
registrar,
|
78
83
|
globalSignaturePolicy = 'StrictSign',
|
79
84
|
canRelayMessage = false,
|
80
85
|
emitSelf = false,
|
@@ -82,14 +87,13 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
82
87
|
} = props
|
83
88
|
|
84
89
|
this.log = logger(debugName)
|
85
|
-
this.multicodecs =
|
86
|
-
this.
|
87
|
-
this.
|
88
|
-
this.peerId = libp2p.peerId
|
90
|
+
this.multicodecs = ensureArray(multicodecs)
|
91
|
+
this.registrar = registrar
|
92
|
+
this.peerId = peerId
|
89
93
|
this.started = false
|
90
94
|
this.topics = new Map()
|
91
95
|
this.subscriptions = new Set()
|
92
|
-
this.peers =
|
96
|
+
this.peers = peerMap<PeerStreams>()
|
93
97
|
this.globalSignaturePolicy = globalSignaturePolicy === 'StrictNoSign' ? 'StrictNoSign' : 'StrictSign'
|
94
98
|
this.canRelayMessage = canRelayMessage
|
95
99
|
this.emitSelf = emitSelf
|
@@ -108,7 +112,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
108
112
|
*
|
109
113
|
* @returns {void}
|
110
114
|
*/
|
111
|
-
start () {
|
115
|
+
async start () {
|
112
116
|
if (this.started) {
|
113
117
|
return
|
114
118
|
}
|
@@ -117,20 +121,15 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
117
121
|
|
118
122
|
// Incoming streams
|
119
123
|
// Called after a peer dials us
|
120
|
-
this.registrar.handle(this.multicodecs, this._onIncomingStream)
|
124
|
+
this._registrarHandlerId = await this.registrar.handle(this.multicodecs, this._onIncomingStream)
|
121
125
|
|
122
126
|
// register protocol with topology
|
123
127
|
// Topology callbacks called on connection manager changes
|
124
|
-
const topology = new
|
125
|
-
|
126
|
-
|
127
|
-
multicodecs: this.multicodecs,
|
128
|
-
handlers: {
|
129
|
-
onConnect: this._onPeerConnected,
|
130
|
-
onDisconnect: this._onPeerDisconnected
|
131
|
-
}
|
128
|
+
const topology = new Topology({
|
129
|
+
onConnect: this._onPeerConnected,
|
130
|
+
onDisconnect: this._onPeerDisconnected
|
132
131
|
})
|
133
|
-
this.
|
132
|
+
this._registrarTopologyId = this.registrar.register(this.multicodecs, topology)
|
134
133
|
|
135
134
|
this.log('started')
|
136
135
|
this.started = true
|
@@ -138,23 +137,26 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
138
137
|
|
139
138
|
/**
|
140
139
|
* Unregister the pubsub protocol and the streams with other peers will be closed.
|
141
|
-
*
|
142
|
-
* @returns {void}
|
143
140
|
*/
|
144
|
-
stop () {
|
141
|
+
async stop () {
|
145
142
|
if (!this.started) {
|
146
143
|
return
|
147
144
|
}
|
148
145
|
|
149
146
|
// unregister protocol and handlers
|
150
|
-
if (this.
|
151
|
-
this.registrar.unregister(this.
|
147
|
+
if (this._registrarTopologyId != null) {
|
148
|
+
this.registrar.unregister(this._registrarTopologyId)
|
149
|
+
}
|
150
|
+
if (this._registrarHandlerId != null) {
|
151
|
+
await this.registrar.unhandle(this._registrarHandlerId)
|
152
152
|
}
|
153
153
|
|
154
154
|
this.log('stopping')
|
155
|
-
|
155
|
+
for (const peerStreams of this.peers.values()) {
|
156
|
+
peerStreams.close()
|
157
|
+
}
|
156
158
|
|
157
|
-
this.peers
|
159
|
+
this.peers.clear()
|
158
160
|
this.subscriptions = new Set()
|
159
161
|
this.started = false
|
160
162
|
this.log('stopped')
|
@@ -167,13 +169,13 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
167
169
|
/**
|
168
170
|
* On an inbound stream opened
|
169
171
|
*/
|
170
|
-
protected _onIncomingStream (
|
172
|
+
protected _onIncomingStream (evt: CustomEvent<IncomingStreamData>) {
|
173
|
+
const { protocol, stream, connection } = evt.detail
|
171
174
|
const peerId = connection.remotePeer
|
172
|
-
const idB58Str = peerId.toString()
|
173
175
|
const peer = this._addPeer(peerId, protocol)
|
174
176
|
const inboundStream = peer.attachInboundStream(stream)
|
175
177
|
|
176
|
-
this._processMessages(
|
178
|
+
this._processMessages(peerId, inboundStream, peer)
|
177
179
|
.catch(err => this.log(err))
|
178
180
|
}
|
179
181
|
|
@@ -181,8 +183,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
181
183
|
* Registrar notifies an established connection with pubsub protocol
|
182
184
|
*/
|
183
185
|
protected async _onPeerConnected (peerId: PeerId, conn: Connection) {
|
184
|
-
|
185
|
-
this.log('connected', idB58Str)
|
186
|
+
this.log('connected %p', peerId)
|
186
187
|
|
187
188
|
try {
|
188
189
|
const { stream, protocol } = await conn.newStream(this.multicodecs)
|
@@ -193,7 +194,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
193
194
|
}
|
194
195
|
|
195
196
|
// Immediately send my own subscriptions to the newly established conn
|
196
|
-
this._sendSubscriptions(
|
197
|
+
this._sendSubscriptions(peerId, Array.from(this.subscriptions), true)
|
197
198
|
}
|
198
199
|
|
199
200
|
/**
|
@@ -209,9 +210,8 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
209
210
|
/**
|
210
211
|
* Notifies the router that a peer has been connected
|
211
212
|
*/
|
212
|
-
protected _addPeer (peerId: PeerId, protocol: string) {
|
213
|
-
const
|
214
|
-
const existing = this.peers.get(id)
|
213
|
+
protected _addPeer (peerId: PeerId, protocol: string): PeerStreams {
|
214
|
+
const existing = this.peers.get(peerId)
|
215
215
|
|
216
216
|
// If peer streams already exists, do nothing
|
217
217
|
if (existing != null) {
|
@@ -219,14 +219,14 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
219
219
|
}
|
220
220
|
|
221
221
|
// else create a new peer streams
|
222
|
-
this.log('new peer',
|
222
|
+
this.log('new peer %p', peerId)
|
223
223
|
|
224
|
-
const peerStreams = new
|
224
|
+
const peerStreams: PeerStreams = new PeerStreamsImpl({
|
225
225
|
id: peerId,
|
226
226
|
protocol
|
227
227
|
})
|
228
228
|
|
229
|
-
this.peers.set(
|
229
|
+
this.peers.set(peerId, peerStreams)
|
230
230
|
peerStreams.addEventListener('close', () => this._removePeer(peerId), {
|
231
231
|
once: true
|
232
232
|
})
|
@@ -239,7 +239,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
239
239
|
*/
|
240
240
|
protected _removePeer (peerId: PeerId) {
|
241
241
|
const id = peerId.toString()
|
242
|
-
const peerStreams = this.peers.get(
|
242
|
+
const peerStreams = this.peers.get(peerId)
|
243
243
|
if (peerStreams == null) {
|
244
244
|
return
|
245
245
|
}
|
@@ -248,8 +248,8 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
248
248
|
peerStreams.close()
|
249
249
|
|
250
250
|
// delete peer streams
|
251
|
-
this.log('delete peer',
|
252
|
-
this.peers.delete(
|
251
|
+
this.log('delete peer %p', peerId)
|
252
|
+
this.peers.delete(peerId)
|
253
253
|
|
254
254
|
// remove peer from topics map
|
255
255
|
for (const peers of this.topics.values()) {
|
@@ -264,20 +264,32 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
264
264
|
/**
|
265
265
|
* Responsible for processing each RPC message received by other peers.
|
266
266
|
*/
|
267
|
-
async _processMessages (
|
267
|
+
async _processMessages (peerId: PeerId, stream: AsyncIterable<Uint8Array>, peerStreams: PeerStreams) {
|
268
268
|
try {
|
269
269
|
await pipe(
|
270
270
|
stream,
|
271
271
|
async (source) => {
|
272
272
|
for await (const data of source) {
|
273
|
-
const
|
274
|
-
const rpcMsg = this._decodeRpc(rpcBytes)
|
273
|
+
const rpcMsg = this._decodeRpc(data)
|
275
274
|
|
276
275
|
// Since _processRpc may be overridden entirely in unsafe ways,
|
277
276
|
// the simplest/safest option here is to wrap in a function and capture all errors
|
278
277
|
// to prevent a top-level unhandled exception
|
279
278
|
// This processing of rpc messages should happen without awaiting full validation/execution of prior messages
|
280
|
-
this.
|
279
|
+
this.processRpc(peerId, peerStreams, {
|
280
|
+
subscriptions: (rpcMsg.subscriptions).map(sub => ({
|
281
|
+
subscribe: Boolean(sub.subscribe),
|
282
|
+
topicID: sub.topicID ?? ''
|
283
|
+
})),
|
284
|
+
msgs: (rpcMsg.msgs ?? []).map(msg => ({
|
285
|
+
from: msg.from ?? peerId.multihash.bytes,
|
286
|
+
data: msg.data ?? new Uint8Array(0),
|
287
|
+
topicIDs: msg.topicIDs ?? [],
|
288
|
+
seqno: msg.seqno ?? undefined,
|
289
|
+
signature: msg.signature ?? undefined,
|
290
|
+
key: msg.key ?? undefined
|
291
|
+
}))
|
292
|
+
})
|
281
293
|
.catch(err => this.log(err))
|
282
294
|
}
|
283
295
|
}
|
@@ -290,23 +302,23 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
290
302
|
/**
|
291
303
|
* Handles an rpc request from a peer
|
292
304
|
*/
|
293
|
-
async
|
294
|
-
this.log('rpc from',
|
305
|
+
async processRpc (from: PeerId, peerStreams: PeerStreams, rpc: RPC) {
|
306
|
+
this.log('rpc from %p', from)
|
295
307
|
const subs = rpc.subscriptions
|
296
308
|
const msgs = rpc.msgs
|
297
309
|
|
298
310
|
if (subs.length > 0) {
|
299
311
|
// update peer subscriptions
|
300
312
|
subs.forEach((subOpt) => {
|
301
|
-
this._processRpcSubOpt(
|
313
|
+
this._processRpcSubOpt(from, subOpt)
|
302
314
|
})
|
303
315
|
this.dispatchEvent(new CustomEvent('pubsub:subscription-change', {
|
304
316
|
detail: { peerId: peerStreams.id, subscriptions: subs }
|
305
317
|
}))
|
306
318
|
}
|
307
319
|
|
308
|
-
if (!this._acceptFrom(
|
309
|
-
this.log('received message from unacceptable peer %
|
320
|
+
if (!this._acceptFrom(from)) {
|
321
|
+
this.log('received message from unacceptable peer %p', from)
|
310
322
|
return false
|
311
323
|
}
|
312
324
|
|
@@ -321,9 +333,12 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
321
333
|
}
|
322
334
|
|
323
335
|
try {
|
324
|
-
const msg =
|
336
|
+
const msg = toMessage({
|
337
|
+
...message,
|
338
|
+
from: from.multihash.bytes
|
339
|
+
})
|
325
340
|
|
326
|
-
await this.
|
341
|
+
await this._processMessage(msg)
|
327
342
|
} catch (err: any) {
|
328
343
|
this.log.error(err)
|
329
344
|
}
|
@@ -336,7 +351,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
336
351
|
/**
|
337
352
|
* Handles a subscription change from a peer
|
338
353
|
*/
|
339
|
-
_processRpcSubOpt (id:
|
354
|
+
_processRpcSubOpt (id: PeerId, subOpt: RPCSubscription) {
|
340
355
|
const t = subOpt.topicID
|
341
356
|
|
342
357
|
if (t == null) {
|
@@ -349,20 +364,20 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
349
364
|
this.topics.set(t, topicSet)
|
350
365
|
}
|
351
366
|
|
352
|
-
if (subOpt.subscribe
|
367
|
+
if (subOpt.subscribe) {
|
353
368
|
// subscribe peer to new topic
|
354
|
-
topicSet.add(id)
|
369
|
+
topicSet.add(id.toString())
|
355
370
|
} else {
|
356
371
|
// unsubscribe from existing topic
|
357
|
-
topicSet.delete(id)
|
372
|
+
topicSet.delete(id.toString())
|
358
373
|
}
|
359
374
|
}
|
360
375
|
|
361
376
|
/**
|
362
377
|
* Handles an message from a peer
|
363
378
|
*/
|
364
|
-
async
|
365
|
-
if (
|
379
|
+
async _processMessage (msg: Message) {
|
380
|
+
if (this.peerId.equals(msg.from) && !this.emitSelf) {
|
366
381
|
return
|
367
382
|
}
|
368
383
|
|
@@ -375,15 +390,15 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
375
390
|
}
|
376
391
|
|
377
392
|
// Emit to self
|
378
|
-
this.
|
393
|
+
this.emitMessage(msg)
|
379
394
|
|
380
|
-
return await this._publish(
|
395
|
+
return await this._publish(toRpcMessage(msg))
|
381
396
|
}
|
382
397
|
|
383
398
|
/**
|
384
399
|
* Emit a message from a peer
|
385
400
|
*/
|
386
|
-
|
401
|
+
emitMessage (message: Message) {
|
387
402
|
message.topicIDs.forEach((topic) => {
|
388
403
|
if (this.subscriptions.has(topic)) {
|
389
404
|
this.dispatchEvent(new CustomEvent(topic, {
|
@@ -401,10 +416,13 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
401
416
|
const signaturePolicy = this.globalSignaturePolicy
|
402
417
|
switch (signaturePolicy) {
|
403
418
|
case 'StrictSign':
|
404
|
-
|
405
|
-
|
419
|
+
if (msg.seqno == null) {
|
420
|
+
throw errcode(new Error('Need seqno when signature policy is StrictSign but it was missing'), codes.ERR_MISSING_SEQNO)
|
421
|
+
}
|
422
|
+
|
423
|
+
return msgId(msg.from, msg.seqno)
|
406
424
|
case 'StrictNoSign':
|
407
|
-
return
|
425
|
+
return noSignMsgId(msg.data)
|
408
426
|
default:
|
409
427
|
throw errcode(new Error('Cannot get message id: unhandled signature policy'), codes.ERR_UNHANDLED_SIGNATURE_POLICY)
|
410
428
|
}
|
@@ -414,7 +432,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
414
432
|
* Whether to accept a message from a peer
|
415
433
|
* Override to create a graylist
|
416
434
|
*/
|
417
|
-
_acceptFrom (id:
|
435
|
+
_acceptFrom (id: PeerId) {
|
418
436
|
return true
|
419
437
|
}
|
420
438
|
|
@@ -423,7 +441,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
423
441
|
* This can be override to use a custom router protobuf.
|
424
442
|
*/
|
425
443
|
_decodeRpc (bytes: Uint8Array) {
|
426
|
-
return
|
444
|
+
return RPCProto.decode(bytes)
|
427
445
|
}
|
428
446
|
|
429
447
|
/**
|
@@ -431,27 +449,29 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
431
449
|
* This can be override to use a custom router protobuf.
|
432
450
|
*/
|
433
451
|
_encodeRpc (rpc: IRPC) {
|
434
|
-
return
|
452
|
+
return RPCProto.encode(rpc).finish()
|
435
453
|
}
|
436
454
|
|
437
455
|
/**
|
438
456
|
* Send an rpc object to a peer
|
439
457
|
*/
|
440
|
-
_sendRpc (
|
441
|
-
const peerStreams = this.peers.get(
|
442
|
-
|
443
|
-
|
458
|
+
_sendRpc (peer: PeerId, rpc: IRPC) {
|
459
|
+
const peerStreams = this.peers.get(peer)
|
460
|
+
|
461
|
+
if (peerStreams == null || !peerStreams.isWritable) {
|
462
|
+
const msg = `Cannot send RPC to ${peer.toString(base58btc)} as there is no open stream to it available`
|
444
463
|
|
445
464
|
this.log.error(msg)
|
446
465
|
return
|
447
466
|
}
|
467
|
+
|
448
468
|
peerStreams.write(this._encodeRpc(rpc))
|
449
469
|
}
|
450
470
|
|
451
471
|
/**
|
452
472
|
* Send subscriptions to a peer
|
453
473
|
*/
|
454
|
-
_sendSubscriptions (id:
|
474
|
+
_sendSubscriptions (id: PeerId, topics: string[], subscribe: boolean) {
|
455
475
|
return this._sendRpc(id, {
|
456
476
|
subscriptions: topics.map(t => ({ topicID: t, subscribe: subscribe }))
|
457
477
|
})
|
@@ -465,9 +485,6 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
465
485
|
const signaturePolicy = this.globalSignaturePolicy
|
466
486
|
switch (signaturePolicy) {
|
467
487
|
case 'StrictNoSign':
|
468
|
-
if (message.from != null) {
|
469
|
-
throw errcode(new Error('StrictNoSigning: from should not be present'), codes.ERR_UNEXPECTED_FROM)
|
470
|
-
}
|
471
488
|
if (message.signature != null) {
|
472
489
|
throw errcode(new Error('StrictNoSigning: signature should not be present'), codes.ERR_UNEXPECTED_SIGNATURE)
|
473
490
|
}
|
@@ -505,12 +522,11 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
505
522
|
* Normalizes the message and signs it, if signing is enabled.
|
506
523
|
* Should be used by the routers to create the message to send.
|
507
524
|
*/
|
508
|
-
protected async
|
525
|
+
protected async _maybeSignMessage (message: Message) {
|
509
526
|
const signaturePolicy = this.globalSignaturePolicy
|
510
527
|
switch (signaturePolicy) {
|
511
528
|
case 'StrictSign':
|
512
|
-
message.
|
513
|
-
message.seqno = utils.randomSeqno()
|
529
|
+
message.seqno = randomSeqno()
|
514
530
|
return await signMessage(this.peerId, message)
|
515
531
|
case 'StrictNoSign':
|
516
532
|
return await Promise.resolve(message)
|
@@ -539,7 +555,7 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
539
555
|
return []
|
540
556
|
}
|
541
557
|
|
542
|
-
return Array.from(peersInTopic)
|
558
|
+
return Array.from(peersInTopic).map(str => peerIdFromString(str))
|
543
559
|
}
|
544
560
|
|
545
561
|
/**
|
@@ -552,29 +568,27 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
552
568
|
|
553
569
|
this.log('publish', topic, message)
|
554
570
|
|
555
|
-
const from = this.peerId.toString()
|
556
571
|
const msgObject = {
|
557
|
-
|
572
|
+
from: this.peerId,
|
558
573
|
data: message,
|
559
574
|
topicIDs: [topic]
|
560
575
|
}
|
561
576
|
|
562
577
|
// ensure that the message follows the signature policy
|
563
|
-
const
|
564
|
-
const msg = utils.normalizeInRpcMessage(outMsg)
|
578
|
+
const msg = await this._maybeSignMessage(msgObject)
|
565
579
|
|
566
580
|
// Emit to self if I'm interested and emitSelf enabled
|
567
|
-
this.emitSelf && this.
|
581
|
+
this.emitSelf && this.emitMessage(msg)
|
568
582
|
|
569
583
|
// send to all the other peers
|
570
|
-
await this._publish(msg)
|
584
|
+
await this._publish(toRpcMessage(msg))
|
571
585
|
}
|
572
586
|
|
573
587
|
/**
|
574
588
|
* Overriding the implementation of publish should handle the appropriate algorithms for the publish/subscriber implementation.
|
575
589
|
* For example, a Floodsub implementation might simply publish each message to each topic for every peer
|
576
590
|
*/
|
577
|
-
abstract _publish (message:
|
591
|
+
abstract _publish (message: RPCMessage): Promise<void>
|
578
592
|
|
579
593
|
/**
|
580
594
|
* Subscribes to a given topic.
|
@@ -586,7 +600,10 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
586
600
|
|
587
601
|
if (!this.subscriptions.has(topic)) {
|
588
602
|
this.subscriptions.add(topic)
|
589
|
-
|
603
|
+
|
604
|
+
for (const peerId of this.peers.keys()) {
|
605
|
+
this._sendSubscriptions(peerId, [topic], true)
|
606
|
+
}
|
590
607
|
}
|
591
608
|
}
|
592
609
|
|
@@ -600,7 +617,10 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
600
617
|
|
601
618
|
if (this.subscriptions.has(topic) && this.listenerCount(topic) === 0) {
|
602
619
|
this.subscriptions.delete(topic)
|
603
|
-
|
620
|
+
|
621
|
+
for (const peerId of this.peers.keys()) {
|
622
|
+
this._sendSubscriptions(peerId, [topic], false)
|
623
|
+
}
|
604
624
|
}
|
605
625
|
}
|
606
626
|
|
@@ -614,4 +634,12 @@ export abstract class PubsubBaseProtocol<EventMap> extends EventEmitter<EventMap
|
|
614
634
|
|
615
635
|
return Array.from(this.subscriptions)
|
616
636
|
}
|
637
|
+
|
638
|
+
getPeers () {
|
639
|
+
if (!this.started) {
|
640
|
+
throw new Error('Pubsub is not started')
|
641
|
+
}
|
642
|
+
|
643
|
+
return Array.from(this.peers.keys())
|
644
|
+
}
|
617
645
|
}
|
package/src/message/sign.ts
CHANGED
@@ -2,8 +2,8 @@ import * as PeerIdFactory from '@libp2p/peer-id-factory'
|
|
2
2
|
import { RPC } from './rpc.js'
|
3
3
|
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
|
4
4
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
5
|
-
import {
|
6
|
-
import { PeerId } from '@libp2p/peer-id'
|
5
|
+
import { toRpcMessage } from '../utils.js'
|
6
|
+
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
7
7
|
import { keys } from '@libp2p/crypto'
|
8
8
|
import type { Message } from '@libp2p/interfaces/pubsub'
|
9
9
|
|
@@ -16,7 +16,7 @@ export async function signMessage (peerId: PeerId, message: Message) {
|
|
16
16
|
// Get the message in bytes, and prepend with the pubsub prefix
|
17
17
|
const bytes = uint8ArrayConcat([
|
18
18
|
SignPrefix,
|
19
|
-
RPC.Message.encode(
|
19
|
+
RPC.Message.encode(toRpcMessage(message)).finish()
|
20
20
|
])
|
21
21
|
|
22
22
|
if (peerId.privateKey == null) {
|
@@ -55,7 +55,7 @@ export async function verifySignature (message: Message) {
|
|
55
55
|
const bytes = uint8ArrayConcat([
|
56
56
|
SignPrefix,
|
57
57
|
RPC.Message.encode({
|
58
|
-
...message,
|
58
|
+
...toRpcMessage(message),
|
59
59
|
signature: undefined,
|
60
60
|
key: undefined
|
61
61
|
}).finish()
|
@@ -79,21 +79,19 @@ export async function messagePublicKey (message: Message) {
|
|
79
79
|
throw new Error('Could not get the public key from the originator id')
|
80
80
|
}
|
81
81
|
|
82
|
-
const from = PeerId.fromBytes(message.from)
|
83
|
-
|
84
82
|
if (message.key != null) {
|
85
83
|
const keyPeerId = await PeerIdFactory.createFromPubKey(keys.unmarshalPublicKey(message.key))
|
86
84
|
|
87
85
|
// the key belongs to the sender, return the key
|
88
|
-
if (!keyPeerId.equals(from)) {
|
86
|
+
if (!keyPeerId.equals(message.from)) {
|
89
87
|
throw new Error('Public Key does not match the originator')
|
90
88
|
}
|
91
89
|
|
92
90
|
if (keyPeerId.publicKey != null) {
|
93
91
|
return keyPeerId.publicKey
|
94
92
|
}
|
95
|
-
} else if (from.publicKey != null) {
|
96
|
-
return from.publicKey
|
93
|
+
} else if (message.from.publicKey != null) {
|
94
|
+
return message.from.publicKey
|
97
95
|
}
|
98
96
|
|
99
97
|
// We couldn't validate pubkey is from the originator, error
|
package/src/peer-streams.ts
CHANGED
@@ -25,19 +25,19 @@ export class PeerStreams extends EventEmitter<PeerStreamEvents> {
|
|
25
25
|
/**
|
26
26
|
* Write stream - it's preferable to use the write method
|
27
27
|
*/
|
28
|
-
public outboundStream
|
28
|
+
public outboundStream?: Pushable<Uint8Array>
|
29
29
|
/**
|
30
30
|
* Read stream
|
31
31
|
*/
|
32
|
-
public inboundStream
|
32
|
+
public inboundStream?: AsyncIterable<Uint8Array>
|
33
33
|
/**
|
34
34
|
* The raw outbound stream, as retrieved from conn.newStream
|
35
35
|
*/
|
36
|
-
private _rawOutboundStream
|
36
|
+
private _rawOutboundStream?: Stream
|
37
37
|
/**
|
38
38
|
* The raw inbound stream, as retrieved from the callback from libp2p.handle
|
39
39
|
*/
|
40
|
-
private _rawInboundStream
|
40
|
+
private _rawInboundStream?: Stream
|
41
41
|
/**
|
42
42
|
* An AbortController for controlled shutdown of the inbound stream
|
43
43
|
*/
|
@@ -142,6 +142,8 @@ export class PeerStreams extends EventEmitter<PeerStreamEvents> {
|
|
142
142
|
if (_prevStream == null) {
|
143
143
|
this.dispatchEvent(new CustomEvent('stream:outbound'))
|
144
144
|
}
|
145
|
+
|
146
|
+
return this.outboundStream
|
145
147
|
}
|
146
148
|
|
147
149
|
/**
|