mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-06-13 01:01:23 +00:00
feat: async peerstore backed by datastores (#1058)
We have a peerstore that keeps all data for all observed peers in memory with no eviction. This is fine when you don't discover many peers but when using the DHT you encounter a significant number of peers so our peer storage grows and grows over time. We have a persistent peer store, but it just periodically writes peers into the datastore to be read at startup, still keeping them in memory. It also means a restart doesn't give you any temporary reprieve from the memory leak as the previously observed peer data is read into memory at startup. This change refactors the peerstore to use a datastore by default, reading and writing peer info as it arrives. It can be configured with a MemoryDatastore if desired. It was necessary to change the peerstore and *book interfaces to be asynchronous since the datastore api is asynchronous. BREAKING CHANGE: `libp2p.handle`, `libp2p.registrar.register` and the peerstore methods have become async
This commit is contained in:
@ -10,6 +10,10 @@ const { baseOptions } = require('./utils')
|
||||
describe('Protocol prefix is configurable', () => {
|
||||
let libp2p
|
||||
|
||||
afterEach(async () => {
|
||||
libp2p && await libp2p.stop()
|
||||
})
|
||||
|
||||
it('protocolPrefix is provided', async () => {
|
||||
const testProtocol = 'test-protocol'
|
||||
libp2p = await create(mergeOptions(baseOptions, {
|
||||
@ -17,31 +21,27 @@ describe('Protocol prefix is configurable', () => {
|
||||
protocolPrefix: testProtocol
|
||||
}
|
||||
}))
|
||||
await libp2p.start()
|
||||
|
||||
const protocols = libp2p.peerStore.protoBook.get(libp2p.peerId);
|
||||
[
|
||||
const protocols = await libp2p.peerStore.protoBook.get(libp2p.peerId)
|
||||
expect(protocols).to.include.members([
|
||||
'/libp2p/circuit/relay/0.1.0',
|
||||
`/${testProtocol}/id/1.0.0`,
|
||||
`/${testProtocol}/id/push/1.0.0`,
|
||||
`/${testProtocol}/ping/1.0.0`
|
||||
].forEach((i, idx) => {
|
||||
expect(protocols[idx]).equals(i)
|
||||
})
|
||||
await libp2p.stop()
|
||||
])
|
||||
})
|
||||
|
||||
it('protocolPrefix is not provided', async () => {
|
||||
libp2p = await create(baseOptions)
|
||||
await libp2p.start()
|
||||
|
||||
const protocols = libp2p.peerStore.protoBook.get(libp2p.peerId);
|
||||
[
|
||||
const protocols = await libp2p.peerStore.protoBook.get(libp2p.peerId)
|
||||
expect(protocols).to.include.members([
|
||||
'/libp2p/circuit/relay/0.1.0',
|
||||
'/ipfs/id/1.0.0',
|
||||
'/ipfs/id/push/1.0.0',
|
||||
'/ipfs/ping/1.0.0'
|
||||
].forEach((i, idx) => {
|
||||
expect(protocols[idx]).equals(i)
|
||||
})
|
||||
await libp2p.stop()
|
||||
])
|
||||
})
|
||||
})
|
||||
|
@ -71,7 +71,7 @@ describe('Connection Manager', () => {
|
||||
sinon.spy(libp2p.connectionManager, 'emit')
|
||||
sinon.spy(remoteLibp2p.connectionManager, 'emit')
|
||||
|
||||
libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||
await libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||
await libp2p.dial(remoteLibp2p.peerId)
|
||||
|
||||
// check connect event
|
||||
@ -219,9 +219,9 @@ describe('libp2p.connections', () => {
|
||||
})
|
||||
|
||||
// Populate PeerStore before starting
|
||||
libp2p.peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs)
|
||||
libp2p.peerStore.addressBook.set(nodes[1].peerId, nodes[1].multiaddrs)
|
||||
libp2p.peerStore.protoBook.set(nodes[1].peerId, ['/protocol-min-conns'])
|
||||
await libp2p.peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs)
|
||||
await libp2p.peerStore.addressBook.set(nodes[1].peerId, nodes[1].multiaddrs)
|
||||
await libp2p.peerStore.protoBook.set(nodes[1].peerId, ['/protocol-min-conns'])
|
||||
|
||||
await libp2p.start()
|
||||
|
||||
|
@ -77,7 +77,7 @@ describe('Connection Manager', () => {
|
||||
const value = Math.random()
|
||||
spies.set(value, spy)
|
||||
libp2p.connectionManager.setPeerValue(connection.remotePeer, value)
|
||||
libp2p.connectionManager.onConnect(connection)
|
||||
await libp2p.connectionManager.onConnect(connection)
|
||||
}))
|
||||
|
||||
// get the lowest value
|
||||
@ -109,8 +109,8 @@ describe('Connection Manager', () => {
|
||||
const spy = sinon.spy()
|
||||
await Promise.all([...new Array(max + 1)].map(async () => {
|
||||
const connection = await mockConnection()
|
||||
sinon.stub(connection, 'close').callsFake(() => spy()) // eslint-disable-line
|
||||
libp2p.connectionManager.onConnect(connection)
|
||||
sinon.stub(connection, 'close').callsFake(async () => spy()) // eslint-disable-line
|
||||
await libp2p.connectionManager.onConnect(connection)
|
||||
}))
|
||||
|
||||
expect(libp2p.connectionManager._maybeDisconnectOne).to.have.property('callCount', 1)
|
||||
|
@ -291,11 +291,11 @@ describe('content-routing', () => {
|
||||
yield result
|
||||
})
|
||||
|
||||
expect(node.peerStore.addressBook.get(providerPeerId)).to.not.be.ok()
|
||||
expect(await node.peerStore.has(providerPeerId)).to.not.be.ok()
|
||||
|
||||
await drain(node.contentRouting.findProviders('a cid'))
|
||||
|
||||
expect(node.peerStore.addressBook.get(providerPeerId)).to.deep.include({
|
||||
expect(await node.peerStore.addressBook.get(providerPeerId)).to.deep.include({
|
||||
isCertified: false,
|
||||
multiaddr: result.multiaddrs[0]
|
||||
})
|
||||
@ -377,7 +377,7 @@ describe('content-routing', () => {
|
||||
|
||||
await drain(node.contentRouting.findProviders('a cid'))
|
||||
|
||||
expect(node.peerStore.addressBook.get(providerPeerId)).to.deep.include({
|
||||
expect(await node.peerStore.addressBook.get(providerPeerId)).to.deep.include({
|
||||
isCertified: false,
|
||||
multiaddr: result1.multiaddrs[0]
|
||||
}).and.to.deep.include({
|
||||
|
@ -45,8 +45,8 @@ describe('DHT subsystem operates correctly', () => {
|
||||
remoteLibp2p.start()
|
||||
])
|
||||
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, [remoteListenAddr])
|
||||
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerId)[0]
|
||||
await libp2p.peerStore.addressBook.set(remotePeerId, [remoteListenAddr]);
|
||||
[remAddr] = await libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerId)
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
@ -106,8 +106,8 @@ describe('DHT subsystem operates correctly', () => {
|
||||
await libp2p.start()
|
||||
await remoteLibp2p.start()
|
||||
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, [remoteListenAddr])
|
||||
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerId)[0]
|
||||
await libp2p.peerStore.addressBook.set(remotePeerId, [remoteListenAddr])
|
||||
remAddr = (await libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerId))[0]
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
|
@ -18,7 +18,7 @@ const AggregateError = require('aggregate-error')
|
||||
const { Connection } = require('libp2p-interfaces/src/connection')
|
||||
const { AbortError } = require('libp2p-interfaces/src/transport/errors')
|
||||
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const Libp2p = require('../../src')
|
||||
const Dialer = require('../../src/dialer')
|
||||
const AddressManager = require('../../src/address-manager')
|
||||
@ -48,7 +48,10 @@ describe('Dialing (direct, TCP)', () => {
|
||||
PeerId.createFromJSON(Peers[1])
|
||||
])
|
||||
|
||||
peerStore = new PeerStore({ peerId: remotePeerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId: remotePeerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
remoteTM = new TransportManager({
|
||||
libp2p: {
|
||||
addressManager: new AddressManager(remotePeerId, { listen: [listenAddr] }),
|
||||
@ -62,7 +65,10 @@ describe('Dialing (direct, TCP)', () => {
|
||||
localTM = new TransportManager({
|
||||
libp2p: {
|
||||
peerId: localPeerId,
|
||||
peerStore: new PeerStore({ peerId: localPeerId })
|
||||
peerStore: new PeerStore({
|
||||
peerId: localPeerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
},
|
||||
upgrader: mockUpgrader
|
||||
})
|
||||
@ -113,7 +119,10 @@ describe('Dialing (direct, TCP)', () => {
|
||||
|
||||
it('should be able to connect to a given peer id', async () => {
|
||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||
const peerStore = new PeerStore({ peerId })
|
||||
const peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore
|
||||
@ -249,7 +258,7 @@ describe('Dialing (direct, TCP)', () => {
|
||||
connEncryption: [Crypto]
|
||||
}
|
||||
})
|
||||
remoteLibp2p.handle('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
|
||||
await remoteLibp2p.handle('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
|
||||
|
||||
await remoteLibp2p.start()
|
||||
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${remotePeerId.toB58String()}`)
|
||||
@ -339,12 +348,12 @@ describe('Dialing (direct, TCP)', () => {
|
||||
})
|
||||
|
||||
// register some stream handlers to simulate several protocols
|
||||
libp2p.handle('/stream-count/1', ({ stream }) => pipe(stream, stream))
|
||||
libp2p.handle('/stream-count/2', ({ stream }) => pipe(stream, stream))
|
||||
remoteLibp2p.handle('/stream-count/3', ({ stream }) => pipe(stream, stream))
|
||||
remoteLibp2p.handle('/stream-count/4', ({ stream }) => pipe(stream, stream))
|
||||
await libp2p.handle('/stream-count/1', ({ stream }) => pipe(stream, stream))
|
||||
await libp2p.handle('/stream-count/2', ({ stream }) => pipe(stream, stream))
|
||||
await remoteLibp2p.handle('/stream-count/3', ({ stream }) => pipe(stream, stream))
|
||||
await remoteLibp2p.handle('/stream-count/4', ({ stream }) => pipe(stream, stream))
|
||||
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||
await libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||
const connection = await libp2p.dial(remotePeerId)
|
||||
|
||||
// Create local to remote streams
|
||||
@ -363,8 +372,8 @@ describe('Dialing (direct, TCP)', () => {
|
||||
|
||||
// Verify stream count
|
||||
const remoteConn = remoteLibp2p.connectionManager.get(libp2p.peerId)
|
||||
expect(connection.streams).to.have.length(5)
|
||||
expect(remoteConn.streams).to.have.length(5)
|
||||
expect(connection.streams).to.have.length(6)
|
||||
expect(remoteConn.streams).to.have.length(6)
|
||||
|
||||
// Close the connection and verify all streams have been closed
|
||||
await connection.close()
|
||||
|
@ -13,7 +13,7 @@ const { NOISE: Crypto } = require('@chainsafe/libp2p-noise')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const AggregateError = require('aggregate-error')
|
||||
const { AbortError } = require('libp2p-interfaces/src/transport/errors')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const { codes: ErrorCodes } = require('../../src/errors')
|
||||
const Constants = require('../../src/constants')
|
||||
const Dialer = require('../../src/dialer')
|
||||
@ -36,7 +36,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
|
||||
before(async () => {
|
||||
[peerId] = await createPeerId()
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
localTM = new TransportManager({
|
||||
libp2p: {},
|
||||
upgrader: mockUpgrader,
|
||||
@ -215,7 +218,7 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
})
|
||||
|
||||
// Inject data in the AddressBook
|
||||
peerStore.addressBook.add(peerId, peerMultiaddrs)
|
||||
await peerStore.addressBook.add(peerId, peerMultiaddrs)
|
||||
|
||||
// Perform 3 multiaddr dials
|
||||
await dialer.connectToPeer(peerId)
|
||||
|
@ -10,7 +10,6 @@ const duplexPair = require('it-pair/duplex')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const { toString: unit8ArrayToString } = require('uint8arrays/to-string')
|
||||
|
||||
const { codes: Errors } = require('../../src/errors')
|
||||
const IdentifyService = require('../../src/identify')
|
||||
const multicodecs = IdentifyService.multicodecs
|
||||
@ -22,7 +21,7 @@ const baseOptions = require('../utils/base-options.browser')
|
||||
const { updateSelfPeerRecord } = require('../../src/record/utils')
|
||||
const pkg = require('../../package.json')
|
||||
const AddressManager = require('../../src/address-manager')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
||||
const remoteAddr = MULTIADDRS_WEBSOCKETS[0]
|
||||
const listenMaddrs = [new Multiaddr('/ip4/127.0.0.1/tcp/15002/ws')]
|
||||
@ -38,10 +37,16 @@ describe('Identify', () => {
|
||||
PeerId.createFromJSON(Peers[1])
|
||||
]))
|
||||
|
||||
localPeerStore = new PeerStore({ peerId: localPeer })
|
||||
localPeerStore = new PeerStore({
|
||||
peerId: localPeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
localPeerStore.protoBook.set(localPeer, protocols)
|
||||
|
||||
remotePeerStore = new PeerStore({ peerId: remotePeer })
|
||||
remotePeerStore = new PeerStore({
|
||||
peerId: remotePeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
remotePeerStore.protoBook.set(remotePeer, protocols)
|
||||
|
||||
localAddressManager = new AddressManager(localPeer)
|
||||
@ -103,7 +108,7 @@ describe('Identify', () => {
|
||||
expect(localIdentify.peerStore.protoBook.set.callCount).to.equal(1)
|
||||
|
||||
// Validate the remote peer gets updated in the peer store
|
||||
const addresses = localIdentify.peerStore.addressBook.get(remotePeer)
|
||||
const addresses = await localIdentify.peerStore.addressBook.get(remotePeer)
|
||||
expect(addresses).to.exist()
|
||||
expect(addresses).have.lengthOf(listenMaddrs.length)
|
||||
expect(addresses.map((a) => a.multiaddr)[0].equals(listenMaddrs[0]))
|
||||
@ -149,7 +154,7 @@ describe('Identify', () => {
|
||||
|
||||
sinon.spy(localIdentify.peerStore.addressBook, 'set')
|
||||
sinon.spy(localIdentify.peerStore.protoBook, 'set')
|
||||
sinon.spy(localIdentify.peerStore.metadataBook, 'set')
|
||||
sinon.spy(localIdentify.peerStore.metadataBook, 'setValue')
|
||||
|
||||
// Run identify
|
||||
await Promise.all([
|
||||
@ -164,7 +169,7 @@ describe('Identify', () => {
|
||||
expect(localIdentify.peerStore.addressBook.set.callCount).to.equal(1)
|
||||
expect(localIdentify.peerStore.protoBook.set.callCount).to.equal(1)
|
||||
|
||||
const metadataArgs = localIdentify.peerStore.metadataBook.set.firstCall.args
|
||||
const metadataArgs = localIdentify.peerStore.metadataBook.setValue.firstCall.args
|
||||
expect(metadataArgs[0].id.bytes).to.equal(remotePeer.bytes)
|
||||
expect(metadataArgs[1]).to.equal('AgentVersion')
|
||||
expect(unit8ArrayToString(metadataArgs[2])).to.equal(agentVersion)
|
||||
@ -221,13 +226,16 @@ describe('Identify', () => {
|
||||
.and.to.have.property('code', Errors.ERR_INVALID_PEER)
|
||||
})
|
||||
|
||||
it('should store host data and protocol version into metadataBook', () => {
|
||||
it('should store host data and protocol version into metadataBook', async () => {
|
||||
const agentVersion = 'js-project/1.0.0'
|
||||
const peerStore = new PeerStore({ peerId: localPeer })
|
||||
const peerStore = new PeerStore({
|
||||
peerId: localPeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
|
||||
sinon.spy(peerStore.metadataBook, 'set')
|
||||
sinon.spy(peerStore.metadataBook, 'setValue')
|
||||
|
||||
new IdentifyService({ // eslint-disable-line no-new
|
||||
const service = new IdentifyService({ // eslint-disable-line no-new
|
||||
libp2p: {
|
||||
peerId: localPeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
@ -243,23 +251,30 @@ describe('Identify', () => {
|
||||
protocols
|
||||
})
|
||||
|
||||
expect(peerStore.metadataBook.set.callCount).to.eql(2)
|
||||
await service.start()
|
||||
|
||||
const storedAgentVersion = peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||
const storedProtocolVersion = peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||
expect(peerStore.metadataBook.setValue.callCount).to.eql(2)
|
||||
|
||||
const storedAgentVersion = await peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||
const storedProtocolVersion = await peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||
|
||||
expect(agentVersion).to.eql(unit8ArrayToString(storedAgentVersion))
|
||||
expect(storedProtocolVersion).to.exist()
|
||||
|
||||
await service.stop()
|
||||
})
|
||||
|
||||
describe('push', () => {
|
||||
it('should be able to push identify updates to another peer', async () => {
|
||||
const storedProtocols = [multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH, '/echo/1.0.0']
|
||||
const storedProtocols = [multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH, '/echo/1.0.0'].sort()
|
||||
const connectionManager = new EventEmitter()
|
||||
connectionManager.getConnection = () => { }
|
||||
|
||||
const localPeerStore = new PeerStore({ peerId: localPeer })
|
||||
localPeerStore.protoBook.set(localPeer, storedProtocols)
|
||||
const localPeerStore = new PeerStore({
|
||||
peerId: localPeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
await localPeerStore.protoBook.set(localPeer, storedProtocols)
|
||||
|
||||
const localIdentify = new IdentifyService({
|
||||
libp2p: {
|
||||
@ -273,8 +288,11 @@ describe('Identify', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const remotePeerStore = new PeerStore({ peerId: remotePeer })
|
||||
remotePeerStore.protoBook.set(remotePeer, storedProtocols)
|
||||
const remotePeerStore = new PeerStore({
|
||||
peerId: remotePeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
await remotePeerStore.protoBook.set(remotePeer, storedProtocols)
|
||||
|
||||
const remoteIdentify = new IdentifyService({
|
||||
libp2p: {
|
||||
@ -316,7 +334,7 @@ describe('Identify', () => {
|
||||
expect(remoteIdentify.peerStore.addressBook.consumePeerRecord.callCount).to.equal(2)
|
||||
expect(remoteIdentify.peerStore.protoBook.set.callCount).to.equal(1)
|
||||
|
||||
const addresses = localIdentify.peerStore.addressBook.get(localPeer)
|
||||
const addresses = await localIdentify.peerStore.addressBook.get(localPeer)
|
||||
expect(addresses).to.exist()
|
||||
expect(addresses).have.lengthOf(listenMaddrs.length)
|
||||
expect(addresses.map((a) => a.multiaddr)).to.eql(listenMaddrs)
|
||||
@ -328,12 +346,15 @@ describe('Identify', () => {
|
||||
|
||||
// LEGACY
|
||||
it('should be able to push identify updates to another peer with no certified peer records support', async () => {
|
||||
const storedProtocols = [multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH, '/echo/1.0.0']
|
||||
const storedProtocols = [multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH, '/echo/1.0.0'].sort()
|
||||
const connectionManager = new EventEmitter()
|
||||
connectionManager.getConnection = () => { }
|
||||
|
||||
const localPeerStore = new PeerStore({ peerId: localPeer })
|
||||
localPeerStore.protoBook.set(localPeer, storedProtocols)
|
||||
const localPeerStore = new PeerStore({
|
||||
peerId: localPeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
await localPeerStore.protoBook.set(localPeer, storedProtocols)
|
||||
|
||||
const localIdentify = new IdentifyService({
|
||||
libp2p: {
|
||||
@ -347,14 +368,17 @@ describe('Identify', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const remotePeerStore = new PeerStore({ peerId: remotePeer })
|
||||
const remotePeerStore = new PeerStore({
|
||||
peerId: remotePeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
remotePeerStore.protoBook.set(remotePeer, storedProtocols)
|
||||
|
||||
const remoteIdentify = new IdentifyService({
|
||||
libp2p: {
|
||||
peerId: remotePeer,
|
||||
connectionManager,
|
||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||
peerStore: remotePeerStore,
|
||||
multiaddrs: [],
|
||||
_options: { host: {} },
|
||||
_config: { protocolPrefix: 'ipfs' },
|
||||
@ -492,11 +516,15 @@ describe('Identify', () => {
|
||||
await libp2p.identifyService.identify.firstCall.returnValue
|
||||
sinon.stub(libp2p, 'isStarted').returns(true)
|
||||
|
||||
libp2p.handle('/echo/2.0.0', () => {})
|
||||
libp2p.unhandle('/echo/2.0.0')
|
||||
await libp2p.handle('/echo/2.0.0', () => {})
|
||||
await libp2p.unhandle('/echo/2.0.0')
|
||||
|
||||
// the protocol change event listener in the identity service is async
|
||||
await pWaitFor(() => libp2p.identifyService.push.callCount === 2)
|
||||
|
||||
// Verify the remote peer is notified of both changes
|
||||
expect(libp2p.identifyService.push.callCount).to.equal(2)
|
||||
|
||||
for (const call of libp2p.identifyService.push.getCalls()) {
|
||||
const [connections] = call.args
|
||||
expect(connections.length).to.equal(1)
|
||||
@ -509,7 +537,7 @@ describe('Identify', () => {
|
||||
await pWaitFor(() => connection.streams.length === 0)
|
||||
})
|
||||
|
||||
it('should store host data and protocol version into metadataBook', () => {
|
||||
it('should store host data and protocol version into metadataBook', async () => {
|
||||
const agentVersion = 'js-project/1.0.0'
|
||||
|
||||
libp2p = new Libp2p({
|
||||
@ -519,9 +547,10 @@ describe('Identify', () => {
|
||||
agentVersion
|
||||
}
|
||||
})
|
||||
await libp2p.start()
|
||||
|
||||
const storedAgentVersion = libp2p.peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||
const storedProtocolVersion = libp2p.peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||
const storedAgentVersion = await libp2p.peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||
const storedProtocolVersion = await libp2p.peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||
|
||||
expect(agentVersion).to.eql(unit8ArrayToString(storedAgentVersion))
|
||||
expect(storedProtocolVersion).to.exist()
|
||||
@ -545,7 +574,10 @@ describe('Identify', () => {
|
||||
await libp2p.identifyService.identify.firstCall.returnValue
|
||||
sinon.stub(libp2p, 'isStarted').returns(true)
|
||||
|
||||
libp2p.peerStore.addressBook.add(libp2p.peerId, [new Multiaddr('/ip4/180.0.0.1/tcp/15001/ws')])
|
||||
await libp2p.peerStore.addressBook.add(libp2p.peerId, [new Multiaddr('/ip4/180.0.0.1/tcp/15001/ws')])
|
||||
|
||||
// the protocol change event listener in the identity service is async
|
||||
await pWaitFor(() => libp2p.identifyService.push.callCount === 1)
|
||||
|
||||
// Verify the remote peer is notified of change
|
||||
expect(libp2p.identifyService.push.callCount).to.equal(1)
|
||||
|
@ -266,10 +266,10 @@ describe('Metrics', () => {
|
||||
const metric = 'some-metric'
|
||||
const value = 1
|
||||
|
||||
metrics.updateComponentMetric(component, metric, value)
|
||||
metrics.updateComponentMetric({ component, metric, value })
|
||||
|
||||
expect(metrics.getComponentMetrics()).to.have.lengthOf(1)
|
||||
expect(metrics.getComponentMetrics().get(component)).to.have.lengthOf(1)
|
||||
expect(metrics.getComponentMetrics().get(component).get(metric)).to.equal(value)
|
||||
expect(metrics.getComponentMetrics().get('libp2p').get(component)).to.have.lengthOf(1)
|
||||
expect(metrics.getComponentMetrics().get('libp2p').get(component).get(metric)).to.equal(value)
|
||||
})
|
||||
})
|
||||
|
@ -658,10 +658,8 @@ describe('peer-routing', () => {
|
||||
|
||||
await node.start()
|
||||
|
||||
await delay(300)
|
||||
expect(node._dht.getClosestPeers.callCount).to.eql(1)
|
||||
await delay(500)
|
||||
expect(node._dht.getClosestPeers.callCount).to.eql(2)
|
||||
// should run more than once
|
||||
await pWaitFor(() => node._dht.getClosestPeers.callCount === 2)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -9,7 +9,7 @@ const arrayEquals = require('libp2p-utils/src/array-equals')
|
||||
const addressSort = require('libp2p-utils/src/address-sort')
|
||||
const PeerId = require('peer-id')
|
||||
const pDefer = require('p-defer')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
const Envelope = require('../../src/record/envelope')
|
||||
const PeerRecord = require('../../src/record/peer-record')
|
||||
@ -19,6 +19,11 @@ const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('../../src/errors')
|
||||
|
||||
/**
|
||||
* @typedef {import('../../src/peer-store/types').PeerStore} PeerStore
|
||||
* @typedef {import('../../src/peer-store/types').AddressBook} AddressBook
|
||||
*/
|
||||
|
||||
const addr1 = new Multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||
const addr2 = new Multiaddr('/ip4/20.0.0.1/tcp/8001')
|
||||
const addr3 = new Multiaddr('/ip4/127.0.0.1/tcp/8002')
|
||||
@ -31,10 +36,16 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
describe('addressBook.set', () => {
|
||||
let peerStore, ab
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {AddressBook} */
|
||||
let ab
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
ab = peerStore.addressBook
|
||||
})
|
||||
|
||||
@ -42,9 +53,9 @@ describe('addressBook', () => {
|
||||
peerStore.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
ab.set('invalid peerId')
|
||||
await ab.set('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -52,9 +63,9 @@ describe('addressBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no addresses provided', () => {
|
||||
it('throws invalid parameters error if no addresses provided', async () => {
|
||||
try {
|
||||
ab.set(peerId)
|
||||
await ab.set(peerId)
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -62,9 +73,9 @@ describe('addressBook', () => {
|
||||
throw new Error('no addresses should throw error')
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
|
||||
it('throws invalid parameters error if invalid multiaddrs are provided', async () => {
|
||||
try {
|
||||
ab.set(peerId, ['invalid multiaddr'])
|
||||
await ab.set(peerId, ['invalid multiaddr'])
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -72,7 +83,7 @@ describe('addressBook', () => {
|
||||
throw new Error('invalid multiaddrs should throw error')
|
||||
})
|
||||
|
||||
it('replaces the stored content by default and emit change event', () => {
|
||||
it('replaces the stored content by default and emit change event', async () => {
|
||||
const defer = pDefer()
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
@ -82,8 +93,8 @@ describe('addressBook', () => {
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
const addresses = ab.get(peerId)
|
||||
await ab.set(peerId, supportedMultiaddrs)
|
||||
const addresses = await ab.get(peerId)
|
||||
const multiaddrs = addresses.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||
|
||||
@ -105,11 +116,11 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
await ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (same content)
|
||||
ab.set(peerId, supportedMultiaddrsB)
|
||||
const addresses = ab.get(peerId)
|
||||
await ab.set(peerId, supportedMultiaddrsB)
|
||||
const addresses = await ab.get(peerId)
|
||||
const multiaddrs = addresses.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsB)
|
||||
|
||||
@ -130,10 +141,10 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
await ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// set 2 (same content)
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
await ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
@ -145,10 +156,16 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
describe('addressBook.add', () => {
|
||||
let peerStore, ab
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {AddressBook} */
|
||||
let ab
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
ab = peerStore.addressBook
|
||||
})
|
||||
|
||||
@ -156,9 +173,9 @@ describe('addressBook', () => {
|
||||
peerStore.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
ab.add('invalid peerId')
|
||||
await ab.add('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -166,9 +183,9 @@ describe('addressBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no addresses provided', () => {
|
||||
it('throws invalid parameters error if no addresses provided', async () => {
|
||||
try {
|
||||
ab.add(peerId)
|
||||
await ab.add(peerId)
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -176,9 +193,9 @@ describe('addressBook', () => {
|
||||
throw new Error('no addresses provided should throw error')
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
|
||||
it('throws invalid parameters error if invalid multiaddrs are provided', async () => {
|
||||
try {
|
||||
ab.add(peerId, ['invalid multiaddr'])
|
||||
await ab.add(peerId, ['invalid multiaddr'])
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -193,7 +210,7 @@ describe('addressBook', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
ab.add(peerId, [])
|
||||
await ab.add(peerId, [])
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
@ -203,7 +220,7 @@ describe('addressBook', () => {
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('adds the new content and emits change event', () => {
|
||||
it('adds the new content and emits change event', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1, addr2]
|
||||
@ -219,14 +236,14 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// Replace
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
let addresses = ab.get(peerId)
|
||||
await ab.set(peerId, supportedMultiaddrsA)
|
||||
let addresses = await ab.get(peerId)
|
||||
let multiaddrs = addresses.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsA)
|
||||
|
||||
// Add
|
||||
ab.add(peerId, supportedMultiaddrsB)
|
||||
addresses = ab.get(peerId)
|
||||
await ab.add(peerId, supportedMultiaddrsB)
|
||||
addresses = await ab.get(peerId)
|
||||
multiaddrs = addresses.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||
|
||||
@ -249,11 +266,11 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
await ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
ab.add(peerId, supportedMultiaddrsB)
|
||||
const addresses = ab.get(peerId)
|
||||
await ab.add(peerId, supportedMultiaddrsB)
|
||||
const addresses = await ab.get(peerId)
|
||||
const multiaddrs = addresses.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||
|
||||
@ -275,10 +292,10 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
await ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
ab.add(peerId, supportedMultiaddrsB)
|
||||
await ab.add(peerId, supportedMultiaddrsB)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
@ -288,26 +305,32 @@ describe('addressBook', () => {
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('does not add replicated content', () => {
|
||||
it('does not add replicated content', async () => {
|
||||
// set 1
|
||||
ab.set(peerId, [addr1, addr1])
|
||||
await ab.set(peerId, [addr1, addr1])
|
||||
|
||||
const addresses = ab.get(peerId)
|
||||
const addresses = await ab.get(peerId)
|
||||
expect(addresses).to.have.lengthOf(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.get', () => {
|
||||
let peerStore, ab
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {AddressBook} */
|
||||
let ab
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
ab = peerStore.addressBook
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
ab.get('invalid peerId')
|
||||
await ab.get('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -315,34 +338,40 @@ describe('addressBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||
const addresses = ab.get(peerId)
|
||||
it('returns empty if no multiaddrs are known for the provided peer', async () => {
|
||||
const addresses = await ab.get(peerId)
|
||||
|
||||
expect(addresses).to.not.exist()
|
||||
expect(addresses).to.be.empty()
|
||||
})
|
||||
|
||||
it('returns the multiaddrs stored', () => {
|
||||
it('returns the multiaddrs stored', async () => {
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
await ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
const addresses = ab.get(peerId)
|
||||
const addresses = await ab.get(peerId)
|
||||
const multiaddrs = addresses.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.getMultiaddrsForPeer', () => {
|
||||
let peerStore, ab
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {AddressBook} */
|
||||
let ab
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
ab = peerStore.addressBook
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
ab.getMultiaddrsForPeer('invalid peerId')
|
||||
await ab.getMultiaddrsForPeer('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -350,28 +379,28 @@ describe('addressBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||
const addresses = ab.getMultiaddrsForPeer(peerId)
|
||||
it('returns empty if no multiaddrs are known for the provided peer', async () => {
|
||||
const addresses = await ab.getMultiaddrsForPeer(peerId)
|
||||
|
||||
expect(addresses).to.not.exist()
|
||||
expect(addresses).to.be.empty()
|
||||
})
|
||||
|
||||
it('returns the multiaddrs stored', () => {
|
||||
it('returns the multiaddrs stored', async () => {
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
await ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
const multiaddrs = ab.getMultiaddrsForPeer(peerId)
|
||||
const multiaddrs = await ab.getMultiaddrsForPeer(peerId)
|
||||
multiaddrs.forEach((m) => {
|
||||
expect(m.getPeerId()).to.equal(peerId.toB58String())
|
||||
})
|
||||
})
|
||||
|
||||
it('can sort multiaddrs providing a sorter', () => {
|
||||
it('can sort multiaddrs providing a sorter', async () => {
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
await ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
const multiaddrs = ab.getMultiaddrsForPeer(peerId, addressSort.publicAddressesFirst)
|
||||
const multiaddrs = await ab.getMultiaddrsForPeer(peerId, addressSort.publicAddressesFirst)
|
||||
const sortedAddresses = addressSort.publicAddressesFirst(supportedMultiaddrs.map((m) => ({ multiaddr: m })))
|
||||
|
||||
multiaddrs.forEach((m, index) => {
|
||||
@ -381,16 +410,22 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
describe('addressBook.delete', () => {
|
||||
let peerStore, ab
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {AddressBook} */
|
||||
let ab
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
ab = peerStore.addressBook
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
ab.delete('invalid peerId')
|
||||
await ab.delete('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -398,16 +433,14 @@ describe('addressBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
it('does not emit an event if no records exist for the peer', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
peerStore.on('change:multiaddrs', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = ab.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
await ab.delete(peerId)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
@ -417,11 +450,11 @@ describe('addressBook', () => {
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
it('emits an event if the record exists', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
await ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// Listen after set
|
||||
peerStore.on('change:multiaddrs', ({ multiaddrs }) => {
|
||||
@ -429,20 +462,24 @@ describe('addressBook', () => {
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = ab.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
await ab.delete(peerId)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('certified records', () => {
|
||||
let peerStore, ab
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {AddressBook} */
|
||||
let ab
|
||||
|
||||
describe('consumes a valid peer record and stores its data', () => {
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
ab = peerStore.addressBook
|
||||
})
|
||||
|
||||
@ -455,15 +492,11 @@ describe('addressBook', () => {
|
||||
const envelope = await Envelope.seal(peerRecord, peerId)
|
||||
|
||||
// consume peer record
|
||||
const consumed = ab.consumePeerRecord(envelope)
|
||||
const consumed = await ab.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
// Validate stored envelope
|
||||
const storedEnvelope = await ab.getPeerRecord(peerId)
|
||||
expect(envelope.equals(storedEnvelope)).to.eql(true)
|
||||
|
||||
// Validate AddressBook addresses
|
||||
const addrs = ab.get(peerId)
|
||||
const addrs = await ab.get(peerId)
|
||||
expect(addrs).to.exist()
|
||||
expect(addrs).to.have.lengthOf(multiaddrs.length)
|
||||
addrs.forEach((addr, index) => {
|
||||
@ -488,7 +521,7 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// consume peer record
|
||||
const consumed = ab.consumePeerRecord(envelope)
|
||||
const consumed = await ab.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
return defer.promise
|
||||
@ -499,10 +532,10 @@ describe('addressBook', () => {
|
||||
const multiaddrs = [addr1, addr2]
|
||||
|
||||
// Set addressBook data
|
||||
ab.set(peerId, multiaddrs)
|
||||
await ab.set(peerId, multiaddrs)
|
||||
|
||||
// Validate data exists, but not certified
|
||||
let addrs = ab.get(peerId)
|
||||
let addrs = await ab.get(peerId)
|
||||
expect(addrs).to.exist()
|
||||
expect(addrs).to.have.lengthOf(multiaddrs.length)
|
||||
|
||||
@ -525,14 +558,14 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// consume peer record
|
||||
const consumed = ab.consumePeerRecord(envelope)
|
||||
const consumed = await ab.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
// Wait event
|
||||
await defer.promise
|
||||
|
||||
// Validate data exists and certified
|
||||
addrs = ab.get(peerId)
|
||||
addrs = await ab.get(peerId)
|
||||
expect(addrs).to.exist()
|
||||
expect(addrs).to.have.lengthOf(multiaddrs.length)
|
||||
addrs.forEach((addr, index) => {
|
||||
@ -546,10 +579,10 @@ describe('addressBook', () => {
|
||||
const multiaddrs = [addr1, addr2]
|
||||
|
||||
// Set addressBook data
|
||||
ab.set(peerId, [addr1])
|
||||
await ab.set(peerId, [addr1])
|
||||
|
||||
// Validate data exists, but not certified
|
||||
let addrs = ab.get(peerId)
|
||||
let addrs = await ab.get(peerId)
|
||||
expect(addrs).to.exist()
|
||||
expect(addrs).to.have.lengthOf(1)
|
||||
expect(addrs[0].isCertified).to.eql(false)
|
||||
@ -569,14 +602,14 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// consume peer record
|
||||
const consumed = ab.consumePeerRecord(envelope)
|
||||
const consumed = await ab.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
// Wait event
|
||||
await defer.promise
|
||||
|
||||
// Validate data exists and certified
|
||||
addrs = ab.get(peerId)
|
||||
addrs = await ab.get(peerId)
|
||||
expect(addrs).to.exist()
|
||||
expect(addrs).to.have.lengthOf(multiaddrs.length)
|
||||
addrs.forEach((addr, index) => {
|
||||
@ -591,10 +624,10 @@ describe('addressBook', () => {
|
||||
const multiaddrsCertified = [addr1, addr2]
|
||||
|
||||
// Set addressBook data
|
||||
ab.set(peerId, multiaddrsUncertified)
|
||||
await ab.set(peerId, multiaddrsUncertified)
|
||||
|
||||
// Validate data exists, but not certified
|
||||
let addrs = ab.get(peerId)
|
||||
let addrs = await ab.get(peerId)
|
||||
expect(addrs).to.exist()
|
||||
expect(addrs).to.have.lengthOf(multiaddrsUncertified.length)
|
||||
addrs.forEach((addr, index) => {
|
||||
@ -616,14 +649,14 @@ describe('addressBook', () => {
|
||||
})
|
||||
|
||||
// consume peer record
|
||||
const consumed = ab.consumePeerRecord(envelope)
|
||||
const consumed = await ab.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
// Wait event
|
||||
await defer.promise
|
||||
|
||||
// Validate data exists and certified
|
||||
addrs = ab.get(peerId)
|
||||
addrs = await ab.get(peerId)
|
||||
expect(addrs).to.exist()
|
||||
expect(addrs).to.have.lengthOf(multiaddrsCertified.length)
|
||||
addrs.forEach((addr, index) => {
|
||||
@ -635,16 +668,19 @@ describe('addressBook', () => {
|
||||
|
||||
describe('fails to consume invalid peer records', () => {
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
ab = peerStore.addressBook
|
||||
})
|
||||
|
||||
it('invalid peer record', () => {
|
||||
it('invalid peer record', async () => {
|
||||
const invalidEnvelope = {
|
||||
payload: Buffer.from('invalid-peerRecord')
|
||||
}
|
||||
|
||||
const consumed = ab.consumePeerRecord(invalidEnvelope)
|
||||
const consumed = await ab.consumePeerRecord(invalidEnvelope)
|
||||
expect(consumed).to.eql(false)
|
||||
})
|
||||
|
||||
@ -659,7 +695,7 @@ describe('addressBook', () => {
|
||||
})
|
||||
const envelope = await Envelope.seal(peerRecord, peerId)
|
||||
|
||||
const consumed = ab.consumePeerRecord(envelope)
|
||||
const consumed = await ab.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(false)
|
||||
})
|
||||
|
||||
@ -679,10 +715,10 @@ describe('addressBook', () => {
|
||||
const envelope2 = await Envelope.seal(peerRecord2, peerId)
|
||||
|
||||
// Consume envelope1 (bigger seqNumber)
|
||||
let consumed = ab.consumePeerRecord(envelope1)
|
||||
let consumed = await ab.consumePeerRecord(envelope1)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
consumed = ab.consumePeerRecord(envelope2)
|
||||
consumed = await ab.consumePeerRecord(envelope2)
|
||||
expect(consumed).to.eql(false)
|
||||
})
|
||||
|
||||
@ -693,7 +729,7 @@ describe('addressBook', () => {
|
||||
})
|
||||
const envelope = await Envelope.seal(peerRecord, peerId)
|
||||
|
||||
const consumed = ab.consumePeerRecord(envelope)
|
||||
const consumed = await ab.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(false)
|
||||
})
|
||||
})
|
||||
|
@ -3,26 +3,43 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
|
||||
const pDefer = require('p-defer')
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('../../src/errors')
|
||||
|
||||
/**
|
||||
* @typedef {import('../../src/peer-store/types').PeerStore} PeerStore
|
||||
* @typedef {import('../../src/peer-store/types').KeyBook} KeyBook
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
*/
|
||||
|
||||
describe('keyBook', () => {
|
||||
let peerId, peerStore, kb
|
||||
/** @type {PeerId} */
|
||||
let peerId
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {KeyBook} */
|
||||
let kb
|
||||
/** @type {MemoryDatastore} */
|
||||
let datastore
|
||||
|
||||
beforeEach(async () => {
|
||||
[peerId] = await peerUtils.createPeerId()
|
||||
peerStore = new PeerStore({ peerId })
|
||||
datastore = new MemoryDatastore()
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore
|
||||
})
|
||||
kb = peerStore.keyBook
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided in set', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided in set', async () => {
|
||||
try {
|
||||
kb.set('invalid peerId')
|
||||
await kb.set('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -30,9 +47,9 @@ describe('keyBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided in get', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided in get', async () => {
|
||||
try {
|
||||
kb.get('invalid peerId')
|
||||
await kb.get('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -40,22 +57,58 @@ describe('keyBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('stores the peerId in the book and returns the public key', () => {
|
||||
it('stores the peerId in the book and returns the public key', async () => {
|
||||
// Set PeerId
|
||||
kb.set(peerId, peerId.pubKey)
|
||||
await kb.set(peerId, peerId.pubKey)
|
||||
|
||||
// Get public key
|
||||
const pubKey = kb.get(peerId)
|
||||
const pubKey = await kb.get(peerId)
|
||||
expect(peerId.pubKey.bytes).to.equalBytes(pubKey.bytes)
|
||||
})
|
||||
|
||||
it('should not store if already stored', () => {
|
||||
const spy = sinon.spy(kb, '_setData')
|
||||
it('should not store if already stored', async () => {
|
||||
const spy = sinon.spy(datastore, 'put')
|
||||
|
||||
// Set PeerId
|
||||
kb.set(peerId, peerId.pubKey)
|
||||
kb.set(peerId, peerId.pubKey)
|
||||
await kb.set(peerId, peerId.pubKey)
|
||||
await kb.set(peerId, peerId.pubKey)
|
||||
|
||||
expect(spy).to.have.property('callCount', 1)
|
||||
})
|
||||
|
||||
it('should emit an event when setting a key', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
peerStore.on('change:pubkey', ({ peerId: id, pubKey }) => {
|
||||
expect(id.toB58String()).to.equal(peerId.toB58String())
|
||||
expect(pubKey.bytes).to.equalBytes(peerId.pubKey.bytes)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
// Set PeerId
|
||||
await kb.set(peerId, peerId.pubKey)
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('should not set when key does not match', async () => {
|
||||
const [edKey] = await peerUtils.createPeerId({ fixture: false, opts: { keyType: 'Ed25519' } })
|
||||
|
||||
// Set PeerId
|
||||
await expect(kb.set(edKey, peerId.pubKey)).to.eventually.be.rejectedWith(/bytes do not match/)
|
||||
})
|
||||
|
||||
it('should emit an event when deleting a key', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
await kb.set(peerId, peerId.pubKey)
|
||||
|
||||
peerStore.on('change:pubkey', ({ peerId: id, pubKey }) => {
|
||||
expect(id.toB58String()).to.equal(peerId.toB58String())
|
||||
expect(pubKey).to.be.undefined()
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
await kb.delete(peerId)
|
||||
await defer.promise
|
||||
})
|
||||
})
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const pDefer = require('p-defer')
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
|
||||
@ -12,7 +12,14 @@ const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('../../src/errors')
|
||||
|
||||
/**
|
||||
* @typedef {import('../../src/peer-store/types').PeerStore} PeerStore
|
||||
* @typedef {import('../../src/peer-store/types').MetadataBook} MetadataBook
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
*/
|
||||
|
||||
describe('metadataBook', () => {
|
||||
/** @type {PeerId} */
|
||||
let peerId
|
||||
|
||||
before(async () => {
|
||||
@ -20,10 +27,16 @@ describe('metadataBook', () => {
|
||||
})
|
||||
|
||||
describe('metadataBook.set', () => {
|
||||
let peerStore, mb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {MetadataBook} */
|
||||
let mb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
mb = peerStore.metadataBook
|
||||
})
|
||||
|
||||
@ -31,9 +44,9 @@ describe('metadataBook', () => {
|
||||
peerStore.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
mb.set('invalid peerId')
|
||||
await mb.set('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -41,9 +54,9 @@ describe('metadataBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if no key provided', () => {
|
||||
it('throws invalid parameters error if no metadata provided', async () => {
|
||||
try {
|
||||
mb.set(peerId)
|
||||
await mb.set(peerId)
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -51,9 +64,9 @@ describe('metadataBook', () => {
|
||||
throw new Error('no key provided should throw error')
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if no value provided', () => {
|
||||
it('throws invalid parameters error if no value provided', async () => {
|
||||
try {
|
||||
mb.set(peerId, 'location')
|
||||
await mb.setValue(peerId, 'location')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -61,9 +74,9 @@ describe('metadataBook', () => {
|
||||
throw new Error('no value provided should throw error')
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if value is not a buffer', () => {
|
||||
it('throws invalid parameters error if value is not a buffer', async () => {
|
||||
try {
|
||||
mb.set(peerId, 'location', 'mars')
|
||||
await mb.setValue(peerId, 'location', 'mars')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -71,30 +84,30 @@ describe('metadataBook', () => {
|
||||
throw new Error('invalid value provided should throw error')
|
||||
})
|
||||
|
||||
it('stores the content and emit change event', () => {
|
||||
it('stores the content and emit change event', async () => {
|
||||
const defer = pDefer()
|
||||
const metadataKey = 'location'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
|
||||
peerStore.once('change:metadata', ({ peerId, metadata }) => {
|
||||
expect(peerId).to.exist()
|
||||
expect(metadata).to.equal(metadataKey)
|
||||
expect(metadata.get(metadataKey)).to.equalBytes(metadataValue)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue)
|
||||
|
||||
const value = mb.getValue(peerId, metadataKey)
|
||||
const value = await mb.getValue(peerId, metadataKey)
|
||||
expect(value).to.equalBytes(metadataValue)
|
||||
|
||||
const peerMetadata = mb.get(peerId)
|
||||
const peerMetadata = await mb.get(peerId)
|
||||
expect(peerMetadata).to.exist()
|
||||
expect(peerMetadata.get(metadataKey)).to.equalBytes(metadataValue)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on set if not storing the exact same content', () => {
|
||||
it('emits on set if not storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
const metadataKey = 'location'
|
||||
const metadataValue1 = uint8ArrayFromString('mars')
|
||||
@ -109,22 +122,22 @@ describe('metadataBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
mb.set(peerId, metadataKey, metadataValue1)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue1)
|
||||
|
||||
// set 2 (same content)
|
||||
mb.set(peerId, metadataKey, metadataValue2)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue2)
|
||||
|
||||
const value = mb.getValue(peerId, metadataKey)
|
||||
const value = await mb.getValue(peerId, metadataKey)
|
||||
expect(value).to.equalBytes(metadataValue2)
|
||||
|
||||
const peerMetadata = mb.get(peerId)
|
||||
const peerMetadata = await mb.get(peerId)
|
||||
expect(peerMetadata).to.exist()
|
||||
expect(peerMetadata.get(metadataKey)).to.equalBytes(metadataValue2)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set if it is storing the exact same content', () => {
|
||||
it('does not emit on set if it is storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
const metadataKey = 'location'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
@ -138,10 +151,10 @@ describe('metadataBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue)
|
||||
|
||||
// set 2 (same content)
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
@ -153,16 +166,22 @@ describe('metadataBook', () => {
|
||||
})
|
||||
|
||||
describe('metadataBook.get', () => {
|
||||
let peerStore, mb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {MetadataBook} */
|
||||
let mb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
mb = peerStore.metadataBook
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
mb.get('invalid peerId')
|
||||
await mb.get('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -170,35 +189,43 @@ describe('metadataBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('returns undefined if no metadata is known for the provided peer', () => {
|
||||
const metadata = mb.get(peerId)
|
||||
it('returns empty if no metadata is known for the provided peer', async () => {
|
||||
const metadata = await mb.get(peerId)
|
||||
|
||||
expect(metadata).to.not.exist()
|
||||
expect(metadata).to.be.empty()
|
||||
})
|
||||
|
||||
it('returns the metadata stored', () => {
|
||||
it('returns the metadata stored', async () => {
|
||||
const metadataKey = 'location'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
const metadata = new Map()
|
||||
metadata.set(metadataKey, metadataValue)
|
||||
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
await mb.set(peerId, metadata)
|
||||
|
||||
const peerMetadata = mb.get(peerId)
|
||||
const peerMetadata = await mb.get(peerId)
|
||||
expect(peerMetadata).to.exist()
|
||||
expect(peerMetadata.get(metadataKey)).to.equalBytes(metadataValue)
|
||||
})
|
||||
})
|
||||
|
||||
describe('metadataBook.getValue', () => {
|
||||
let peerStore, mb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {MetadataBook} */
|
||||
let mb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
mb = peerStore.metadataBook
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
mb.getValue('invalid peerId')
|
||||
await mb.getValue('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -206,48 +233,53 @@ describe('metadataBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('returns undefined if no metadata is known for the provided peer', () => {
|
||||
it('returns undefined if no metadata is known for the provided peer', async () => {
|
||||
const metadataKey = 'location'
|
||||
const metadata = mb.getValue(peerId, metadataKey)
|
||||
const metadata = await mb.getValue(peerId, metadataKey)
|
||||
|
||||
expect(metadata).to.not.exist()
|
||||
})
|
||||
|
||||
it('returns the metadata value stored for the given key', () => {
|
||||
it('returns the metadata value stored for the given key', async () => {
|
||||
const metadataKey = 'location'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue)
|
||||
|
||||
const value = mb.getValue(peerId, metadataKey)
|
||||
const value = await mb.getValue(peerId, metadataKey)
|
||||
expect(value).to.exist()
|
||||
expect(value).to.equalBytes(metadataValue)
|
||||
})
|
||||
|
||||
it('returns undefined if no metadata is known for the provided peer and key', () => {
|
||||
it('returns undefined if no metadata is known for the provided peer and key', async () => {
|
||||
const metadataKey = 'location'
|
||||
const metadataBadKey = 'nickname'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
|
||||
const metadata = mb.getValue(peerId, metadataBadKey)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue)
|
||||
|
||||
const metadata = await mb.getValue(peerId, metadataBadKey)
|
||||
expect(metadata).to.not.exist()
|
||||
})
|
||||
})
|
||||
|
||||
describe('metadataBook.delete', () => {
|
||||
let peerStore, mb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {MetadataBook} */
|
||||
let mb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
mb = peerStore.metadataBook
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
mb.delete('invalid peerId')
|
||||
await mb.delete('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -255,16 +287,14 @@ describe('metadataBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
it('should not emit event if no records exist for the peer', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
peerStore.on('change:metadata', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = mb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
await mb.delete(peerId)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
@ -274,37 +304,41 @@ describe('metadataBook', () => {
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
it('should emit an event if the record exists for the peer', async () => {
|
||||
const defer = pDefer()
|
||||
const metadataKey = 'location'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue)
|
||||
|
||||
// Listen after set
|
||||
peerStore.on('change:metadata', () => {
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = mb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
await mb.delete(peerId)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('metadataBook.deleteValue', () => {
|
||||
let peerStore, mb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {MetadataBook} */
|
||||
let mb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
mb = peerStore.metadataBook
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided', () => {
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
try {
|
||||
mb.deleteValue('invalid peerId')
|
||||
await mb.deleteValue('invalid peerId')
|
||||
} catch (/** @type {any} */ err) {
|
||||
expect(err.code).to.equal(ERR_INVALID_PARAMETERS)
|
||||
return
|
||||
@ -312,7 +346,7 @@ describe('metadataBook', () => {
|
||||
throw new Error('invalid peerId should throw error')
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
it('should not emit event if no records exist for the peer', async () => {
|
||||
const defer = pDefer()
|
||||
const metadataKey = 'location'
|
||||
|
||||
@ -320,9 +354,7 @@ describe('metadataBook', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = mb.deleteValue(peerId, metadataKey)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
await mb.deleteValue(peerId, metadataKey)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
@ -332,45 +364,19 @@ describe('metadataBook', () => {
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
it('should emit event if a record exists for the peer', async () => {
|
||||
const defer = pDefer()
|
||||
const metadataKey = 'location'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
await mb.setValue(peerId, metadataKey, metadataValue)
|
||||
|
||||
// Listen after set
|
||||
peerStore.on('change:metadata', () => {
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = mb.deleteValue(peerId, metadataKey)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns false if there is a record for the peer but not the given metadata key', () => {
|
||||
const defer = pDefer()
|
||||
const metadataKey = 'location'
|
||||
const metadataBadKey = 'nickname'
|
||||
const metadataValue = uint8ArrayFromString('mars')
|
||||
|
||||
mb.set(peerId, metadataKey, metadataValue)
|
||||
|
||||
peerStore.on('change:metadata', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = mb.deleteValue(peerId, metadataBadKey)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
await mb.deleteValue(peerId, metadataKey)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
@ -6,6 +6,7 @@ const sinon = require('sinon')
|
||||
|
||||
const baseOptions = require('../utils/base-options')
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
const all = require('it-all')
|
||||
|
||||
describe('libp2p.peerStore', () => {
|
||||
let libp2p, remoteLibp2p
|
||||
@ -35,13 +36,14 @@ describe('libp2p.peerStore', () => {
|
||||
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)
|
||||
const localPeers = await all(libp2p.peerStore.getPeers())
|
||||
|
||||
const publicKeyInLocalPeer = localPeers.get(remoteIdStr).id.pubKey
|
||||
expect(localPeers.length).to.equal(1)
|
||||
|
||||
const publicKeyInLocalPeer = localPeers[0].id.pubKey
|
||||
expect(publicKeyInLocalPeer.bytes).to.equalBytes(remoteLibp2p.peerId.pubKey.bytes)
|
||||
|
||||
const publicKeyInRemotePeer = remoteLibp2p.peerStore.keyBook.get(libp2p.peerId)
|
||||
const publicKeyInRemotePeer = await remoteLibp2p.peerStore.keyBook.get(libp2p.peerId)
|
||||
expect(publicKeyInRemotePeer).to.exist()
|
||||
expect(publicKeyInRemotePeer.bytes).to.equalBytes(libp2p.peerId.pubKey.bytes)
|
||||
})
|
||||
|
@ -2,11 +2,11 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
|
||||
const all = require('it-all')
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
const addr1 = new Multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||
@ -18,6 +18,10 @@ const proto1 = '/protocol1'
|
||||
const proto2 = '/protocol2'
|
||||
const proto3 = '/protocol3'
|
||||
|
||||
/**
|
||||
* @typedef {import('../../src/peer-store/types').PeerStore} PeerStore
|
||||
*/
|
||||
|
||||
describe('peer-store', () => {
|
||||
let peerIds
|
||||
before(async () => {
|
||||
@ -27,62 +31,65 @@ describe('peer-store', () => {
|
||||
})
|
||||
|
||||
describe('empty books', () => {
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId: peerIds[4] })
|
||||
peerStore = new PeerStore({
|
||||
peerId: peerIds[4],
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
})
|
||||
|
||||
it('has an empty map of peers', () => {
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(0)
|
||||
it('has an empty map of peers', async () => {
|
||||
const peers = await all(peerStore.getPeers())
|
||||
expect(peers.length).to.equal(0)
|
||||
})
|
||||
|
||||
it('returns false on trying to delete a non existant peerId', () => {
|
||||
const deleted = peerStore.delete(peerIds[0])
|
||||
expect(deleted).to.equal(false)
|
||||
it('deletes a peerId', async () => {
|
||||
await peerStore.addressBook.set(peerIds[0], [new Multiaddr('/ip4/127.0.0.1/tcp/4001')])
|
||||
await expect(peerStore.has(peerIds[0])).to.eventually.be.true()
|
||||
await peerStore.delete(peerIds[0])
|
||||
await expect(peerStore.has(peerIds[0])).to.eventually.be.false()
|
||||
})
|
||||
|
||||
it('returns undefined on trying to find a non existant peerId', () => {
|
||||
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()
|
||||
it('sets the peer\'s public key to the KeyBook', async () => {
|
||||
await peerStore.keyBook.set(peerIds[0], peerIds[0].pubKey)
|
||||
await expect(peerStore.keyBook.get(peerIds[0])).to.eventually.deep.equal(peerIds[0].pubKey)
|
||||
})
|
||||
})
|
||||
|
||||
describe('previously populated books', () => {
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId: peerIds[4] })
|
||||
beforeEach(async () => {
|
||||
peerStore = new PeerStore({
|
||||
peerId: peerIds[4],
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
|
||||
// Add peer0 with { addr1, addr2 } and { proto1 }
|
||||
peerStore.addressBook.set(peerIds[0], [addr1, addr2])
|
||||
peerStore.protoBook.set(peerIds[0], [proto1])
|
||||
await peerStore.addressBook.set(peerIds[0], [addr1, addr2])
|
||||
await peerStore.protoBook.set(peerIds[0], [proto1])
|
||||
|
||||
// Add peer1 with { addr3 } and { proto2, proto3 }
|
||||
peerStore.addressBook.set(peerIds[1], [addr3])
|
||||
peerStore.protoBook.set(peerIds[1], [proto2, proto3])
|
||||
await peerStore.addressBook.set(peerIds[1], [addr3])
|
||||
await peerStore.protoBook.set(peerIds[1], [proto2, proto3])
|
||||
|
||||
// Add peer2 with { addr4 }
|
||||
peerStore.addressBook.set(peerIds[2], [addr4])
|
||||
await peerStore.addressBook.set(peerIds[2], [addr4])
|
||||
|
||||
// Add peer3 with { addr4 } and { proto2 }
|
||||
peerStore.addressBook.set(peerIds[3], [addr4])
|
||||
peerStore.protoBook.set(peerIds[3], [proto2])
|
||||
await peerStore.addressBook.set(peerIds[3], [addr4])
|
||||
await peerStore.protoBook.set(peerIds[3], [proto2])
|
||||
})
|
||||
|
||||
it('has peers', () => {
|
||||
const peers = peerStore.peers
|
||||
it('has peers', async () => {
|
||||
const peers = await all(peerStore.getPeers())
|
||||
|
||||
expect(peers.size).to.equal(4)
|
||||
expect(Array.from(peers.keys())).to.have.members([
|
||||
expect(peers.length).to.equal(4)
|
||||
expect(peers.map(peer => peer.id.toB58String())).to.have.members([
|
||||
peerIds[0].toB58String(),
|
||||
peerIds[1].toB58String(),
|
||||
peerIds[2].toB58String(),
|
||||
@ -90,47 +97,45 @@ describe('peer-store', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('returns true on deleting a stored peer', () => {
|
||||
const deleted = peerStore.delete(peerIds[0])
|
||||
expect(deleted).to.equal(true)
|
||||
it('deletes a stored peer', async () => {
|
||||
await peerStore.delete(peerIds[0])
|
||||
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(3)
|
||||
const peers = await all(peerStore.getPeers())
|
||||
expect(peers.length).to.equal(3)
|
||||
expect(Array.from(peers.keys())).to.not.have.members([peerIds[0].toB58String()])
|
||||
})
|
||||
|
||||
it('returns true on deleting a stored peer which is only on one book', () => {
|
||||
const deleted = peerStore.delete(peerIds[2])
|
||||
expect(deleted).to.equal(true)
|
||||
it('deletes a stored peer which is only on one book', async () => {
|
||||
await peerStore.delete(peerIds[2])
|
||||
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(3)
|
||||
const peers = await all(peerStore.getPeers())
|
||||
expect(peers.length).to.equal(3)
|
||||
})
|
||||
|
||||
it('gets the stored information of a peer in all its books', () => {
|
||||
const peer = peerStore.get(peerIds[0])
|
||||
it('gets the stored information of a peer in all its books', async () => {
|
||||
const peer = await peerStore.get(peerIds[0])
|
||||
expect(peer).to.exist()
|
||||
expect(peer.protocols).to.have.members([proto1])
|
||||
|
||||
const peerMultiaddrs = peer.addresses.map((mi) => mi.multiaddr)
|
||||
expect(peerMultiaddrs).to.have.members([addr1, addr2])
|
||||
expect(peerMultiaddrs).to.have.deep.members([addr1, addr2])
|
||||
|
||||
expect(peer.id).to.exist()
|
||||
expect(peer.id.toB58String()).to.equal(peerIds[0].toB58String())
|
||||
})
|
||||
|
||||
it('gets the stored information of a peer that is not present in all its books', () => {
|
||||
const peers = peerStore.get(peerIds[2])
|
||||
it('gets the stored information of a peer that is not present in all its books', async () => {
|
||||
const peers = await peerStore.get(peerIds[2])
|
||||
expect(peers).to.exist()
|
||||
expect(peers.protocols.length).to.eql(0)
|
||||
|
||||
const peerMultiaddrs = peers.addresses.map((mi) => mi.multiaddr)
|
||||
expect(peerMultiaddrs).to.have.members([addr4])
|
||||
expect(peerMultiaddrs).to.have.deep.members([addr4])
|
||||
})
|
||||
|
||||
it('can find all the peers supporting a protocol', () => {
|
||||
it('can find all the peers supporting a protocol', async () => {
|
||||
const peerSupporting2 = []
|
||||
|
||||
for (const [, peer] of peerStore.peers.entries()) {
|
||||
for await (const peer of peerStore.getPeers()) {
|
||||
if (peer.protocols.includes(proto2)) {
|
||||
peerSupporting2.push(peer)
|
||||
}
|
||||
@ -141,67 +146,71 @@ describe('peer-store', () => {
|
||||
expect(peerSupporting2[1].id.toB58String()).to.eql(peerIds[3].toB58String())
|
||||
})
|
||||
|
||||
it('can find all the peers listening on a given address', () => {
|
||||
const peerListenint4 = []
|
||||
it('can find all the peers listening on a given address', async () => {
|
||||
const peerListening4 = []
|
||||
|
||||
for (const [, peer] of peerStore.peers.entries()) {
|
||||
const multiaddrs = peer.addresses.map((mi) => mi.multiaddr)
|
||||
for await (const peer of peerStore.getPeers()) {
|
||||
const multiaddrs = peer.addresses.map((mi) => mi.multiaddr.toString())
|
||||
|
||||
if (multiaddrs.includes(addr4)) {
|
||||
peerListenint4.push(peer)
|
||||
if (multiaddrs.includes(addr4.toString())) {
|
||||
peerListening4.push(peer)
|
||||
}
|
||||
}
|
||||
|
||||
expect(peerListenint4.length).to.eql(2)
|
||||
expect(peerListenint4[0].id.toB58String()).to.eql(peerIds[2].toB58String())
|
||||
expect(peerListenint4[1].id.toB58String()).to.eql(peerIds[3].toB58String())
|
||||
expect(peerListening4.length).to.eql(2)
|
||||
expect(peerListening4[0].id.toB58String()).to.eql(peerIds[2].toB58String())
|
||||
expect(peerListening4[1].id.toB58String()).to.eql(peerIds[3].toB58String())
|
||||
})
|
||||
})
|
||||
|
||||
describe('peerStore.peers', () => {
|
||||
describe('peerStore.getPeers', () => {
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId: peerIds[4] })
|
||||
peerStore = new PeerStore({
|
||||
peerId: peerIds[4],
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
})
|
||||
|
||||
it('returns peers if only addresses are known', () => {
|
||||
peerStore.addressBook.set(peerIds[0], [addr1])
|
||||
it('returns peers if only addresses are known', async () => {
|
||||
await peerStore.addressBook.set(peerIds[0], [addr1])
|
||||
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(1)
|
||||
const peers = await all(peerStore.getPeers())
|
||||
expect(peers.length).to.equal(1)
|
||||
|
||||
const peerData = peers.get(peerIds[0].toB58String())
|
||||
const peerData = peers[0]
|
||||
expect(peerData).to.exist()
|
||||
expect(peerData.id).to.exist()
|
||||
expect(peerData.addresses).to.have.lengthOf(1)
|
||||
expect(peerData.protocols).to.have.lengthOf(0)
|
||||
expect(peerData.metadata).to.not.exist()
|
||||
expect(peerData.metadata).to.be.empty()
|
||||
})
|
||||
|
||||
it('returns peers if only protocols are known', () => {
|
||||
peerStore.protoBook.set(peerIds[0], [proto1])
|
||||
it('returns peers if only protocols are known', async () => {
|
||||
await peerStore.protoBook.set(peerIds[0], [proto1])
|
||||
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(1)
|
||||
const peers = await all(peerStore.getPeers())
|
||||
expect(peers.length).to.equal(1)
|
||||
|
||||
const peerData = peers.get(peerIds[0].toB58String())
|
||||
const peerData = peers[0]
|
||||
expect(peerData).to.exist()
|
||||
expect(peerData.id).to.exist()
|
||||
expect(peerData.addresses).to.have.lengthOf(0)
|
||||
expect(peerData.protocols).to.have.lengthOf(1)
|
||||
expect(peerData.metadata).to.not.exist()
|
||||
expect(peerData.metadata).to.be.empty()
|
||||
})
|
||||
|
||||
it('returns peers if only metadata is known', () => {
|
||||
it('returns peers if only metadata is known', async () => {
|
||||
const metadataKey = 'location'
|
||||
const metadataValue = uint8ArrayFromString('earth')
|
||||
peerStore.metadataBook.set(peerIds[0], metadataKey, metadataValue)
|
||||
await peerStore.metadataBook.setValue(peerIds[0], metadataKey, metadataValue)
|
||||
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(1)
|
||||
const peers = await all(peerStore.getPeers())
|
||||
expect(peers.length).to.equal(1)
|
||||
|
||||
const peerData = peers.get(peerIds[0].toB58String())
|
||||
const peerData = peers[0]
|
||||
expect(peerData).to.exist()
|
||||
expect(peerData.id).to.exist()
|
||||
expect(peerData.addresses).to.have.lengthOf(0)
|
||||
|
@ -1,608 +0,0 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const Envelope = require('../../src/record/envelope')
|
||||
const PeerRecord = require('../../src/record/peer-record')
|
||||
const PeerStore = require('../../src/peer-store/persistent')
|
||||
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
describe('Persisted PeerStore', () => {
|
||||
let datastore, peerStore
|
||||
let peerId
|
||||
|
||||
before(async () => {
|
||||
[peerId] = await peerUtils.createPeerId({ fixture: false })
|
||||
})
|
||||
|
||||
describe('start and stop flows', () => {
|
||||
beforeEach(() => {
|
||||
datastore = new MemoryDatastore()
|
||||
peerStore = new PeerStore({ datastore, peerId })
|
||||
})
|
||||
|
||||
afterEach(() => peerStore.stop())
|
||||
|
||||
it('should try to load content from an empty datastore on start', async () => {
|
||||
const spyQuery = sinon.spy(datastore, 'query')
|
||||
const spyProcessEntry = sinon.spy(peerStore, '_processDatastoreEntry')
|
||||
|
||||
await peerStore.start()
|
||||
expect(spyQuery).to.have.property('callCount', 1)
|
||||
expect(spyProcessEntry).to.have.property('callCount', 0)
|
||||
|
||||
// No data to populate
|
||||
expect(peerStore.peers.size).to.eq(0)
|
||||
})
|
||||
|
||||
it('should try to commit data on stop but should not add to batch if not exists', async () => {
|
||||
const spyDs = sinon.spy(peerStore, '_commitData')
|
||||
const spyBatch = sinon.spy(datastore, 'batch')
|
||||
|
||||
await peerStore.start()
|
||||
expect(spyDs).to.have.property('callCount', 0)
|
||||
|
||||
await peerStore.stop()
|
||||
expect(spyBatch).to.have.property('callCount', 0)
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('simple setup with content stored per change (threshold 1)', () => {
|
||||
beforeEach(() => {
|
||||
datastore = new MemoryDatastore()
|
||||
peerStore = new PeerStore({ datastore, peerId, threshold: 1 })
|
||||
})
|
||||
|
||||
afterEach(() => peerStore.stop())
|
||||
|
||||
it('should store peerStore content on datastore after peer marked as dirty (threshold 1)', async () => {
|
||||
const [peer] = await peerUtils.createPeerId({ number: 2 })
|
||||
const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')]
|
||||
const protocols = ['/ping/1.0.0']
|
||||
const spyDirty = sinon.spy(peerStore, '_addDirtyPeer')
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
const commitSpy = sinon.spy(peerStore, '_commitData')
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
// AddressBook
|
||||
peerStore.addressBook.set(peer, multiaddrs)
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 1) // Address
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
// ProtoBook
|
||||
peerStore.protoBook.set(peer, protocols)
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 2) // Protocol
|
||||
expect(spyDs).to.have.property('callCount', 2)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
// Should have three peer records stored in the datastore
|
||||
const queryParams = {
|
||||
prefix: '/peers/'
|
||||
}
|
||||
|
||||
let count = 0
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
count++
|
||||
}
|
||||
expect(count).to.equal(2)
|
||||
|
||||
// Validate data
|
||||
const storedPeer = peerStore.get(peer)
|
||||
expect(storedPeer.id.toB58String()).to.eql(peer.toB58String())
|
||||
expect(storedPeer.protocols).to.have.members(protocols)
|
||||
expect(storedPeer.addresses.map((a) => a.multiaddr.toString())).to.have.members([multiaddrs[0].toString()])
|
||||
expect(storedPeer.addresses.map((a) => a.isCertified)).to.have.members([false])
|
||||
})
|
||||
|
||||
it('should load content to the peerStore when restart but not put in datastore again', async () => {
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
const peers = await peerUtils.createPeerId({ number: 2 })
|
||||
const commitSpy = sinon.spy(peerStore, '_commitData')
|
||||
const multiaddrs = [
|
||||
new Multiaddr('/ip4/156.10.1.22/tcp/1000'),
|
||||
new Multiaddr('/ip4/156.10.1.23/tcp/1000')
|
||||
]
|
||||
const protocols = ['/ping/1.0.0']
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
// AddressBook
|
||||
peerStore.addressBook.set(peers[0], [multiaddrs[0]])
|
||||
peerStore.addressBook.set(peers[1], [multiaddrs[1]])
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
// KeyBook
|
||||
peerStore.keyBook.set(peers[0], peers[0].pubKey)
|
||||
peerStore.keyBook.set(peers[1], peers[1].pubKey)
|
||||
|
||||
// no batch commit as public key inline
|
||||
|
||||
// ProtoBook
|
||||
peerStore.protoBook.set(peers[0], protocols)
|
||||
peerStore.protoBook.set(peers[1], protocols)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
// MetadataBook
|
||||
peerStore.metadataBook.set(peers[0], 'location', uint8ArrayFromString('earth'))
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
expect(spyDs).to.have.property('callCount', 5) // 2 Address + 2 Proto + 1 Metadata
|
||||
expect(peerStore.peers.size).to.equal(2)
|
||||
|
||||
await peerStore.stop()
|
||||
peerStore.keyBook.data.clear()
|
||||
peerStore.addressBook.data.clear()
|
||||
peerStore.protoBook.data.clear()
|
||||
|
||||
// Load on restart
|
||||
const spy = sinon.spy(peerStore, '_processDatastoreEntry')
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
expect(spy).to.have.property('callCount', 5)
|
||||
expect(spyDs).to.have.property('callCount', 5)
|
||||
|
||||
expect(peerStore.peers.size).to.equal(2)
|
||||
expect(peerStore.addressBook.data.size).to.equal(2)
|
||||
expect(peerStore.keyBook.data.size).to.equal(0)
|
||||
expect(peerStore.protoBook.data.size).to.equal(2)
|
||||
expect(peerStore.metadataBook.data.size).to.equal(1)
|
||||
})
|
||||
|
||||
it('should delete content from the datastore on delete', async () => {
|
||||
const [peer] = await peerUtils.createPeerId()
|
||||
const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')]
|
||||
const protocols = ['/ping/1.0.0']
|
||||
const commitSpy = sinon.spy(peerStore, '_commitData')
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
// AddressBook
|
||||
peerStore.addressBook.set(peer, multiaddrs)
|
||||
// ProtoBook
|
||||
peerStore.protoBook.set(peer, protocols)
|
||||
// MetadataBook
|
||||
peerStore.metadataBook.set(peer, 'location', uint8ArrayFromString('earth'))
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
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')
|
||||
const spyMetadataBook = sinon.spy(peerStore.metadataBook, 'delete')
|
||||
|
||||
// Delete from PeerStore
|
||||
peerStore.delete(peer)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
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(spyMetadataBook).to.have.property('callCount', 1)
|
||||
expect(spyDs).to.have.property('callCount', 3)
|
||||
|
||||
// Should have zero peer records stored in the datastore
|
||||
const queryParams = {
|
||||
prefix: '/peers/'
|
||||
}
|
||||
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
throw new Error('Datastore should be empty')
|
||||
}
|
||||
})
|
||||
|
||||
it('should store certified peer records after peer marked as dirty (threshold 1)', async () => {
|
||||
const [peerId] = await peerUtils.createPeerId()
|
||||
const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')]
|
||||
const spyDirty = sinon.spy(peerStore, '_addDirtyPeer')
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
const commitSpy = sinon.spy(peerStore, '_commitData')
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
const peerRecord = new PeerRecord({
|
||||
peerId,
|
||||
multiaddrs
|
||||
})
|
||||
const envelope = await Envelope.seal(peerRecord, peerId)
|
||||
|
||||
// consume peer record
|
||||
const consumed = peerStore.addressBook.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(true)
|
||||
expect(spyDirty).to.have.property('callCount', 1) // Address
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
// Should have three peer records stored in the datastore
|
||||
const queryParams = {
|
||||
prefix: '/peers/'
|
||||
}
|
||||
|
||||
let count = 0
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
count++
|
||||
}
|
||||
expect(count).to.equal(1)
|
||||
|
||||
// Validate data
|
||||
const storedPeer = peerStore.get(peerId)
|
||||
expect(storedPeer.id.toB58String()).to.eql(peerId.toB58String())
|
||||
expect(storedPeer.addresses.map((a) => a.multiaddr.toString())).to.have.members([multiaddrs[0].toString()])
|
||||
expect(storedPeer.addresses.map((a) => a.isCertified)).to.have.members([true])
|
||||
})
|
||||
|
||||
it('should load certified peer records to the peerStore when restart but not put in datastore again', async () => {
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
const peers = await peerUtils.createPeerId({ number: 2 })
|
||||
const commitSpy = sinon.spy(peerStore, '_commitData')
|
||||
const multiaddrs = [
|
||||
new Multiaddr('/ip4/156.10.1.22/tcp/1000'),
|
||||
new Multiaddr('/ip4/156.10.1.23/tcp/1000')
|
||||
]
|
||||
const peerRecord0 = new PeerRecord({
|
||||
peerId: peers[0],
|
||||
multiaddrs: [multiaddrs[0]]
|
||||
})
|
||||
const envelope0 = await Envelope.seal(peerRecord0, peers[0])
|
||||
const peerRecord1 = new PeerRecord({
|
||||
peerId: peers[1],
|
||||
multiaddrs: [multiaddrs[1]]
|
||||
})
|
||||
const envelope1 = await Envelope.seal(peerRecord1, peers[1])
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
// AddressBook
|
||||
let consumed = peerStore.addressBook.consumePeerRecord(envelope0)
|
||||
expect(consumed).to.eql(true)
|
||||
consumed = peerStore.addressBook.consumePeerRecord(envelope1)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
expect(spyDs).to.have.property('callCount', 2) // 2 Address + 2 Key + 2 Proto + 1 Metadata
|
||||
expect(peerStore.peers.size).to.equal(2)
|
||||
|
||||
await peerStore.stop()
|
||||
peerStore.addressBook.data.clear()
|
||||
|
||||
// Load on restart
|
||||
const spy = sinon.spy(peerStore, '_processDatastoreEntry')
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
expect(spy).to.have.property('callCount', 2)
|
||||
expect(spyDs).to.have.property('callCount', 2)
|
||||
|
||||
expect(peerStore.peers.size).to.equal(2)
|
||||
expect(peerStore.addressBook.data.size).to.equal(2)
|
||||
|
||||
expect(peerStore.addressBook.getRawEnvelope(peers[0])).to.exist()
|
||||
expect(peerStore.addressBook.getRawEnvelope(peers[1])).to.exist()
|
||||
|
||||
// Validate stored envelopes
|
||||
const storedEnvelope0 = await peerStore.addressBook.getPeerRecord(peers[0])
|
||||
expect(envelope0.equals(storedEnvelope0)).to.eql(true)
|
||||
|
||||
const storedEnvelope1 = await peerStore.addressBook.getPeerRecord(peers[1])
|
||||
expect(envelope1.equals(storedEnvelope1)).to.eql(true)
|
||||
|
||||
// Validate multiaddrs
|
||||
const storedPeer0 = peerStore.get(peers[0])
|
||||
expect(storedPeer0.id.toB58String()).to.eql(peers[0].toB58String())
|
||||
expect(storedPeer0.addresses.map((a) => a.multiaddr.toString())).to.have.members([multiaddrs[0].toString()])
|
||||
expect(storedPeer0.addresses.map((a) => a.isCertified)).to.have.members([true])
|
||||
|
||||
const storedPeer1 = peerStore.get(peers[1])
|
||||
expect(storedPeer1.id.toB58String()).to.eql(peers[1].toB58String())
|
||||
expect(storedPeer1.addresses.map((a) => a.multiaddr.toString())).to.have.members([multiaddrs[1].toString()])
|
||||
expect(storedPeer1.addresses.map((a) => a.isCertified)).to.have.members([true])
|
||||
})
|
||||
|
||||
it('should delete certified peer records from the datastore on delete', async () => {
|
||||
const [peer] = await peerUtils.createPeerId()
|
||||
const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')]
|
||||
const commitSpy = sinon.spy(peerStore, '_commitData')
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
// AddressBook
|
||||
const peerRecord = new PeerRecord({
|
||||
peerId: peer,
|
||||
multiaddrs
|
||||
})
|
||||
const envelope = await Envelope.seal(peerRecord, peer)
|
||||
|
||||
// consume peer record
|
||||
const consumed = peerStore.addressBook.consumePeerRecord(envelope)
|
||||
expect(consumed).to.eql(true)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
expect(peerStore.addressBook.getRawEnvelope(peer)).to.exist()
|
||||
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
const spyAddressBook = sinon.spy(peerStore.addressBook, 'delete')
|
||||
|
||||
// Delete from PeerStore
|
||||
peerStore.delete(peer)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
await peerStore.stop()
|
||||
|
||||
expect(spyAddressBook).to.have.property('callCount', 1)
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
|
||||
// Should have zero peer records stored in the datastore
|
||||
const queryParams = {
|
||||
prefix: '/peers/'
|
||||
}
|
||||
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
throw new Error('Datastore should be empty')
|
||||
}
|
||||
|
||||
expect(peerStore.addressBook.getRawEnvelope(peer)).to.not.exist()
|
||||
})
|
||||
})
|
||||
|
||||
describe('setup with content not stored per change (threshold 2)', () => {
|
||||
beforeEach(() => {
|
||||
datastore = new MemoryDatastore()
|
||||
peerStore = new PeerStore({ datastore, peerId, threshold: 2 })
|
||||
})
|
||||
|
||||
afterEach(() => peerStore.stop())
|
||||
|
||||
it('should not commit until threshold is reached', async () => {
|
||||
const spyDirty = sinon.spy(peerStore, '_addDirtyPeer')
|
||||
const spyDirtyMetadata = sinon.spy(peerStore, '_addDirtyPeerMetadata')
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
const commitSpy = sinon.spy(peerStore, '_commitData')
|
||||
|
||||
const peers = await peerUtils.createPeerId({ number: 2 })
|
||||
|
||||
const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')]
|
||||
const protocols = ['/ping/1.0.0']
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 0)
|
||||
expect(spyDs).to.have.property('callCount', 0)
|
||||
|
||||
// Add Peer0 data in multiple books
|
||||
peerStore.addressBook.set(peers[0], multiaddrs)
|
||||
peerStore.protoBook.set(peers[0], protocols)
|
||||
peerStore.metadataBook.set(peers[0], 'location', uint8ArrayFromString('earth'))
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
// Remove data from the same Peer
|
||||
peerStore.addressBook.delete(peers[0])
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 3) // 2 AddrBook ops, 1 ProtoBook op
|
||||
expect(spyDirtyMetadata).to.have.property('callCount', 1) // 1 MetadataBook op
|
||||
expect(peerStore._dirtyPeers.size).to.equal(1)
|
||||
expect(spyDs).to.have.property('callCount', 0)
|
||||
|
||||
const queryParams = {
|
||||
prefix: '/peers/'
|
||||
}
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
throw new Error('Datastore should be empty')
|
||||
}
|
||||
|
||||
// Add data for second book
|
||||
peerStore.addressBook.set(peers[1], multiaddrs)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 4)
|
||||
expect(spyDirtyMetadata).to.have.property('callCount', 1)
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
|
||||
// Should have three peer records stored in the datastore
|
||||
let count = 0
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
count++
|
||||
}
|
||||
expect(count).to.equal(3)
|
||||
expect(peerStore.peers.size).to.equal(2)
|
||||
})
|
||||
|
||||
it('should commit on stop if threshold was not reached', async () => {
|
||||
const spyDirty = sinon.spy(peerStore, '_addDirtyPeer')
|
||||
const spyDs = sinon.spy(datastore, 'batch')
|
||||
|
||||
const protocols = ['/ping/1.0.0']
|
||||
const [peer] = await peerUtils.createPeerId()
|
||||
|
||||
await peerStore.start()
|
||||
|
||||
// Add Peer data in a book
|
||||
peerStore.protoBook.set(peer, protocols)
|
||||
|
||||
expect(spyDs).to.have.property('callCount', 0)
|
||||
expect(spyDirty).to.have.property('callCount', 1) // ProtoBook
|
||||
expect(peerStore._dirtyPeers.size).to.equal(1)
|
||||
|
||||
const queryParams = {
|
||||
prefix: '/peers/'
|
||||
}
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
throw new Error('Datastore should be empty')
|
||||
}
|
||||
|
||||
await peerStore.stop()
|
||||
|
||||
expect(spyDirty).to.have.property('callCount', 1)
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
expect(peerStore._dirtyPeers.size).to.equal(0) // Reset
|
||||
|
||||
// Should have one peer record stored in the datastore
|
||||
let count = 0
|
||||
for await (const _ of datastore.query(queryParams)) { // eslint-disable-line
|
||||
count++
|
||||
}
|
||||
expect(count).to.equal(1)
|
||||
expect(peerStore.peers.size).to.equal(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('libp2p.peerStore (Persisted)', () => {
|
||||
describe('disabled by default', () => {
|
||||
let libp2p
|
||||
|
||||
before(async () => {
|
||||
[libp2p] = await peerUtils.createPeer({
|
||||
started: false
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => libp2p.stop())
|
||||
|
||||
it('should not have have persistence capabilities', async () => {
|
||||
await libp2p.start()
|
||||
expect(libp2p.peerStore._dirtyPeers).to.not.exist()
|
||||
expect(libp2p.peerStore.threshold).to.not.exist()
|
||||
})
|
||||
})
|
||||
|
||||
describe('enabled', () => {
|
||||
let libp2p
|
||||
let memoryDatastore
|
||||
|
||||
beforeEach(async () => {
|
||||
memoryDatastore = new MemoryDatastore()
|
||||
;[libp2p] = await peerUtils.createPeer({
|
||||
started: false,
|
||||
config: {
|
||||
datastore: memoryDatastore,
|
||||
peerStore: {
|
||||
persistence: true,
|
||||
threshold: 2 // trigger on second peer changed
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => libp2p.stop())
|
||||
|
||||
it('should start on libp2p start and load content', async () => {
|
||||
const spyPeerStore = sinon.spy(libp2p.peerStore, 'start')
|
||||
const spyDs = sinon.spy(memoryDatastore, 'query')
|
||||
|
||||
await libp2p.start()
|
||||
expect(spyPeerStore).to.have.property('callCount', 1)
|
||||
expect(spyDs).to.have.property('callCount', 1)
|
||||
})
|
||||
|
||||
it('should load content to the peerStore when a new node is started with the same datastore', async () => {
|
||||
const commitSpy = sinon.spy(libp2p.peerStore, '_commitData')
|
||||
const peers = await peerUtils.createPeerId({ number: 3 })
|
||||
const multiaddrs = [
|
||||
new Multiaddr('/ip4/156.10.1.22/tcp/1000'),
|
||||
new Multiaddr('/ip4/156.10.1.23/tcp/1000')
|
||||
]
|
||||
const protocols = ['/ping/1.0.0']
|
||||
|
||||
await libp2p.start()
|
||||
|
||||
// AddressBook
|
||||
libp2p.peerStore.addressBook.set(peers[1], [multiaddrs[0]])
|
||||
libp2p.peerStore.addressBook.set(peers[2], [multiaddrs[1]])
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
// ProtoBook
|
||||
libp2p.peerStore.protoBook.set(peers[1], protocols)
|
||||
libp2p.peerStore.protoBook.set(peers[2], protocols)
|
||||
|
||||
// let batch commit complete
|
||||
await Promise.all(commitSpy.returnValues)
|
||||
|
||||
expect(libp2p.peerStore.peers.size).to.equal(2)
|
||||
|
||||
await libp2p.stop()
|
||||
|
||||
// Use a new node with the previously populated datastore
|
||||
const [newNode] = await peerUtils.createPeer({
|
||||
started: false,
|
||||
config: {
|
||||
datastore: memoryDatastore,
|
||||
peerStore: {
|
||||
persistence: true
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
autoDial: false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
expect(newNode.peerStore.peers.size).to.equal(0)
|
||||
|
||||
const spy = sinon.spy(newNode.peerStore, '_processDatastoreEntry')
|
||||
|
||||
await newNode.start()
|
||||
|
||||
expect(spy).to.have.property('callCount', 4) // 4 datastore entries
|
||||
|
||||
expect(newNode.peerStore.peers.size).to.equal(2)
|
||||
|
||||
// Validate data
|
||||
const peer0 = newNode.peerStore.get(peers[1])
|
||||
expect(peer0.id.toB58String()).to.eql(peers[1].toB58String())
|
||||
expect(peer0.protocols).to.have.members(protocols)
|
||||
expect(peer0.addresses.map((a) => a.multiaddr.toString())).to.have.members([multiaddrs[0].toString()])
|
||||
|
||||
const peer1 = newNode.peerStore.get(peers[2])
|
||||
expect(peer1.id.toB58String()).to.eql(peers[2].toB58String())
|
||||
expect(peer1.protocols).to.have.members(protocols)
|
||||
expect(peer1.addresses.map((a) => a.multiaddr.toString())).to.have.members([multiaddrs[1].toString()])
|
||||
|
||||
await newNode.stop()
|
||||
})
|
||||
})
|
||||
})
|
@ -3,7 +3,7 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const pDefer = require('p-defer')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
|
||||
@ -11,12 +11,19 @@ const PeerStore = require('../../src/peer-store')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('../../src/errors')
|
||||
|
||||
/**
|
||||
* @typedef {import('../../src/peer-store/types').PeerStore} PeerStore
|
||||
* @typedef {import('../../src/peer-store/types').ProtoBook} ProtoBook
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
*/
|
||||
|
||||
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
|
||||
|
||||
describe('protoBook', () => {
|
||||
/** @type {PeerId} */
|
||||
let peerId
|
||||
|
||||
before(async () => {
|
||||
@ -24,10 +31,16 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
describe('protoBook.set', () => {
|
||||
let peerStore, pb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {ProtoBook} */
|
||||
let pb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
pb = peerStore.protoBook
|
||||
})
|
||||
|
||||
@ -35,19 +48,15 @@ describe('protoBook', () => {
|
||||
peerStore.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.set('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
await expect(pb.set('invalid peerId')).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no protocols provided', () => {
|
||||
expect(() => {
|
||||
pb.set(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if no protocols provided', async () => {
|
||||
await expect(pb.set(peerId)).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('replaces the stored content by default and emit change event', () => {
|
||||
it('replaces the stored content by default and emit change event', async () => {
|
||||
const defer = pDefer()
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
@ -57,14 +66,14 @@ describe('protoBook', () => {
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
pb.set(peerId, supportedProtocols)
|
||||
const protocols = pb.get(peerId)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
const protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
|
||||
return defer.promise
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('emits on set if not storing the exact same content', () => {
|
||||
it('emits on set if not storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
@ -79,17 +88,17 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
await pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (same content)
|
||||
pb.set(peerId, supportedProtocolsB)
|
||||
const protocols = pb.get(peerId)
|
||||
await pb.set(peerId, supportedProtocolsB)
|
||||
const protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocolsB)
|
||||
|
||||
return defer.promise
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set if it is storing the exact same content', () => {
|
||||
it('does not emit on set if it is storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
@ -103,10 +112,10 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocols)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
|
||||
// set 2 (same content)
|
||||
pb.set(peerId, supportedProtocols)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
@ -118,10 +127,16 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
describe('protoBook.add', () => {
|
||||
let peerStore, pb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {ProtoBook} */
|
||||
let pb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
pb = peerStore.protoBook
|
||||
})
|
||||
|
||||
@ -129,19 +144,15 @@ describe('protoBook', () => {
|
||||
peerStore.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.add('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
await expect(pb.add('invalid peerId')).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no protocols provided', () => {
|
||||
expect(() => {
|
||||
pb.add(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if no protocols provided', async () => {
|
||||
await expect(pb.add(peerId)).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('adds the new content and emits change event', () => {
|
||||
it('adds the new content and emits change event', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
@ -157,19 +168,19 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
// Replace
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
let protocols = pb.get(peerId)
|
||||
await pb.set(peerId, supportedProtocolsA)
|
||||
let protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocolsA)
|
||||
|
||||
// Add
|
||||
pb.add(peerId, supportedProtocolsB)
|
||||
protocols = pb.get(peerId)
|
||||
await pb.add(peerId, supportedProtocolsB)
|
||||
protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on add if the content to add not exists', () => {
|
||||
it('emits on add if the content to add not exists', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1']
|
||||
@ -185,17 +196,17 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
await pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
pb.add(peerId, supportedProtocolsB)
|
||||
const protocols = pb.get(peerId)
|
||||
await pb.add(peerId, supportedProtocolsB)
|
||||
const protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on add if the content to add already exists', () => {
|
||||
it('does not emit on add if the content to add already exists', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
@ -210,10 +221,10 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
await pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
pb.add(peerId, supportedProtocolsB)
|
||||
await pb.add(peerId, supportedProtocolsB)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
@ -225,10 +236,16 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
describe('protoBook.remove', () => {
|
||||
let peerStore, pb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {ProtoBook} */
|
||||
let pb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
pb = peerStore.protoBook
|
||||
})
|
||||
|
||||
@ -236,16 +253,12 @@ describe('protoBook', () => {
|
||||
peerStore.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.remove('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
await expect(pb.remove('invalid peerId')).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throws invalid parameters error if no protocols provided', () => {
|
||||
expect(() => {
|
||||
pb.remove(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if no protocols provided', async () => {
|
||||
await expect(pb.remove(peerId)).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('removes the given protocol and emits change event', async () => {
|
||||
@ -258,13 +271,13 @@ describe('protoBook', () => {
|
||||
peerStore.on('change:protocols', spy)
|
||||
|
||||
// Replace
|
||||
pb.set(peerId, supportedProtocols)
|
||||
let protocols = pb.get(peerId)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
let protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
|
||||
// Remove
|
||||
pb.remove(peerId, removedProtocols)
|
||||
protocols = pb.get(peerId)
|
||||
await pb.remove(peerId, removedProtocols)
|
||||
protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
await pWaitFor(() => spy.callCount === 2)
|
||||
@ -275,7 +288,7 @@ describe('protoBook', () => {
|
||||
expect(arraysAreEqual(secondCallArgs.protocols, finalProtocols))
|
||||
})
|
||||
|
||||
it('emits on remove if the content changes', () => {
|
||||
it('emits on remove if the content changes', async () => {
|
||||
const spy = sinon.spy()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
@ -285,17 +298,17 @@ describe('protoBook', () => {
|
||||
peerStore.on('change:protocols', spy)
|
||||
|
||||
// set
|
||||
pb.set(peerId, supportedProtocols)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
|
||||
// remove (content already existing)
|
||||
pb.remove(peerId, removedProtocols)
|
||||
const protocols = pb.get(peerId)
|
||||
await pb.remove(peerId, removedProtocols)
|
||||
const protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
return pWaitFor(() => spy.callCount === 2)
|
||||
})
|
||||
|
||||
it('does not emit on remove if the content does not change', () => {
|
||||
it('does not emit on remove if the content does not change', async () => {
|
||||
const spy = sinon.spy()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
@ -304,10 +317,10 @@ describe('protoBook', () => {
|
||||
peerStore.on('change:protocols', spy)
|
||||
|
||||
// set
|
||||
pb.set(peerId, supportedProtocols)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
|
||||
// remove
|
||||
pb.remove(peerId, removedProtocols)
|
||||
await pb.remove(peerId, removedProtocols)
|
||||
|
||||
// Only one event
|
||||
expect(spy.callCount).to.eql(1)
|
||||
@ -315,73 +328,79 @@ describe('protoBook', () => {
|
||||
})
|
||||
|
||||
describe('protoBook.get', () => {
|
||||
let peerStore, pb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {ProtoBook} */
|
||||
let pb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
pb = peerStore.protoBook
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.get('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
await expect(pb.get('invalid peerId')).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns undefined if no protocols are known for the provided peer', () => {
|
||||
const protocols = pb.get(peerId)
|
||||
it('returns empty if no protocols are known for the provided peer', async () => {
|
||||
const protocols = await pb.get(peerId)
|
||||
|
||||
expect(protocols).to.not.exist()
|
||||
expect(protocols).to.be.empty()
|
||||
})
|
||||
|
||||
it('returns the protocols stored', () => {
|
||||
it('returns the protocols stored', async () => {
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
pb.set(peerId, supportedProtocols)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
|
||||
const protocols = pb.get(peerId)
|
||||
const protocols = await pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
})
|
||||
})
|
||||
|
||||
describe('protoBook.delete', () => {
|
||||
let peerStore, pb
|
||||
/** @type {PeerStore} */
|
||||
let peerStore
|
||||
/** @type {ProtoBook} */
|
||||
let pb
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
pb = peerStore.protoBook
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.delete('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
it('throws invalid parameters error if invalid PeerId is provided', async () => {
|
||||
await expect(pb.delete('invalid peerId')).to.eventually.be.rejected().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
it('should not emit event if no records exist for the peer', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
peerStore.on('change:protocols', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = pb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
await pb.delete(peerId)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
it('should emit event if a record exists for the peer', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
pb.set(peerId, supportedProtocols)
|
||||
await pb.set(peerId, supportedProtocols)
|
||||
|
||||
// Listen after set
|
||||
peerStore.on('change:protocols', ({ protocols }) => {
|
||||
@ -389,11 +408,9 @@ describe('protoBook', () => {
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = pb.delete(peerId)
|
||||
await pb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
return defer.promise
|
||||
await defer.promise
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ const { expect } = require('aegir/utils/chai')
|
||||
const pDefer = require('p-defer')
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const Topology = require('libp2p-interfaces/src/topology/multicodec-topology')
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
const Registrar = require('../../src/registrar')
|
||||
@ -27,19 +27,23 @@ describe('registrar', () => {
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore({ peerId })
|
||||
peerStore = new PeerStore({
|
||||
peerId,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
registrar = new Registrar({ peerStore, connectionManager: new EventEmitter() })
|
||||
})
|
||||
|
||||
it('should fail to register a protocol if no multicodec is provided', () => {
|
||||
expect(() => registrar.register()).to.throw()
|
||||
return expect(registrar.register()).to.eventually.be.rejected()
|
||||
})
|
||||
|
||||
it('should fail to register a protocol if an invalid topology is provided', () => {
|
||||
const fakeTopology = {
|
||||
random: 1
|
||||
}
|
||||
expect(() => registrar.register(fakeTopology)).to.throw()
|
||||
|
||||
return expect(registrar.register(fakeTopology)).to.eventually.be.rejected()
|
||||
})
|
||||
})
|
||||
|
||||
@ -57,7 +61,7 @@ describe('registrar', () => {
|
||||
|
||||
afterEach(() => libp2p.stop())
|
||||
|
||||
it('should be able to register a protocol', () => {
|
||||
it('should be able to register a protocol', async () => {
|
||||
const topologyProps = new Topology({
|
||||
multicodecs: multicodec,
|
||||
handlers: {
|
||||
@ -66,12 +70,12 @@ describe('registrar', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const identifier = libp2p.registrar.register(topologyProps)
|
||||
const identifier = await libp2p.registrar.register(topologyProps)
|
||||
|
||||
expect(identifier).to.exist()
|
||||
})
|
||||
|
||||
it('should be able to unregister a protocol', () => {
|
||||
it('should be able to unregister a protocol', async () => {
|
||||
const topologyProps = new Topology({
|
||||
multicodecs: multicodec,
|
||||
handlers: {
|
||||
@ -80,7 +84,7 @@ describe('registrar', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const identifier = libp2p.registrar.register(topologyProps)
|
||||
const identifier = await libp2p.registrar.register(topologyProps)
|
||||
const success = libp2p.registrar.unregister(identifier)
|
||||
|
||||
expect(success).to.eql(true)
|
||||
@ -100,12 +104,6 @@ describe('registrar', () => {
|
||||
const conn = await createMockConnection()
|
||||
const remotePeerId = conn.remotePeer
|
||||
|
||||
// Add connected peer with protocol to peerStore and registrar
|
||||
libp2p.peerStore.protoBook.add(remotePeerId, [multicodec])
|
||||
|
||||
libp2p.connectionManager.onConnect(conn)
|
||||
expect(libp2p.connectionManager.size).to.eql(1)
|
||||
|
||||
const topologyProps = new Topology({
|
||||
multicodecs: multicodec,
|
||||
handlers: {
|
||||
@ -124,12 +122,18 @@ describe('registrar', () => {
|
||||
})
|
||||
|
||||
// Register protocol
|
||||
const identifier = libp2p.registrar.register(topologyProps)
|
||||
const identifier = await libp2p.registrar.register(topologyProps)
|
||||
const topology = libp2p.registrar.topologies.get(identifier)
|
||||
|
||||
// Topology created
|
||||
expect(topology).to.exist()
|
||||
|
||||
// Add connected peer with protocol to peerStore and registrar
|
||||
await libp2p.peerStore.protoBook.add(remotePeerId, [multicodec])
|
||||
|
||||
await libp2p.connectionManager.onConnect(conn)
|
||||
expect(libp2p.connectionManager.size).to.eql(1)
|
||||
|
||||
await conn.close()
|
||||
|
||||
libp2p.connectionManager.onDisconnect(conn)
|
||||
@ -159,7 +163,7 @@ describe('registrar', () => {
|
||||
})
|
||||
|
||||
// Register protocol
|
||||
const identifier = libp2p.registrar.register(topologyProps)
|
||||
const identifier = await libp2p.registrar.register(topologyProps)
|
||||
const topology = libp2p.registrar.topologies.get(identifier)
|
||||
|
||||
// Topology created
|
||||
@ -171,16 +175,16 @@ describe('registrar', () => {
|
||||
const remotePeerId = conn.remotePeer
|
||||
|
||||
// Add connected peer to peerStore and registrar
|
||||
libp2p.peerStore.protoBook.set(remotePeerId, [])
|
||||
libp2p.connectionManager.onConnect(conn)
|
||||
await libp2p.peerStore.protoBook.set(remotePeerId, [])
|
||||
|
||||
// Add protocol to peer and update it
|
||||
libp2p.peerStore.protoBook.add(remotePeerId, [multicodec])
|
||||
await libp2p.peerStore.protoBook.add(remotePeerId, [multicodec])
|
||||
|
||||
await libp2p.connectionManager.onConnect(conn)
|
||||
await onConnectDefer.promise
|
||||
|
||||
// Remove protocol to peer and update it
|
||||
libp2p.peerStore.protoBook.set(remotePeerId, [])
|
||||
await libp2p.peerStore.protoBook.set(remotePeerId, [])
|
||||
|
||||
await onDisconnectDefer.promise
|
||||
})
|
||||
|
@ -82,7 +82,7 @@ describe('auto-relay', () => {
|
||||
const originalMultiaddrsLength = relayLibp2p.multiaddrs.length
|
||||
|
||||
// Discover relay
|
||||
libp2p.peerStore.addressBook.add(relayLibp2p.peerId, relayLibp2p.multiaddrs)
|
||||
await libp2p.peerStore.addressBook.add(relayLibp2p.peerId, relayLibp2p.multiaddrs)
|
||||
await libp2p.dial(relayLibp2p.peerId)
|
||||
|
||||
// Wait for peer added as listen relay
|
||||
@ -94,7 +94,7 @@ describe('auto-relay', () => {
|
||||
expect(libp2p.multiaddrs[originalMultiaddrsLength].getPeerId()).to.eql(relayLibp2p.peerId.toB58String())
|
||||
|
||||
// Peer has relay multicodec
|
||||
const knownProtocols = libp2p.peerStore.protoBook.get(relayLibp2p.peerId)
|
||||
const knownProtocols = await libp2p.peerStore.protoBook.get(relayLibp2p.peerId)
|
||||
expect(knownProtocols).to.include(relayMulticodec)
|
||||
})
|
||||
})
|
||||
@ -165,7 +165,7 @@ describe('auto-relay', () => {
|
||||
sinon.spy(autoRelay1, '_addListenRelay')
|
||||
|
||||
// Discover relay
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
|
||||
const originalMultiaddrs1Length = relayLibp2p1.multiaddrs.length
|
||||
const originalMultiaddrs2Length = relayLibp2p2.multiaddrs.length
|
||||
@ -184,7 +184,7 @@ describe('auto-relay', () => {
|
||||
expect(relayLibp2p1.multiaddrs[originalMultiaddrs1Length].getPeerId()).to.eql(relayLibp2p2.peerId.toB58String())
|
||||
|
||||
// Peer has relay multicodec
|
||||
const knownProtocols = relayLibp2p1.peerStore.protoBook.get(relayLibp2p2.peerId)
|
||||
const knownProtocols = await relayLibp2p1.peerStore.protoBook.get(relayLibp2p2.peerId)
|
||||
expect(knownProtocols).to.include(relayMulticodec)
|
||||
})
|
||||
|
||||
@ -193,7 +193,7 @@ describe('auto-relay', () => {
|
||||
const originalMultiaddrs2Length = relayLibp2p2.multiaddrs.length
|
||||
|
||||
// Discover relay
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
|
||||
await relayLibp2p1.dial(relayLibp2p2.peerId)
|
||||
|
||||
@ -206,7 +206,7 @@ describe('auto-relay', () => {
|
||||
|
||||
// Dial from the other through a relay
|
||||
const relayedMultiaddr2 = new Multiaddr(`${relayLibp2p1.multiaddrs[0]}/p2p/${relayLibp2p1.peerId.toB58String()}/p2p-circuit`)
|
||||
libp2p.peerStore.addressBook.add(relayLibp2p2.peerId, [relayedMultiaddr2])
|
||||
await libp2p.peerStore.addressBook.add(relayLibp2p2.peerId, [relayedMultiaddr2])
|
||||
|
||||
await libp2p.dial(relayLibp2p2.peerId)
|
||||
})
|
||||
@ -220,7 +220,7 @@ describe('auto-relay', () => {
|
||||
sinon.spy(autoRelay1._listenRelays, 'add')
|
||||
|
||||
// Discover one relay and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p2.peerId)
|
||||
|
||||
expect(relayLibp2p1.connectionManager.size).to.eql(1)
|
||||
@ -237,11 +237,11 @@ describe('auto-relay', () => {
|
||||
expect(relayLibp2p1.multiaddrs[originalMultiaddrs1Length].getPeerId()).to.eql(relayLibp2p2.peerId.toB58String())
|
||||
|
||||
// Relay2 has relay multicodec
|
||||
const knownProtocols2 = relayLibp2p1.peerStore.protoBook.get(relayLibp2p2.peerId)
|
||||
const knownProtocols2 = await relayLibp2p1.peerStore.protoBook.get(relayLibp2p2.peerId)
|
||||
expect(knownProtocols2).to.include(relayMulticodec)
|
||||
|
||||
// Discover an extra relay and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p3.peerId)
|
||||
|
||||
// Wait to guarantee the dialed peer is not added as a listen relay
|
||||
@ -253,7 +253,7 @@ describe('auto-relay', () => {
|
||||
expect(relayLibp2p1.connectionManager.size).to.eql(2)
|
||||
|
||||
// Relay2 has relay multicodec
|
||||
const knownProtocols3 = relayLibp2p1.peerStore.protoBook.get(relayLibp2p3.peerId)
|
||||
const knownProtocols3 = await relayLibp2p1.peerStore.protoBook.get(relayLibp2p3.peerId)
|
||||
expect(knownProtocols3).to.include(relayMulticodec)
|
||||
})
|
||||
|
||||
@ -264,7 +264,7 @@ describe('auto-relay', () => {
|
||||
sinon.spy(relayLibp2p1.identifyService, 'pushToPeerStore')
|
||||
|
||||
// Discover one relay and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p2.peerId)
|
||||
|
||||
// Wait for listenning on the relay
|
||||
@ -283,7 +283,7 @@ describe('auto-relay', () => {
|
||||
expect(autoRelay1._listenRelays.size).to.equal(0)
|
||||
|
||||
// Identify push for removing listen relay multiaddr
|
||||
expect(relayLibp2p1.identifyService.pushToPeerStore.callCount).to.equal(2)
|
||||
await pWaitFor(() => relayLibp2p1.identifyService.pushToPeerStore.callCount === 2)
|
||||
})
|
||||
|
||||
it('should try to listen on other connected peers relayed address if one used relay disconnects', async () => {
|
||||
@ -294,11 +294,11 @@ describe('auto-relay', () => {
|
||||
sinon.spy(relayLibp2p1.transportManager, 'listen')
|
||||
|
||||
// Discover one relay and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p2.peerId)
|
||||
|
||||
// Discover an extra relay and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p3.peerId)
|
||||
|
||||
// Wait for both peer to be attempted to added as listen relay
|
||||
@ -337,11 +337,11 @@ describe('auto-relay', () => {
|
||||
sinon.spy(relayLibp2p1.transportManager, 'listen')
|
||||
|
||||
// Discover one relay and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p2.peerId)
|
||||
|
||||
// Discover an extra relay and connect to gather its Hop support
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p3.peerId)
|
||||
|
||||
// Wait for both peer to be attempted to added as listen relay
|
||||
@ -382,11 +382,11 @@ describe('auto-relay', () => {
|
||||
sinon.spy(relayLibp2p1.transportManager, 'listen')
|
||||
|
||||
// Discover one relay and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, relayLibp2p2.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p2.peerId)
|
||||
|
||||
// Discover an extra relay and connect to gather its Hop support
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p3.peerId)
|
||||
|
||||
// Wait for both peer to be attempted to added as listen relay
|
||||
@ -479,7 +479,7 @@ describe('auto-relay', () => {
|
||||
sinon.spy(autoRelay2, '_addListenRelay')
|
||||
|
||||
// Relay 1 discovers Relay 3 and connect
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p1.dial(relayLibp2p3.peerId)
|
||||
|
||||
// Wait for peer added as listen relay
|
||||
@ -487,7 +487,7 @@ describe('auto-relay', () => {
|
||||
expect(autoRelay1._listenRelays.size).to.equal(1)
|
||||
|
||||
// Relay 2 discovers Relay 3 and connect
|
||||
relayLibp2p2.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p2.peerStore.addressBook.add(relayLibp2p3.peerId, relayLibp2p3.multiaddrs)
|
||||
await relayLibp2p2.dial(relayLibp2p3.peerId)
|
||||
|
||||
// Wait for peer added as listen relay
|
||||
@ -496,7 +496,7 @@ describe('auto-relay', () => {
|
||||
|
||||
// Relay 1 discovers Relay 2 relayed multiaddr via Relay 3
|
||||
const ma2RelayedBy3 = relayLibp2p2.multiaddrs[relayLibp2p2.multiaddrs.length - 1]
|
||||
relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, [ma2RelayedBy3])
|
||||
await relayLibp2p1.peerStore.addressBook.add(relayLibp2p2.peerId, [ma2RelayedBy3])
|
||||
await relayLibp2p1.dial(relayLibp2p2.peerId)
|
||||
|
||||
// Peer not added as listen relay
|
||||
|
@ -8,7 +8,6 @@ const { Multiaddr } = require('multiaddr')
|
||||
const { collect } = require('streaming-iterables')
|
||||
const pipe = require('it-pipe')
|
||||
const AggregateError = require('aggregate-error')
|
||||
const PeerId = require('peer-id')
|
||||
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
||||
|
||||
const { createPeerId } = require('../utils/creators/peer')
|
||||
@ -46,14 +45,13 @@ describe('Dialing (via relay, TCP)', () => {
|
||||
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(libp2p => libp2p.start()))
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
afterEach(async () => {
|
||||
// Stop each node
|
||||
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(async libp2p => {
|
||||
await libp2p.stop()
|
||||
// Clear the peer stores
|
||||
for (const peerIdStr of libp2p.peerStore.peers.keys()) {
|
||||
const peerId = PeerId.createFromB58String(peerIdStr)
|
||||
libp2p.peerStore.delete(peerId)
|
||||
for await (const peer of libp2p.peerStore.getPeers()) {
|
||||
libp2p.peerStore.delete(peer.id)
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
@ -2,7 +2,7 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
|
||||
const { MemoryDatastore } = require('datastore-core/memory')
|
||||
const AddressManager = require('../../src/address-manager')
|
||||
const TransportManager = require('../../src/transport-manager')
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
@ -33,7 +33,10 @@ describe('Transport Manager (TCP)', () => {
|
||||
peerId: localPeer,
|
||||
multiaddrs: addrs,
|
||||
addressManager: new AddressManager({ listen: addrs }),
|
||||
peerStore: new PeerStore({ peerId: localPeer })
|
||||
peerStore: new PeerStore({
|
||||
peerId: localPeer,
|
||||
datastore: new MemoryDatastore()
|
||||
})
|
||||
},
|
||||
upgrader: mockUpgrader,
|
||||
onConnection: () => {}
|
||||
@ -67,7 +70,7 @@ describe('Transport Manager (TCP)', () => {
|
||||
})
|
||||
|
||||
it('should create self signed peer record on listen', async () => {
|
||||
let signedPeerRecord = await tm.libp2p.peerStore.addressBook.getPeerRecord(localPeer)
|
||||
let signedPeerRecord = await tm.libp2p.peerStore.addressBook.getRawEnvelope(localPeer)
|
||||
expect(signedPeerRecord).to.not.exist()
|
||||
|
||||
tm.add(Transport.prototype[Symbol.toStringTag], Transport)
|
||||
|
@ -2,17 +2,17 @@
|
||||
"name": "ts-use",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"datastore-level": "^6.0.0",
|
||||
"ipfs-http-client": "^50.1.2",
|
||||
"@achingbrain/libp2p-gossipsub": "^0.12.2",
|
||||
"@chainsafe/libp2p-noise": "^5.0.0",
|
||||
"datastore-level": "^7.0.1",
|
||||
"ipfs-http-client": "^55.0.0",
|
||||
"libp2p": "file:../..",
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-bootstrap": "^0.14.0",
|
||||
"libp2p-delegated-content-routing": "^0.11.0",
|
||||
"libp2p-delegated-peer-routing": "^0.11.1",
|
||||
"libp2p-gossipsub": "^0.9.0",
|
||||
"libp2p-interfaces": "^1.0.1",
|
||||
"libp2p-kad-dht": "^0.26.5",
|
||||
"libp2p-interfaces": "^4.0.0",
|
||||
"libp2p-kad-dht": "^0.28.6",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"@chainsafe/libp2p-noise": "^4.1.0",
|
||||
"libp2p-record": "^0.10.4",
|
||||
"libp2p-tcp": "^0.17.1",
|
||||
"libp2p-websockets": "^0.16.1",
|
||||
|
@ -105,8 +105,7 @@ async function main() {
|
||||
},
|
||||
datastore: new LevelStore('path/to/store'),
|
||||
peerStore: {
|
||||
persistence: false,
|
||||
threshold: 5
|
||||
persistence: false
|
||||
},
|
||||
keychain: {
|
||||
pass: 'notsafepassword123456789',
|
||||
|
@ -58,12 +58,13 @@ function _populateAddressBooks (peers) {
|
||||
* @param {Object} [properties]
|
||||
* @param {number} [properties.number] - number of peers (default: 1).
|
||||
* @param {boolean} [properties.fixture] - use fixture for peer-id generation (default: true)
|
||||
* @param {PeerId.CreateOptions} [properties.opts]
|
||||
* @returns {Promise<Array<PeerId>>}
|
||||
*/
|
||||
function createPeerId ({ number = 1, fixture = true } = {}) {
|
||||
function createPeerId ({ number = 1, fixture = true, opts = {} } = {}) {
|
||||
return pTimes(number, (i) => fixture
|
||||
? PeerId.createFromJSON(Peers[i])
|
||||
: PeerId.create()
|
||||
: PeerId.create(opts)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ module.exports = async (properties = {}) => {
|
||||
protocol: protocols[0]
|
||||
}
|
||||
},
|
||||
close: () => { },
|
||||
close: async () => { },
|
||||
getStreams: () => openStreams,
|
||||
...properties
|
||||
})
|
||||
|
Reference in New Issue
Block a user