Skip to content

Commit 7b8d016

Browse files
vasco-santosjacobheun
andcommittedMay 28, 2020
chore: apply suggestions from code review
Co-authored-by: Jacob Heun <jacobheun@gmail.com>
1 parent ce38033 commit 7b8d016

10 files changed

+112
-82
lines changed
 

‎doc/API.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,6 @@ Add known `protocols` of a given peer.
814814
peerStore.protoBook.add(peerId, protocols)
815815
```
816816

817-
* [`peerStore.keyBook.get`](#peerstorekeybookget)
818-
* [`peerStore.keyBook.set`](#peerstorekeybookset)
819817

820818
### peerStore.keyBook.delete
821819

@@ -840,7 +838,7 @@ Delete the provided peer from the book.
840838
```js
841839
peerStore.keyBook.delete(peerId)
842840
// false
843-
peerStore.keyBook.set(peerId)
841+
peerStore.keyBook.set(peerId, publicKey)
844842
peerStore.keyBook.delete(peerId)
845843
// true
846844
```
@@ -868,7 +866,7 @@ Get the known `PublicKey` of a provided peer.
868866
```js
869867
peerStore.keyBook.get(peerId)
870868
// undefined
871-
peerStore.keyBook.set(peerId) // with inline public key
869+
peerStore.keyBook.set(peerId, publicKey)
872870
peerStore.keyBook.get(peerId)
873871
// PublicKey
874872
```
@@ -877,13 +875,14 @@ peerStore.keyBook.get(peerId)
877875

878876
Set known `peerId`. This can include its Public Key.
879877

880-
`peerStore.keyBook.set(peerId)`
878+
`peerStore.keyBook.set(peerId, publicKey)`
881879

882880
#### Parameters
883881

884882
| Name | Type | Description |
885883
|------|------|-------------|
886884
| peerId | [`PeerId`][peer-id] | peerId to set |
885+
| publicKey | [`RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey`][keys] | peer's public key |
887886

888887
#### Returns
889888

@@ -894,7 +893,8 @@ Set known `peerId`. This can include its Public Key.
894893
#### Example
895894

896895
```js
897-
peerStore.keyBook.set(peerId)
896+
const publicKey = peerId.pubKey
897+
peerStore.keyBook.set(peerId, publicKey)
898898
```
899899

900900
### peerStore.protoBook.delete
@@ -1420,3 +1420,4 @@ This event will be triggered anytime we are disconnected from another peer, rega
14201420
[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
14211421
[multiaddr]: https://github.com/multiformats/js-multiaddr
14221422
[peer-id]: https://github.com/libp2p/js-peer-id
1423+
[keys]: https://github.com/libp2p/js-libp2p-crypto/tree/master/src/keys

‎src/peer-store/README.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ Several libp2p subsystems will perform operations, which will gather relevant in
1010

1111
In a libp2p node's life, it will discover peers through its discovery protocols. In a typical discovery protocol, addresses of the peer are discovered along with its peer id. Once this happens, the PeerStore should collect this information for future (or immediate) usage by other subsystems. When the information is stored, the PeerStore should inform interested parties of the peer discovered (`peer` event).
1212

13-
Taking into account a different scenario, a peer might perform/receive a dial request to/from a unkwown peer. In such a scenario, the PeerStore must store the peer's multiaddr once a connection is established.
13+
Taking into account a different scenario, a peer might perform/receive a dial request to/from a unkwown peer. In such a scenario, the PeerStore must store the peer's multiaddr once a connection is established.
14+
15+
When a connection is being upgraded, more precisely after its encryption, or even in a discovery protocol, a libp2p node can get to know other parties public keys. In this scenario, libp2p will add the peer's public key to its `KeyBook`.
1416

1517
After a connection is established with a peer, the Identify protocol will run automatically. A stream is created and peers exchange their information (Multiaddrs, running protocols and their public key). Once this information is obtained, it should be added to the PeerStore. In this specific case, as we are speaking to the source of truth, we should ensure the PeerStore is prioritizing these records. If the recorded `multiaddrs` or `protocols` have changed, interested parties must be informed via the `change:multiaddrs` or `change:protocols` events respectively.
1618

@@ -42,7 +44,7 @@ The `addressBook` keeps the known multiaddrs of a peer. The multiaddrs of each p
4244

4345
`Map<string, Address>`
4446

45-
A `peerId.toString()` identifier mapping to a `Address` object, which should have the following structure:
47+
A `peerId.toB58String()` identifier mapping to a `Address` object, which should have the following structure:
4648

4749
```js
4850
{
@@ -52,19 +54,19 @@ A `peerId.toString()` identifier mapping to a `Address` object, which should hav
5254

5355
#### Key Book
5456

55-
The `keyBook` tracks the publick keys of the peers by keeping their [`PeerId`][peer-id].
57+
The `keyBook` tracks the public keys of the peers by keeping their [`PeerId`][peer-id].
5658

5759
`Map<string, PeerId`
5860

59-
A `peerId.toString()` identifier mapping to a `PeerId` of the peer. This instance contains the peer public key.
61+
A `peerId.toB58String()` identifier mapping to a `PeerId` of the peer. This instance contains the peer public key.
6062

6163
#### Protocol Book
6264

6365
The `protoBook` holds the identifiers of the protocols supported by each peer. The protocols supported by each peer are dynamic and will change over time.
6466

6567
`Map<string, Set<string>>`
6668

67-
A `peerId.toString()` identifier mapping to a `Set` of protocol identifier strings.
69+
A `peerId.toB58String()` identifier mapping to a `Set` of protocol identifier strings.
6870

6971
#### Metadata Book
7072

@@ -129,4 +131,4 @@ Metadata is stored under the following key pattern:
129131
- When improving libp2p configuration for specific runtimes, we should take into account the PeerStore recommended datastore.
130132
- When improving libp2p configuration, we should think about a possible way of allowing the configuration of Bootstrap to be influenced by the persisted peers, as a way to decrease the load on Bootstrap nodes.
131133

132-
[peer-id]: https://github.com/libp2p/js-peer-id
134+
[peer-id]: https://github.com/libp2p/js-peer-id

‎src/peer-store/address-book.js

+10
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ class AddressBook extends Book {
8686
this._setData(peerId, addresses)
8787
log(`stored provided multiaddrs for ${id}`)
8888

89+
// Notify the existance of a new peer
90+
if (!rec) {
91+
this._ps.emit('peer', peerId)
92+
}
93+
8994
return this
9095
}
9196

@@ -125,6 +130,11 @@ class AddressBook extends Book {
125130

126131
log(`added provided multiaddrs for ${id}`)
127132

133+
// Notify the existance of a new peer
134+
if (!rec) {
135+
this._ps.emit('peer', peerId)
136+
}
137+
128138
return this
129139
}
130140

‎src/peer-store/book.js

-5
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,6 @@ class Book {
5858
// Store data in memory
5959
this.data.set(b58key, data)
6060

61-
// Store PeerId
62-
if (!PeerId.isPeerId(data)) {
63-
this._ps.keyBook.set(peerId)
64-
}
65-
6661
// Emit event
6762
emit && this._emit(peerId, data)
6863
}

‎src/peer-store/key-book.js

+13-11
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class KeyBook extends Book {
2424
constructor (peerStore) {
2525
super({
2626
peerStore,
27-
eventName: 'change:pubkey', // TODO: the name is not probably the best!?
27+
eventName: 'change:pubkey',
2828
eventProperty: 'pubkey',
2929
eventTransformer: (data) => data.pubKey
3030
})
@@ -37,12 +37,13 @@ class KeyBook extends Book {
3737
}
3838

3939
/**
40-
* Set PeerId. If the peer was not known before, it will be added.
40+
* Set the Peer public key.
4141
* @override
4242
* @param {PeerId} peerId
43+
* @param {RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey} publicKey
4344
* @return {KeyBook}
44-
*/
45-
set (peerId) {
45+
*/
46+
set (peerId, publicKey) {
4647
if (!PeerId.isPeerId(peerId)) {
4748
log.error('peerId must be an instance of peer-id to store data')
4849
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
@@ -51,12 +52,13 @@ class KeyBook extends Book {
5152
const id = peerId.toB58String()
5253
const recPeerId = this.data.get(id)
5354

54-
!recPeerId && this._ps.emit('peer', peerId)
55-
// If no record available, or it is incomplete
56-
if (!recPeerId || (peerId.pubKey && !recPeerId.pubKey)) {
57-
this._setData(peerId, peerId, {
58-
emit: Boolean(peerId.pubKey) // No persistence if no public key
59-
})
55+
// If no record available, and this is valid
56+
if (!recPeerId && publicKey) {
57+
// This might be unecessary, but we want to store the PeerId
58+
// to avoid an async operation when reconstructing the PeerId
59+
peerId.pubKey = publicKey
60+
61+
this._setData(peerId, peerId)
6062
log(`stored provided public key for ${id}`)
6163
}
6264

@@ -67,7 +69,7 @@ class KeyBook extends Book {
6769
* Get Public key of the given PeerId, if stored.
6870
* @override
6971
* @param {PeerId} peerId
70-
* @return {PublicKey}
72+
* @return {RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey}
7173
*/
7274
get (peerId) {
7375
if (!PeerId.isPeerId(peerId)) {

‎src/peer-store/persistent/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class PersistentPeerStore extends PeerStore {
111111
log('create batch commit')
112112
const batch = this._datastore.batch()
113113
for (const peerIdStr of commitPeers) {
114-
// PeerId (replace by keyBook)
114+
// PeerId
115115
const peerId = this.keyBook.data.get(peerIdStr) || PeerId.createFromB58String(peerIdStr)
116116

117117
// Address Book

‎test/peer-store/key-book.spec.js

+14-18
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ chai.use(require('chai-bytes'))
77
const { expect } = chai
88
const sinon = require('sinon')
99

10-
const PeerId = require('peer-id')
1110
const PeerStore = require('../../src/peer-store')
1211

1312
const peerUtils = require('../utils/creators/peer')
@@ -24,7 +23,7 @@ describe('keyBook', () => {
2423
kb = peerStore.keyBook
2524
})
2625

27-
it('throwns invalid parameters error if invalid PeerId is provided', () => {
26+
it('throwns invalid parameters error if invalid PeerId is provided in set', () => {
2827
try {
2928
kb.set('invalid peerId')
3029
} catch (err) {
@@ -34,9 +33,19 @@ describe('keyBook', () => {
3433
throw new Error('invalid peerId should throw error')
3534
})
3635

36+
it('throwns invalid parameters error if invalid PeerId is provided in get', () => {
37+
try {
38+
kb.get('invalid peerId')
39+
} catch (err) {
40+
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
41+
return
42+
}
43+
throw new Error('invalid peerId should throw error')
44+
})
45+
3746
it('stores the peerId in the book and returns the public key', () => {
3847
// Set PeerId
39-
kb.set(peerId)
48+
kb.set(peerId, peerId.pubKey)
4049

4150
// Get public key
4251
const pubKey = kb.get(peerId)
@@ -47,22 +56,9 @@ describe('keyBook', () => {
4756
const spy = sinon.spy(kb, '_setData')
4857

4958
// Set PeerId
50-
kb.set(peerId)
51-
kb.set(peerId)
59+
kb.set(peerId, peerId.pubKey)
60+
kb.set(peerId, peerId.pubKey)
5261

5362
expect(spy).to.have.property('callCount', 1)
5463
})
55-
56-
it('stores if already stored but there was no public key stored', () => {
57-
const spy = sinon.spy(kb, '_setData')
58-
59-
// Set PeerId without public key
60-
const p = PeerId.createFromB58String(peerId.toB58String())
61-
kb.set(p)
62-
63-
// Set complete peerId
64-
kb.set(peerId)
65-
66-
expect(spy).to.have.property('callCount', 2)
67-
})
6864
})

‎test/peer-store/peer-store.node.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict'
2+
/* eslint-env mocha */
3+
4+
const chai = require('chai')
5+
chai.use(require('dirty-chai'))
6+
chai.use(require('chai-as-promised'))
7+
const { expect } = chai
8+
const sinon = require('sinon')
9+
10+
const baseOptions = require('../utils/base-options')
11+
const peerUtils = require('../utils/creators/peer')
12+
13+
describe('libp2p.peerStore', () => {
14+
let libp2p, remoteLibp2p
15+
16+
beforeEach(async () => {
17+
[libp2p, remoteLibp2p] = await peerUtils.createPeer({
18+
number: 2,
19+
populateAddressBooks: false,
20+
config: {
21+
...baseOptions
22+
}
23+
})
24+
})
25+
26+
it('adds peer address to AddressBook when establishing connection', async () => {
27+
const spyAddressBook = sinon.spy(libp2p.peerStore.addressBook, 'add')
28+
const remoteMultiaddr = `${remoteLibp2p.multiaddrs[0]}/p2p/${remoteLibp2p.peerId.toB58String()}`
29+
const conn = await libp2p.dial(remoteMultiaddr)
30+
31+
expect(conn).to.exist()
32+
expect(spyAddressBook).to.have.property('callCount', 1)
33+
})
34+
})

‎test/peer-store/peer-store.spec.js

+4-19
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
const chai = require('chai')
55
chai.use(require('dirty-chai'))
66
const { expect } = chai
7-
const sinon = require('sinon')
87

98
const PeerStore = require('../../src/peer-store')
109
const multiaddr = require('multiaddr')
@@ -50,25 +49,11 @@ describe('peer-store', () => {
5049
expect(peer).to.not.exist()
5150
})
5251

53-
it('sets the peer to the KeyBook when added to the AddressBook', () => {
54-
const spyPeerStore = sinon.spy(peerStore.keyBook, 'set')
52+
it('sets the peer\'s public key to the KeyBook', () => {
53+
peerStore.keyBook.set(peerIds[0], peerIds[0].pubKey)
5554

56-
peerStore.addressBook.set(peerIds[0], [addr1, addr2])
57-
expect(spyPeerStore).to.have.property('callCount', 1)
58-
})
59-
60-
it('sets the peer to the KeyBook when added to the ProtoBook', () => {
61-
const spyPeerStore = sinon.spy(peerStore.keyBook, 'set')
62-
63-
peerStore.protoBook.set(peerIds[0], [proto1])
64-
expect(spyPeerStore).to.have.property('callCount', 1)
65-
})
66-
67-
it('does not re-set the to the KeyBook when directly added to it', () => {
68-
const spyPeerStore = sinon.spy(peerStore.keyBook, 'set')
69-
70-
peerStore.keyBook.set(peerIds[0])
71-
expect(spyPeerStore).to.have.property('callCount', 1)
55+
const pubKey = peerStore.keyBook.get(peerIds[0])
56+
expect(pubKey).to.exist()
7257
})
7358
})
7459

‎test/peer-store/persisted-peer-store.spec.js

+21-16
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,14 @@ describe('Persisted PeerStore', () => {
6868
// AddressBook
6969
peerStore.addressBook.set(peer, multiaddrs)
7070

71-
expect(spyDirty).to.have.property('callCount', 2) // Address + PeerId
72-
expect(spyDs).to.have.property('callCount', 2)
71+
expect(spyDirty).to.have.property('callCount', 1) // Address
72+
expect(spyDs).to.have.property('callCount', 1)
7373

7474
// ProtoBook
7575
peerStore.protoBook.set(peer, protocols)
7676

77-
expect(spyDirty).to.have.property('callCount', 3) // Protocol
78-
expect(spyDs).to.have.property('callCount', 3)
77+
expect(spyDirty).to.have.property('callCount', 2) // Protocol
78+
expect(spyDs).to.have.property('callCount', 2)
7979

8080
// Should have three peer records stored in the datastore
8181
const queryParams = {
@@ -86,7 +86,7 @@ describe('Persisted PeerStore', () => {
8686
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
8787
count++
8888
}
89-
expect(count).to.equal(3)
89+
expect(count).to.equal(2)
9090

9191
// Validate data
9292
const storedPeer = peerStore.get(peer)
@@ -110,11 +110,15 @@ describe('Persisted PeerStore', () => {
110110
peerStore.addressBook.set(peers[0], [multiaddrs[0]])
111111
peerStore.addressBook.set(peers[1], [multiaddrs[1]])
112112

113+
// KeyBook
114+
peerStore.keyBook.set(peers[0], peers[0].pubKey)
115+
peerStore.keyBook.set(peers[1], peers[1].pubKey)
116+
113117
// ProtoBook
114118
peerStore.protoBook.set(peers[0], protocols)
115119
peerStore.protoBook.set(peers[1], protocols)
116120

117-
expect(spyDs).to.have.property('callCount', 6) // 2 AddressBook + 2 ProtoBook + 2 KeyBook
121+
expect(spyDs).to.have.property('callCount', 6) // 2 AddressBook + 2 KeyBook + 2 ProtoBook
118122
expect(peerStore.peers.size).to.equal(2)
119123

120124
await peerStore.stop()
@@ -127,11 +131,12 @@ describe('Persisted PeerStore', () => {
127131

128132
await peerStore.start()
129133

130-
expect(spy).to.have.property('callCount', 6) // 6 datastore entries
131-
expect(spyDs).to.have.property('callCount', 6) // 6 previous operations
134+
expect(spy).to.have.property('callCount', 6)
135+
expect(spyDs).to.have.property('callCount', 6)
132136

133137
expect(peerStore.peers.size).to.equal(2)
134138
expect(peerStore.addressBook.data.size).to.equal(2)
139+
expect(peerStore.keyBook.data.size).to.equal(2)
135140
expect(peerStore.protoBook.data.size).to.equal(2)
136141
})
137142

@@ -159,7 +164,7 @@ describe('Persisted PeerStore', () => {
159164
expect(spyAddressBook).to.have.property('callCount', 1)
160165
expect(spyKeyBook).to.have.property('callCount', 1)
161166
expect(spyProtoBook).to.have.property('callCount', 1)
162-
expect(spyDs).to.have.property('callCount', 3)
167+
expect(spyDs).to.have.property('callCount', 2)
163168

164169
// Should have zero peer records stored in the datastore
165170
const queryParams = {
@@ -201,7 +206,7 @@ describe('Persisted PeerStore', () => {
201206
// Remove data from the same Peer
202207
peerStore.addressBook.delete(peers[0])
203208

204-
expect(spyDirty).to.have.property('callCount', 4) // 2 AddrBook ops, 1 ProtoBook op, 1 KeyBook op
209+
expect(spyDirty).to.have.property('callCount', 3) // 2 AddrBook ops, 1 ProtoBook op
205210
expect(peerStore._dirtyPeers.size).to.equal(1)
206211
expect(spyDs).to.have.property('callCount', 0)
207212

@@ -215,15 +220,15 @@ describe('Persisted PeerStore', () => {
215220
// Add data for second book
216221
peerStore.addressBook.set(peers[1], multiaddrs)
217222

218-
expect(spyDirty).to.have.property('callCount', 6)
223+
expect(spyDirty).to.have.property('callCount', 4)
219224
expect(spyDs).to.have.property('callCount', 1)
220225

221226
// Should have two peer records stored in the datastore
222227
let count = 0
223228
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
224229
count++
225230
}
226-
expect(count).to.equal(4)
231+
expect(count).to.equal(2)
227232
expect(peerStore.peers.size).to.equal(2)
228233
})
229234

@@ -240,7 +245,7 @@ describe('Persisted PeerStore', () => {
240245
peerStore.protoBook.set(peer, protocols)
241246

242247
expect(spyDs).to.have.property('callCount', 0)
243-
expect(spyDirty).to.have.property('callCount', 2) // ProtoBook + KeyBook
248+
expect(spyDirty).to.have.property('callCount', 1) // ProtoBook
244249
expect(peerStore._dirtyPeers.size).to.equal(1)
245250

246251
const queryParams = {
@@ -252,7 +257,7 @@ describe('Persisted PeerStore', () => {
252257

253258
await peerStore.stop()
254259

255-
expect(spyDirty).to.have.property('callCount', 2)
260+
expect(spyDirty).to.have.property('callCount', 1)
256261
expect(spyDs).to.have.property('callCount', 1)
257262
expect(peerStore._dirtyPeers.size).to.equal(0) // Reset
258263

@@ -261,7 +266,7 @@ describe('Persisted PeerStore', () => {
261266
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
262267
count++
263268
}
264-
expect(count).to.equal(2)
269+
expect(count).to.equal(1)
265270
expect(peerStore.peers.size).to.equal(1)
266271
})
267272
})
@@ -354,7 +359,7 @@ describe('libp2p.peerStore (Persisted)', () => {
354359

355360
await newNode.start()
356361

357-
expect(spy).to.have.property('callCount', 6) // 6 datastore entries
362+
expect(spy).to.have.property('callCount', 4) // 4 datastore entries
358363

359364
expect(newNode.peerStore.peers.size).to.equal(2)
360365

0 commit comments

Comments
 (0)
Please sign in to comment.