Skip to content

Commit f3eb1f1

Browse files
committed
fix: clean up peer discovery flow (#494)
* fix: clean up peer discovery flow * test(fix): let libp2p start after connecting * test(fix): dont auto dial in disco tests
1 parent dbb9e57 commit f3eb1f1

File tree

8 files changed

+71
-66
lines changed

8 files changed

+71
-66
lines changed

src/identify/index.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,9 @@ class IdentifyService {
148148
*
149149
* @async
150150
* @param {Connection} connection
151-
* @param {PeerID} expectedPeer The PeerId the identify response should match
152151
* @returns {Promise<void>}
153152
*/
154-
async identify (connection, expectedPeer) {
153+
async identify (connection) {
155154
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY)
156155
const [data] = await pipe(
157156
stream,
@@ -181,7 +180,7 @@ class IdentifyService {
181180

182181
const id = await PeerId.createFromPubKey(publicKey)
183182
const peerInfo = new PeerInfo(id)
184-
if (expectedPeer && expectedPeer.toB58String() !== id.toB58String()) {
183+
if (connection.remotePeer.toString() !== id.toString()) {
185184
throw errCode(new Error('identified peer does not match the expected peer'), codes.ERR_INVALID_PEER)
186185
}
187186

@@ -192,7 +191,7 @@ class IdentifyService {
192191
IdentifyService.updatePeerAddresses(peerInfo, listenAddrs)
193192
IdentifyService.updatePeerProtocols(peerInfo, protocols)
194193

195-
this.registrar.peerStore.update(peerInfo)
194+
this.registrar.peerStore.replace(peerInfo)
196195
// TODO: Track our observed address so that we can score it
197196
log('received observed address of %s', observedAddr)
198197
}
@@ -283,7 +282,7 @@ class IdentifyService {
283282
IdentifyService.updatePeerProtocols(peerInfo, message.protocols)
284283

285284
// Update the peer in the PeerStore
286-
this.registrar.peerStore.update(peerInfo)
285+
this.registrar.peerStore.replace(peerInfo)
287286
}
288287
}
289288

src/index.js

+14-18
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ class Libp2p extends EventEmitter {
5454
this.upgrader = new Upgrader({
5555
localPeer: this.peerInfo.id,
5656
onConnection: (connection) => {
57-
const peerInfo = getPeerInfo(connection.remotePeer)
58-
59-
this.peerStore.put(peerInfo)
57+
const peerInfo = this.peerStore.put(new PeerInfo(connection.remotePeer))
6058
this.registrar.onConnect(peerInfo, connection)
6159
this.emit('peer:connect', peerInfo)
6260
},
@@ -144,7 +142,7 @@ class Libp2p extends EventEmitter {
144142
this.peerRouting = peerRouting(this)
145143
this.contentRouting = contentRouting(this)
146144

147-
this._peerDiscovered = this._peerDiscovered.bind(this)
145+
this._onDiscoveryPeer = this._onDiscoveryPeer.bind(this)
148146
}
149147

150148
/**
@@ -340,7 +338,7 @@ class Libp2p extends EventEmitter {
340338

341339
// TODO: this should be modified once random-walk is used as
342340
// the other discovery modules
343-
this._dht.on('peer', this._peerDiscovered)
341+
this._dht.on('peer', this._onDiscoveryPeer)
344342
}
345343
}
346344

@@ -351,6 +349,11 @@ class Libp2p extends EventEmitter {
351349
_onDidStart () {
352350
this._isStarted = true
353351

352+
this.peerStore.on('peer', peerInfo => {
353+
this.emit('peer:discovery', peerInfo)
354+
this._maybeConnect(peerInfo)
355+
})
356+
354357
// Peer discovery
355358
this._setupPeerDiscovery()
356359

@@ -362,24 +365,17 @@ class Libp2p extends EventEmitter {
362365
}
363366

364367
/**
365-
* Handles discovered peers. Each discovered peer will be emitted via
366-
* the `peer:discovery` event. If auto dial is enabled for libp2p
367-
* and the current connection count is under the low watermark, the
368-
* peer will be dialed.
368+
* Called whenever peer discovery services emit `peer` events.
369+
* Known peers may be emitted.
369370
* @private
370371
* @param {PeerInfo} peerInfo
371372
*/
372-
_peerDiscovered (peerInfo) {
373-
if (peerInfo.id.toB58String() === this.peerInfo.id.toB58String()) {
373+
_onDiscoveryPeer (peerInfo) {
374+
if (peerInfo.id.toString() === this.peerInfo.id.toString()) {
374375
log.error(new Error(codes.ERR_DISCOVERED_SELF))
375376
return
376377
}
377-
peerInfo = this.peerStore.put(peerInfo)
378-
379-
if (!this.isStarted()) return
380-
381-
this.emit('peer:discovery', peerInfo)
382-
this._maybeConnect(peerInfo)
378+
this.peerStore.put(peerInfo)
383379
}
384380

385381
/**
@@ -432,7 +428,7 @@ class Libp2p extends EventEmitter {
432428
discoveryService = DiscoveryService
433429
}
434430

435-
discoveryService.on('peer', this._peerDiscovered)
431+
discoveryService.on('peer', this._onDiscoveryPeer)
436432
this._discovery.push(discoveryService)
437433
}
438434
}

src/peer-store/index.js

+14-15
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class PeerStore extends EventEmitter {
4545

4646
let peer
4747
// Already know the peer?
48-
if (this.peers.has(peerInfo.id.toB58String())) {
48+
if (this.has(peerInfo.id)) {
4949
peer = this.update(peerInfo)
5050
} else {
5151
peer = this.add(peerInfo)
@@ -118,15 +118,12 @@ class PeerStore extends EventEmitter {
118118

119119
if (multiaddrsIntersection.length !== peerInfo.multiaddrs.size ||
120120
multiaddrsIntersection.length !== recorded.multiaddrs.size) {
121-
// recorded.multiaddrs = peerInfo.multiaddrs
122-
recorded.multiaddrs.clear()
123-
124121
for (const ma of peerInfo.multiaddrs.toArray()) {
125122
recorded.multiaddrs.add(ma)
126123
}
127124

128125
this.emit('change:multiaddrs', {
129-
peerInfo: peerInfo,
126+
peerInfo: recorded,
130127
multiaddrs: recorded.multiaddrs.toArray()
131128
})
132129
}
@@ -139,14 +136,12 @@ class PeerStore extends EventEmitter {
139136

140137
if (protocolsIntersection.size !== peerInfo.protocols.size ||
141138
protocolsIntersection.size !== recorded.protocols.size) {
142-
recorded.protocols.clear()
143-
144139
for (const protocol of peerInfo.protocols) {
145140
recorded.protocols.add(protocol)
146141
}
147142

148143
this.emit('change:protocols', {
149-
peerInfo: peerInfo,
144+
peerInfo: recorded,
150145
protocols: Array.from(recorded.protocols)
151146
})
152147
}
@@ -170,13 +165,7 @@ class PeerStore extends EventEmitter {
170165
peerId = peerId.toB58String()
171166
}
172167

173-
const peerInfo = this.peers.get(peerId)
174-
175-
if (peerInfo) {
176-
return peerInfo
177-
}
178-
179-
return undefined
168+
return this.peers.get(peerId)
180169
}
181170

182171
/**
@@ -217,6 +206,16 @@ class PeerStore extends EventEmitter {
217206

218207
this.remove(peerInfo.id.toB58String())
219208
this.add(peerInfo)
209+
210+
// This should be cleaned up in PeerStore v2
211+
this.emit('change:multiaddrs', {
212+
peerInfo,
213+
multiaddrs: peerInfo.multiaddrs.toArray()
214+
})
215+
this.emit('change:protocols', {
216+
peerInfo,
217+
protocols: Array.from(peerInfo.protocols)
218+
})
220219
}
221220
}
222221

test/dialing/direct.spec.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ describe('Dialing (direct, WebSockets)', () => {
216216
})
217217

218218
sinon.spy(libp2p.dialer.identifyService, 'identify')
219-
sinon.spy(libp2p.peerStore, 'update')
219+
sinon.spy(libp2p.peerStore, 'replace')
220+
sinon.spy(libp2p.upgrader, 'onConnection')
220221

221222
const connection = await libp2p.dialer.connectToMultiaddr(remoteAddr)
222223
expect(connection).to.exist()
@@ -225,7 +226,7 @@ describe('Dialing (direct, WebSockets)', () => {
225226
expect(libp2p.dialer.identifyService.identify.callCount).to.equal(1)
226227
await libp2p.dialer.identifyService.identify.firstCall.returnValue
227228

228-
expect(libp2p.peerStore.update.callCount).to.equal(1)
229+
expect(libp2p.peerStore.replace.callCount).to.equal(1)
229230
})
230231

231232
it('should be able to use hangup to close connections', async () => {

test/identify/index.spec.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('Identify', () => {
4747
protocols,
4848
registrar: {
4949
peerStore: {
50-
update: () => {}
50+
replace: () => {}
5151
}
5252
}
5353
})
@@ -57,27 +57,27 @@ describe('Identify', () => {
5757
})
5858

5959
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
60-
const localConnectionMock = { newStream: () => {} }
60+
const localConnectionMock = { newStream: () => {}, remotePeer: remotePeer.id }
6161
const remoteConnectionMock = { remoteAddr: observedAddr }
6262

6363
const [local, remote] = duplexPair()
6464
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY })
6565

66-
sinon.spy(localIdentify.registrar.peerStore, 'update')
66+
sinon.spy(localIdentify.registrar.peerStore, 'replace')
6767

6868
// Run identify
6969
await Promise.all([
70-
localIdentify.identify(localConnectionMock, remotePeer.id),
70+
localIdentify.identify(localConnectionMock),
7171
remoteIdentify.handleMessage({
7272
connection: remoteConnectionMock,
7373
stream: remote,
7474
protocol: multicodecs.IDENTIFY
7575
})
7676
])
7777

78-
expect(localIdentify.registrar.peerStore.update.callCount).to.equal(1)
78+
expect(localIdentify.registrar.peerStore.replace.callCount).to.equal(1)
7979
// Validate the remote peer gets updated in the peer store
80-
const call = localIdentify.registrar.peerStore.update.firstCall
80+
const call = localIdentify.registrar.peerStore.replace.firstCall
8181
expect(call.args[0].id.bytes).to.equal(remotePeer.id.bytes)
8282
})
8383

@@ -92,7 +92,7 @@ describe('Identify', () => {
9292
})
9393

9494
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
95-
const localConnectionMock = { newStream: () => {} }
95+
const localConnectionMock = { newStream: () => {}, remotePeer }
9696
const remoteConnectionMock = { remoteAddr: observedAddr }
9797

9898
const [local, remote] = duplexPair()
@@ -128,7 +128,7 @@ describe('Identify', () => {
128128
peerInfo: remotePeer,
129129
registrar: {
130130
peerStore: {
131-
update: () => {}
131+
replace: () => {}
132132
}
133133
}
134134
})
@@ -148,7 +148,7 @@ describe('Identify', () => {
148148

149149
sinon.spy(IdentifyService, 'updatePeerAddresses')
150150
sinon.spy(IdentifyService, 'updatePeerProtocols')
151-
sinon.spy(remoteIdentify.registrar.peerStore, 'update')
151+
sinon.spy(remoteIdentify.registrar.peerStore, 'replace')
152152

153153
// Run identify
154154
await Promise.all([
@@ -163,8 +163,8 @@ describe('Identify', () => {
163163
expect(IdentifyService.updatePeerAddresses.callCount).to.equal(1)
164164
expect(IdentifyService.updatePeerProtocols.callCount).to.equal(1)
165165

166-
expect(remoteIdentify.registrar.peerStore.update.callCount).to.equal(1)
167-
const [peerInfo] = remoteIdentify.registrar.peerStore.update.firstCall.args
166+
expect(remoteIdentify.registrar.peerStore.replace.callCount).to.equal(1)
167+
const [peerInfo] = remoteIdentify.registrar.peerStore.replace.firstCall.args
168168
expect(peerInfo.id.bytes).to.eql(localPeer.id.bytes)
169169
expect(peerInfo.multiaddrs.toArray()).to.eql([listeningAddr])
170170
expect(peerInfo.protocols).to.eql(localProtocols)
@@ -198,7 +198,7 @@ describe('Identify', () => {
198198
})
199199

200200
sinon.spy(libp2p.dialer.identifyService, 'identify')
201-
sinon.spy(libp2p.peerStore, 'update')
201+
sinon.spy(libp2p.peerStore, 'replace')
202202

203203
const connection = await libp2p.dialer.connectToMultiaddr(remoteAddr)
204204
expect(connection).to.exist()
@@ -207,7 +207,7 @@ describe('Identify', () => {
207207
expect(libp2p.dialer.identifyService.identify.callCount).to.equal(1)
208208
await libp2p.dialer.identifyService.identify.firstCall.returnValue
209209

210-
expect(libp2p.peerStore.update.callCount).to.equal(1)
210+
expect(libp2p.peerStore.replace.callCount).to.equal(1)
211211
await connection.close()
212212
})
213213

test/peer-discovery/index.node.js

+22-10
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ describe('peer discovery scenarios', () => {
4848
},
4949
config: {
5050
peerDiscovery: {
51+
autoDial: false,
5152
bootstrap: {
5253
enabled: true,
5354
list: bootstrappers
@@ -84,6 +85,7 @@ describe('peer discovery scenarios', () => {
8485
},
8586
config: {
8687
peerDiscovery: {
88+
autoDial: false,
8789
mdns: {
8890
enabled: true,
8991
interval: 200, // discover quickly
@@ -111,9 +113,11 @@ describe('peer discovery scenarios', () => {
111113
}
112114
})
113115

114-
await remoteLibp2p1.start()
115-
await remoteLibp2p2.start()
116-
await libp2p.start()
116+
await Promise.all([
117+
remoteLibp2p1.start(),
118+
remoteLibp2p2.start(),
119+
libp2p.start()
120+
])
117121

118122
await deferred.promise
119123

@@ -130,11 +134,14 @@ describe('peer discovery scenarios', () => {
130134
dht: KadDht
131135
},
132136
config: {
137+
peerDiscovery: {
138+
autoDial: false
139+
},
133140
dht: {
134141
randomWalk: {
135142
enabled: true,
136-
delay: 100,
137-
interval: 200, // start the query sooner
143+
delay: 100, // start the first query quickly
144+
interval: 1000,
138145
timeout: 3000
139146
},
140147
enabled: true
@@ -153,9 +160,10 @@ describe('peer discovery scenarios', () => {
153160
}
154161
})
155162

156-
await remoteLibp2p1.start()
157-
await remoteLibp2p2.start()
158-
await libp2p.start()
163+
await Promise.all([
164+
remoteLibp2p1.start(),
165+
remoteLibp2p2.start()
166+
])
159167

160168
// Topology:
161169
// A -> B
@@ -165,8 +173,12 @@ describe('peer discovery scenarios', () => {
165173
remoteLibp2p2.dial(remotePeerInfo1)
166174
])
167175

176+
libp2p.start()
177+
168178
await deferred.promise
169-
await remoteLibp2p1.stop()
170-
await remoteLibp2p2.stop()
179+
return Promise.all([
180+
remoteLibp2p1.stop(),
181+
remoteLibp2p2.stop()
182+
])
171183
})
172184
})

0 commit comments

Comments
 (0)