Compare commits

..

1 Commits

10 changed files with 18 additions and 303 deletions

View File

@ -1,23 +1,3 @@
<a name="0.28.9"></a>
## [0.28.9](https://github.com/libp2p/js-libp2p/compare/v0.28.8...v0.28.9) (2020-07-27)
### Bug Fixes
* ping multiaddr from peer not previously stored in peerstore ([#719](https://github.com/libp2p/js-libp2p/issues/719)) ([2440c87](https://github.com/libp2p/js-libp2p/commit/2440c87))
<a name="0.28.8"></a>
## [0.28.8](https://github.com/libp2p/js-libp2p/compare/v0.28.7...v0.28.8) (2020-07-20)
### Bug Fixes
* create dial target for peer with no known addrs ([#715](https://github.com/libp2p/js-libp2p/issues/715)) ([7da9ad4](https://github.com/libp2p/js-libp2p/commit/7da9ad4))
<a name="0.28.7"></a>
## [0.28.7](https://github.com/libp2p/js-libp2p/compare/v0.28.6...v0.28.7) (2020-07-14)

View File

@ -418,7 +418,7 @@ const latency = await libp2p.ping(otherPeerId)
## multiaddrs
Gets the multiaddrs the libp2p node announces to the network. This computes the advertising multiaddrs
Gets the multiaddrs the libp2p node announces to the network. This computes the advertising multiaddrs
of the peer by joining the multiaddrs that libp2p transports are listening on with the announce multiaddrs
provided in the libp2p config. Configured no announce multiaddrs will be filtered out of the advertised addresses.
@ -1454,7 +1454,7 @@ Create a key in the keychain.
|------|------|-------------|
| name | `string` | The local key name. It cannot already exist. |
| type | `string` | One of the key types; 'rsa' |
| [size] | `number` | The key size in bits. Must be provided for rsa keys. |
| size | `number` | The key size in bits. |
#### Returns
@ -1801,7 +1801,7 @@ console.log(peerStats.toJSON())
## Events
Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events.
Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events.
### libp2p

View File

@ -1,82 +0,0 @@
/* eslint-disable no-console */
'use strict'
const { Buffer } = require('buffer')
const Libp2p = require('../../../')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise')
const SECIO = require('libp2p-secio')
const Gossipsub = require('libp2p-gossipsub')
const createNode = async () => {
const node = await Libp2p.create({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
modules: {
transport: [TCP],
streamMuxer: [Mplex],
connEncryption: [NOISE, SECIO],
pubsub: Gossipsub
}
})
await node.start()
return node
}
(async () => {
const topic = 'fruit'
const [node1, node2, node3] = await Promise.all([
createNode(),
createNode(),
createNode(),
])
// node1 conect to node2 and node2 conect to node3
node1.peerStore.addressBook.set(node2.peerId, node2.multiaddrs)
await node1.dial(node2.peerId)
node2.peerStore.addressBook.set(node3.peerId, node3.multiaddrs)
await node2.dial(node3.peerId)
//subscribe
await node1.pubsub.subscribe(topic, (msg) => {
console.log(`node1 received: ${msg.data.toString()}`)
})
await node2.pubsub.subscribe(topic, (msg) => {
console.log(`node2 received: ${msg.data.toString()}`)
})
await node3.pubsub.subscribe(topic, (msg) => {
console.log(`node3 received: ${msg.data.toString()}`)
})
const validateFruit = (msgTopic, peer, msg) => {
const fruit = msg.data.toString();
const validFruit = ['banana', 'apple', 'orange']
const valid = validFruit.includes(fruit);
return valid;
}
//validate fruit
node1.pubsub._pubsub.topicValidators.set(topic, validateFruit);
node2.pubsub._pubsub.topicValidators.set(topic, validateFruit);
node3.pubsub._pubsub.topicValidators.set(topic, validateFruit);
// node1 publishes "fruits" every five seconds
var count = 0;
const myFruits = ['banana', 'apple', 'car', 'orange'];
// car is not a fruit !
setInterval(() => {
console.log('############## fruit ' + myFruits[count] + ' ##############')
node1.pubsub.publish(topic, Buffer.from(myFruits[count]))
count++
if (count == myFruits.length) {
count = 0
}
}, 5000)
})()

View File

@ -1,108 +0,0 @@
# Filter Messages
To prevent undesired data from being propagated on the network, we can apply a filter to Gossipsub. Messages that fail validation in the filter will not be re-shared.
## 1. Setting up a PubSub network with three nodes
First, let's update our libp2p configuration with a pubsub implementation.
```JavaScript
const Libp2p = require('libp2p')
const Gossipsub = require('libp2p-gossipsub')
const node = await Libp2p.create({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
modules: {
transport: [ TCP ],
streamMuxer: [ Mplex ],
connEncryption: [ NOISE, SECIO ],
pubsub: Gossipsub
}
})
```
Then, create three nodes and connect them together. In this example, we will connect the nodes in series. Node 1 connected with node 2 and node 2 connected with node 3.
```JavaScript
const [node1, node2, node3] = await Promise.all([
createNode(),
createNode(),
createNode(),
])
node1.peerStore.addressBook.set(node2.peerId, node2.multiaddrs)
await node1.dial(node2.peerId)
node2.peerStore.addressBook.set(node3.peerId, node3.multiaddrs)
await node2.dial(node3.peerId)
```
Now we' can subscribe to the fruit topic and log incoming messages.
```JavaScript
const topic = 'fruit'
await node1.pubsub.subscribe(topic, (msg) => {
console.log(`node1 received: ${msg.data.toString()}`)
})
await node2.pubsub.subscribe(topic, (msg) => {
console.log(`node2 received: ${msg.data.toString()}`)
})
await node3.pubsub.subscribe(topic, (msg) => {
console.log(`node3 received: ${msg.data.toString()}`)
})
```
Finally, let's define the additional filter in the fruit topic.
```JavaScript
const validateFruit = (msgTopic, peer, msg) => {
const fruit = msg.data.toString();
const validFruit = ['banana', 'apple', 'orange']
const valid = validFruit.includes(fruit);
return valid;
}
node1.pubsub._pubsub.topicValidators.set(topic, validateFruit);
node2.pubsub._pubsub.topicValidators.set(topic, validateFruit);
node3.pubsub._pubsub.topicValidators.set(topic, validateFruit);
```
In this example, node one has an outdated version of the system, or is a malicious node. When it tries to publish fruit, the messages are re-shared and all the nodes share the message. However, when it tries to publish a vehicle the message is not re-shared.
```JavaScript
var count = 0;
const myFruits = ['banana', 'apple', 'car', 'orange'];
setInterval(() => {
console.log('############## fruit ' + myFruits[count] + ' ##############')
node1.pubsub.publish(topic, Buffer.from(myFruits[count]))
count++
if (count == myFruits.length) {
count = 0
}
}, 5000)
```
Result
```
> node 1.js
############## fruit banana ##############
node1 received: banana
node2 received: banana
node3 received: banana
############## fruit apple ##############
node1 received: apple
node2 received: apple
node3 received: apple
############## fruit car ##############
node1 received: car
############## fruit orange ##############
node1 received: orange
node2 received: orange
node3 received: orange
```

View File

@ -1,6 +1,6 @@
{
"name": "libp2p",
"version": "0.28.9",
"version": "0.28.7",
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js",
@ -58,7 +58,7 @@
"it-length-prefixed": "^3.0.1",
"it-pipe": "^1.1.0",
"it-protocol-buffers": "^0.2.0",
"libp2p-crypto": "^0.17.9",
"libp2p-crypto": "^0.17.6",
"libp2p-interfaces": "^0.3.1",
"libp2p-utils": "^0.1.2",
"mafmt": "^7.0.0",

View File

@ -324,7 +324,7 @@ class Libp2p extends EventEmitter {
* @returns {Promise<Connection|*>}
*/
async dialProtocol (peer, protocols, options) {
const { id, multiaddrs } = getPeer(peer)
const { id, multiaddrs } = getPeer(peer, this.peerStore)
let connection = this.connectionManager.get(id)
if (!connection) {
@ -396,12 +396,7 @@ class Libp2p extends EventEmitter {
* @returns {Promise<number>}
*/
ping (peer) {
const { id, multiaddrs } = getPeer(peer)
// If received multiaddr, ping it
if (multiaddrs) {
return ping(this, multiaddrs[0])
}
const { id } = getPeer(peer)
return ping(this, id)
}

View File

@ -7,9 +7,6 @@ const crypto = require('libp2p-crypto')
const DS = require('interface-datastore')
const CMS = require('./cms')
const errcode = require('err-code')
const { Number } = require('ipfs-utils/src/globalthis')
require('node-forge/lib/sha512')
const keyPrefix = '/pkcs8/'
const infoPrefix = '/info/'
@ -174,8 +171,8 @@ class Keychain {
*
* @param {string} name - The local key name; cannot already exist.
* @param {string} type - One of the key types; 'rsa'.
* @param {int} [size] - The key size in bits. Used for rsa keys only.
* @returns {KeyInfo}
* @param {int} size - The key size in bits.
* @returns {KeyInfo}
*/
async createKey (name, type, size) {
const self = this
@ -188,13 +185,17 @@ class Keychain {
return throwDelayed(errcode(new Error(`Invalid key type '${type}'`), 'ERR_INVALID_KEY_TYPE'))
}
if (!Number.isSafeInteger(size)) {
return throwDelayed(errcode(new Error(`Invalid key size '${size}'`), 'ERR_INVALID_KEY_SIZE'))
}
const dsname = DsName(name)
const exists = await self.store.has(dsname)
if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`), 'ERR_KEY_ALREADY_EXISTS'))
switch (type.toLowerCase()) {
case 'rsa':
if (!Number.isSafeInteger(size) || size < 2048) {
if (size < 2048) {
return throwDelayed(errcode(new Error(`Invalid RSA key size ${size}`), 'ERR_INVALID_KEY_SIZE'))
}
break

View File

@ -15,11 +15,11 @@ const { PROTOCOL, PING_LENGTH } = require('./constants')
/**
* Ping a given peer and wait for its response, getting the operation latency.
* @param {Libp2p} node
* @param {PeerId|multiaddr} peer
* @param {PeerId} peer
* @returns {Promise<Number>}
*/
async function ping (node, peer) {
log('dialing %s to %s', PROTOCOL, peer.toB58String ? peer.toB58String() : peer)
log('dialing %s to %s', PROTOCOL, peer.toB58String())
const { stream } = await node.dialProtocol(peer, PROTOCOL)

View File

@ -17,7 +17,7 @@ describe('ping', () => {
beforeEach(async () => {
nodes = await peerUtils.createPeer({
number: 3,
number: 2,
config: baseOptions
})
@ -25,14 +25,7 @@ describe('ping', () => {
nodes[1].peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs)
})
it('ping once from peer0 to peer1 using a multiaddr', async () => {
const ma = `${nodes[2].multiaddrs[0]}/p2p/${nodes[2].peerId.toB58String()}`
const latency = await nodes[0].ping(ma)
expect(latency).to.be.a('Number')
})
it('ping once from peer0 to peer1 using a peerId', async () => {
it('ping once from peer0 to peer1', async () => {
const latency = await nodes[0].ping(nodes[1].peerId)
expect(latency).to.be.a('Number')

View File

@ -149,70 +149,6 @@ describe('keychain', () => {
})
})
describe('ed25519 keys', () => {
const keyName = 'my custom key'
it('can be an ed25519 key', async () => {
const keyInfo = await ks.createKey(keyName, 'ed25519')
expect(keyInfo).to.exist()
expect(keyInfo).to.have.property('name', keyName)
expect(keyInfo).to.have.property('id')
})
it('does not overwrite existing key', async () => {
const err = await ks.createKey(keyName, 'ed25519').then(fail, err => err)
expect(err).to.have.property('code', 'ERR_KEY_ALREADY_EXISTS')
})
it('can export/import a key', async () => {
const keyName = 'a new key'
const password = 'my sneaky password'
const keyInfo = await ks.createKey(keyName, 'ed25519')
const exportedKey = await ks.exportKey(keyName, password)
// remove it so we can import it
await ks.removeKey(keyName)
const importedKey = await ks.importKey(keyName, exportedKey, password)
expect(importedKey.id).to.eql(keyInfo.id)
})
it('cannot create the "self" key', async () => {
const err = await ks.createKey('self', 'ed25519').then(fail, err => err)
expect(err).to.exist()
expect(err).to.have.property('code', 'ERR_INVALID_KEY_NAME')
})
})
describe('secp256k1 keys', () => {
const keyName = 'my secp256k1 key'
it('can be an secp256k1 key', async () => {
const keyInfo = await ks.createKey(keyName, 'secp256k1')
expect(keyInfo).to.exist()
expect(keyInfo).to.have.property('name', keyName)
expect(keyInfo).to.have.property('id')
})
it('does not overwrite existing key', async () => {
const err = await ks.createKey(keyName, 'secp256k1').then(fail, err => err)
expect(err).to.have.property('code', 'ERR_KEY_ALREADY_EXISTS')
})
it('can export/import a key', async () => {
const keyName = 'a new secp256k1 key'
const password = 'my sneaky password'
const keyInfo = await ks.createKey(keyName, 'secp256k1')
const exportedKey = await ks.exportKey(keyName, password)
// remove it so we can import it
await ks.removeKey(keyName)
const importedKey = await ks.importKey(keyName, exportedKey, password)
expect(importedKey.id).to.eql(keyInfo.id)
})
it('cannot create the "self" key', async () => {
const err = await ks.createKey('self', 'secp256k1').then(fail, err => err)
expect(err).to.exist()
expect(err).to.have.property('code', 'ERR_INVALID_KEY_NAME')
})
})
describe('query', () => {
it('finds all existing keys', async () => {
const keys = await ks.listKeys()