mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-27 03:22:15 +00:00
chore: merge 0.28x updates
This commit is contained in:
commit
c0bbda24c2
87
doc/API.md
87
doc/API.md
@ -26,6 +26,9 @@
|
||||
* [`peerStore.addressBook.get`](#peerstoreaddressbookget)
|
||||
* [`peerStore.addressBook.getMultiaddrsForPeer`](#peerstoreaddressbookgetmultiaddrsforpeer)
|
||||
* [`peerStore.addressBook.set`](#peerstoreaddressbookset)
|
||||
* [`peerStore.keyBook.delete`](#peerstorekeybookdelete)
|
||||
* [`peerStore.keyBook.get`](#peerstorekeybookget)
|
||||
* [`peerStore.keyBook.set`](#peerstorekeybookset)
|
||||
* [`peerStore.protoBook.add`](#peerstoreprotobookadd)
|
||||
* [`peerStore.protoBook.delete`](#peerstoreprotobookdelete)
|
||||
* [`peerStore.protoBook.get`](#peerstoreprotobookget)
|
||||
@ -870,6 +873,89 @@ Add known `protocols` of a given peer.
|
||||
peerStore.protoBook.add(peerId, protocols)
|
||||
```
|
||||
|
||||
|
||||
### peerStore.keyBook.delete
|
||||
|
||||
Delete the provided peer from the book.
|
||||
|
||||
`peerStore.keyBook.delete(peerId)`
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| peerId | [`PeerId`][peer-id] | peerId to remove |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `boolean` | true if found and removed |
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
peerStore.keyBook.delete(peerId)
|
||||
// false
|
||||
peerStore.keyBook.set(peerId, publicKey)
|
||||
peerStore.keyBook.delete(peerId)
|
||||
// true
|
||||
```
|
||||
|
||||
### peerStore.keyBook.get
|
||||
|
||||
Get the known `PublicKey` of a provided peer.
|
||||
|
||||
`peerStore.keyBook.get(peerId)`
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| peerId | [`PeerId`][peer-id] | peerId to get |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey` | Peer PublicKey |
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
peerStore.keyBook.get(peerId)
|
||||
// undefined
|
||||
peerStore.keyBook.set(peerId, publicKey)
|
||||
peerStore.keyBook.get(peerId)
|
||||
// PublicKey
|
||||
```
|
||||
|
||||
### peerStore.keyBook.set
|
||||
|
||||
Set known `peerId`. This can include its Public Key.
|
||||
|
||||
`peerStore.keyBook.set(peerId, publicKey)`
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| peerId | [`PeerId`][peer-id] | peerId to set |
|
||||
| publicKey | [`RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey`][keys] | peer's public key |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `KeyBook` | Returns the Key Book component |
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
const publicKey = peerId.pubKey
|
||||
peerStore.keyBook.set(peerId, publicKey)
|
||||
```
|
||||
|
||||
### peerStore.protoBook.delete
|
||||
|
||||
Delete the provided peer from the book.
|
||||
@ -1393,3 +1479,4 @@ This event will be triggered anytime we are disconnected from another peer, rega
|
||||
[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
|
||||
[multiaddr]: https://github.com/multiformats/js-multiaddr
|
||||
[peer-id]: https://github.com/libp2p/js-peer-id
|
||||
[keys]: https://github.com/libp2p/js-libp2p-crypto/tree/master/src/keys
|
@ -83,6 +83,7 @@
|
||||
"aegir": "^21.9.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-bytes": "^0.1.2",
|
||||
"chai-string": "^1.5.0",
|
||||
"cids": "^0.8.0",
|
||||
"datastore-fs": "^1.0.0",
|
||||
|
@ -171,18 +171,22 @@ class ConnectionManager extends EventEmitter {
|
||||
* @param {Connection} connection
|
||||
*/
|
||||
onConnect (connection) {
|
||||
const peerId = connection.remotePeer.toB58String()
|
||||
const storedConn = this.connections.get(peerId)
|
||||
const peerId = connection.remotePeer
|
||||
const peerIdStr = peerId.toB58String()
|
||||
const storedConn = this.connections.get(peerIdStr)
|
||||
|
||||
if (storedConn) {
|
||||
storedConn.push(connection)
|
||||
} else {
|
||||
this.connections.set(peerId, [connection])
|
||||
this.connections.set(peerIdStr, [connection])
|
||||
this.emit('peer:connect', connection)
|
||||
}
|
||||
|
||||
if (!this._peerValues.has(peerId)) {
|
||||
this._peerValues.set(peerId, this._options.defaultPeerValue)
|
||||
this._libp2p.peerStore.addressBook.add(peerId, [connection.remoteAddr])
|
||||
this._libp2p.peerStore.keyBook.set(peerId, peerId.pubKey)
|
||||
|
||||
if (!this._peerValues.has(peerIdStr)) {
|
||||
this._peerValues.set(peerIdStr, this._options.defaultPeerValue)
|
||||
}
|
||||
|
||||
this._checkLimit('maxConnections', this.size)
|
||||
|
@ -10,7 +10,9 @@ Several libp2p subsystems will perform operations, which will gather relevant in
|
||||
|
||||
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).
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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`.
|
||||
|
||||
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.
|
||||
|
||||
@ -42,7 +44,7 @@ The `addressBook` keeps the known multiaddrs of a peer. The multiaddrs of each p
|
||||
|
||||
`Map<string, Address>`
|
||||
|
||||
A `peerId.toString()` identifier mapping to a `Address` object, which should have the following structure:
|
||||
A `peerId.toB58String()` identifier mapping to a `Address` object, which should have the following structure:
|
||||
|
||||
```js
|
||||
{
|
||||
@ -52,9 +54,11 @@ A `peerId.toString()` identifier mapping to a `Address` object, which should hav
|
||||
|
||||
#### Key Book
|
||||
|
||||
The `keyBook` tracks the keys of the peers.
|
||||
The `keyBook` tracks the public keys of the peers by keeping their [`PeerId`][peer-id].
|
||||
|
||||
**Not Yet Implemented**
|
||||
`Map<string, PeerId`
|
||||
|
||||
A `peerId.toB58String()` identifier mapping to a `PeerId` of the peer. This instance contains the peer public key.
|
||||
|
||||
#### Protocol Book
|
||||
|
||||
@ -62,7 +66,7 @@ The `protoBook` holds the identifiers of the protocols supported by each peer. T
|
||||
|
||||
`Map<string, Set<string>>`
|
||||
|
||||
A `peerId.toString()` identifier mapping to a `Set` of protocol identifier strings.
|
||||
A `peerId.toB58String()` identifier mapping to a `Set` of protocol identifier strings.
|
||||
|
||||
#### Metadata Book
|
||||
|
||||
@ -74,8 +78,9 @@ For the complete API documentation, you should check the [API.md](../../doc/API.
|
||||
|
||||
Access to its underlying books:
|
||||
|
||||
- `peerStore.protoBook.*`
|
||||
- `peerStore.addressBook.*`
|
||||
- `peerStore.keyBook.*`
|
||||
- `peerStore.protoBook.*`
|
||||
|
||||
### Events
|
||||
|
||||
@ -107,8 +112,6 @@ All the known peer protocols are stored with a key pattern as follows:
|
||||
|
||||
**KeyBook**
|
||||
|
||||
_NOT_YET_IMPLEMENTED_
|
||||
|
||||
All public keys are stored under the following pattern:
|
||||
|
||||
` /peers/keys/<b32 peer id no padding>`
|
||||
@ -127,3 +130,5 @@ Metadata is stored under the following key pattern:
|
||||
- Further API methods will probably need to be added in the context of multiaddr validity and confidence.
|
||||
- When improving libp2p configuration for specific runtimes, we should take into account the PeerStore recommended datastore.
|
||||
- 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.
|
||||
|
||||
[peer-id]: https://github.com/libp2p/js-peer-id
|
||||
|
@ -47,7 +47,7 @@ class Book {
|
||||
* Set data into the datastructure, persistence and emit it using the provided transformers.
|
||||
* @private
|
||||
* @param {PeerId} peerId peerId of the data to store
|
||||
* @param {Array<*>} data data to store.
|
||||
* @param {*} data data to store.
|
||||
* @param {Object} [options] storing options.
|
||||
* @param {boolean} [options.emit = true] emit the provided data.
|
||||
* @return {void}
|
||||
@ -57,22 +57,22 @@ class Book {
|
||||
|
||||
// Store data in memory
|
||||
this.data.set(b58key, data)
|
||||
this._setPeerId(peerId)
|
||||
|
||||
// Emit event
|
||||
emit && this._ps.emit(this.eventName, {
|
||||
peerId,
|
||||
[this.eventProperty]: this.eventTransformer(data)
|
||||
})
|
||||
emit && this._emit(peerId, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add known data of a provided peer.
|
||||
* Emit data.
|
||||
* @private
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<Data>|Data} data
|
||||
* @param {*} data
|
||||
*/
|
||||
add (peerId, data) {
|
||||
throw errcode(new Error('set must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||
_emit (peerId, data) {
|
||||
this._ps.emit(this.eventName, {
|
||||
peerId,
|
||||
[this.eventProperty]: this.eventTransformer(data)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,24 +104,10 @@ class Book {
|
||||
return false
|
||||
}
|
||||
|
||||
this._ps.emit(this.eventName, {
|
||||
peerId,
|
||||
[this.eventProperty]: []
|
||||
})
|
||||
this._emit(peerId, [])
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Set PeerId into peerStore datastructure.
|
||||
* @private
|
||||
* @param {PeerId} peerId
|
||||
*/
|
||||
_setPeerId (peerId) {
|
||||
if (!this._ps.peerIds.get(peerId)) {
|
||||
this._ps.peerIds.set(peerId.toB58String(), peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Book
|
||||
|
@ -9,6 +9,7 @@ const { EventEmitter } = require('events')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const AddressBook = require('./address-book')
|
||||
const KeyBook = require('./key-book')
|
||||
const ProtoBook = require('./proto-book')
|
||||
|
||||
const {
|
||||
@ -41,17 +42,15 @@ class PeerStore extends EventEmitter {
|
||||
*/
|
||||
this.addressBook = new AddressBook(this)
|
||||
|
||||
/**
|
||||
* KeyBook containing a map of peerIdStr to their PeerId with public keys.
|
||||
*/
|
||||
this.keyBook = new KeyBook(this)
|
||||
|
||||
/**
|
||||
* ProtoBook containing a map of peerIdStr to supported protocols.
|
||||
*/
|
||||
this.protoBook = new ProtoBook(this)
|
||||
|
||||
/**
|
||||
* TODO: this should only exist until we have the key-book
|
||||
* Map known peers to their peer-id.
|
||||
* @type {Map<string, Array<PeerId>}
|
||||
*/
|
||||
this.peerIds = new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +72,7 @@ class PeerStore extends EventEmitter {
|
||||
|
||||
// AddressBook
|
||||
for (const [idStr, addresses] of this.addressBook.data.entries()) {
|
||||
const id = PeerId.createFromCID(idStr)
|
||||
const id = this.keyBook.data.get(idStr) || PeerId.createFromCID(idStr)
|
||||
peersData.set(idStr, {
|
||||
id,
|
||||
addresses,
|
||||
@ -84,10 +83,11 @@ class PeerStore extends EventEmitter {
|
||||
// ProtoBook
|
||||
for (const [idStr, protocols] of this.protoBook.data.entries()) {
|
||||
const pData = peersData.get(idStr)
|
||||
const id = this.keyBook.data.get(idStr) || PeerId.createFromCID(idStr)
|
||||
|
||||
if (!pData) {
|
||||
peersData.set(idStr, {
|
||||
id: PeerId.createFromCID(idStr),
|
||||
id,
|
||||
addresses: [],
|
||||
protocols: Array.from(protocols)
|
||||
})
|
||||
@ -104,8 +104,10 @@ class PeerStore extends EventEmitter {
|
||||
*/
|
||||
delete (peerId) {
|
||||
const addressesDeleted = this.addressBook.delete(peerId)
|
||||
const keyDeleted = this.keyBook.delete(peerId)
|
||||
const protocolsDeleted = this.protoBook.delete(peerId)
|
||||
return addressesDeleted || protocolsDeleted
|
||||
|
||||
return addressesDeleted || keyDeleted || protocolsDeleted
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +120,7 @@ class PeerStore extends EventEmitter {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
const id = this.peerIds.get(peerId.toB58String())
|
||||
const id = this.keyBook.data.get(peerId.toB58String())
|
||||
const addresses = this.addressBook.get(peerId)
|
||||
const protocols = this.protoBook.get(peerId)
|
||||
|
||||
|
85
src/peer-store/key-book.js
Normal file
85
src/peer-store/key-book.js
Normal file
@ -0,0 +1,85 @@
|
||||
'use strict'
|
||||
|
||||
const errcode = require('err-code')
|
||||
const debug = require('debug')
|
||||
const log = debug('libp2p:peer-store:key-book')
|
||||
log.error = debug('libp2p:peer-store:key-book:error')
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const Book = require('./book')
|
||||
|
||||
const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('../errors')
|
||||
|
||||
/**
|
||||
* The KeyBook is responsible for keeping the known public keys of a peer.
|
||||
*/
|
||||
class KeyBook extends Book {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {PeerStore} peerStore
|
||||
*/
|
||||
constructor (peerStore) {
|
||||
super({
|
||||
peerStore,
|
||||
eventName: 'change:pubkey',
|
||||
eventProperty: 'pubkey',
|
||||
eventTransformer: (data) => data.pubKey
|
||||
})
|
||||
|
||||
/**
|
||||
* Map known peers to their known Public Key.
|
||||
* @type {Map<string, PeerId>}
|
||||
*/
|
||||
this.data = new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Peer public key.
|
||||
* @override
|
||||
* @param {PeerId} peerId
|
||||
* @param {RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey} publicKey
|
||||
* @return {KeyBook}
|
||||
*/
|
||||
set (peerId, publicKey) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
log.error('peerId must be an instance of peer-id to store data')
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
const id = peerId.toB58String()
|
||||
const recPeerId = this.data.get(id)
|
||||
|
||||
// If no record available, and this is valid
|
||||
if (!recPeerId && publicKey) {
|
||||
// This might be unecessary, but we want to store the PeerId
|
||||
// to avoid an async operation when reconstructing the PeerId
|
||||
peerId.pubKey = publicKey
|
||||
|
||||
this._setData(peerId, peerId)
|
||||
log(`stored provided public key for ${id}`)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Public key of the given PeerId, if stored.
|
||||
* @override
|
||||
* @param {PeerId} peerId
|
||||
* @return {RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey}
|
||||
*/
|
||||
get (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
const rec = this.data.get(peerId.toB58String())
|
||||
|
||||
return rec ? rec.pubKey : undefined
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = KeyBook
|
@ -5,5 +5,8 @@ module.exports.NAMESPACE_COMMON = '/peers/'
|
||||
// /peers/protos/<b32 peer id no padding>
|
||||
module.exports.NAMESPACE_ADDRESS = '/peers/addrs/'
|
||||
|
||||
// /peers/keys/<b32 peer id no padding>
|
||||
module.exports.NAMESPACE_KEYS = '/peers/keys/'
|
||||
|
||||
// /peers/addrs/<b32 peer id no padding>
|
||||
module.exports.NAMESPACE_PROTOCOL = '/peers/protos/'
|
||||
|
@ -13,6 +13,7 @@ const PeerStore = require('..')
|
||||
const {
|
||||
NAMESPACE_ADDRESS,
|
||||
NAMESPACE_COMMON,
|
||||
NAMESPACE_KEYS,
|
||||
NAMESPACE_PROTOCOL
|
||||
} = require('./consts')
|
||||
|
||||
@ -56,10 +57,11 @@ class PersistentPeerStore extends PeerStore {
|
||||
// Handlers for dirty peers
|
||||
this.on('change:protocols', this._addDirtyPeer)
|
||||
this.on('change:multiaddrs', this._addDirtyPeer)
|
||||
this.on('change:pubkey', this._addDirtyPeer)
|
||||
|
||||
// Load data
|
||||
for await (const entry of this._datastore.query({ prefix: NAMESPACE_COMMON })) {
|
||||
this._processDatastoreEntry(entry)
|
||||
await this._processDatastoreEntry(entry)
|
||||
}
|
||||
|
||||
log('PeerStore started')
|
||||
@ -109,12 +111,15 @@ class PersistentPeerStore extends PeerStore {
|
||||
log('create batch commit')
|
||||
const batch = this._datastore.batch()
|
||||
for (const peerIdStr of commitPeers) {
|
||||
// PeerId (replace by keyBook)
|
||||
const peerId = this.peerIds.get(peerIdStr)
|
||||
// PeerId
|
||||
const peerId = this.keyBook.data.get(peerIdStr) || PeerId.createFromCID(peerIdStr)
|
||||
|
||||
// Address Book
|
||||
this._batchAddressBook(peerId, batch)
|
||||
|
||||
// Key Book
|
||||
this._batchKeyBook(peerId, batch)
|
||||
|
||||
// Proto Book
|
||||
this._batchProtoBook(peerId, batch)
|
||||
}
|
||||
@ -154,6 +159,31 @@ class PersistentPeerStore extends PeerStore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Key book data of the peer to the batch.
|
||||
* @private
|
||||
* @param {PeerId} peerId
|
||||
* @param {Object} batch
|
||||
*/
|
||||
_batchKeyBook (peerId, batch) {
|
||||
const b32key = peerId.toString()
|
||||
const key = new Key(`${NAMESPACE_KEYS}${b32key}`)
|
||||
|
||||
try {
|
||||
// Deleted from the book
|
||||
if (!peerId.pubKey) {
|
||||
batch.delete(key)
|
||||
return
|
||||
}
|
||||
|
||||
const encodedData = peerId.marshalPubKey()
|
||||
|
||||
batch.put(key, encodedData)
|
||||
} catch (err) {
|
||||
log.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add proto book data of the peer to the batch.
|
||||
* @private
|
||||
@ -187,8 +217,9 @@ class PersistentPeerStore extends PeerStore {
|
||||
* @param {Object} params
|
||||
* @param {Key} params.key datastore key
|
||||
* @param {Buffer} params.value datastore value stored
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
_processDatastoreEntry ({ key, value }) {
|
||||
async _processDatastoreEntry ({ key, value }) {
|
||||
try {
|
||||
const keyParts = key.toString().split('/')
|
||||
const peerId = PeerId.createFromCID(keyParts[3])
|
||||
@ -205,6 +236,14 @@ class PersistentPeerStore extends PeerStore {
|
||||
})),
|
||||
{ emit: false })
|
||||
break
|
||||
case 'keys':
|
||||
decoded = await PeerId.createFromPubKey(value)
|
||||
|
||||
this.keyBook._setData(
|
||||
decoded,
|
||||
decoded,
|
||||
{ emit: false })
|
||||
break
|
||||
case 'protos':
|
||||
decoded = Protocols.decode(value)
|
||||
|
||||
|
@ -242,8 +242,8 @@ describe('Identify', () => {
|
||||
expect(connection).to.exist()
|
||||
|
||||
// Wait for peer store to be updated
|
||||
// Dialer._createDialTarget (add), Identify (replace)
|
||||
await pWaitFor(() => peerStoreSpySet.callCount === 1 && peerStoreSpyAdd.callCount === 1)
|
||||
// Dialer._createDialTarget (add), Connected (add), Identify (replace)
|
||||
await pWaitFor(() => peerStoreSpySet.callCount === 1 && peerStoreSpyAdd.callCount === 2)
|
||||
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
||||
|
||||
// The connection should have no open streams
|
||||
|
64
test/peer-store/key-book.spec.js
Normal file
64
test/peer-store/key-book.spec.js
Normal file
@ -0,0 +1,64 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
chai.use(require('chai-bytes'))
|
||||
const { expect } = chai
|
||||
const sinon = require('sinon')
|
||||
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('../../src/errors')
|
||||
|
||||
describe('keyBook', () => {
|
||||
let peerId, peerStore, kb
|
||||
|
||||
beforeEach(async () => {
|
||||
[peerId] = await peerUtils.createPeerId()
|
||||
peerStore = new PeerStore()
|
||||
kb = peerStore.keyBook
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided in set', () => {
|
||||
try {
|
||||
kb.set('invalid peerId')
|
||||
} catch (err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
}
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided in get', () => {
|
||||
try {
|
||||
kb.get('invalid peerId')
|
||||
} catch (err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
}
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('stores the peerId in the book and returns the public key', () => {
|
||||
// Set PeerId
|
||||
kb.set(peerId, peerId.pubKey)
|
||||
|
||||
// Get public key
|
||||
const pubKey = kb.get(peerId)
|
||||
expect(peerId.pubKey.bytes).to.equalBytes(pubKey.bytes)
|
||||
})
|
||||
|
||||
it('should not store if already stored', () => {
|
||||
const spy = sinon.spy(kb, '_setData')
|
||||
|
||||
// Set PeerId
|
||||
kb.set(peerId, peerId.pubKey)
|
||||
kb.set(peerId, peerId.pubKey)
|
||||
|
||||
expect(spy).to.have.property('callCount', 1)
|
||||
})
|
||||
})
|
53
test/peer-store/peer-store.node.js
Normal file
53
test/peer-store/peer-store.node.js
Normal file
@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
chai.use(require('chai-bytes'))
|
||||
const { expect } = chai
|
||||
const sinon = require('sinon')
|
||||
|
||||
const baseOptions = require('../utils/base-options')
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
describe('libp2p.peerStore', () => {
|
||||
let libp2p, remoteLibp2p
|
||||
|
||||
beforeEach(async () => {
|
||||
[libp2p, remoteLibp2p] = await peerUtils.createPeer({
|
||||
number: 2,
|
||||
populateAddressBooks: false,
|
||||
config: {
|
||||
...baseOptions
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('adds peer address to AddressBook and keys to the keybook when establishing connection', async () => {
|
||||
const idStr = libp2p.peerId.toB58String()
|
||||
const remoteIdStr = remoteLibp2p.peerId.toB58String()
|
||||
|
||||
const spyAddressBook = sinon.spy(libp2p.peerStore.addressBook, 'add')
|
||||
const spyKeyBook = sinon.spy(libp2p.peerStore.keyBook, 'set')
|
||||
|
||||
const remoteMultiaddr = `${remoteLibp2p.multiaddrs[0]}/p2p/${remoteIdStr}`
|
||||
const conn = await libp2p.dial(remoteMultiaddr)
|
||||
|
||||
expect(conn).to.exist()
|
||||
expect(spyAddressBook).to.have.property('called', true)
|
||||
expect(spyKeyBook).to.have.property('called', true)
|
||||
|
||||
const localPeers = libp2p.peerStore.peers
|
||||
expect(localPeers.size).to.equal(1)
|
||||
|
||||
// TODO: needs https://github.com/NodeFactoryIo/js-libp2p-noise/issues/58
|
||||
// const publicKeyInLocalPeer = localPeers.get(remoteIdStr).id.pubKey
|
||||
// expect(publicKeyInLocalPeer.bytes).to.equalBytes(remoteLibp2p.peerId.pubKey.bytes)
|
||||
|
||||
const remotePeers = remoteLibp2p.peerStore.peers
|
||||
expect(remotePeers.size).to.equal(1)
|
||||
const publicKeyInRemotePeer = remotePeers.get(idStr).id.pubKey
|
||||
expect(publicKeyInRemotePeer).to.exist()
|
||||
expect(publicKeyInRemotePeer.bytes).to.equalBytes(libp2p.peerId.pubKey.bytes)
|
||||
})
|
||||
})
|
@ -48,6 +48,13 @@ describe('peer-store', () => {
|
||||
const peer = peerStore.get(peerIds[0])
|
||||
expect(peer).to.not.exist()
|
||||
})
|
||||
|
||||
it('sets the peer\'s public key to the KeyBook', () => {
|
||||
peerStore.keyBook.set(peerIds[0], peerIds[0].pubKey)
|
||||
|
||||
const pubKey = peerStore.keyBook.get(peerIds[0])
|
||||
expect(pubKey).to.exist()
|
||||
})
|
||||
})
|
||||
|
||||
describe('previously populated books', () => {
|
||||
@ -108,6 +115,8 @@ describe('peer-store', () => {
|
||||
|
||||
const peerMultiaddrs = peer.addresses.map((mi) => mi.multiaddr)
|
||||
expect(peerMultiaddrs).to.have.members([addr1, addr2])
|
||||
|
||||
expect(peer.id).to.exist()
|
||||
})
|
||||
|
||||
it('gets the stored information of a peer that is not present in all its books', () => {
|
||||
|
@ -68,16 +68,16 @@ describe('Persisted PeerStore', () => {
|
||||
// AddressBook
|
||||
peerStore.addressBook.set(peer, multiaddrs)
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 1)
|
||||
expect(spyDirty).to.have.property('callCount', 1) // Address
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
|
||||
// ProtoBook
|
||||
peerStore.protoBook.set(peer, protocols)
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 2)
|
||||
expect(spyDirty).to.have.property('callCount', 2) // Protocol
|
||||
expect(spyDs).to.have.property('callCount', 2)
|
||||
|
||||
// Should have two peer records stored in the datastore
|
||||
// Should have three peer records stored in the datastore
|
||||
const queryParams = {
|
||||
prefix: '/peers/'
|
||||
}
|
||||
@ -110,15 +110,19 @@ describe('Persisted PeerStore', () => {
|
||||
peerStore.addressBook.set(peers[0], [multiaddrs[0]])
|
||||
peerStore.addressBook.set(peers[1], [multiaddrs[1]])
|
||||
|
||||
// KeyBook
|
||||
peerStore.keyBook.set(peers[0], peers[0].pubKey)
|
||||
peerStore.keyBook.set(peers[1], peers[1].pubKey)
|
||||
|
||||
// ProtoBook
|
||||
peerStore.protoBook.set(peers[0], protocols)
|
||||
peerStore.protoBook.set(peers[1], protocols)
|
||||
|
||||
expect(spyDs).to.have.property('callCount', 4)
|
||||
expect(spyDs).to.have.property('callCount', 6) // 2 AddressBook + 2 KeyBook + 2 ProtoBook
|
||||
expect(peerStore.peers.size).to.equal(2)
|
||||
|
||||
await peerStore.stop()
|
||||
peerStore.peerIds.clear()
|
||||
peerStore.keyBook.data.clear()
|
||||
peerStore.addressBook.data.clear()
|
||||
peerStore.protoBook.data.clear()
|
||||
|
||||
@ -127,11 +131,12 @@ describe('Persisted PeerStore', () => {
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
expect(spy).to.have.property('callCount', 4) // 4 datastore entries
|
||||
expect(spyDs).to.have.property('callCount', 4) // 4 previous operations
|
||||
expect(spy).to.have.property('callCount', 6)
|
||||
expect(spyDs).to.have.property('callCount', 6)
|
||||
|
||||
expect(peerStore.peers.size).to.equal(2)
|
||||
expect(peerStore.addressBook.data.size).to.equal(2)
|
||||
expect(peerStore.keyBook.data.size).to.equal(2)
|
||||
expect(peerStore.protoBook.data.size).to.equal(2)
|
||||
})
|
||||
|
||||
@ -149,6 +154,7 @@ describe('Persisted PeerStore', () => {
|
||||
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
const spyAddressBook = sinon.spy(peerStore.addressBook, 'delete')
|
||||
const spyKeyBook = sinon.spy(peerStore.keyBook, 'delete')
|
||||
const spyProtoBook = sinon.spy(peerStore.protoBook, 'delete')
|
||||
|
||||
// Delete from PeerStore
|
||||
@ -156,6 +162,7 @@ describe('Persisted PeerStore', () => {
|
||||
await peerStore.stop()
|
||||
|
||||
expect(spyAddressBook).to.have.property('callCount', 1)
|
||||
expect(spyKeyBook).to.have.property('callCount', 1)
|
||||
expect(spyProtoBook).to.have.property('callCount', 1)
|
||||
expect(spyDs).to.have.property('callCount', 2)
|
||||
|
||||
@ -199,7 +206,7 @@ describe('Persisted PeerStore', () => {
|
||||
// Remove data from the same Peer
|
||||
peerStore.addressBook.delete(peers[0])
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 3)
|
||||
expect(spyDirty).to.have.property('callCount', 3) // 2 AddrBook ops, 1 ProtoBook op
|
||||
expect(peerStore._dirtyPeers.size).to.equal(1)
|
||||
expect(spyDs).to.have.property('callCount', 0)
|
||||
|
||||
@ -215,7 +222,6 @@ describe('Persisted PeerStore', () => {
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 4)
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
expect(peerStore._dirtyPeers.size).to.equal(0) // Reset
|
||||
|
||||
// Should have two peer records stored in the datastore
|
||||
let count = 0
|
||||
@ -239,7 +245,7 @@ describe('Persisted PeerStore', () => {
|
||||
peerStore.protoBook.set(peer, protocols)
|
||||
|
||||
expect(spyDs).to.have.property('callCount', 0)
|
||||
expect(spyDirty).to.have.property('callCount', 1)
|
||||
expect(spyDirty).to.have.property('callCount', 1) // ProtoBook
|
||||
expect(peerStore._dirtyPeers.size).to.equal(1)
|
||||
|
||||
const queryParams = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user