mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-16 09:01:58 +00:00
Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b11126ca89 | ||
|
df53ab4e65 | ||
|
0701de40b1 | ||
|
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 | ||
|
d163ffd224 | ||
|
b29d6c9304 | ||
|
890dd05941 | ||
|
a79c6b50d7 | ||
|
d372a68692 | ||
|
4e3fc19623 | ||
|
2fa82b387c | ||
|
8fc6f8af81 | ||
|
924585b143 | ||
|
556f0203db | ||
|
b5a9eb2087 | ||
|
e5187d02ba | ||
|
150e4f97c1 | ||
|
302bb90058 | ||
|
f860ffb3e7 | ||
|
2572f3e034 |
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: libp2p Official Forum
|
||||
url: https://discuss.libp2p.io
|
||||
about: For general questions, support requests and discussions
|
55
.github/ISSUE_TEMPLATE/open_an_issue.md
vendored
Normal file
55
.github/ISSUE_TEMPLATE/open_an_issue.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: Open an issue
|
||||
about: For reporting bugs or errors in the JavaScript libp2p implementation
|
||||
title: ''
|
||||
labels: need/triage
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for reporting an issue.
|
||||
|
||||
This issue tracker is for bugs found within the JavaScript implementation of libp2p.
|
||||
|
||||
If you are asking a question about how to use libp2p, please ask on https://discuss.libp2p.io
|
||||
|
||||
Otherwise please fill in as much of the template below as possible.
|
||||
-->
|
||||
|
||||
- **Version**:
|
||||
<!--
|
||||
Check package.json version
|
||||
-->
|
||||
|
||||
- **Platform**:
|
||||
<!--
|
||||
Output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows). If using in a Browser, please share the browser version as well
|
||||
-->
|
||||
|
||||
- **Subsystem**:
|
||||
<!--
|
||||
If known, please specify affected core module name (e.g Dialer, Pubsub, Relay etc)
|
||||
-->
|
||||
|
||||
#### Severity:
|
||||
<!--
|
||||
One of following:
|
||||
Critical - System crash, application panic.
|
||||
High - The main functionality of the application does not work, API breakage, repo format breakage, etc.
|
||||
Medium - A non-essential functionality does not work, performance issues, etc.
|
||||
Low - An optional functionality does not work.
|
||||
Very Low - Translation or documentation mistake. Something that won't give anyone a bad day.
|
||||
-->
|
||||
|
||||
#### Description:
|
||||
<!--
|
||||
- What you did
|
||||
- What happened
|
||||
- What you expected to happen
|
||||
-->
|
||||
|
||||
#### Steps to reproduce the error:
|
||||
<!--
|
||||
If possible, please provide code that demonstrates the problem, keeping it as simple and free of external dependencies as you are able
|
||||
-->
|
||||
|
@@ -25,7 +25,6 @@
|
||||
- [ ] [js-ipfs](https://github.com/ipfs/js-ipfs)
|
||||
- Documentation
|
||||
- [ ] Ensure that README.md is up to date
|
||||
- [ ] Ensure [libp2p/js-libp2p-examples](https://github.com/libp2p/js-libp2p-examples) is updated
|
||||
- [ ] Ensure that [libp2p/docs](https://github.com/libp2p/docs) is updated
|
||||
- Communication
|
||||
- [ ] Create the release issue
|
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
|
||||
|
93
CHANGELOG.md
93
CHANGELOG.md
@@ -1,3 +1,96 @@
|
||||
## [0.32.1](https://github.com/libp2p/js-libp2p/compare/v0.32.0...v0.32.1) (2021-07-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* turn compliance tests into devDependency ([#960](https://github.com/libp2p/js-libp2p/issues/960)) ([0701de4](https://github.com/libp2p/js-libp2p/commit/0701de40b1ebdf319959846d8c4fdd30b3cf34a4))
|
||||
|
||||
|
||||
|
||||
# [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* peerRouting.findPeer() trying to find self ([#941](https://github.com/libp2p/js-libp2p/issues/941)) ([a79c6b5](https://github.com/libp2p/js-libp2p/commit/a79c6b50d7fddbcdb1af53efae922cecad4c9a83))
|
||||
|
||||
|
||||
|
||||
## [0.31.3](https://github.com/libp2p/js-libp2p/compare/v0.31.2...v0.31.3) (2021-05-04)
|
||||
|
||||
|
||||
|
||||
## [0.31.2](https://github.com/libp2p/js-libp2p/compare/v0.31.1...v0.31.2) (2021-04-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* moving averages record types ([#935](https://github.com/libp2p/js-libp2p/issues/935)) ([b5a9eb2](https://github.com/libp2p/js-libp2p/commit/b5a9eb208763efa027d0b4caae87c515b6f5869b))
|
||||
|
||||
|
||||
|
||||
## [0.31.1](https://github.com/libp2p/js-libp2p/compare/v0.31.0...v0.31.1) (2021-04-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* event emitter and interfaces types for discovery and routing ([#934](https://github.com/libp2p/js-libp2p/issues/934)) ([302bb90](https://github.com/libp2p/js-libp2p/commit/302bb9005891aa06b70a5f354bfac6b2d5a3c3b8))
|
||||
|
||||
|
||||
|
||||
# [0.31.0](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.7...v0.31.0) (2021-04-28)
|
||||
|
||||
|
||||
|
@@ -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
|
||||
@@ -515,7 +515,7 @@ const node = await Libp2p.create({
|
||||
}
|
||||
})
|
||||
|
||||
await libp2p.loadKeychain()
|
||||
await node.loadKeychain()
|
||||
```
|
||||
|
||||
#### Configuring Dialing
|
||||
@@ -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: {
|
||||
|
123
doc/migrations/v0.30-v0.31.md
Normal file
123
doc/migrations/v0.30-v0.31.md
Normal file
@@ -0,0 +1,123 @@
|
||||
<!--Specify versions for migration below-->
|
||||
# Migrating to libp2p@31
|
||||
|
||||
A migration guide for refactoring your application code from libp2p v0.30.x to v0.31.0.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Types](#types)
|
||||
- [API](#api)
|
||||
- [Module Updates](#module-updates)
|
||||
|
||||
## Types
|
||||
|
||||
Most of the type definitions in the libp2p configuration were `any` or were not included before this release. This might cause breaking changes on upstream projects relying on the previous provided types, as well as to libp2p modules implemented by the libp2p community.
|
||||
|
||||
## API
|
||||
|
||||
### Core API
|
||||
|
||||
`libp2p.dialProtocol` does not accept empty or null protocols returning a connection anymore and `dial` must be used instead.
|
||||
|
||||
```js
|
||||
const connection = await libp2p.dialProtocol(peerId)
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
const connection = await libp2p.dial(peerId)
|
||||
```
|
||||
|
||||
### Connection Manager Options
|
||||
|
||||
We updated the connection manager options naming in `libp2p@0.29` but kept it backward compatible until now.
|
||||
|
||||
**Before**
|
||||
|
||||
```js
|
||||
const node = await Libp2p.create({
|
||||
connectionManager: {
|
||||
minPeers: 0
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
const node = await Libp2p.create({
|
||||
connectionManager: {
|
||||
minConnections: 0
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You can see full details on how to configure the connection manager [here](https://github.com/libp2p/js-libp2p/blob/master/doc/CONFIGURATION.md#configuring-connection-manager).
|
||||
|
||||
### Dialer and Keychain components
|
||||
|
||||
Internal property names to create a libp2p `Dialer` and `Keychain` were updated to reflect the properties naming in the libp2p configuration. These are internal modules of libp2p core and should not impact most of the users, but as it is possible to use them separately here follow the changes:
|
||||
|
||||
***Before**
|
||||
|
||||
```js
|
||||
const dialer = new Dialer({
|
||||
transportManager,
|
||||
peerStore,
|
||||
concurrency,
|
||||
perPeerLimit,
|
||||
timeout,
|
||||
resolvers,
|
||||
addressSorter
|
||||
})
|
||||
|
||||
const keychain = new Keychain(datastore, {
|
||||
passPhrase
|
||||
})
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
this.dialer = new Dialer({
|
||||
transportManager,
|
||||
peerStore,
|
||||
maxParallelDials,
|
||||
maxDialsPerPeer,
|
||||
dialTimeout,
|
||||
resolvers,
|
||||
addressSorter
|
||||
})
|
||||
|
||||
const keychain = new Keychain(datastore, {
|
||||
pass
|
||||
})
|
||||
```
|
||||
|
||||
## 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.12.3",
|
||||
"libp2p-crypto": "^0.19.4",
|
||||
"libp2p-interfaces": "^0.10.0",
|
||||
"libp2p-delegated-content-routing": "^0.10.0",
|
||||
"libp2p-delegated-peer-routing": "^0.9.0",
|
||||
"libp2p-floodsub": "^0.25.1",
|
||||
"libp2p-gossipsub": "^0.9.0",
|
||||
"libp2p-kad-dht": "^0.22.0",
|
||||
"libp2p-mdns": "^0.16.0",
|
||||
"libp2p-noise": "^3.0.0",
|
||||
"libp2p-tcp": "^0.15.4",
|
||||
"libp2p-webrtc-star": "^0.22.2",
|
||||
"libp2p-websockets": "^0.15.6"
|
||||
```
|
||||
|
||||
One of the main changes in this new release is the update to `multiaddr@9.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.
|
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"
|
||||
|
106
package.json
106
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.31.0",
|
||||
"version": "0.32.1",
|
||||
"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": "^6.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,16 @@
|
||||
"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",
|
||||
"libp2p-crypto": "^0.19.0",
|
||||
"libp2p-interfaces": "^0.10.3",
|
||||
"libp2p-utils": "^0.3.1",
|
||||
"mafmt": "^9.0.0",
|
||||
"it-take": "^1.0.0",
|
||||
"libp2p-crypto": "^0.19.4",
|
||||
"libp2p-interfaces": "^1.0.0",
|
||||
"libp2p-utils": "^0.4.0",
|
||||
"mafmt": "^10.0.0",
|
||||
"merge-options": "^3.0.4",
|
||||
"moving-average": "^1.0.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 +116,61 @@
|
||||
"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.8.0",
|
||||
"libp2p-kad-dht": "^0.21.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-interfaces-compliance-tests": "^1.0.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.1",
|
||||
"libp2p-webrtc-star": "^0.22.0",
|
||||
"libp2p-websockets": "^0.15.0",
|
||||
"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>",
|
||||
@@ -179,20 +179,25 @@
|
||||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||
"Maciej Krüger <mkg20001@gmail.com>",
|
||||
"Hugo Dias <mail@hugodias.me>",
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"Volker Mische <volker.mische@gmail.com>",
|
||||
"Chris Dostert <chrisdostert@users.noreply.github.com>",
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"zeim839 <50573884+zeim839@users.noreply.github.com>",
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"a1300 <matthias-knopp@gmx.net>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"Samlior <samlior@foxmail.com>",
|
||||
"Ryan Bell <ryan@piing.net>",
|
||||
"a1300 <matthias-knopp@gmx.net>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"Samlior <samlior@foxmail.com>",
|
||||
"Franck Royer <franck@royer.one>",
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"acolytec3 <17355484+acolytec3@users.noreply.github.com>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||
"Didrik Nordström <didrik.nordstrom@gmail.com>",
|
||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||
"Philipp Muens <raute1337@gmx.de>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"Robert Kiel <robert.kiel@hoprnet.org>",
|
||||
"Aditya Bose <13054902+adbose@users.noreply.github.com>",
|
||||
"Smite Chow <xiaopengyou@live.com>",
|
||||
"Soeren <nikorpoulsen@gmail.com>",
|
||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||
@@ -202,8 +207,12 @@
|
||||
"Zane Starr <zcstarr@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>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"shresthagrawal <34920931+shresthagrawal@users.noreply.github.com>",
|
||||
"swedneck <40505480+swedneck@users.noreply.github.com>",
|
||||
"Aleksei <vozhdb@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
@@ -216,13 +225,20 @@
|
||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||
"Francis Gulotta <wizard@roborooter.com>",
|
||||
"Franck Royer <franck@royer.one>",
|
||||
"Guy Sviry <32539816+guysv@users.noreply.github.com>",
|
||||
"Henrique Dias <hacdias@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>",
|
||||
"Miguel Mota <miguelmota2@gmail.com>"
|
||||
"Lars Gierth <lgierth@users.noreply.github.com>",
|
||||
"Marcin Tojek <mtojek@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>"
|
||||
]
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ const LatencyMonitor = require('./latency-monitor')
|
||||
// @ts-ignore retimer does not have types
|
||||
const retimer = require('retimer')
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
@@ -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()
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* This code is based on `latency-monitor` (https://github.com/mlucool/latency-monitor) by `mlucool` (https://github.com/mlucool), available under Apache License 2.0 (https://github.com/mlucool/latency-monitor/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
const VisibilityChangeEmitter = require('./visibility-change-emitter')
|
||||
const debug = require('debug')('latency-monitor:LatencyMonitor')
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const debug = require('debug')('latency-monitor:VisibilityChangeEmitter')
|
||||
|
||||
|
@@ -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,8 +15,8 @@ const { pipe } = require('it-pipe')
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||
* @typedef {import('cids')} CID
|
||||
* @typedef {import('libp2p-interfaces/src/content-routing/types')} ContentRoutingModule
|
||||
* @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)
|
||||
|
12
src/index.js
12
src/index.js
@@ -4,7 +4,7 @@ const debug = require('debug')
|
||||
const log = Object.assign(debug('libp2p'), {
|
||||
error: debug('libp2p:err')
|
||||
})
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const errCode = require('err-code')
|
||||
const PeerId = require('peer-id')
|
||||
@@ -40,9 +40,9 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
|
||||
* @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory<any, any>} TransportFactory
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxerFactory} MuxerFactory
|
||||
* @typedef {import('libp2p-interfaces/src/content-routing/types')} ContentRoutingModule
|
||||
* @typedef {import('libp2p-interfaces/src/peer-discovery/types')} PeerDiscoveryModule
|
||||
* @typedef {import('libp2p-interfaces/src/peer-routing/types')} PeerRoutingModule
|
||||
* @typedef {import('libp2p-interfaces/src/content-routing/types').ContentRouting} ContentRoutingModule
|
||||
* @typedef {import('libp2p-interfaces/src/peer-discovery/types').PeerDiscoveryFactory} PeerDiscoveryFactory
|
||||
* @typedef {import('libp2p-interfaces/src/peer-routing/types').PeerRouting} PeerRoutingModule
|
||||
* @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto
|
||||
* @typedef {import('libp2p-interfaces/src/pubsub')} Pubsub
|
||||
* @typedef {import('libp2p-interfaces/src/pubsub').PubsubOptions} PubsubOptions
|
||||
@@ -100,7 +100,7 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
* @property {TransportFactory[]} transport
|
||||
* @property {MuxerFactory[]} streamMuxer
|
||||
* @property {Crypto[]} connEncryption
|
||||
* @property {PeerDiscoveryModule[]} [peerDiscovery]
|
||||
* @property {PeerDiscoveryFactory[]} [peerDiscovery]
|
||||
* @property {PeerRoutingModule[]} [peerRouting]
|
||||
* @property {ContentRoutingModule[]} [contentRouting]
|
||||
* @property {Object} [dht]
|
||||
@@ -714,7 +714,7 @@ class Libp2p extends EventEmitter {
|
||||
*/
|
||||
async _setupPeerDiscovery () {
|
||||
/**
|
||||
* @param {PeerDiscoveryModule} DiscoveryService
|
||||
* @param {PeerDiscoveryFactory} DiscoveryService
|
||||
*/
|
||||
const setupService = (DiscoveryService) => {
|
||||
let config = {
|
||||
|
@@ -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
|
||||
|
@@ -1,11 +1,15 @@
|
||||
// @ts-nocheck
|
||||
'use strict'
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
const { BigNumber: Big } = require('bignumber.js')
|
||||
const MovingAverage = require('moving-average')
|
||||
const MovingAverage = require('@vascosantos/moving-average')
|
||||
const retimer = require('retimer')
|
||||
|
||||
/**
|
||||
* @typedef {import('@vascosantos/moving-average').IMovingAverage} IMovingAverage
|
||||
*/
|
||||
|
||||
class Stats extends EventEmitter {
|
||||
/**
|
||||
* A queue based manager for stat processing
|
||||
@@ -29,7 +33,7 @@ class Stats extends EventEmitter {
|
||||
this._frequencyLastTime = Date.now()
|
||||
this._frequencyAccumulators = {}
|
||||
|
||||
/** @type {{ dataReceived: MovingAverage[], dataSent: MovingAverage[] }} */
|
||||
/** @type {{ dataReceived: IMovingAverage[], dataSent: IMovingAverage[] }} */
|
||||
this._movingAverages = {}
|
||||
|
||||
this._update = this._update.bind(this)
|
||||
|
@@ -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')
|
||||
|
@@ -25,7 +25,7 @@ const {
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||
* @typedef {import('libp2p-interfaces/src/peer-routing/types')} PeerRoutingModule
|
||||
* @typedef {import('libp2p-interfaces/src/peer-routing/types').PeerRouting} PeerRoutingModule
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -104,6 +104,10 @@ class PeerRouting {
|
||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||
}
|
||||
|
||||
if (id.toB58String() === this._peerId.toB58String()) {
|
||||
throw errCode(new Error('Should not try to find self'), 'ERR_FIND_SELF')
|
||||
}
|
||||
|
||||
const output = await pipe(
|
||||
merge(
|
||||
...this._routers.map(router => [router.findPeer(id, options)])
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
const errcode = require('err-code')
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const AddressBook = require('./address-book')
|
||||
@@ -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
|
||||
|
@@ -137,7 +137,12 @@ class Upgrader {
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
async upgradeOutbound (maConn) {
|
||||
const remotePeerId = PeerId.createFromB58String(maConn.remoteAddr.getPeerId())
|
||||
const idStr = maConn.remoteAddr.getPeerId()
|
||||
if (!idStr) {
|
||||
throw errCode(new Error('outbound connection must have a peer id'), codes.ERR_INVALID_MULTIADDR)
|
||||
}
|
||||
|
||||
const remotePeerId = PeerId.createFromB58String(idStr)
|
||||
|
||||
let encryptedConn
|
||||
let remotePeer
|
||||
|
@@ -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())
|
||||
})
|
||||
|
||||
|
@@ -100,6 +100,12 @@ describe('peer-routing', () => {
|
||||
|
||||
return deferred.promise
|
||||
})
|
||||
|
||||
it('should error when peer tries to find itself', async () => {
|
||||
await expect(nodes[0].peerRouting.findPeer(nodes[0].peerId))
|
||||
.to.eventually.be.rejected()
|
||||
.and.to.have.property('code', 'ERR_FIND_SELF')
|
||||
})
|
||||
})
|
||||
|
||||
describe('via delegate router', () => {
|
||||
@@ -107,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
|
||||
@@ -187,6 +193,12 @@ describe('peer-routing', () => {
|
||||
expect(mockApi.isDone()).to.equal(true)
|
||||
})
|
||||
|
||||
it('should error when peer tries to find itself', async () => {
|
||||
await expect(node.peerRouting.findPeer(node.peerId))
|
||||
.to.eventually.be.rejected()
|
||||
.and.to.have.property('code', 'ERR_FIND_SELF')
|
||||
})
|
||||
|
||||
it('should error when a peer cannot be found', async () => {
|
||||
const peerKey = 'key of a peer not on the network'
|
||||
const mockApi = nock('http://0.0.0.0:60197')
|
||||
@@ -276,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