mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-22 12:01:57 +00:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d6bb967243 | ||
|
d48005b8b7 | ||
|
67b97e32da | ||
|
664ba2d1e7 | ||
|
608564b033 | ||
|
af723b355e | ||
|
13cf476148 | ||
|
39b03586e8 | ||
|
f7183e8afd | ||
|
b9988adce9 | ||
|
b291bc06ec | ||
|
755eb909f2 | ||
|
afe0f854e8 | ||
|
50f7f32e53 | ||
|
052aad4e06 | ||
|
2c4b567b00 | ||
|
2a6a635f13 | ||
|
cd152f122f | ||
|
2959794796 | ||
|
2068c845cb | ||
|
d8ba284883 | ||
|
869d35d852 | ||
|
d6540bf01d | ||
|
478963ad2d | ||
|
d22ad83890 | ||
|
538f296b0a | ||
|
7bac2045cc | ||
|
818d2b2a98 |
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -12,6 +12,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
- run: npm install
|
||||
- run: npx aegir lint
|
||||
- uses: gozala/typescript-error-reporter-action@v1.0.8
|
||||
@@ -27,7 +31,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||
node: [14]
|
||||
node: [14, 16]
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
53
CHANGELOG.md
53
CHANGELOG.md
@@ -1,3 +1,56 @@
|
||||
# [0.32.0](https://github.com/libp2p/js-libp2p/compare/v0.32.0-rc.0...v0.32.0) (2021-07-15)
|
||||
|
||||
|
||||
|
||||
# [0.32.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.31.7...v0.32.0-rc.0) (2021-07-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not allow dial to large number of multiaddrs ([#954](https://github.com/libp2p/js-libp2p/issues/954)) ([af723b3](https://github.com/libp2p/js-libp2p/commit/af723b355e1ddf4aecf439f81c3aa67613d45fa4))
|
||||
|
||||
|
||||
### chore
|
||||
|
||||
* update to new multiformats ([#948](https://github.com/libp2p/js-libp2p/issues/948)) ([13cf476](https://github.com/libp2p/js-libp2p/commit/13cf4761489d59b22924bb8ec2ec6dbe207b280c))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* uses the CID class from the new multiformats module
|
||||
|
||||
Co-authored-by: Vasco Santos <vasco.santos@moxy.studio>
|
||||
|
||||
|
||||
|
||||
## [0.31.7](https://github.com/libp2p/js-libp2p/compare/v0.31.6...v0.31.7) (2021-06-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* chat example with new multiaddr ([#946](https://github.com/libp2p/js-libp2p/issues/946)) ([d8ba284](https://github.com/libp2p/js-libp2p/commit/d8ba2848833d9fb8a963d1b7c8d27062c6f829da))
|
||||
* dialer leaking resources after stopping ([#947](https://github.com/libp2p/js-libp2p/issues/947)) ([b291bc0](https://github.com/libp2p/js-libp2p/commit/b291bc06ec13feeb6e010730edfad754a3b2dc1b))
|
||||
|
||||
|
||||
|
||||
## [0.31.6](https://github.com/libp2p/js-libp2p/compare/v0.31.5...v0.31.6) (2021-05-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* keychain rotate passphrase ([#944](https://github.com/libp2p/js-libp2p/issues/944)) ([478963a](https://github.com/libp2p/js-libp2p/commit/478963ad2d195444494c0acc54cb3847a29e117c))
|
||||
|
||||
|
||||
|
||||
## [0.31.5](https://github.com/libp2p/js-libp2p/compare/v0.31.4...v0.31.5) (2021-05-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* store remote agent and protocol version during identify ([#943](https://github.com/libp2p/js-libp2p/issues/943)) ([818d2b2](https://github.com/libp2p/js-libp2p/commit/818d2b2a98736f4242694479089396f6070cdad5))
|
||||
|
||||
|
||||
|
||||
## [0.31.4](https://github.com/libp2p/js-libp2p/compare/v0.31.3...v0.31.4) (2021-05-12)
|
||||
|
||||
|
||||
|
@@ -282,7 +282,7 @@ const node = await Libp2p.create({
|
||||
interval: 1000,
|
||||
enabled: true
|
||||
},
|
||||
[Bootstrap.tag:] {
|
||||
[Bootstrap.tag]: {
|
||||
list: [ // A list of bootstrap peers to connect to starting up the node
|
||||
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
|
||||
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
||||
@@ -373,7 +373,7 @@ const node = await Libp2p.create({
|
||||
config: {
|
||||
dht: { // The DHT options (and defaults) can be found in its documentation
|
||||
kBucketSize: 20,
|
||||
enabled: true,
|
||||
enabled: true, // This flag is required for DHT to run (disabled by default)
|
||||
randomWalk: {
|
||||
enabled: true, // Allows to disable discovery (enabled by default)
|
||||
interval: 300e3,
|
||||
@@ -399,13 +399,13 @@ const PeerId = require('peer-id')
|
||||
// create a peerId
|
||||
const peerId = await PeerId.create()
|
||||
|
||||
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({
|
||||
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient.create({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
}))
|
||||
|
||||
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({
|
||||
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
@@ -525,6 +525,7 @@ Dialing in libp2p can be configured to limit the rate of dialing, and how long d
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| maxParallelDials | `number` | How many multiaddrs we can dial in parallel. |
|
||||
| maxAddrsToDial | `number` | How many multiaddrs is the dial allowed to dial for a single peer. |
|
||||
| maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. |
|
||||
| dialTimeout | `number` | Second dial timeout per peer in ms. |
|
||||
| resolvers | `object` | Dial [Resolvers](https://github.com/multiformats/js-multiaddr/blob/master/src/resolvers/index.js) for resolving multiaddrs |
|
||||
@@ -549,6 +550,7 @@ const node = await Libp2p.create({
|
||||
},
|
||||
dialer: {
|
||||
maxParallelDials: 100,
|
||||
maxAddrsToDial: 25,
|
||||
maxDialsPerPeer: 4,
|
||||
dialTimeout: 30e3,
|
||||
resolvers: {
|
||||
|
36
doc/migrations/v0.31-v0.32.md
Normal file
36
doc/migrations/v0.31-v0.32.md
Normal file
@@ -0,0 +1,36 @@
|
||||
<!--Specify versions for migration below-->
|
||||
# Migrating to libp2p@32
|
||||
|
||||
A migration guide for refactoring your application code from libp2p v0.31.x to v0.32.0.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Module Updates](#module-updates)
|
||||
|
||||
## Module Updates
|
||||
|
||||
With this release you should update the following libp2p modules if you are relying on them:
|
||||
|
||||
<!--Specify module versions in JSON for migration below.
|
||||
It's recommended to check package.json changes for this:
|
||||
`git diff <release> <prev> -- package.json`
|
||||
-->
|
||||
|
||||
```json
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-crypto": "^0.19.4",
|
||||
"libp2p-interfaces": "^1.0.0",
|
||||
"libp2p-delegated-content-routing": "^0.11.0",
|
||||
"libp2p-delegated-peer-routing": "^0.10.0",
|
||||
"libp2p-floodsub": "^0.27.0",
|
||||
"libp2p-gossipsub": "^0.11.0",
|
||||
"libp2p-kad-dht": "^0.23.0",
|
||||
"libp2p-mdns": "^0.17.0",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
"libp2p-tcp": "^0.17.0",
|
||||
"libp2p-webrtc-direct": "^0.7.0",
|
||||
"libp2p-webrtc-star": "^0.23.0",
|
||||
"libp2p-websockets": "^0.16.0"
|
||||
```
|
||||
|
||||
One of the main changes in this new release is the update to `multiaddr@10.0.0`. This should also be updated in upstream projects to avoid several multiaddr versions in the bundle and to avoid potential problems when libp2p interacts with provided outdated multiaddr instances.
|
@@ -2,11 +2,11 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const createLibp2p = require('./libp2p')
|
||||
const { stdinToStream, streamToConsole } = require('./stream')
|
||||
|
||||
async function run() {
|
||||
async function run () {
|
||||
const [idDialer, idListener] = await Promise.all([
|
||||
PeerId.createFromJSON(require('./peer-id-dialer')),
|
||||
PeerId.createFromJSON(require('./peer-id-listener'))
|
||||
@@ -30,7 +30,7 @@ async function run() {
|
||||
})
|
||||
|
||||
// Dial to the remote peer (the "listener")
|
||||
const listenerMa = multiaddr(`/ip4/127.0.0.1/tcp/10333/p2p/${idListener.toB58String()}`)
|
||||
const listenerMa = new Multiaddr(`/ip4/127.0.0.1/tcp/10333/p2p/${idListener.toB58String()}`)
|
||||
const { stream } = await nodeDialer.dialProtocol(listenerMa, '/chat/1.0.0')
|
||||
|
||||
console.log('Dialer dialed to listener on protocol: /chat/1.0.0')
|
||||
|
@@ -5,7 +5,7 @@ const PeerId = require('peer-id')
|
||||
const createLibp2p = require('./libp2p.js')
|
||||
const { stdinToStream, streamToConsole } = require('./stream')
|
||||
|
||||
async function run() {
|
||||
async function run () {
|
||||
// Create a new libp2p node with the given multi-address
|
||||
const idListener = await PeerId.createFromJSON(require('./peer-id-listener'))
|
||||
const nodeListener = await createLibp2p({
|
||||
|
@@ -17,11 +17,11 @@
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.13.0",
|
||||
"libp2p": "../../",
|
||||
"libp2p-bootstrap": "^0.12.1",
|
||||
"libp2p-mplex": "^0.10.0",
|
||||
"libp2p-noise": "^2.0.0",
|
||||
"libp2p-webrtc-star": "^0.22.0",
|
||||
"libp2p-websockets": "^0.15.0"
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
"libp2p-webrtc-star": "^0.23.0",
|
||||
"libp2p-websockets": "^0.16.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.13.10",
|
||||
|
@@ -10,12 +10,14 @@
|
||||
"dependencies": {
|
||||
"execa": "^2.1.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"libp2p-pubsub-peer-discovery": "^3.0.0",
|
||||
"libp2p-relay-server": "^0.1.2",
|
||||
"libp2p-pubsub-peer-discovery": "^4.0.0",
|
||||
"libp2p-relay-server": "^0.2.0",
|
||||
"libp2p-gossipsub": "^0.9.1",
|
||||
"p-defer": "^3.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"https": "^1.0.0",
|
||||
"playwright": "^1.7.1"
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ const Libp2p = require('../../')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const CID = require('cids')
|
||||
const { CID } = require('multiformats/cid')
|
||||
const KadDHT = require('libp2p-kad-dht')
|
||||
|
||||
const all = require('it-all')
|
||||
@@ -51,10 +51,10 @@ const createNode = async () => {
|
||||
// Wait for onConnect handlers in the DHT
|
||||
await delay(100)
|
||||
|
||||
const cid = new CID('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
|
||||
const cid = CID.parse('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
|
||||
await node1.contentRouting.provide(cid)
|
||||
|
||||
console.log('Node %s is providing %s', node1.peerId.toB58String(), cid.toBaseEncodedString())
|
||||
console.log('Node %s is providing %s', node1.peerId.toB58String(), cid.toString())
|
||||
|
||||
// wait for propagation
|
||||
await delay(300)
|
||||
|
@@ -81,7 +81,7 @@ Instead of calling `peerRouting.findPeer`, we will use `contentRouting.provide`
|
||||
|
||||
```JavaScript
|
||||
await node1.contentRouting.provide(cid)
|
||||
console.log('Node %s is providing %s', node1.peerId.toB58String(), cid.toBaseEncodedString())
|
||||
console.log('Node %s is providing %s', node1.peerId.toB58String(), cid.toString())
|
||||
|
||||
const provs = await all(node3.contentRouting.findProviders(cid, { timeout: 5000 }))
|
||||
|
||||
|
@@ -8,6 +8,10 @@ We've seen many interesting use cases appear with this, here are some highlights
|
||||
- [IPFS PubSub (using libp2p-floodsub) for IoT](https://www.youtube.com/watch?v=qLpM5pBDGiE).
|
||||
- [Real Time distributed Applications](https://www.youtube.com/watch?v=vQrbxyDPSXg)
|
||||
|
||||
## 0. Set up the example
|
||||
|
||||
Before moving into the examples, you should run `npm install` on the top level `js-libp2p` folder, in order to install all the dependencies needed for this example. In addition, you will need to install the example related dependencies by doing `cd examples && npm install`. Once the install finishes, you should move into the example folder with `cd pubsub`.
|
||||
|
||||
## 1. Setting up a simple PubSub network on top of libp2p
|
||||
|
||||
For this example, we will use MulticastDNS for automatic Peer Discovery. This example is based the previous examples found in [Discovery Mechanisms](../discovery-mechanisms). You can find the complete version at [1.js](./1.js).
|
||||
|
89
examples/transports/4.js
Normal file
89
examples/transports/4.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const Libp2p = require('../..')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const WebSockets = require('libp2p-websockets')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const pipe = require('it-pipe')
|
||||
|
||||
const transportKey = WebSockets.prototype[Symbol.toStringTag];
|
||||
|
||||
const httpServer = https.createServer({
|
||||
cert: fs.readFileSync('./test_certs/cert.pem'),
|
||||
key: fs.readFileSync('./test_certs/key.pem'),
|
||||
});
|
||||
|
||||
const createNode = async (addresses = []) => {
|
||||
if (!Array.isArray(addresses)) {
|
||||
addresses = [addresses]
|
||||
}
|
||||
|
||||
const node = await Libp2p.create({
|
||||
addresses: {
|
||||
listen: addresses
|
||||
},
|
||||
modules: {
|
||||
transport: [WebSockets],
|
||||
connEncryption: [NOISE],
|
||||
streamMuxer: [MPLEX]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
// Disable autoDial as it would fail because we are using a self-signed cert.
|
||||
// `dialProtocol` does not fail because we pass `rejectUnauthorized: false`.
|
||||
autoDial: false
|
||||
},
|
||||
transport: {
|
||||
[transportKey]: {
|
||||
listenerOptions: { server: httpServer },
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
await node.start()
|
||||
return node
|
||||
}
|
||||
|
||||
function printAddrs(node, number) {
|
||||
console.log('node %s is listening on:', number)
|
||||
node.multiaddrs.forEach((ma) => console.log(`${ma.toString()}/p2p/${node.peerId.toB58String()}`))
|
||||
}
|
||||
|
||||
function print ({ stream }) {
|
||||
pipe(
|
||||
stream,
|
||||
async function (source) {
|
||||
for await (const msg of source) {
|
||||
console.log(msg.toString())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
const [node1, node2] = await Promise.all([
|
||||
createNode('/ip4/127.0.0.1/tcp/10000/wss'),
|
||||
createNode([])
|
||||
])
|
||||
|
||||
printAddrs(node1, '1')
|
||||
printAddrs(node2, '2')
|
||||
|
||||
node1.handle('/print', print)
|
||||
node2.handle('/print', print)
|
||||
|
||||
const targetAddr = `${node1.multiaddrs[0]}/p2p/${node1.peerId.toB58String()}`;
|
||||
|
||||
// node 2 (Secure WebSockets) dials to node 1 (Secure Websockets)
|
||||
const { stream } = await node2.dialProtocol(targetAddr, '/print', { websocket: { rejectUnauthorized: false } })
|
||||
await pipe(
|
||||
['node 2 dialed to node 1 successfully'],
|
||||
stream
|
||||
)
|
||||
})();
|
33
examples/transports/test-4.js
Normal file
33
examples/transports/test-4.js
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const deferNode1 = pDefer()
|
||||
|
||||
process.stdout.write('4.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '4.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('node 2 dialed to node 1 successfully')) {
|
||||
deferNode1.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
deferNode1.promise,
|
||||
])
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -3,11 +3,13 @@
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
const test3 = require('./test-3')
|
||||
const test4 = require('./test-4')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await test2()
|
||||
await test3()
|
||||
await test4()
|
||||
}
|
||||
|
||||
module.exports = test
|
||||
|
32
examples/transports/test_certs/cert.pem
Normal file
32
examples/transports/test_certs/cert.pem
Normal file
@@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
52
examples/transports/test_certs/key.pem
Normal file
52
examples/transports/test_certs/key.pem
Normal file
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
9avp6VlyVNfe4KEKW7IekrI0cmfMdXkl
|
||||
-----END PRIVATE KEY-----
|
@@ -21,11 +21,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"libp2p": "../../",
|
||||
"libp2p-bootstrap": "^0.12.1",
|
||||
"libp2p-mplex": "^0.10.1",
|
||||
"libp2p-noise": "^2.0.1",
|
||||
"libp2p-webrtc-direct": "^0.6.0",
|
||||
"peer-id": "^0.14.3"
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
"libp2p-webrtc-direct": "^0.7.0",
|
||||
"peer-id": "^0.15.0"
|
||||
},
|
||||
"browser": {
|
||||
"ipfs": "ipfs/dist/index.min.js"
|
||||
|
131
package.json
131
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.31.4",
|
||||
"version": "0.32.0",
|
||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
@@ -79,19 +79,18 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@motrix/nat-api": "^0.3.1",
|
||||
"@vascosantos/moving-average": "^1.1.0",
|
||||
"abort-controller": "^3.0.0",
|
||||
"aggregate-error": "^3.1.0",
|
||||
"any-signal": "^2.1.1",
|
||||
"bignumber.js": "^9.0.1",
|
||||
"cids": "^1.1.5",
|
||||
"class-is": "^1.1.0",
|
||||
"debug": "^4.3.1",
|
||||
"err-code": "^3.0.0",
|
||||
"es6-promisify": "^6.1.1",
|
||||
"events": "^3.3.0",
|
||||
"hashlru": "^2.3.0",
|
||||
"interface-datastore": "^4.0.0",
|
||||
"ipfs-utils": "^7.0.0",
|
||||
"interface-datastore": "^5.1.1",
|
||||
"it-all": "^1.0.4",
|
||||
"it-buffer": "^0.1.2",
|
||||
"it-drain": "^1.0.3",
|
||||
@@ -100,18 +99,17 @@
|
||||
"it-handshake": "^2.0.0",
|
||||
"it-length-prefixed": "^5.0.2",
|
||||
"it-map": "^1.0.4",
|
||||
"it-merge": "1.0.0",
|
||||
"it-merge": "^1.0.0",
|
||||
"it-pipe": "^1.1.0",
|
||||
"it-take": "1.0.0",
|
||||
"it-take": "^1.0.0",
|
||||
"libp2p-crypto": "^0.19.4",
|
||||
"libp2p-interfaces": "^0.10.4",
|
||||
"libp2p-utils": "^0.3.1",
|
||||
"mafmt": "^9.0.0",
|
||||
"libp2p-interfaces": "^1.0.0",
|
||||
"libp2p-interfaces-compliance-tests": "^1.0.0",
|
||||
"libp2p-utils": "^0.4.0",
|
||||
"mafmt": "^10.0.0",
|
||||
"merge-options": "^3.0.4",
|
||||
"@vascosantos/moving-average": "^1.1.0",
|
||||
"multiaddr": "^9.0.1",
|
||||
"multicodec": "^3.0.1",
|
||||
"multihashing-async": "^2.1.2",
|
||||
"multiaddr": "^10.0.0",
|
||||
"multiformats": "^9.0.0",
|
||||
"multistream-select": "^2.0.0",
|
||||
"mutable-proxy": "^1.0.0",
|
||||
"node-forge": "^0.10.0",
|
||||
@@ -119,58 +117,60 @@
|
||||
"p-fifo": "^1.0.0",
|
||||
"p-retry": "^4.4.0",
|
||||
"p-settle": "^4.1.1",
|
||||
"peer-id": "^0.14.2",
|
||||
"peer-id": "^0.15.0",
|
||||
"private-ip": "^2.1.0",
|
||||
"protobufjs": "^6.10.2",
|
||||
"retimer": "^3.0.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"set-delayed-interval": "^1.0.0",
|
||||
"streaming-iterables": "^5.0.2",
|
||||
"streaming-iterables": "^6.0.0",
|
||||
"timeout-abort-controller": "^1.1.1",
|
||||
"varint": "^6.0.0",
|
||||
"wherearewe": "^1.0.0",
|
||||
"xsalsa20": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nodeutils/defaults-deep": "^1.1.0",
|
||||
"@types/es6-promisify": "^6.0.0",
|
||||
"@types/node-forge": "^0.9.7",
|
||||
"@types/node": "^16.0.1",
|
||||
"@types/node-forge": "^0.10.1",
|
||||
"@types/varint": "^6.0.0",
|
||||
"abortable-iterator": "^3.0.0",
|
||||
"aegir": "^33.1.1",
|
||||
"buffer": "^6.0.3",
|
||||
"delay": "^5.0.0",
|
||||
"interop-libp2p": "^0.3.0",
|
||||
"interop-libp2p": "^0.4.0",
|
||||
"into-stream": "^6.0.0",
|
||||
"ipfs-http-client": "^49.0.4",
|
||||
"it-concat": "^1.0.0",
|
||||
"ipfs-http-client": "^50.1.1",
|
||||
"it-concat": "^2.0.0",
|
||||
"it-pair": "^1.0.0",
|
||||
"it-pushable": "^1.4.0",
|
||||
"libp2p": ".",
|
||||
"libp2p-bootstrap": "^0.12.3",
|
||||
"libp2p-delegated-content-routing": "^0.10.0",
|
||||
"libp2p-delegated-peer-routing": "^0.9.0",
|
||||
"libp2p-floodsub": "^0.25.0",
|
||||
"libp2p-gossipsub": "^0.9.0",
|
||||
"libp2p-kad-dht": "^0.22.0",
|
||||
"libp2p-mdns": "^0.16.0",
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-delegated-content-routing": "^0.11.0",
|
||||
"libp2p-delegated-peer-routing": "^0.10.0",
|
||||
"libp2p-floodsub": "^0.27.0",
|
||||
"libp2p-gossipsub": "^0.10.0",
|
||||
"libp2p-kad-dht": "^0.23.0",
|
||||
"libp2p-mdns": "^0.17.0",
|
||||
"libp2p-mplex": "^0.10.1",
|
||||
"libp2p-noise": "^3.0.0",
|
||||
"libp2p-tcp": "^0.15.4",
|
||||
"libp2p-webrtc-star": "^0.22.2",
|
||||
"libp2p-websockets": "^0.15.6",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
"libp2p-tcp": "^0.17.0",
|
||||
"libp2p-webrtc-star": "^0.23.0",
|
||||
"libp2p-websockets": "^0.16.0",
|
||||
"multihashes": "^4.0.2",
|
||||
"nock": "^13.0.3",
|
||||
"p-defer": "^3.0.0",
|
||||
"p-times": "^3.0.0",
|
||||
"p-wait-for": "^3.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"sinon": "^10.0.0",
|
||||
"sinon": "^11.1.1",
|
||||
"uint8arrays": "^2.1.3",
|
||||
"util": "^0.12.3"
|
||||
},
|
||||
"contributors": [
|
||||
"David Dias <daviddias.p@gmail.com>",
|
||||
"Vasco Santos <vasco.santos@moxy.studio>",
|
||||
"David Dias <daviddias.p@gmail.com>",
|
||||
"Jacob Heun <jacobheun@gmail.com>",
|
||||
"Alex Potsides <alex@achingbrain.net>",
|
||||
"Alan Shaw <alan@tableflip.io>",
|
||||
@@ -180,49 +180,64 @@
|
||||
"Maciej Krüger <mkg20001@gmail.com>",
|
||||
"Hugo Dias <mail@hugodias.me>",
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"Chris Dostert <chrisdostert@users.noreply.github.com>",
|
||||
"Volker Mische <volker.mische@gmail.com>",
|
||||
"zeim839 <50573884+zeim839@users.noreply.github.com>",
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"Ryan Bell <ryan@piing.net>",
|
||||
"a1300 <matthias-knopp@gmx.net>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"Ryan Bell <ryan@piing.net>",
|
||||
"Samlior <samlior@foxmail.com>",
|
||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"Didrik Nordström <didrik@betamos.se>",
|
||||
"Fei Liu <liu.feiwood@gmail.com>",
|
||||
"Ethan Lam <elmemphis2000@gmail.com>",
|
||||
"Joel Gustafson <joelg@mit.edu>",
|
||||
"Julien Bouquillon <contact@revolunet.com>",
|
||||
"Kevin Kwok <antimatter15@gmail.com>",
|
||||
"Kevin Lacker <lacker@gmail.com>",
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"Miguel Mota <miguelmota2@gmail.com>",
|
||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||
"Diogo Silva <fsdiogo@gmail.com>",
|
||||
"Philipp Muens <raute1337@gmx.de>",
|
||||
"Franck Royer <franck@royer.one>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"acolytec3 <17355484+acolytec3@users.noreply.github.com>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Didrik Nordström <didrik.nordstrom@gmail.com>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"Smite Chow <xiaopengyou@live.com>",
|
||||
"Soeren <nikorpoulsen@gmail.com>",
|
||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||
"TJKoury <TJKoury@gmail.com>",
|
||||
"robertkiel <robert.kiel@validitylabs.org>",
|
||||
"Tiago Alves <alvesjtiago@gmail.com>",
|
||||
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
||||
"Cindy Wu <ciindy.wu@gmail.com>",
|
||||
"Yusef Napora <yusef@napora.org>",
|
||||
"Zane Starr <zcstarr@gmail.com>",
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"ebinks <elizabethjbinks@gmail.com>",
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"mayerwin <mayerwin@users.noreply.github.com>",
|
||||
"mcclure <andi.m.mcclure@gmail.com>",
|
||||
"phillmac <phillmac@users.noreply.github.com>",
|
||||
"robertkiel <robert.kiel@validitylabs.org>",
|
||||
"shresthagrawal <34920931+shresthagrawal@users.noreply.github.com>",
|
||||
"swedneck <40505480+swedneck@users.noreply.github.com>",
|
||||
"Marcin Tojek <mtojek@users.noreply.github.com>",
|
||||
"Aleksei <vozhdb@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
"Cindy Wu <ciindy.wu@gmail.com>",
|
||||
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
||||
"Diogo Silva <fsdiogo@gmail.com>",
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"Ethan Lam <elmemphis2000@gmail.com>",
|
||||
"Fei Liu <liu.feiwood@gmail.com>",
|
||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||
"Francis Gulotta <wizard@roborooter.com>",
|
||||
"Franck Royer <franck@royer.one>",
|
||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||
"Aleksei <vozhdb@gmail.com>",
|
||||
"Guy Sviry <32539816+guysv@users.noreply.github.com>",
|
||||
"Henrique Dias <hacdias@gmail.com>",
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"Irakli Gozalishvili <rfobic@gmail.com>"
|
||||
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||
"Joel Gustafson <joelg@mit.edu>",
|
||||
"John Rees <johnrees@users.noreply.github.com>",
|
||||
"João Santos <joaosantos15@users.noreply.github.com>",
|
||||
"Julien Bouquillon <contact@revolunet.com>",
|
||||
"Kevin Kwok <antimatter15@gmail.com>",
|
||||
"Kevin Lacker <lacker@gmail.com>",
|
||||
"Lars Gierth <lgierth@users.noreply.github.com>",
|
||||
"Aditya Bose <13054902+adbose@users.noreply.github.com>",
|
||||
"Michael Burns <5170+mburns@users.noreply.github.com>",
|
||||
"Miguel Mota <miguelmota2@gmail.com>",
|
||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||
"Philipp Muens <raute1337@gmx.de>"
|
||||
]
|
||||
}
|
||||
|
@@ -222,7 +222,7 @@ class AutoRelay {
|
||||
continue
|
||||
}
|
||||
|
||||
const peerId = PeerId.createFromCID(id)
|
||||
const peerId = PeerId.createFromB58String(id)
|
||||
const connection = this._connectionManager.get(peerId)
|
||||
|
||||
// If not connected, store for possible later use.
|
||||
|
@@ -136,8 +136,8 @@ class Circuit {
|
||||
throw errCode(new Error(errMsg), codes.ERR_RELAYED_DIAL)
|
||||
}
|
||||
|
||||
const relayPeer = PeerId.createFromCID(relayId)
|
||||
const destinationPeer = PeerId.createFromCID(destinationId)
|
||||
const relayPeer = PeerId.createFromB58String(relayId)
|
||||
const destinationPeer = PeerId.createFromB58String(destinationId)
|
||||
|
||||
let disconnectOnFailure = false
|
||||
let relayConnection = this._connectionManager.get(relayPeer)
|
||||
|
@@ -1,9 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const CID = require('cids')
|
||||
const multihashing = require('multihashing-async')
|
||||
|
||||
const TextEncoder = require('ipfs-utils/src/text-encoder')
|
||||
const { CID } = require('multiformats/cid')
|
||||
const { sha256 } = require('multiformats/hashes/sha2')
|
||||
|
||||
/**
|
||||
* Convert a namespace string into a cid.
|
||||
@@ -13,7 +11,7 @@ const TextEncoder = require('ipfs-utils/src/text-encoder')
|
||||
*/
|
||||
module.exports.namespaceToCid = async (namespace) => {
|
||||
const bytes = new TextEncoder().encode(namespace)
|
||||
const hash = await multihashing(bytes, 'sha2-256')
|
||||
const hash = await sha256.digest(bytes)
|
||||
|
||||
return new CID(hash)
|
||||
return CID.createV0(hash)
|
||||
}
|
||||
|
@@ -97,6 +97,11 @@ class ConnectionManager extends EventEmitter {
|
||||
this._autoDialTimeout = null
|
||||
this._checkMetrics = this._checkMetrics.bind(this)
|
||||
this._autoDial = this._autoDial.bind(this)
|
||||
|
||||
this._latencyMonitor = new LatencyMonitor({
|
||||
latencyCheckIntervalMs: this._options.pollInterval,
|
||||
dataEmitIntervalMs: this._options.pollInterval
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,10 +122,7 @@ class ConnectionManager extends EventEmitter {
|
||||
}
|
||||
|
||||
// latency monitor
|
||||
this._latencyMonitor = new LatencyMonitor({
|
||||
latencyCheckIntervalMs: this._options.pollInterval,
|
||||
dataEmitIntervalMs: this._options.pollInterval
|
||||
})
|
||||
this._latencyMonitor.start()
|
||||
this._onLatencyMeasure = this._onLatencyMeasure.bind(this)
|
||||
this._latencyMonitor.on('data', this._onLatencyMeasure)
|
||||
|
||||
@@ -138,7 +140,9 @@ class ConnectionManager extends EventEmitter {
|
||||
async stop () {
|
||||
this._autoDialTimeout && this._autoDialTimeout.clear()
|
||||
this._timer && this._timer.clear()
|
||||
this._latencyMonitor && this._latencyMonitor.removeListener('data', this._onLatencyMeasure)
|
||||
|
||||
this._latencyMonitor.removeListener('data', this._onLatencyMeasure)
|
||||
this._latencyMonitor.stop()
|
||||
|
||||
this._started = false
|
||||
await this._close()
|
||||
|
@@ -69,49 +69,55 @@ class LatencyMonitor extends EventEmitter {
|
||||
}
|
||||
|
||||
that.asyncTestFn = asyncTestFn // If there is no asyncFn, we measure latency
|
||||
}
|
||||
|
||||
start () {
|
||||
// If process: use high resolution timer
|
||||
if (globalThis.process && globalThis.process.hrtime) { // eslint-disable-line no-undef
|
||||
debug('Using process.hrtime for timing')
|
||||
that.now = globalThis.process.hrtime // eslint-disable-line no-undef
|
||||
that.getDeltaMS = (startTime) => {
|
||||
const hrtime = that.now(startTime)
|
||||
this.now = globalThis.process.hrtime // eslint-disable-line no-undef
|
||||
this.getDeltaMS = (startTime) => {
|
||||
const hrtime = this.now(startTime)
|
||||
return (hrtime[0] * 1000) + (hrtime[1] / 1000000)
|
||||
}
|
||||
// Let's try for a timer that only monotonically increases
|
||||
} else if (typeof window !== 'undefined' && window.performance && window.performance.now) {
|
||||
debug('Using performance.now for timing')
|
||||
that.now = window.performance.now.bind(window.performance)
|
||||
that.getDeltaMS = (startTime) => Math.round(that.now() - startTime)
|
||||
this.now = window.performance.now.bind(window.performance)
|
||||
this.getDeltaMS = (startTime) => Math.round(this.now() - startTime)
|
||||
} else {
|
||||
debug('Using Date.now for timing')
|
||||
that.now = Date.now
|
||||
that.getDeltaMS = (startTime) => that.now() - startTime
|
||||
this.now = Date.now
|
||||
this.getDeltaMS = (startTime) => this.now() - startTime
|
||||
}
|
||||
|
||||
that._latencyData = that._initLatencyData()
|
||||
this._latencyData = this._initLatencyData()
|
||||
|
||||
// We check for isBrowser because of browsers set max rates of timeouts when a page is hidden,
|
||||
// so we fall back to another library
|
||||
// See: http://stackoverflow.com/questions/6032429/chrome-timeouts-interval-suspended-in-background-tabs
|
||||
if (isBrowser()) {
|
||||
that._visibilityChangeEmitter = new VisibilityChangeEmitter()
|
||||
this._visibilityChangeEmitter = new VisibilityChangeEmitter()
|
||||
|
||||
that._visibilityChangeEmitter.on('visibilityChange', (pageInFocus) => {
|
||||
this._visibilityChangeEmitter.on('visibilityChange', (pageInFocus) => {
|
||||
if (pageInFocus) {
|
||||
that._startTimers()
|
||||
this._startTimers()
|
||||
} else {
|
||||
that._emitSummary()
|
||||
that._stopTimers()
|
||||
this._emitSummary()
|
||||
this._stopTimers()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!that._visibilityChangeEmitter || that._visibilityChangeEmitter.isVisible()) {
|
||||
that._startTimers()
|
||||
if (!this._visibilityChangeEmitter || this._visibilityChangeEmitter.isVisible()) {
|
||||
this._startTimers()
|
||||
}
|
||||
}
|
||||
|
||||
stop () {
|
||||
this._stopTimers()
|
||||
}
|
||||
|
||||
/**
|
||||
* Start internal timers
|
||||
*
|
||||
|
@@ -4,6 +4,7 @@ module.exports = {
|
||||
DIAL_TIMEOUT: 30e3, // How long in ms a dial attempt is allowed to take
|
||||
MAX_PARALLEL_DIALS: 100, // Maximum allowed concurrent dials
|
||||
MAX_PER_PEER_DIALS: 4, // Allowed parallel dials per DialRequest
|
||||
MAX_ADDRS_TO_DIAL: 25, // Maximum number of allowed addresses to attempt to dial
|
||||
METRICS: {
|
||||
computeThrottleMaxQueueSize: 1000,
|
||||
computeThrottleTimeout: 2000,
|
||||
|
@@ -15,7 +15,7 @@ const { pipe } = require('it-pipe')
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||
* @typedef {import('cids')} CID
|
||||
* @typedef {import('multiformats/cid').CID} CID
|
||||
* @typedef {import('libp2p-interfaces/src/content-routing/types').ContentRouting} ContentRoutingModule
|
||||
*/
|
||||
|
||||
|
@@ -8,6 +8,7 @@ const errCode = require('err-code')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
// @ts-ignore timeout-abourt-controles does not export types
|
||||
const TimeoutController = require('timeout-abort-controller')
|
||||
const { AbortError } = require('abortable-iterator')
|
||||
const { anySignal } = require('any-signal')
|
||||
|
||||
const DialRequest = require('./dial-request')
|
||||
@@ -18,7 +19,8 @@ const { codes } = require('../errors')
|
||||
const {
|
||||
DIAL_TIMEOUT,
|
||||
MAX_PARALLEL_DIALS,
|
||||
MAX_PER_PEER_DIALS
|
||||
MAX_PER_PEER_DIALS,
|
||||
MAX_ADDRS_TO_DIAL
|
||||
} = require('../constants')
|
||||
|
||||
/**
|
||||
@@ -39,6 +41,7 @@ const {
|
||||
* @typedef {Object} DialerOptions
|
||||
* @property {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial.
|
||||
* @property {number} [maxParallelDials = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
|
||||
* @property {number} [maxAddrsToDial = MAX_ADDRS_TO_DIAL] - Number of max addresses to dial for a given peer.
|
||||
* @property {number} [maxDialsPerPeer = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
|
||||
* @property {number} [dialTimeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
|
||||
* @property {Record<string, Resolver>} [resolvers = {}] - multiaddr resolvers to use when dialing
|
||||
@@ -64,6 +67,7 @@ class Dialer {
|
||||
peerStore,
|
||||
addressSorter = publicAddressesFirst,
|
||||
maxParallelDials = MAX_PARALLEL_DIALS,
|
||||
maxAddrsToDial = MAX_ADDRS_TO_DIAL,
|
||||
dialTimeout = DIAL_TIMEOUT,
|
||||
maxDialsPerPeer = MAX_PER_PEER_DIALS,
|
||||
resolvers = {}
|
||||
@@ -72,10 +76,12 @@ class Dialer {
|
||||
this.peerStore = peerStore
|
||||
this.addressSorter = addressSorter
|
||||
this.maxParallelDials = maxParallelDials
|
||||
this.maxAddrsToDial = maxAddrsToDial
|
||||
this.timeout = dialTimeout
|
||||
this.maxDialsPerPeer = maxDialsPerPeer
|
||||
this.tokens = [...new Array(maxParallelDials)].map((_, index) => index)
|
||||
this._pendingDials = new Map()
|
||||
this._pendingDialTargets = new Map()
|
||||
|
||||
for (const [key, value] of Object.entries(resolvers)) {
|
||||
Multiaddr.resolvers.set(key, value)
|
||||
@@ -94,6 +100,11 @@ class Dialer {
|
||||
}
|
||||
}
|
||||
this._pendingDials.clear()
|
||||
|
||||
for (const pendingTarget of this._pendingDialTargets.values()) {
|
||||
pendingTarget.reject(new AbortError('Dialer was destroyed'))
|
||||
}
|
||||
this._pendingDialTargets.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +118,7 @@ class Dialer {
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
async connectToPeer (peer, options = {}) {
|
||||
const dialTarget = await this._createDialTarget(peer)
|
||||
const dialTarget = await this._createCancellableDialTarget(peer)
|
||||
|
||||
if (!dialTarget.addrs.length) {
|
||||
throw errCode(new Error('The dial request has no valid addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
||||
@@ -130,6 +141,31 @@ class Dialer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a given `peer` by dialing all of its known addresses.
|
||||
* The dial to the first address that is successfully able to upgrade a connection
|
||||
* will be used.
|
||||
*
|
||||
* @param {PeerId|Multiaddr|string} peer - The peer to dial
|
||||
* @returns {Promise<DialTarget>}
|
||||
*/
|
||||
async _createCancellableDialTarget (peer) {
|
||||
// Make dial target promise cancellable
|
||||
const id = `${(parseInt(String(Math.random() * 1e9), 10)).toString() + Date.now()}`
|
||||
const cancellablePromise = new Promise((resolve, reject) => {
|
||||
this._pendingDialTargets.set(id, { resolve, reject })
|
||||
})
|
||||
|
||||
const dialTarget = await Promise.race([
|
||||
this._createDialTarget(peer),
|
||||
cancellablePromise
|
||||
])
|
||||
|
||||
this._pendingDialTargets.delete(id)
|
||||
|
||||
return dialTarget
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DialTarget. The DialTarget is used to create and track
|
||||
* the DialRequest to a given peer.
|
||||
@@ -166,6 +202,11 @@ class Dialer {
|
||||
// Multiaddrs not supported by the available transports will be filtered out.
|
||||
const supportedAddrs = addrs.filter(a => this.transportManager.transportForMultiaddr(a))
|
||||
|
||||
if (supportedAddrs.length > this.maxAddrsToDial) {
|
||||
this.peerStore.delete(id)
|
||||
throw errCode(new Error('dial with more addresses than allowed'), codes.ERR_TOO_MANY_ADDRESSES)
|
||||
}
|
||||
|
||||
return {
|
||||
id: id.toB58String(),
|
||||
addrs: supportedAddrs
|
||||
|
@@ -16,6 +16,7 @@ exports.codes = {
|
||||
ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED',
|
||||
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
|
||||
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
|
||||
ERR_TOO_MANY_ADDRESSES: 'ERR_TOO_MANY_ADDRESSES',
|
||||
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
|
||||
ERR_RELAYED_DIAL: 'ERR_RELAYED_DIAL',
|
||||
ERR_DIALED_SELF: 'ERR_DIALED_SELF',
|
||||
|
@@ -189,6 +189,8 @@ class IdentifyService {
|
||||
const envelope = await Envelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN)
|
||||
if (this.peerStore.addressBook.consumePeerRecord(envelope)) {
|
||||
this.peerStore.protoBook.set(id, protocols)
|
||||
this.peerStore.metadataBook.set(id, 'AgentVersion', uint8ArrayFromString(message.agentVersion))
|
||||
this.peerStore.metadataBook.set(id, 'ProtocolVersion', uint8ArrayFromString(message.protocolVersion))
|
||||
return
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -204,6 +206,7 @@ class IdentifyService {
|
||||
|
||||
this.peerStore.protoBook.set(id, protocols)
|
||||
this.peerStore.metadataBook.set(id, 'AgentVersion', uint8ArrayFromString(message.agentVersion))
|
||||
this.peerStore.metadataBook.set(id, 'ProtocolVersion', uint8ArrayFromString(message.protocolVersion))
|
||||
|
||||
// TODO: Add and score our observed addr
|
||||
log('received observed address of %s', cleanObservedAddr)
|
||||
|
@@ -1,6 +1,9 @@
|
||||
/* eslint max-nested-callbacks: ["error", 5] */
|
||||
'use strict'
|
||||
|
||||
const debug = require('debug')
|
||||
const log = Object.assign(debug('libp2p:keychain'), {
|
||||
error: debug('libp2p:keychain:err')
|
||||
})
|
||||
const sanitize = require('sanitize-filename')
|
||||
const mergeOptions = require('merge-options')
|
||||
const crypto = require('libp2p-crypto')
|
||||
@@ -503,6 +506,55 @@ class Keychain {
|
||||
return throwDelayed(errcode(new Error(`Key '${name}' does not exist. ${err.message}`), 'ERR_KEY_NOT_FOUND'))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate keychain password and re-encrypt all assosciated keys
|
||||
*
|
||||
* @param {string} oldPass - The old local keychain password
|
||||
* @param {string} newPass - The new local keychain password
|
||||
*/
|
||||
async rotateKeychainPass (oldPass, newPass) {
|
||||
if (typeof oldPass !== 'string') {
|
||||
return throwDelayed(errcode(new Error(`Invalid old pass type '${typeof oldPass}'`), 'ERR_INVALID_OLD_PASS_TYPE'))
|
||||
}
|
||||
if (typeof newPass !== 'string') {
|
||||
return throwDelayed(errcode(new Error(`Invalid new pass type '${typeof newPass}'`), 'ERR_INVALID_NEW_PASS_TYPE'))
|
||||
}
|
||||
if (newPass.length < 20) {
|
||||
return throwDelayed(errcode(new Error(`Invalid pass length ${newPass.length}`), 'ERR_INVALID_PASS_LENGTH'))
|
||||
}
|
||||
log('recreating keychain')
|
||||
const oldDek = privates.get(this).dek
|
||||
this.opts.pass = newPass
|
||||
const newDek = newPass
|
||||
? crypto.pbkdf2(
|
||||
newPass,
|
||||
this.opts.dek.salt,
|
||||
this.opts.dek.iterationCount,
|
||||
this.opts.dek.keyLength,
|
||||
this.opts.dek.hash)
|
||||
: ''
|
||||
privates.set(this, { dek: newDek })
|
||||
const keys = await this.listKeys()
|
||||
for (const key of keys) {
|
||||
const res = await this.store.get(DsName(key.name))
|
||||
const pem = uint8ArrayToString(res)
|
||||
const privateKey = await crypto.keys.import(pem, oldDek)
|
||||
const password = newDek.toString()
|
||||
const keyAsPEM = await privateKey.export(password)
|
||||
|
||||
// Update stored key
|
||||
const batch = this.store.batch()
|
||||
const keyInfo = {
|
||||
name: key.name,
|
||||
id: key.id
|
||||
}
|
||||
batch.put(DsName(key.name), uint8ArrayFromString(keyAsPEM))
|
||||
batch.put(DsInfoName(key.name), uint8ArrayFromString(JSON.stringify(keyInfo)))
|
||||
await batch.commit()
|
||||
}
|
||||
log('keychain reconstructed')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Keychain
|
||||
|
@@ -8,7 +8,7 @@ const { Multiaddr } = require('multiaddr')
|
||||
const log = Object.assign(debug('libp2p:nat'), {
|
||||
error: debug('libp2p:nat:err')
|
||||
})
|
||||
const { isBrowser } = require('ipfs-utils/src/env')
|
||||
const { isBrowser } = require('wherearewe')
|
||||
const retry = require('p-retry')
|
||||
// @ts-ignore private-api does not export types
|
||||
const isPrivateIp = require('private-ip')
|
||||
|
@@ -99,7 +99,7 @@ class PeerStore extends EventEmitter {
|
||||
|
||||
const peersData = new Map()
|
||||
storedPeers.forEach((idStr) => {
|
||||
peersData.set(idStr, this.get(PeerId.createFromCID(idStr)))
|
||||
peersData.set(idStr, this.get(PeerId.createFromB58String(idStr)))
|
||||
})
|
||||
|
||||
return peersData
|
||||
|
@@ -7,6 +7,7 @@ const log = Object.assign(debug('libp2p:persistent-peer-store'), {
|
||||
const { Key } = require('interface-datastore')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
const { base32 } = require('multiformats/bases/base32')
|
||||
|
||||
const PeerStore = require('..')
|
||||
|
||||
@@ -195,7 +196,7 @@ class PersistentPeerStore extends PeerStore {
|
||||
const batch = this._datastore.batch()
|
||||
for (const peerIdStr of commitPeers) {
|
||||
// PeerId
|
||||
const peerId = this.keyBook.data.get(peerIdStr) || PeerId.createFromCID(peerIdStr)
|
||||
const peerId = this.keyBook.data.get(peerIdStr) || PeerId.createFromB58String(peerIdStr)
|
||||
|
||||
// Address Book
|
||||
this._batchAddressBook(peerId, batch)
|
||||
@@ -346,7 +347,7 @@ class PersistentPeerStore extends PeerStore {
|
||||
async _processDatastoreEntry ({ key, value }) {
|
||||
try {
|
||||
const keyParts = key.toString().split('/')
|
||||
const peerId = PeerId.createFromCID(keyParts[3])
|
||||
const peerId = PeerId.createFromBytes(base32.decode(keyParts[3]))
|
||||
|
||||
let decoded
|
||||
switch (keyParts[2]) {
|
||||
|
@@ -1,9 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const multicodec = require('multicodec')
|
||||
|
||||
// The domain string used for peer records contained in a Envelope.
|
||||
const domain = multicodec.getName(multicodec.LIBP2P_PEER_RECORD) || 'libp2p-peer-record'
|
||||
const domain = 'libp2p-peer-record'
|
||||
|
||||
// The type hint used to identify peer records in a Envelope.
|
||||
// Defined in https://github.com/multiformats/multicodec/blob/master/table.csv
|
||||
|
@@ -3,14 +3,13 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const mergeOptions = require('merge-options')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const pDefer = require('p-defer')
|
||||
const delay = require('delay')
|
||||
|
||||
const { create } = require('../../src')
|
||||
const { baseOptions, subsystemOptions } = require('./utils')
|
||||
const { baseOptions, pubsubSubsystemOptions } = require('./utils')
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
|
||||
describe('Pubsub subsystem is configurable', () => {
|
||||
let libp2p
|
||||
|
||||
@@ -24,18 +23,15 @@ describe('Pubsub subsystem is configurable', () => {
|
||||
})
|
||||
|
||||
it('should exist if the module is provided', async () => {
|
||||
libp2p = await create(subsystemOptions)
|
||||
libp2p = await create(pubsubSubsystemOptions)
|
||||
expect(libp2p.pubsub).to.exist()
|
||||
})
|
||||
|
||||
it('should start and stop by default once libp2p starts', async () => {
|
||||
const [peerId] = await peerUtils.createPeerId()
|
||||
|
||||
const customOptions = mergeOptions(subsystemOptions, {
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [listenAddr]
|
||||
}
|
||||
const customOptions = mergeOptions(pubsubSubsystemOptions, {
|
||||
peerId
|
||||
})
|
||||
|
||||
libp2p = await create(customOptions)
|
||||
@@ -51,11 +47,8 @@ describe('Pubsub subsystem is configurable', () => {
|
||||
it('should not start if disabled once libp2p starts', async () => {
|
||||
const [peerId] = await peerUtils.createPeerId()
|
||||
|
||||
const customOptions = mergeOptions(subsystemOptions, {
|
||||
const customOptions = mergeOptions(pubsubSubsystemOptions, {
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [listenAddr]
|
||||
},
|
||||
config: {
|
||||
pubsub: {
|
||||
enabled: false
|
||||
@@ -73,11 +66,8 @@ describe('Pubsub subsystem is configurable', () => {
|
||||
it('should allow a manual start', async () => {
|
||||
const [peerId] = await peerUtils.createPeerId()
|
||||
|
||||
const customOptions = mergeOptions(subsystemOptions, {
|
||||
const customOptions = mergeOptions(pubsubSubsystemOptions, {
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [listenAddr]
|
||||
},
|
||||
config: {
|
||||
pubsub: {
|
||||
enabled: false
|
||||
@@ -93,3 +83,47 @@ describe('Pubsub subsystem is configurable', () => {
|
||||
expect(libp2p.pubsub.started).to.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Pubsub subscription handlers adapter', () => {
|
||||
let libp2p
|
||||
|
||||
beforeEach(async () => {
|
||||
const [peerId] = await peerUtils.createPeerId()
|
||||
|
||||
libp2p = await create(mergeOptions(pubsubSubsystemOptions, {
|
||||
peerId
|
||||
}))
|
||||
|
||||
await libp2p.start()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
libp2p && await libp2p.stop()
|
||||
})
|
||||
|
||||
it('extends pubsub with subscribe handler', async () => {
|
||||
let countMessages = 0
|
||||
const topic = 'topic'
|
||||
const defer = pDefer()
|
||||
|
||||
const handler = () => {
|
||||
countMessages++
|
||||
if (countMessages > 1) {
|
||||
throw new Error('only one message should be received')
|
||||
}
|
||||
|
||||
defer.resolve()
|
||||
}
|
||||
|
||||
await libp2p.pubsub.subscribe(topic, handler)
|
||||
|
||||
libp2p.pubsub.emit(topic, 'useless-data')
|
||||
await defer.promise
|
||||
|
||||
await libp2p.pubsub.unsubscribe(topic, handler)
|
||||
libp2p.pubsub.emit(topic, 'useless-data')
|
||||
|
||||
// wait to guarantee that the handler is not called twice
|
||||
await delay(100)
|
||||
})
|
||||
})
|
52
test/configuration/utils.js
Normal file
52
test/configuration/utils.js
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict'
|
||||
|
||||
const Pubsub = require('libp2p-interfaces/src/pubsub')
|
||||
const { NOISE: Crypto } = require('libp2p-noise')
|
||||
const Muxer = require('libp2p-mplex')
|
||||
const Transport = require('libp2p-websockets')
|
||||
const filters = require('libp2p-websockets/src/filters')
|
||||
const transportKey = Transport.prototype[Symbol.toStringTag]
|
||||
|
||||
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
||||
const relayAddr = MULTIADDRS_WEBSOCKETS[0]
|
||||
|
||||
const mergeOptions = require('merge-options')
|
||||
|
||||
const baseOptions = {
|
||||
modules: {
|
||||
transport: [Transport],
|
||||
streamMuxer: [Muxer],
|
||||
connEncryption: [Crypto]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.baseOptions = baseOptions
|
||||
|
||||
class MockPubsub extends Pubsub {
|
||||
constructor (libp2p, options = {}) {
|
||||
super({
|
||||
debugName: 'mock-pubsub',
|
||||
multicodecs: '/mock-pubsub',
|
||||
libp2p,
|
||||
...options
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const pubsubSubsystemOptions = mergeOptions(baseOptions, {
|
||||
modules: {
|
||||
pubsub: MockPubsub
|
||||
},
|
||||
addresses: {
|
||||
listen: [`${relayAddr}/p2p-circuit`]
|
||||
},
|
||||
config: {
|
||||
transport: {
|
||||
[transportKey]: {
|
||||
filter: filters.all
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
module.exports.pubsubSubsystemOptions = pubsubSubsystemOptions
|
@@ -8,7 +8,7 @@ const sinon = require('sinon')
|
||||
const pDefer = require('p-defer')
|
||||
const mergeOptions = require('merge-options')
|
||||
|
||||
const CID = require('cids')
|
||||
const { CID } = require('multiformats/cid')
|
||||
const ipfsHttpClient = require('ipfs-http-client')
|
||||
const DelegatedContentRouter = require('libp2p-delegated-content-routing')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
@@ -105,7 +105,7 @@ describe('content-routing', () => {
|
||||
beforeEach(async () => {
|
||||
const [peerId] = await peerUtils.createPeerId({ fixture: true })
|
||||
|
||||
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient({
|
||||
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
|
||||
host: '0.0.0.0',
|
||||
protocol: 'http',
|
||||
port: 60197
|
||||
@@ -164,7 +164,7 @@ describe('content-routing', () => {
|
||||
})
|
||||
|
||||
it('should be able to register as a provider', async () => {
|
||||
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const cid = CID.parse('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const provider = 'QmZNgCqZCvTsi3B4Vt7gsSqpkqDpE7M2Y9TDmEhbDb4ceF'
|
||||
|
||||
const mockBlockApi = nock('http://0.0.0.0:60197')
|
||||
@@ -191,7 +191,7 @@ describe('content-routing', () => {
|
||||
})
|
||||
|
||||
it('should handle errors when registering as a provider', async () => {
|
||||
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const cid = CID.parse('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const mockApi = nock('http://0.0.0.0:60197')
|
||||
// mock the block/stat call
|
||||
.post('/api/v0/block/stat')
|
||||
@@ -205,7 +205,7 @@ describe('content-routing', () => {
|
||||
})
|
||||
|
||||
it('should be able to find providers', async () => {
|
||||
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const cid = CID.parse('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const provider = 'QmZNgCqZCvTsi3B4Vt7gsSqpkqDpE7M2Y9TDmEhbDb4ceF'
|
||||
|
||||
const mockApi = nock('http://0.0.0.0:60197')
|
||||
@@ -227,7 +227,7 @@ describe('content-routing', () => {
|
||||
})
|
||||
|
||||
it('should handle errors when finding providers', async () => {
|
||||
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const cid = CID.parse('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
|
||||
const mockApi = nock('http://0.0.0.0:60197')
|
||||
.post('/api/v0/dht/findprovs')
|
||||
.query(true)
|
||||
@@ -253,7 +253,7 @@ describe('content-routing', () => {
|
||||
beforeEach(async () => {
|
||||
const [peerId] = await peerUtils.createPeerId({ fixture: true })
|
||||
|
||||
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient({
|
||||
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
|
||||
host: '0.0.0.0',
|
||||
protocol: 'http',
|
||||
port: 60197
|
||||
|
@@ -177,6 +177,26 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
.and.to.have.property('code', ErrorCodes.ERR_TIMEOUT)
|
||||
})
|
||||
|
||||
it('should throw when a peer advertises more than the allowed number of peers', async () => {
|
||||
const spy = sinon.spy()
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
maxAddrsToDial: 10,
|
||||
peerStore: {
|
||||
delete: spy,
|
||||
addressBook: {
|
||||
add: () => { },
|
||||
getMultiaddrsForPeer: () => Array.from({ length: 11 }, (_, i) => new Multiaddr(`/ip4/127.0.0.1/tcp/1500${i}/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5`))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await expect(dialer.connectToPeer(remoteAddr))
|
||||
.to.eventually.be.rejected()
|
||||
.and.to.have.property('code', ErrorCodes.ERR_TOO_MANY_ADDRESSES)
|
||||
expect(spy.calledOnce).to.be.true()
|
||||
})
|
||||
|
||||
it('should sort addresses on dial', async () => {
|
||||
const peerMultiaddrs = [
|
||||
new Multiaddr('/ip4/127.0.0.1/tcp/15001/ws'),
|
||||
@@ -290,6 +310,34 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should cancel pending dial targets before proceeding', async () => {
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore: {
|
||||
addressBook: {
|
||||
set: () => { }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
sinon.stub(dialer, '_createDialTarget').callsFake(() => {
|
||||
const deferredDial = pDefer()
|
||||
return deferredDial.promise
|
||||
})
|
||||
|
||||
// Perform dial
|
||||
const dialPromise = dialer.connectToPeer(peerId)
|
||||
|
||||
// Let the call stack run
|
||||
await delay(0)
|
||||
|
||||
dialer.destroy()
|
||||
|
||||
await expect(dialPromise)
|
||||
.to.eventually.be.rejected()
|
||||
.and.to.have.property('code', 'ABORT_ERR')
|
||||
})
|
||||
|
||||
describe('libp2p.dialer', () => {
|
||||
const transportKey = Transport.prototype[Symbol.toStringTag]
|
||||
let libp2p
|
||||
@@ -462,6 +510,42 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
await libp2p.hangUp(remoteAddr)
|
||||
})
|
||||
|
||||
it('should cancel pending dial targets and stop', async () => {
|
||||
const [, remotePeerId] = await createPeerId({ number: 2 })
|
||||
|
||||
libp2p = new Libp2p({
|
||||
peerId,
|
||||
modules: {
|
||||
transport: [Transport],
|
||||
streamMuxer: [Muxer],
|
||||
connEncryption: [Crypto]
|
||||
},
|
||||
config: {
|
||||
transport: {
|
||||
[transportKey]: {
|
||||
filter: filters.all
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
sinon.stub(libp2p.dialer, '_createDialTarget').callsFake(() => {
|
||||
const deferredDial = pDefer()
|
||||
return deferredDial.promise
|
||||
})
|
||||
|
||||
// Perform dial
|
||||
const dialPromise = libp2p.dial(remotePeerId)
|
||||
|
||||
// Let the call stack run
|
||||
await delay(0)
|
||||
|
||||
await libp2p.stop()
|
||||
await expect(dialPromise)
|
||||
.to.eventually.be.rejected()
|
||||
.and.to.have.property('code', 'ABORT_ERR')
|
||||
})
|
||||
|
||||
it('should abort pending dials on stop', async () => {
|
||||
libp2p = new Libp2p({
|
||||
peerId,
|
||||
|
@@ -430,6 +430,39 @@ describe('Identify', () => {
|
||||
await connection.close()
|
||||
})
|
||||
|
||||
it('should store remote agent and protocol versions in metadataBook after connecting', async () => {
|
||||
libp2p = new Libp2p({
|
||||
...baseOptions,
|
||||
peerId
|
||||
})
|
||||
|
||||
await libp2p.start()
|
||||
|
||||
sinon.spy(libp2p.identifyService, 'identify')
|
||||
const peerStoreSpyConsumeRecord = sinon.spy(libp2p.peerStore.addressBook, 'consumePeerRecord')
|
||||
const peerStoreSpyAdd = sinon.spy(libp2p.peerStore.addressBook, 'add')
|
||||
|
||||
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
|
||||
expect(connection).to.exist()
|
||||
|
||||
// Wait for peer store to be updated
|
||||
// Dialer._createDialTarget (add), Identify (consume)
|
||||
await pWaitFor(() => peerStoreSpyConsumeRecord.callCount === 1 && peerStoreSpyAdd.callCount === 1)
|
||||
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
||||
|
||||
// The connection should have no open streams
|
||||
await pWaitFor(() => connection.streams.length === 0)
|
||||
await connection.close()
|
||||
|
||||
const remotePeer = PeerId.createFromB58String(remoteAddr.getPeerId())
|
||||
|
||||
const storedAgentVersion = libp2p.peerStore.metadataBook.getValue(remotePeer, 'AgentVersion')
|
||||
const storedProtocolVersion = libp2p.peerStore.metadataBook.getValue(remotePeer, 'ProtocolVersion')
|
||||
|
||||
expect(storedAgentVersion).to.exist()
|
||||
expect(storedProtocolVersion).to.exist()
|
||||
})
|
||||
|
||||
it('should push protocol updates to an already connected peer', async () => {
|
||||
libp2p = new Libp2p({
|
||||
...baseOptions,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const tests = require('libp2p-interfaces/src/crypto/tests')
|
||||
const tests = require('libp2p-interfaces-compliance-tests/src/crypto')
|
||||
const plaintext = require('../../src/insecure/plaintext')
|
||||
|
||||
describe('plaintext compliance', () => {
|
||||
|
@@ -9,9 +9,10 @@ const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
const { MemoryDatastore } = require('interface-datastore')
|
||||
const { MemoryDatastore, Key } = require('interface-datastore')
|
||||
const Keychain = require('../../src/keychain')
|
||||
const PeerId = require('peer-id')
|
||||
const crypto = require('libp2p-crypto')
|
||||
|
||||
describe('keychain', () => {
|
||||
const passPhrase = 'this is not a secure phrase'
|
||||
@@ -492,6 +493,88 @@ describe('keychain', () => {
|
||||
expect(key).to.have.property('id', rsaKeyInfo.id)
|
||||
})
|
||||
})
|
||||
|
||||
describe('rotate keychain passphrase', () => {
|
||||
let oldPass
|
||||
let kc
|
||||
let options
|
||||
let ds
|
||||
before(async () => {
|
||||
ds = new MemoryDatastore()
|
||||
oldPass = `hello-${Date.now()}-${Date.now()}`
|
||||
options = {
|
||||
pass: oldPass,
|
||||
dek: {
|
||||
salt: '3Nd/Ya4ENB3bcByNKptb4IR',
|
||||
iterationCount: 10000,
|
||||
keyLength: 64,
|
||||
hash: 'sha2-512'
|
||||
}
|
||||
}
|
||||
kc = new Keychain(ds, options)
|
||||
await ds.open()
|
||||
})
|
||||
|
||||
it('should validate newPass is a string', async () => {
|
||||
try {
|
||||
await kc.rotateKeychainPass(oldPass, 1234567890)
|
||||
} catch (err) {
|
||||
expect(err).to.exist()
|
||||
}
|
||||
})
|
||||
|
||||
it('should validate oldPass is a string', async () => {
|
||||
try {
|
||||
await kc.rotateKeychainPass(1234, 'newInsecurePassword1')
|
||||
} catch (err) {
|
||||
expect(err).to.exist()
|
||||
}
|
||||
})
|
||||
|
||||
it('should validate newPass is at least 20 characters', async () => {
|
||||
try {
|
||||
await kc.rotateKeychainPass(oldPass, 'not20Chars')
|
||||
} catch (err) {
|
||||
expect(err).to.exist()
|
||||
}
|
||||
})
|
||||
|
||||
it('can rotate keychain passphrase', async () => {
|
||||
await kc.createKey('keyCreatedWithOldPassword', 'rsa', 2048)
|
||||
await kc.rotateKeychainPass(oldPass, 'newInsecurePassphrase')
|
||||
|
||||
// Get Key PEM from datastore
|
||||
const dsname = new Key('/pkcs8/' + 'keyCreatedWithOldPassword')
|
||||
const res = await ds.get(dsname)
|
||||
const pem = uint8ArrayToString(res)
|
||||
|
||||
const oldDek = options.pass
|
||||
? crypto.pbkdf2(
|
||||
options.pass,
|
||||
options.dek.salt,
|
||||
options.dek.iterationCount,
|
||||
options.dek.keyLength,
|
||||
options.dek.hash)
|
||||
: ''
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
const newDek = 'newInsecurePassphrase'
|
||||
? crypto.pbkdf2(
|
||||
'newInsecurePassphrase',
|
||||
options.dek.salt,
|
||||
options.dek.iterationCount,
|
||||
options.dek.keyLength,
|
||||
options.dek.hash)
|
||||
: ''
|
||||
|
||||
// Dek with old password should not work:
|
||||
await expect(kc.importKey('keyWhosePassChanged', pem, oldDek))
|
||||
.to.eventually.be.rejected()
|
||||
// Dek with new password should work:
|
||||
await expect(kc.importKey('keyWhosePasswordChanged', pem, newDek))
|
||||
.to.eventually.have.property('name', 'keyWhosePasswordChanged')
|
||||
}).timeout(10000)
|
||||
})
|
||||
})
|
||||
|
||||
describe('libp2p.keychain', () => {
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const PeerId = require('peer-id')
|
||||
const multihash = require('multihashes')
|
||||
const { base58btc } = require('multiformats/bases/base58')
|
||||
const crypto = require('libp2p-crypto')
|
||||
const rsaUtils = require('libp2p-crypto/src/keys/rsa-utils')
|
||||
const rsaClass = require('libp2p-crypto/src/keys/rsa-class')
|
||||
@@ -40,7 +40,7 @@ describe('peer ID', () => {
|
||||
const jwk = rsaUtils.pkixToJwk(publicKeyDer)
|
||||
const rsa = new rsaClass.RsaPublicKey(jwk)
|
||||
const keyId = await rsa.hash()
|
||||
const kids = multihash.toB58String(keyId)
|
||||
const kids = base58btc.encode(keyId).substring(1)
|
||||
expect(kids).to.equal(peer.toB58String())
|
||||
})
|
||||
|
||||
@@ -54,7 +54,7 @@ describe('peer ID', () => {
|
||||
}
|
||||
const rsa = new rsaClass.RsaPublicKey(jwk)
|
||||
const keyId = await rsa.hash()
|
||||
const kids = multihash.toB58String(keyId)
|
||||
const kids = base58btc.encode(keyId).substring(1)
|
||||
expect(kids).to.equal(peer.toB58String())
|
||||
})
|
||||
|
||||
|
@@ -113,7 +113,7 @@ describe('peer-routing', () => {
|
||||
let delegate
|
||||
|
||||
beforeEach(async () => {
|
||||
delegate = new DelegatedPeerRouter(ipfsHttpClient({
|
||||
delegate = new DelegatedPeerRouter(ipfsHttpClient.create({
|
||||
host: '0.0.0.0',
|
||||
protocol: 'http',
|
||||
port: 60197
|
||||
@@ -288,7 +288,7 @@ describe('peer-routing', () => {
|
||||
let delegate
|
||||
|
||||
beforeEach(async () => {
|
||||
delegate = new DelegatedPeerRouter(ipfsHttpClient({
|
||||
delegate = new DelegatedPeerRouter(ipfsHttpClient.create({
|
||||
host: '0.0.0.0',
|
||||
protocol: 'http',
|
||||
port: 60197
|
||||
|
@@ -1,95 +0,0 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const pDefer = require('p-defer')
|
||||
const mergeOptions = require('merge-options')
|
||||
|
||||
const Floodsub = require('libp2p-floodsub')
|
||||
const Gossipsub = require('libp2p-gossipsub')
|
||||
const { multicodec: floodsubMulticodec } = require('libp2p-floodsub')
|
||||
const { multicodec: gossipsubMulticodec } = require('libp2p-gossipsub')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
|
||||
const { create } = require('../../src')
|
||||
const { baseOptions } = require('./utils')
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
|
||||
describe('Pubsub subsystem is able to use different implementations', () => {
|
||||
let peerId, remotePeerId
|
||||
let libp2p, remoteLibp2p
|
||||
|
||||
beforeEach(async () => {
|
||||
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
libp2p && libp2p.stop(),
|
||||
remoteLibp2p && remoteLibp2p.stop()
|
||||
]))
|
||||
|
||||
it('Floodsub nodes', () => {
|
||||
return pubsubTest(floodsubMulticodec, Floodsub)
|
||||
})
|
||||
|
||||
it('Gossipsub nodes', () => {
|
||||
return pubsubTest(gossipsubMulticodec, Gossipsub)
|
||||
})
|
||||
|
||||
const pubsubTest = async (multicodec, pubsub) => {
|
||||
const defer = pDefer()
|
||||
const topic = 'test-topic'
|
||||
const data = 'hey!'
|
||||
|
||||
libp2p = await create(mergeOptions(baseOptions, {
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [listenAddr]
|
||||
},
|
||||
modules: {
|
||||
pubsub: pubsub
|
||||
}
|
||||
}))
|
||||
|
||||
remoteLibp2p = await create(mergeOptions(baseOptions, {
|
||||
peerId: remotePeerId,
|
||||
addresses: {
|
||||
listen: [remoteListenAddr]
|
||||
},
|
||||
modules: {
|
||||
pubsub: pubsub
|
||||
}
|
||||
}))
|
||||
|
||||
await Promise.all([
|
||||
libp2p.start(),
|
||||
remoteLibp2p.start()
|
||||
])
|
||||
|
||||
const libp2pId = libp2p.peerId.toB58String()
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||
|
||||
const connection = await libp2p.dialProtocol(remotePeerId, multicodec)
|
||||
expect(connection).to.exist()
|
||||
|
||||
libp2p.pubsub.subscribe(topic, (msg) => {
|
||||
expect(uint8ArrayToString(msg.data)).to.equal(data)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
// wait for remoteLibp2p to know about libp2p subscription
|
||||
await pWaitFor(() => {
|
||||
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
|
||||
return subscribedPeers.includes(libp2pId)
|
||||
})
|
||||
|
||||
remoteLibp2p.pubsub.publish(topic, data)
|
||||
await defer.promise
|
||||
}
|
||||
})
|
@@ -1,326 +0,0 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const pDefer = require('p-defer')
|
||||
const mergeOptions = require('merge-options')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const { create } = require('../../src')
|
||||
const { subsystemOptions, subsystemMulticodecs } = require('./utils')
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
|
||||
describe('Pubsub subsystem operates correctly', () => {
|
||||
let peerId, remotePeerId
|
||||
let libp2p, remoteLibp2p
|
||||
|
||||
beforeEach(async () => {
|
||||
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
|
||||
})
|
||||
|
||||
describe('pubsub started before connect', () => {
|
||||
beforeEach(async () => {
|
||||
libp2p = await create(mergeOptions(subsystemOptions, {
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [listenAddr]
|
||||
}
|
||||
}))
|
||||
|
||||
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
|
||||
peerId: remotePeerId,
|
||||
addresses: {
|
||||
listen: [remoteListenAddr]
|
||||
}
|
||||
}))
|
||||
|
||||
await Promise.all([
|
||||
libp2p.start(),
|
||||
remoteLibp2p.start()
|
||||
])
|
||||
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
libp2p && libp2p.stop(),
|
||||
remoteLibp2p && remoteLibp2p.stop()
|
||||
]))
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
it('should get notified of connected peers on dial', async () => {
|
||||
const connection = await libp2p.dialProtocol(remotePeerId, subsystemMulticodecs)
|
||||
|
||||
expect(connection).to.exist()
|
||||
|
||||
return Promise.all([
|
||||
pWaitFor(() => libp2p.pubsub.peers.size === 1),
|
||||
pWaitFor(() => remoteLibp2p.pubsub.peers.size === 1)
|
||||
])
|
||||
})
|
||||
|
||||
it('should receive pubsub messages', async () => {
|
||||
const defer = pDefer()
|
||||
const topic = 'test-topic'
|
||||
const data = 'hey!'
|
||||
const libp2pId = libp2p.peerId.toB58String()
|
||||
|
||||
await libp2p.dialProtocol(remotePeerId, subsystemMulticodecs)
|
||||
|
||||
let subscribedTopics = libp2p.pubsub.getTopics()
|
||||
expect(subscribedTopics).to.not.include(topic)
|
||||
|
||||
libp2p.pubsub.subscribe(topic, (msg) => {
|
||||
expect(uint8ArrayToString(msg.data)).to.equal(data)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
subscribedTopics = libp2p.pubsub.getTopics()
|
||||
expect(subscribedTopics).to.include(topic)
|
||||
|
||||
// wait for remoteLibp2p to know about libp2p subscription
|
||||
await pWaitFor(() => {
|
||||
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
|
||||
return subscribedPeers.includes(libp2pId)
|
||||
})
|
||||
remoteLibp2p.pubsub.publish(topic, data)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('pubsub started after connect', () => {
|
||||
beforeEach(async () => {
|
||||
libp2p = await create(mergeOptions(subsystemOptions, {
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [listenAddr]
|
||||
}
|
||||
}))
|
||||
|
||||
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
|
||||
peerId: remotePeerId,
|
||||
addresses: {
|
||||
listen: [remoteListenAddr]
|
||||
},
|
||||
config: {
|
||||
pubsub: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
await libp2p.start()
|
||||
await remoteLibp2p.start()
|
||||
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
libp2p && libp2p.stop(),
|
||||
remoteLibp2p && remoteLibp2p.stop()
|
||||
]))
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
it('should get notified of connected peers after starting', async () => {
|
||||
const connection = await libp2p.dial(remotePeerId)
|
||||
|
||||
expect(connection).to.exist()
|
||||
expect(libp2p.pubsub.peers.size).to.be.eql(0)
|
||||
expect(remoteLibp2p.pubsub.peers.size).to.be.eql(0)
|
||||
|
||||
remoteLibp2p.pubsub.start()
|
||||
|
||||
return Promise.all([
|
||||
pWaitFor(() => libp2p.pubsub.peers.size === 1),
|
||||
pWaitFor(() => remoteLibp2p.pubsub.peers.size === 1)
|
||||
])
|
||||
})
|
||||
|
||||
it('should receive pubsub messages', async function () {
|
||||
this.timeout(10e3)
|
||||
const defer = pDefer()
|
||||
const libp2pId = libp2p.peerId.toB58String()
|
||||
const topic = 'test-topic'
|
||||
const data = 'hey!'
|
||||
|
||||
await libp2p.dial(remotePeerId)
|
||||
|
||||
remoteLibp2p.pubsub.start()
|
||||
|
||||
await Promise.all([
|
||||
pWaitFor(() => libp2p.pubsub.peers.size === 1),
|
||||
pWaitFor(() => remoteLibp2p.pubsub.peers.size === 1)
|
||||
])
|
||||
|
||||
let subscribedTopics = libp2p.pubsub.getTopics()
|
||||
expect(subscribedTopics).to.not.include(topic)
|
||||
|
||||
libp2p.pubsub.subscribe(topic, (msg) => {
|
||||
expect(uint8ArrayToString(msg.data)).to.equal(data)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
subscribedTopics = libp2p.pubsub.getTopics()
|
||||
expect(subscribedTopics).to.include(topic)
|
||||
|
||||
// wait for remoteLibp2p to know about libp2p subscription
|
||||
await pWaitFor(() => {
|
||||
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
|
||||
return subscribedPeers.includes(libp2pId)
|
||||
})
|
||||
|
||||
remoteLibp2p.pubsub.publish(topic, data)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('pubsub with intermittent connections', () => {
|
||||
beforeEach(async () => {
|
||||
libp2p = await create(mergeOptions(subsystemOptions, {
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [listenAddr]
|
||||
},
|
||||
config: {
|
||||
pubsub: {
|
||||
enabled: true,
|
||||
emitSelf: false
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
|
||||
peerId: remotePeerId,
|
||||
addresses: {
|
||||
listen: [remoteListenAddr]
|
||||
},
|
||||
config: {
|
||||
pubsub: {
|
||||
enabled: true,
|
||||
emitSelf: false
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
await libp2p.start()
|
||||
await remoteLibp2p.start()
|
||||
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
libp2p && libp2p.stop(),
|
||||
remoteLibp2p && remoteLibp2p.stop()
|
||||
]))
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
it('should receive pubsub messages after a node restart', async () => {
|
||||
const topic = 'test-topic'
|
||||
const data = 'hey!'
|
||||
const libp2pId = libp2p.peerId.toB58String()
|
||||
|
||||
let counter = 0
|
||||
const defer1 = pDefer()
|
||||
const defer2 = pDefer()
|
||||
const handler = (msg) => {
|
||||
expect(uint8ArrayToString(msg.data)).to.equal(data)
|
||||
counter++
|
||||
counter === 1 ? defer1.resolve() : defer2.resolve()
|
||||
}
|
||||
|
||||
await libp2p.dial(remotePeerId)
|
||||
|
||||
let subscribedTopics = libp2p.pubsub.getTopics()
|
||||
expect(subscribedTopics).to.not.include(topic)
|
||||
|
||||
libp2p.pubsub.subscribe(topic, handler)
|
||||
|
||||
subscribedTopics = libp2p.pubsub.getTopics()
|
||||
expect(subscribedTopics).to.include(topic)
|
||||
|
||||
// wait for remoteLibp2p to know about libp2p subscription
|
||||
await pWaitFor(() => {
|
||||
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
|
||||
return subscribedPeers.includes(libp2pId)
|
||||
})
|
||||
remoteLibp2p.pubsub.publish(topic, data)
|
||||
|
||||
await defer1.promise
|
||||
|
||||
await remoteLibp2p.stop()
|
||||
await remoteLibp2p.start()
|
||||
|
||||
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||
await libp2p.dial(remotePeerId)
|
||||
|
||||
// wait for remoteLibp2p to know about libp2p subscription
|
||||
await pWaitFor(() => {
|
||||
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
|
||||
return subscribedPeers.includes(libp2pId)
|
||||
})
|
||||
|
||||
remoteLibp2p.pubsub.publish(topic, data)
|
||||
|
||||
await defer2.promise
|
||||
})
|
||||
|
||||
it('should handle quick reconnects with a delayed disconnect', async () => {
|
||||
// Subscribe on both
|
||||
const handlerSpy = sinon.spy()
|
||||
const topic = 'reconnect-channel'
|
||||
await Promise.all([
|
||||
libp2p.pubsub.subscribe(topic, handlerSpy),
|
||||
remoteLibp2p.pubsub.subscribe(topic, handlerSpy)
|
||||
])
|
||||
// Create two connections to the remote peer
|
||||
const originalConnection = await libp2p.dialer.connectToPeer(remoteLibp2p.peerId)
|
||||
// second connection
|
||||
await libp2p.dialer.connectToPeer(remoteLibp2p.peerId)
|
||||
expect(libp2p.connections.get(remoteLibp2p.peerId.toB58String())).to.have.length(2)
|
||||
|
||||
// Wait for subscriptions to occur
|
||||
await pWaitFor(() => {
|
||||
return libp2p.pubsub.getSubscribers(topic).includes(remoteLibp2p.peerId.toB58String()) &&
|
||||
remoteLibp2p.pubsub.getSubscribers(topic).includes(libp2p.peerId.toB58String())
|
||||
})
|
||||
|
||||
// Verify messages go both ways
|
||||
libp2p.pubsub.publish(topic, 'message1')
|
||||
remoteLibp2p.pubsub.publish(topic, 'message2')
|
||||
await pWaitFor(() => handlerSpy.callCount === 2)
|
||||
expect(handlerSpy.args.map(([message]) => uint8ArrayToString(message.data))).to.include.members(['message1', 'message2'])
|
||||
|
||||
// Disconnect the first connection (this acts as a delayed reconnect)
|
||||
const libp2pConnUpdateSpy = sinon.spy(libp2p.connectionManager.connections, 'set')
|
||||
const remoteLibp2pConnUpdateSpy = sinon.spy(remoteLibp2p.connectionManager.connections, 'set')
|
||||
|
||||
await originalConnection.close()
|
||||
await pWaitFor(() => libp2pConnUpdateSpy.callCount === 1 && remoteLibp2pConnUpdateSpy.callCount === 1)
|
||||
|
||||
// Verify messages go both ways after the disconnect
|
||||
handlerSpy.resetHistory()
|
||||
libp2p.pubsub.publish(topic, 'message3')
|
||||
remoteLibp2p.pubsub.publish(topic, 'message4')
|
||||
await pWaitFor(() => handlerSpy.callCount === 2)
|
||||
expect(handlerSpy.args.map(([message]) => uint8ArrayToString(message.data))).to.include.members(['message3', 'message4'])
|
||||
})
|
||||
})
|
||||
})
|
@@ -1,29 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const Gossipsub = require('libp2p-gossipsub')
|
||||
const { multicodec } = require('libp2p-gossipsub')
|
||||
const Crypto = require('../../src/insecure/plaintext')
|
||||
const Muxer = require('libp2p-mplex')
|
||||
const Transport = require('libp2p-tcp')
|
||||
|
||||
const mergeOptions = require('merge-options')
|
||||
|
||||
const baseOptions = {
|
||||
modules: {
|
||||
transport: [Transport],
|
||||
streamMuxer: [Muxer],
|
||||
connEncryption: [Crypto]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.baseOptions = baseOptions
|
||||
|
||||
const subsystemOptions = mergeOptions(baseOptions, {
|
||||
modules: {
|
||||
pubsub: Gossipsub
|
||||
}
|
||||
})
|
||||
|
||||
module.exports.subsystemOptions = subsystemOptions
|
||||
|
||||
module.exports.subsystemMulticodecs = [multicodec]
|
@@ -3,7 +3,7 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
|
||||
const tests = require('libp2p-interfaces/src/record/tests')
|
||||
const tests = require('libp2p-interfaces-compliance-tests/src/record')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
|
@@ -515,7 +515,7 @@ describe('auto-relay', () => {
|
||||
|
||||
// Create 2 nodes, and turn HOP on for the relay
|
||||
;[local, remote, relayLibp2p] = peerIds.map((peerId, index) => {
|
||||
const delegate = new DelegatedContentRouter(peerId, ipfsHttpClient({
|
||||
const delegate = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
|
||||
host: '0.0.0.0',
|
||||
protocol: 'http',
|
||||
port: 60197
|
||||
|
@@ -52,7 +52,7 @@ describe('Dialing (via relay, TCP)', () => {
|
||||
await libp2p.stop()
|
||||
// Clear the peer stores
|
||||
for (const peerIdStr of libp2p.peerStore.peers.keys()) {
|
||||
const peerId = PeerId.createFromCID(peerIdStr)
|
||||
const peerId = PeerId.createFromB58String(peerIdStr)
|
||||
libp2p.peerStore.delete(peerId)
|
||||
}
|
||||
}))
|
||||
|
@@ -2,21 +2,21 @@
|
||||
"name": "ts-use",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"datastore-level": "^4.0.0",
|
||||
"ipfs-http-client": "^49.0.4",
|
||||
"datastore-level": "^6.0.0",
|
||||
"ipfs-http-client": "^50.1.2",
|
||||
"libp2p": "file:../..",
|
||||
"libp2p-bootstrap": "^0.12.2",
|
||||
"libp2p-delegated-content-routing": "^0.9.0",
|
||||
"libp2p-delegated-peer-routing": "^0.8.2",
|
||||
"libp2p-gossipsub": "^0.8.0",
|
||||
"libp2p-interfaces": "^0.10.1",
|
||||
"libp2p-kad-dht": "^0.21.0",
|
||||
"libp2p-mplex": "^0.10.2",
|
||||
"libp2p-noise": "^2.0.5",
|
||||
"libp2p-record": "^0.10.2",
|
||||
"libp2p-tcp": "^0.15.3",
|
||||
"libp2p-websockets": "^0.15.3",
|
||||
"peer-id": "^0.14.3"
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-delegated-content-routing": "^0.11.0",
|
||||
"libp2p-delegated-peer-routing": "^0.10.0",
|
||||
"libp2p-gossipsub": "^0.9.0",
|
||||
"libp2p-interfaces": "^1.0.1",
|
||||
"libp2p-kad-dht": "^0.23.1",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
"libp2p-record": "^0.10.4",
|
||||
"libp2p-tcp": "^0.17.1",
|
||||
"libp2p-websockets": "^0.16.1",
|
||||
"peer-id": "^0.15.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npx tsc",
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import Libp2p = require('libp2p')
|
||||
import Libp2pRecord = require('libp2p-record')
|
||||
import TCP = require('libp2p-tcp')
|
||||
|
||||
const TCP = require('libp2p-tcp')
|
||||
const WEBSOCKETS = require('libp2p-websockets')
|
||||
const NOISE = require('libp2p-noise')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
@@ -35,13 +35,13 @@ async function main() {
|
||||
// create a peerId
|
||||
const peerId = await PeerId.create()
|
||||
|
||||
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({
|
||||
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient.create({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
}))
|
||||
|
||||
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({
|
||||
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
|
Reference in New Issue
Block a user