Compare commits

..

92 Commits

Author SHA1 Message Date
Jacob Heun
7e1a9d677b test(fix): fix listening test for ci 2020-01-24 14:31:38 +01:00
Jacob Heun
1ba1ca7714 chore: release version v0.27.0-rc.0 2020-01-24 11:55:59 +01:00
Jacob Heun
691e9b7f7b chore: update contributors 2020-01-24 11:55:59 +01:00
Vasco Santos
751a22741f refactor: examples-browser (#508)
* refactor: examples-browser

* chore: add information to use signalling server

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: update deps

* docs: refactor libp2p browser example

* docs(examples): add back websockets and boostrap nodes

docs(examples): redo the browser readme

* fix: handle edge case of connections closing early

* chore: fix lint

* chore: update example deps and readme

* chore: update webrtc-star

* chore: apply suggestions from code review

Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Alan Shaw <alan.shaw@protocol.ai>
2020-01-24 11:43:56 +01:00
Vasco Santos
461faca1ca docs: getting started (#514)
* docs: getting started

* docs: review getting started (#520)

* doc: initial review of getting started

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>

* chore: move multiplexing to basic setup

* chore: add read more cta

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: just configure multiplexer

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: just use websockets and changed dht module introduction

* chore: add reference for events in the API doc

* docs: simplify getting started guide and clean up language

* chore: apply suggestions from code review

Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>

* docs(fix): address review comments

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Alan Shaw <alan.shaw@protocol.ai>
2020-01-23 17:12:41 +01:00
Jacob Heun
31d1b2369a fix: use toB58String everywhere to be consistent (#537)
* chore: update deps

* fix: consistently use b58 peerid string

The migration to base32 will happen at a later date
2020-01-22 11:47:30 +01:00
Vasco Santos
83409deaa6 fix: registrar should filter the disconnected conn (#532)
* fix: registrar on disconnect only when no connections

* chore: add test
2020-01-14 12:26:24 +01:00
Alan Shaw
c44e6e33ed fix: stop discoveries (#530)
* fix: stop discoveries

* test: add discovery stop test

* chore: fix lint

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-07 16:27:32 +01:00
Jacob Heun
999d086278 chore: release version v0.27.0-pre.2 2020-01-07 15:31:13 +01:00
Jacob Heun
122a114d96 chore: update contributors 2020-01-07 15:30:59 +01:00
Vasco Santos
21362b5cbe refactor: examples transports (#503)
* refactor: examples-transports

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: address review

* chore: address review

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-07 14:56:05 +01:00
Vasco Santos
0840739a00 refactor: examples/pnet (#523)
* refactor: examples/pnet

* chore: rename pnet-ipfs to pnet

* chore: address review
2020-01-07 14:53:27 +01:00
Vasco Santos
f182f5bcd9 refactor: examples/discovery-mechanisms (#498)
* refactor: examples-discovery-mechanisms

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: suggestion interval

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: add peer connected event

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-06 10:01:28 -07:00
Alan Shaw
a1717dac6a fix: conn mngr min/max connection values (#528)
Fixes the case when options are passed with `maxConnections` and/or `minConnections` set to `undefined`:

```console
{
  defaultOptions: {
    maxConnections: Infinity,
    minConnections: 0,
    maxData: Infinity,
    maxSentData: Infinity,
    maxReceivedData: Infinity,
    maxEventLoopDelay: Infinity,
    pollInterval: 2000,
    movingAverageInterval: 60000,
    defaultPeerValue: 1
  },
  options: {
    minPeers: 25,
    maxConnections: undefined,
    minConnections: undefined
  }
}
{ maxConnections: undefined, minConnections: undefined }
      1) "before all" hook in "custom config"
(node:67176) UnhandledPromiseRejectionWarning: AssertionError [ERR_ASSERTION]: Connection Manager maxConnections must be greater than minConnections
    at new ConnectionManager (node_modules/libp2p/src/connection-manager/index.js:43:5)
    at new Libp2p (node_modules/libp2p/src/index.js:92:30)
    at Object.module.exports [as libp2p] (src/core/components/libp2p.js:27:10)
    at Proxy.start (src/core/components/start.js:48:31)
    at async Daemon.start (src/cli/daemon.js:63:31)
    at async startHttpAPI (test/http-api/routes.js:29:5)
    at async Context.<anonymous> (test/http-api/routes.js:48:7)
```
2020-01-06 07:03:07 -07:00
Vasco Santos
dec8dc450f refactor: examples/protocol-and-stream-muxing (#502) 2020-01-02 21:51:02 +01:00
Jacob Heun
0d4b2bd23d feat: allow transport options to be passed on creation (#524)
* feat: allow transport options to be passed on creation

* fix: only add circuit transport if enabled

* chore: fix lint
2019-12-20 08:32:46 -08:00
Vasco Santos
fdb48c8df5 refactor: examples/peer-and-content-routing (#500)
* refactor: examples-peer-and-content-routing

* chore: address review

* chore: review suggestions

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2019-12-18 03:37:36 +01:00
Vasco Santos
506af15b6b refactor: examples/encrypted-communications (#499)
* refactor: examples/encrypted-communications

* chore: address review
2019-12-18 03:35:49 +01:00
Vasco Santos
9f0f08f586 refactor: examples-pubsub (#504) 2019-12-16 23:28:35 +01:00
Jacob Heun
6ca19c5ef4 feat: add libp2p.connections getter (#522)
* fix: make hangup accept what the API says it does

* feat: add libp2p.connections getter

* chore: fix typo
2019-12-16 19:24:35 +01:00
Jacob Heun
24c3ce6f8d fix: make dialer configurable (#521)
docs: update configuration and api docs
2019-12-16 16:49:29 +01:00
Vasco Santos
56a1825639 fix: upgrader should not need muxers (#517)
* fix: upgrader should not need muxers

* chore: address review

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2019-12-16 12:26:38 +01:00
Jacob Heun
92ed56657c chore: release version v0.27.0-pre.1 2019-12-15 17:36:47 +01:00
Jacob Heun
9900beb243 chore: update contributors 2019-12-15 17:36:46 +01:00
Jacob Heun
4a871bbf8b feat: coalescing dial support (#518)
* docs: fix spelling in api

* fix: dont create peerstore twice

* feat: add support for dial coalescing

* doc(fix): add setPeerValue to API TOC

* docs: add more jsdocs to dialer

* chore: remove old comment

* fix: ensure connections are closed

* fix: registrar.getConnections returns first open conn

* fix: directly set the closed status

* chore: remove unneeded log

* refactor: peerStore.put takes an options object
2019-12-15 17:33:16 +01:00
Alan Shaw
a39889c4ea docs: add ToC link to pubsub.unsubscribe 2019-12-13 10:50:06 +01:00
Alan Shaw
9bbe93c772 docs: fix the ToC links (#515) 2019-12-12 18:40:40 +01:00
Vasco Santos
cc65a4b06f chore: update readme (#513) 2019-12-12 13:08:06 +01:00
Jacob Heun
9c884a72b0 chore: release version v0.27.0-pre.0 2019-12-12 10:43:18 +01:00
Jacob Heun
3ee1e22242 chore: update contributors 2019-12-12 10:43:17 +01:00
Jacob Heun
45f47023d2 refactor: connection manager (#511)
* refactor: initial refactor of the connection manager

* fix: start/stop issues

* fix: add tests and resolve pruning issues

* chore: fix lint

* test: move conn manager tests to node only for now

* chore: apply suggestions from code review

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>

* fix: assert min max connection options

* test: fix assertion check for browser

* docs: add api and config docs for conn manager
2019-12-12 10:29:10 +01:00
Vasco Santos
af96dcc499 feat: discovery modules from transports should be added (#510)
* feat: discovery modules from transports should be added

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: address review

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2019-12-12 10:29:10 +01:00
Jacob Heun
f540112835 refactor: stats (#501)
* docs: add initial notes on stats

* feat: initial refactor of stats to metrics

* feat: add support for placeholder metrics

This is helpful for tracking metrics prior to knowing the remote peers id

* fix: add metrics tests and fix issues

* fix: always clear the dial timeout timer

* docs: add metrics to api doc

* chore: apply suggestions from code review

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>

* docs: update metrics docs

* fix: call metrics.onDisconnect

* docs(config): add example headers so they appear in the TOC

* docs(config): add metrics configuration

* docs(relay): fix relay configuration docs
2019-12-12 10:29:10 +01:00
Vasco Santos
3d30cb18cd docs: config (#495)
* docs: new api

* chore: new iteration

* chore: apply suggestions from code review

Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: address review

* docs: add events

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* docs: configuration

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: update peer routing description

Co-Authored-By: Yusef Napora <yusef@protocol.ai>

* chore: decouple examples

* chore: address pr comment

* fix: connection encryption is required

* chore: apply review suggestion

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2019-12-12 10:29:10 +01:00
Vasco Santos
64cbf90e02 refactor: ping (#505)
* refactor: ping

* chore: ping is now a function

* chore: address review
2019-12-12 10:29:10 +01:00
Jacob Heun
7fc1900343 chore: it-all over async-iterator-all 2019-12-12 10:29:09 +01:00
Jacob Heun
ad15d4ed09 chore: add bundlesize check back to ci 2019-12-12 10:29:09 +01:00
Jacob Heun
600f761009 chore: remove uneeded dep check exclusions 2019-12-12 10:29:09 +01:00
Jacob Heun
a2f31d99d2 chore: disable pull dep check until ping is refactored 2019-12-12 10:29:09 +01:00
Jacob Heun
edaa67dfd0 chore: remove unused packages 2019-12-12 10:29:09 +01:00
Jacob Heun
9b10e09cc0 chore: move stats folder and delete old switch code 2019-12-12 10:29:09 +01:00
Vasco Santos
8c6ad79630 docs: new api (#472)
* docs: new api

* chore: new iteration

* chore: apply suggestions from code review

Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: address review

* docs: add events

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2019-12-12 10:29:08 +01:00
Jacob Heun
1838a641d9 fix: token release logic 2019-12-12 10:29:08 +01:00
Jacob Heun
3cadeb39cb test: bump delay for ci 2019-12-12 10:29:08 +01:00
Jacob Heun
43440aa8a6 fix: release tokens as soon as they are available 2019-12-12 10:29:08 +01:00
Jacob Heun
7c3371bf17 fix: clean up pending dials abort per feedback 2019-12-12 10:29:08 +01:00
Jacob Heun
43b98e64b6 docs: add DialRequest description 2019-12-12 10:29:07 +01:00
Jacob Heun
962081f448 test: remove timeout 2019-12-12 10:29:07 +01:00
Jacob Heun
754fbc2d0b feat: abort all pending dials on stop 2019-12-12 10:29:07 +01:00
Jacob Heun
0a8f9f3238 test: reduce randomwalk timeout 2019-12-12 10:29:07 +01:00
Jacob Heun
3b52236dee chore: fix lint
test: reduce interval of randomwalk in test

chore(test): glob fix
2019-12-12 10:29:07 +01:00
Jacob Heun
c7dcfe5e48 test: add tests for DialRequest 2019-12-12 10:29:06 +01:00
Jacob Heun
3b06283ad8 test(fix): fix support for it.only, it.skip, etc 2019-12-12 10:29:06 +01:00
Jacob Heun
74bfe6bea5 docs(release): point to libp2p weekly sync 2019-12-12 10:29:06 +01:00
Jacob Heun
53ce404260 chore: update per feedback 2019-12-12 10:29:06 +01:00
Jacob Heun
43a3b85f1a refactor: cleanup and reorganize 2019-12-12 10:29:06 +01:00
Jacob Heun
e8bf12b68a chore: update docs
fix: protect against duplicate token releases
2019-12-12 10:29:05 +01:00
Jacob Heun
7d1cb5423f chore: fix linting 2019-12-12 10:29:05 +01:00
Jacob Heun
c4be5f4aaf refactor: consolidation multiaddr dial methods 2019-12-12 10:29:05 +01:00
Jacob Heun
a37c5c0144 refactor: clean up dial timeout abort 2019-12-12 10:29:05 +01:00
Jacob Heun
24c603741f feat: add early token recycling in 2019-12-12 10:29:05 +01:00
Jacob Heun
ea62c52701 refactor: simplify DialRequest logic per feedback 2019-12-12 10:29:04 +01:00
Jacob Heun
f9fe44f6b7 chore: use any-signal module 2019-12-12 10:29:04 +01:00
Jacob Heun
d5405dbb08 refactor: PER_PEER_LIMIT is now MAX_PER_PEER_DIALS 2019-12-12 10:29:04 +01:00
Jacob Heun
571fd3b7d1 chore: apply suggestions from code review
Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>
Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>
2019-12-12 10:29:04 +01:00
Jacob Heun
cba2c6d8b2 chore: remove commented code 2019-12-12 10:29:04 +01:00
Jacob Heun
f8540fa3ed feat: add token based dialer 2019-12-12 10:29:03 +01:00
Jacob Heun
0cacfe29a5 doc: add initial dialer readme 2019-12-12 10:29:03 +01:00
Jacob Heun
c4bc00be9c fix: correct release readme 2019-12-12 10:29:03 +01:00
Jacob Heun
f3eb1f1201 fix: clean up peer discovery flow (#494)
* fix: clean up peer discovery flow

* test(fix): let libp2p start after connecting

* test(fix): dont auto dial in disco tests
2019-12-12 10:29:03 +01:00
Vasco Santos
dbb9e57311 chore: update pubsub implementations (#493) 2019-12-12 10:29:03 +01:00
Vasco Santos
11ed6bd14c feat: support peer-id instances in peer store operations (#491) 2019-12-12 10:29:02 +01:00
Vasco Santos
fc22c36ba7 refactor: async routing (#489)
* feat: async routing

* chore: put dht extra api commands under content routing

* chore: add default option to createPeerInfo

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: address review

* chore: rm dlv
2019-12-12 10:29:02 +01:00
Jacob Heun
b518391a47 refactor: circuit relay to async (#477)
* refactor: add dialing over relay support

* chore: fix lint

* fix: dont clear listeners on close

* fix: if dial errors already have codes, just rethrow them

* fix: clear the registrar when libp2p stops

* fix: improve connection maintenance with circuit

* chore: correct feedback

* test: use chai as promised

* test(fix): reset multiaddrs on dial test
2019-12-12 10:29:02 +01:00
Vasco Santos
997ee166b0 feat: discovery modules (#486)
* feat: discovery modules

* chore: address review
2019-12-12 10:29:02 +01:00
dirkmc
acbbc0f84e fix: replace peerInfo addresses with listen addresses (#485)
* feat: replace peer info addresses with listen addresses

* test: add listening test

* chore: fix linting
2019-12-12 10:29:02 +01:00
dirkmc
995640ee2f refactor(docs): async await version of examples/chat (#482)
* fix: performance bottleneck in stat.js (#463)

Array.shift seems to be very slow, perhaps linear, on some
engines, resulting in  _update consuming a lot of CPU.

* docs(fix): correct docs and example for pnet (#464)

* docs(fix): correct docs and example for pnet

* docs(fix): correct pnet docs

* docs(fix): update README.md language (#468)

* docs: reciprocate (#474)

* docs(example): fix ipfs cat (#475)

`ipfs.files.cat` is incorrect. the correct function is `ipfs.cat`

* fix: async-await example chat

* fix: move handler before start

* fix: examples readme typos (#481)

* fix: simplify libp2p bundle for echo example

* chore: remove unused vars
2019-12-12 10:29:01 +01:00
dirkmc
b316cdd19b refactor(docs): async await version of examples/echo (#483)
* fix: performance bottleneck in stat.js (#463)

Array.shift seems to be very slow, perhaps linear, on some
engines, resulting in  _update consuming a lot of CPU.

* docs(fix): correct docs and example for pnet (#464)

* docs(fix): correct docs and example for pnet

* docs(fix): correct pnet docs

* docs(fix): update README.md language (#468)

* docs: reciprocate (#474)

* docs(example): fix ipfs cat (#475)

`ipfs.files.cat` is incorrect. the correct function is `ipfs.cat`

* fix: async await examples/echo

* fix: examples readme typos (#481)

* fix: simplify libp2p bundle for echo example
2019-12-12 10:29:01 +01:00
Vasco Santos
1ea945ad24 refactor: dht async/await (#480)
* refactor: core async (#478)

* refactor: cleanup core

test: auto dial on startup

* fix: make hangup work properly

* chore: fix lint

* chore: apply suggestions from code review

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>

* fix: provide libp2p dialer to the dht

* chore: use dht release
2019-12-12 10:29:01 +01:00
Jacob Heun
c37703dc17 refactor: update secio and tests to use it (#484)
* refactor: use async secio

* test: add secio to most test suites

* chore: update secio version
2019-12-12 10:29:01 +01:00
Jacob Heun
86b275a0d3 refactor: core async (#478)
* refactor: cleanup core

test: auto dial on startup

* fix: make hangup work properly

* chore: fix lint

* chore: apply suggestions from code review

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>
2019-12-12 10:29:01 +01:00
Vasco Santos
3c79d33db9 chore: use gossipsub release (#479) 2019-12-12 10:29:00 +01:00
Vasco Santos
34d57f8989 refactor: pubsub (#467)
* feat: peer-store v0

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: address review

* refactor: pubsub subsystem

* chore: address review

* chore: use topology interface

* chore: address review

* chore: address review

* chore: simplify tests
2019-12-12 10:29:00 +01:00
Jacob Heun
ced2dbf318 chore: update it-length-prefixed (#476)
fix: decode.fromReader usage
2019-12-12 10:29:00 +01:00
Jacob Heun
44d47087d1 refactor: async identify and identify push (#473)
* chore: add missing dep

* feat: import from identify push branch

https://github.com/libp2p/js-libp2p-identify/tree/feat/identify-push

* feat: add the connection to stream handlers

* refactor: identify to async/await

* chore: fix lint

* test: add identify tests

* refactor: add identify to the dialer flow

* feat: connect identify to the registrar

* fix: resolve review feedback

* fix: perform identify push when our protocols change
2019-12-12 10:29:00 +01:00
Vasco Santos
797d8f0cf1 feat: registrar (#471)
* feat: peer-store v0

* feat: registrar

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: address review

* chore: support multiple conns

* chore: address review

* fix: no remote peer from topology on disconnect
2019-12-12 10:29:00 +01:00
Vasco Santos
f3e276eb79 feat: peer store (#470)
* feat: peer-store v0

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2019-12-12 10:28:59 +01:00
Jacob Heun
138bb0bbae refactor: crypto and pnet (#469)
* feat: add initial plaintext 2 module

* refactor: initial refactor of pnet

* chore: fix lint

* fix: update plaintext api usage

* test: use plaintext for test crypto

* chore: update deps

test: update dialer suite scope

* feat: add connection protection to the upgrader

* refactor: cleanup and lint fix

* chore: remove unncessary transforms

* chore: temporarily disable bundlesize

* chore: add missing dep

* fix: use it-handshake to prevent overreading

* chore(fix): PR feedback updates

* chore: apply suggestions from code review

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>
2019-12-12 10:28:59 +01:00
Jacob Heun
af364b070b refactor(async): add dialer and upgrader (#462)
* chore(deps): update connection and multistream

* feat: add basic dial support for addresses and peers

* test: automatically require all node test files

* fix: dont catch and log in the wrong place

* test: add direct spec test

fix: improve dial error consistency

* feat: add dial timeouts and concurrency

Queue timeouts will result in aborts of the dials

* chore: fix linting

* test: verify dialer defaults

* feat: add initial upgrader

* fix: add more test coverage and fix bugs

* feat: libp2p creates the upgrader

* feat: hook up handle to the upgrader

* feat: hook up the dialer to libp2p

test: add node dialer libp2p tests

* feat: add connection listeners to upgrader

* feat: emit connect and disconnect events

* chore: use libp2p-interfaces

* fix: address review feedback

* fix: correct import

* refactor: dedupe connection creation code
2019-12-12 10:28:59 +01:00
Jacob Heun
10c8553c58 docs: add stream wrapping example (#466)
* docs: add duplex wrapping example

docs: add iterable types from @alanshaw's gist

* docs(fix): add feedback fix

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>

* docs: clean up based on feedback
2019-12-12 10:28:59 +01:00
Jacob Heun
a7d5e67e06 refactor(async): update transports subsystem (#461)
* test: remove all tests for a clean slate

The refactor will require a large number of updates to the tests. In order
to ensure we have done a decent deduplication, and have a cleaner suite of tests
we've removed all tests. This will also allow us to more easily see tests
for the refactored systems.

We have a record of the latest test suites in master, so we are not losing any history.

* chore: update tcp and websockets
* chore: remove other transports until they are converted
* chore: use mafmt and multiaddr async versions
* chore: add and fix dependencies
* chore: clean up travis file
* feat: add new transport manager
* docs: add constructor jsdocs
* refactor(config): check that transports exist
This also removes the other logic, it can be added when those subsystems are refactored

* chore(deps): use async peer-id and peer-info
* feat: wire up the transport manager with libp2p
* chore: remove superstruct dep
2019-12-12 10:28:59 +01:00
Jacob Heun
4f8043d259 Add streaming iterables guide (#459)
* docs: add streaming iterables guide placeholder

* chore: move peer discovery readme to doc fold:wqer

* docs: add link to async refactor issue
2019-12-12 10:28:58 +01:00
86 changed files with 1789 additions and 2994 deletions

View File

@@ -4,6 +4,7 @@ const Libp2p = require('./src')
const { MULTIADDRS_WEBSOCKETS } = require('./test/fixtures/browser')
const Peers = require('./test/fixtures/peers')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const WebSockets = require('libp2p-websockets')
const Muxer = require('libp2p-mplex')
const Crypto = require('libp2p-secio')
@@ -13,12 +14,11 @@ let libp2p
const before = async () => {
// Use the last peer
const peerId = await PeerId.createFromJSON(Peers[Peers.length - 1])
const peerInfo = new PeerInfo(peerId)
peerInfo.multiaddrs.add(MULTIADDRS_WEBSOCKETS[0])
libp2p = new Libp2p({
addresses: {
listen: [MULTIADDRS_WEBSOCKETS[0]]
},
peerId,
peerInfo,
modules: {
transport: [WebSockets],
streamMuxer: [Muxer],

View File

@@ -39,12 +39,5 @@ jobs:
script:
- npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless
- stage: test
name: interop
script:
- cd node_modules/interop-libp2p
- npm install
- LIBP2P_JS=${TRAVIS_BUILD_DIR}/src/index.js npx aegir test -t node --bail
notifications:
email: false

View File

@@ -1,94 +1,3 @@
<a name="0.27.5"></a>
## [0.27.5](https://github.com/libp2p/js-libp2p/compare/v0.27.4...v0.27.5) (2020-04-06)
### Bug Fixes
* await peer discovery start in libp2p start ([#600](https://github.com/libp2p/js-libp2p/issues/600)) ([bd7fd0f](https://github.com/libp2p/js-libp2p/commit/bd7fd0f))
<a name="0.27.4"></a>
## [0.27.4](https://github.com/libp2p/js-libp2p/compare/v0.27.3...v0.27.4) (2020-03-31)
### Bug Fixes
* only use a single export ([#596](https://github.com/libp2p/js-libp2p/issues/596)) ([3072875](https://github.com/libp2p/js-libp2p/commit/3072875))
* pass libp2p to discovery services ([#597](https://github.com/libp2p/js-libp2p/issues/597)) ([9e35fbc](https://github.com/libp2p/js-libp2p/commit/9e35fbc))
* **test:** improve flakey random walk discovery test ([#574](https://github.com/libp2p/js-libp2p/issues/574)) ([f4ec355](https://github.com/libp2p/js-libp2p/commit/f4ec355))
* remove use of assert module ([#561](https://github.com/libp2p/js-libp2p/issues/561)) ([a8984c6](https://github.com/libp2p/js-libp2p/commit/a8984c6))
<a name="0.27.3"></a>
## [0.27.3](https://github.com/libp2p/js-libp2p/compare/v0.27.2...v0.27.3) (2020-02-11)
### Bug Fixes
* dont allow multiaddr dials without a peer id ([#558](https://github.com/libp2p/js-libp2p/issues/558)) ([a317a8b](https://github.com/libp2p/js-libp2p/commit/a317a8b))
<a name="0.27.2"></a>
## [0.27.2](https://github.com/libp2p/js-libp2p/compare/v0.27.1...v0.27.2) (2020-02-05)
### Bug Fixes
* ensure identify streams are closed ([#551](https://github.com/libp2p/js-libp2p/issues/551)) ([f662fdc](https://github.com/libp2p/js-libp2p/commit/f662fdc))
<a name="0.27.1"></a>
## [0.27.1](https://github.com/libp2p/js-libp2p/compare/v0.27.0...v0.27.1) (2020-02-03)
### Bug Fixes
* stop stream after first pong received ([#545](https://github.com/libp2p/js-libp2p/issues/545)) ([be8fc9d](https://github.com/libp2p/js-libp2p/commit/be8fc9d))
<a name="0.27.0"></a>
# [0.27.0](https://github.com/libp2p/js-libp2p/compare/v0.26.2...v0.27.0) (2020-01-28)
### Bug Fixes
* clean up peer discovery flow ([#494](https://github.com/libp2p/js-libp2p/issues/494)) ([12fc069](https://github.com/libp2p/js-libp2p/commit/12fc069))
* clean up pending dials abort per feedback ([633b0c2](https://github.com/libp2p/js-libp2p/commit/633b0c2))
* conn mngr min/max connection values ([#528](https://github.com/libp2p/js-libp2p/issues/528)) ([ba4681b](https://github.com/libp2p/js-libp2p/commit/ba4681b))
* correct release readme ([ce8e60b](https://github.com/libp2p/js-libp2p/commit/ce8e60b))
* examples readme typos ([#481](https://github.com/libp2p/js-libp2p/issues/481)) ([35ac02d](https://github.com/libp2p/js-libp2p/commit/35ac02d))
* make dialer configurable ([#521](https://github.com/libp2p/js-libp2p/issues/521)) ([4ca481b](https://github.com/libp2p/js-libp2p/commit/4ca481b))
* performance bottleneck in stat.js ([#463](https://github.com/libp2p/js-libp2p/issues/463)) ([93a1e42](https://github.com/libp2p/js-libp2p/commit/93a1e42))
* registrar should filter the disconnected conn ([#532](https://github.com/libp2p/js-libp2p/issues/532)) ([bb2e56e](https://github.com/libp2p/js-libp2p/commit/bb2e56e))
* release tokens as soon as they are available ([2570a1b](https://github.com/libp2p/js-libp2p/commit/2570a1b))
* replace peerInfo addresses with listen addresses ([#485](https://github.com/libp2p/js-libp2p/issues/485)) ([1999606](https://github.com/libp2p/js-libp2p/commit/1999606))
* stop discoveries ([#530](https://github.com/libp2p/js-libp2p/issues/530)) ([4222c49](https://github.com/libp2p/js-libp2p/commit/4222c49))
* token release logic ([90ecc57](https://github.com/libp2p/js-libp2p/commit/90ecc57))
* upgrader should not need muxers ([#517](https://github.com/libp2p/js-libp2p/issues/517)) ([5d7ee50](https://github.com/libp2p/js-libp2p/commit/5d7ee50))
* use toB58String everywhere to be consistent ([#537](https://github.com/libp2p/js-libp2p/issues/537)) ([c1038be](https://github.com/libp2p/js-libp2p/commit/c1038be))
### Features
* abort all pending dials on stop ([ba02764](https://github.com/libp2p/js-libp2p/commit/ba02764))
* add early token recycling in ([a5b54a7](https://github.com/libp2p/js-libp2p/commit/a5b54a7))
* add libp2p.connections getter ([#522](https://github.com/libp2p/js-libp2p/issues/522)) ([6445fda](https://github.com/libp2p/js-libp2p/commit/6445fda))
* add token based dialer ([e445a17](https://github.com/libp2p/js-libp2p/commit/e445a17))
* allow transport options to be passed on creation ([#524](https://github.com/libp2p/js-libp2p/issues/524)) ([c339be1](https://github.com/libp2p/js-libp2p/commit/c339be1))
* coalescing dial support ([#518](https://github.com/libp2p/js-libp2p/issues/518)) ([15f7c2a](https://github.com/libp2p/js-libp2p/commit/15f7c2a))
* discovery modules ([#486](https://github.com/libp2p/js-libp2p/issues/486)) ([18a062e](https://github.com/libp2p/js-libp2p/commit/18a062e))
* discovery modules from transports should be added ([#510](https://github.com/libp2p/js-libp2p/issues/510)) ([f1eb373](https://github.com/libp2p/js-libp2p/commit/f1eb373))
* peer store ([#470](https://github.com/libp2p/js-libp2p/issues/470)) ([582094a](https://github.com/libp2p/js-libp2p/commit/582094a))
* registrar ([#471](https://github.com/libp2p/js-libp2p/issues/471)) ([9d52b80](https://github.com/libp2p/js-libp2p/commit/9d52b80))
* support peer-id instances in peer store operations ([#491](https://github.com/libp2p/js-libp2p/issues/491)) ([8da9fc9](https://github.com/libp2p/js-libp2p/commit/8da9fc9))
<a name="0.27.0-rc.0"></a>
# [0.27.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.2...v0.27.0-rc.0) (2020-01-24)

View File

@@ -37,7 +37,7 @@ One of following:
<!--
This is for you! Please read, and then delete this text before posting it.
The js-libp2p issues are only for bug reports and directly actionable features.
The js-ipfs issues are only for bug reports and directly actionable features.
Read https://github.com/ipfs/community/blob/master/CONTRIBUTING.md#reporting-issues if your issue doesn't fit either of those categories.
-->

View File

@@ -5,14 +5,12 @@
<h3 align="center">The JavaScript implementation of the libp2p Networking Stack.</h3>
<p align="center">
<a href="http://protocol.ai"><img src="https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square" /></a>
<a href="http://ipn.io"><img src="https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square" /></a>
<a href="http://libp2p.io/"><img src="https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square" /></a>
<a href="http://webchat.freenode.net/?channels=%23libp2p"><img src="https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square" /></a>
<a href="https://riot.im/app/#/room/#libp2p:matrix.org"><img src="https://img.shields.io/badge/matrix-%23libp2p%3Apermaweb.io-blue.svg?style=flat-square" /> </a>
<a href="https://riot.permaweb.io/#/room/#libp2p:permaweb.io"><img src="https://img.shields.io/badge/matrix-%23libp2p%3Apermaweb.io-blue.svg?style=flat-square" /> </a>
<a href="https://discord.gg/66KBrm2"><img src="https://img.shields.io/discord/475789330380488707?color=blueviolet&label=discord&style=flat-square" /></a>
<a href="https://discuss.libp2p.io"><img src="https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg" /></a>
<a href="https://www.npmjs.com/package/libp2p"><img src="https://img.shields.io/npm/dm/libp2p.svg" /></a>
<a href="https://www.jsdelivr.com/package/npm/libp2p"><img src="https://data.jsdelivr.com/v1/package/npm/libp2p/badge"/></a>
</p>
<p align="center">
@@ -32,9 +30,6 @@
We've come a long way, but this project is still in Alpha, lots of development is happening, API might change, beware of the Dragons 🐉..
The documentation in the master branch may contain changes from a pre-release.
If you are looking for the documentation of the latest release, you can view the latest release on [**npm**](https://www.npmjs.com/package/libp2p), or select the tag in github that matches the version you are looking for.
**Want to get started?** Check our [examples folder](/examples).
[**`Weekly Core Dev Calls`**](https://github.com/ipfs/pm/issues/650)
@@ -137,45 +132,49 @@ List of packages currently in existence for libp2p
| Package | Version | Deps | CI | Coverage | Lead Maintainer |
| ---------|---------|---------|---------|---------|--------- |
| **libp2p** |
| [`libp2p`](//github.com/libp2p/js-libp2p) | [![npm](https://img.shields.io/npm/v/libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p/master)](https://travis-ci.com/libp2p/js-libp2p) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon`](//github.com/libp2p/js-libp2p-daemon) | [![npm](https://img.shields.io/npm/v/libp2p-daemon.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon/master)](https://travis-ci.com/libp2p/js-libp2p-daemon) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon-client`](//github.com/libp2p/js-libp2p-daemon-client) | [![npm](https://img.shields.io/npm/v/libp2p-daemon-client.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon-client/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon-client.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon-client) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon-client/master)](https://travis-ci.com/libp2p/js-libp2p-daemon-client) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon-client/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon-client) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-interfaces`](//github.com/libp2p/js-interfaces) | [![npm](https://img.shields.io/npm/v/libp2p-interfaces.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-interfaces/releases) | [![Deps](https://david-dm.org/libp2p/js-interfaces.svg?style=flat-square)](https://david-dm.org/libp2p/js-interfaces) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-interfaces/master)](https://travis-ci.com/libp2p/js-interfaces) | [![codecov](https://codecov.io/gh/libp2p/js-interfaces/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-interfaces) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`interop-libp2p`](//github.com/libp2p/interop) | [![npm](https://img.shields.io/npm/v/interop-libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interop/releases) | [![Deps](https://david-dm.org/libp2p/interop.svg?style=flat-square)](https://david-dm.org/libp2p/interop) | [![Travis CI](https://flat.badgen.net/travis/libp2p/interop/master)](https://travis-ci.com/libp2p/interop) | [![codecov](https://codecov.io/gh/libp2p/interop/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/interop) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p`](//github.com/libp2p/js-libp2p) | [![npm](https://img.shields.io/npm/v/libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon`](//github.com/libp2p/js-libp2p-daemon) | [![npm](https://img.shields.io/npm/v/libp2p-daemon.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-daemon) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon-client`](//github.com/libp2p/js-libp2p-daemon-client) | [![npm](https://img.shields.io/npm/v/libp2p-daemon-client.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon-client/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon-client.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon-client) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon-client.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-daemon-client) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon-client/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon-client) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-interfaces`](//github.com/libp2p/js-interfaces) | [![npm](https://img.shields.io/npm/v/libp2p-interfaces.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-interfaces/releases) | [![Deps](https://david-dm.org/libp2p/js-interfaces.svg?style=flat-square)](https://david-dm.org/libp2p/js-interfaces) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-interfaces.svg?branch=master)](https://travis-ci.com/libp2p/js-interfaces) | [![codecov](https://codecov.io/gh/libp2p/js-interfaces/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-interfaces) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`interop-libp2p`](//github.com/libp2p/interop) | [![npm](https://img.shields.io/npm/v/interop-libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interop/releases) | [![Deps](https://david-dm.org/libp2p/interop.svg?style=flat-square)](https://david-dm.org/libp2p/interop) | [![Travis CI](https://flat.badgen.net/travis/libp2p/interop.svg?branch=master)](https://travis-ci.com/libp2p/interop) | [![codecov](https://codecov.io/gh/libp2p/interop/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/interop) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| **transports** |
| [`libp2p-tcp`](//github.com/libp2p/js-libp2p-tcp) | [![npm](https://img.shields.io/npm/v/libp2p-tcp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-tcp) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-tcp/master)](https://travis-ci.com/libp2p/js-libp2p-tcp) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-tcp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-tcp) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-webrtc-direct`](//github.com/libp2p/js-libp2p-webrtc-direct) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-direct.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-direct/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-direct.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-direct) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-direct/master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-direct) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star/master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websockets/master)](https://travis-ci.com/libp2p/js-libp2p-websockets) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websockets/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websockets) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-tcp`](//github.com/libp2p/js-libp2p-tcp) | [![npm](https://img.shields.io/npm/v/libp2p-tcp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-tcp) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-tcp.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-tcp) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-tcp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-tcp) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-utp.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-utp) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-utp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-utp) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-webrtc-direct`](//github.com/libp2p/js-libp2p-webrtc-direct) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-direct.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-direct/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-direct.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-direct) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-direct.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-direct) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websockets.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-websockets) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websockets/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websockets) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-websocket-star`](//github.com/libp2p/js-libp2p-websocket-star) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websocket-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websocket-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-websocket-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websocket-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websocket-star) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| **secure channels** |
| [`libp2p-secio`](//github.com/libp2p/js-libp2p-secio) | [![npm](https://img.shields.io/npm/v/libp2p-secio.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-secio/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-secio.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-secio) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-secio/master)](https://travis-ci.com/libp2p/js-libp2p-secio) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-secio/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-secio) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| [`libp2p-secio`](//github.com/libp2p/js-libp2p-secio) | [![npm](https://img.shields.io/npm/v/libp2p-secio.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-secio/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-secio.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-secio) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-secio.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-secio) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-secio/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-secio) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| **stream multiplexers** |
| [`libp2p-mplex`](//github.com/libp2p/js-libp2p-mplex) | [![npm](https://img.shields.io/npm/v/libp2p-mplex.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mplex.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mplex) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mplex/master)](https://travis-ci.com/libp2p/js-libp2p-mplex) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mplex/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mplex) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-mplex`](//github.com/libp2p/js-libp2p-mplex) | [![npm](https://img.shields.io/npm/v/libp2p-mplex.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mplex.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mplex) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mplex.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-mplex) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mplex/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mplex) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-spdy`](//github.com/libp2p/js-libp2p-spdy) | [![npm](https://img.shields.io/npm/v/libp2p-spdy.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-spdy/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-spdy.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-spdy) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-spdy.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-spdy) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-spdy/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-spdy) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| **peer discovery** |
| [`libp2p-bootstrap`](//github.com/libp2p/js-libp2p-bootstrap) | [![npm](https://img.shields.io/npm/v/libp2p-bootstrap.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-bootstrap.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-bootstrap) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-bootstrap/master)](https://travis-ci.com/libp2p/js-libp2p-bootstrap) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-bootstrap/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-bootstrap) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht/master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-mdns`](//github.com/libp2p/js-libp2p-mdns) | [![npm](https://img.shields.io/npm/v/libp2p-mdns.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mdns.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mdns) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mdns/master)](https://travis-ci.com/libp2p/js-libp2p-mdns) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mdns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mdns) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star/master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`discv5`](//github.com/ChainSafe/discv5) | [![npm](https://img.shields.io/npm/v/discv5.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/discv5/releases) | [![Deps](https://david-dm.org/ChainSafe/discv5.svg?style=flat-square)](https://david-dm.org/ChainSafe/discv5) | [![Travis CI](https://flat.badgen.net/travis/ChainSafe/discv5/master)](https://travis-ci.com/ChainSafe/discv5) | [![codecov](https://codecov.io/gh/ChainSafe/discv5/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/discv5) | [Cayman Nava](mailto:caymannava@gmail.com) |
| [`libp2p-bootstrap`](//github.com/libp2p/js-libp2p-bootstrap) | [![npm](https://img.shields.io/npm/v/libp2p-bootstrap.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-bootstrap.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-bootstrap) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-bootstrap.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-bootstrap) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-bootstrap/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-bootstrap) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-mdns`](//github.com/libp2p/js-libp2p-mdns) | [![npm](https://img.shields.io/npm/v/libp2p-mdns.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mdns.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mdns) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mdns.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-mdns) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mdns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mdns) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-rendezvous`](//github.com/libp2p/js-libp2p-rendezvous) | [![npm](https://img.shields.io/npm/v/libp2p-rendezvous.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-rendezvous/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-rendezvous.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-rendezvous) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-rendezvous.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-rendezvous) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-rendezvous/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-rendezvous) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-websocket-star`](//github.com/libp2p/js-libp2p-websocket-star) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websocket-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websocket-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-websocket-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websocket-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websocket-star) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| **content routing** |
| [`libp2p-delegated-content-routing`](//github.com/libp2p/js-libp2p-delegated-content-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-content-routing/master)](https://travis-ci.com/libp2p/js-libp2p-delegated-content-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht/master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-delegated-content-routing`](//github.com/libp2p/js-libp2p-delegated-content-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-content-routing.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-delegated-content-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| **peer routing** |
| [`libp2p-delegated-peer-routing`](//github.com/libp2p/js-libp2p-delegated-peer-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-peer-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-peer-routing/master)](https://travis-ci.com/libp2p/js-libp2p-delegated-peer-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht/master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-delegated-peer-routing`](//github.com/libp2p/js-libp2p-delegated-peer-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-peer-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-peer-routing.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-delegated-peer-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| **utilities** |
| [`libp2p-crypto`](//github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/libp2p-crypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto/master)](https://travis-ci.com/libp2p/js-libp2p-crypto) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-crypto-secp256k1`](//github.com/libp2p/js-libp2p-crypto-secp256k1) | [![npm](https://img.shields.io/npm/v/libp2p-crypto-secp256k1.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto-secp256k1/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto-secp256k1/master)](https://travis-ci.com/libp2p/js-libp2p-crypto-secp256k1) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| [`libp2p-crypto`](//github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/libp2p-crypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-crypto) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-crypto-secp256k1`](//github.com/libp2p/js-libp2p-crypto-secp256k1) | [![npm](https://img.shields.io/npm/v/libp2p-crypto-secp256k1.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto-secp256k1/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto-secp256k1.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-crypto-secp256k1) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| **data types** |
| [`peer-id`](//github.com/libp2p/js-peer-id) | [![npm](https://img.shields.io/npm/v/peer-id.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-id/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-id.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-id) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-id/master)](https://travis-ci.com/libp2p/js-peer-id) | [![codecov](https://codecov.io/gh/libp2p/js-peer-id/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-id) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`peer-info`](//github.com/libp2p/js-peer-info) | [![npm](https://img.shields.io/npm/v/peer-info.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-info/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-info.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-info) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-info/master)](https://travis-ci.com/libp2p/js-peer-info) | [![codecov](https://codecov.io/gh/libp2p/js-peer-info/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-info) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`peer-id`](//github.com/libp2p/js-peer-id) | [![npm](https://img.shields.io/npm/v/peer-id.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-id/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-id.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-id) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-id.svg?branch=master)](https://travis-ci.com/libp2p/js-peer-id) | [![codecov](https://codecov.io/gh/libp2p/js-peer-id/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-id) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`peer-info`](//github.com/libp2p/js-peer-info) | [![npm](https://img.shields.io/npm/v/peer-info.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-info/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-info.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-info) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-info.svg?branch=master)](https://travis-ci.com/libp2p/js-peer-info) | [![codecov](https://codecov.io/gh/libp2p/js-peer-info/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-info) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| **pubsub** |
| [`libp2p-pubsub`](//github.com/libp2p/js-libp2p-pubsub) | [![npm](https://img.shields.io/npm/v/libp2p-pubsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-pubsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-pubsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-pubsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-pubsub/master)](https://travis-ci.com/libp2p/js-libp2p-pubsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-pubsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-pubsub) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-floodsub`](//github.com/libp2p/js-libp2p-floodsub) | [![npm](https://img.shields.io/npm/v/libp2p-floodsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-floodsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-floodsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-floodsub/master)](https://travis-ci.com/libp2p/js-libp2p-floodsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-floodsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-floodsub) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-gossipsub`](//github.com/ChainSafe/gossipsub-js) | [![npm](https://img.shields.io/npm/v/libp2p-gossipsub.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/gossipsub-js/releases) | [![Deps](https://david-dm.org/ChainSafe/gossipsub-js.svg?style=flat-square)](https://david-dm.org/ChainSafe/gossipsub-js) | [![Travis CI](https://flat.badgen.net/travis/ChainSafe/gossipsub-js/master)](https://travis-ci.com/ChainSafe/gossipsub-js) | [![codecov](https://codecov.io/gh/ChainSafe/gossipsub-js/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/gossipsub-js) | [Cayman Nava](mailto:caymannava@gmail.com) |
| [`libp2p-pubsub`](//github.com/libp2p/js-libp2p-pubsub) | [![npm](https://img.shields.io/npm/v/libp2p-pubsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-pubsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-pubsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-pubsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-pubsub.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-pubsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-pubsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-pubsub) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-floodsub`](//github.com/libp2p/js-libp2p-floodsub) | [![npm](https://img.shields.io/npm/v/libp2p-floodsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-floodsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-floodsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-floodsub.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-floodsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-floodsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-floodsub) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-gossipsub`](//github.com/ChainSafe/gossipsub-js) | [![npm](https://img.shields.io/npm/v/libp2p-gossipsub.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/gossipsub-js/releases) | [![Deps](https://david-dm.org/ChainSafe/gossipsub-js.svg?style=flat-square)](https://david-dm.org/ChainSafe/gossipsub-js) | [![Travis CI](https://flat.badgen.net/travis/ChainSafe/gossipsub-js.svg?branch=master)](https://travis-ci.com/ChainSafe/gossipsub-js) | [![codecov](https://codecov.io/gh/ChainSafe/gossipsub-js/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/gossipsub-js) | [Cayman Nava](mailto:caymannava@gmail.com) |
| **extensions** |
| [`libp2p-nat-mgnr`](//github.com/libp2p/js-libp2p-nat-mgnr) | [![npm](https://img.shields.io/npm/v/libp2p-nat-mgnr.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-nat-mgnr/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-nat-mgnr.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-nat-mgnr) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-nat-mgnr/master)](https://travis-ci.com/libp2p/js-libp2p-nat-mgnr) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr) | N/A |
| [`libp2p-utils`](//github.com/libp2p/js-libp2p-utils) | [![npm](https://img.shields.io/npm/v/libp2p-utils.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utils/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-utils.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utils) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-utils/master)](https://travis-ci.com/libp2p/js-libp2p-utils) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-utils/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-utils) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-nat-mgnr`](//github.com/libp2p/js-libp2p-nat-mgnr) | [![npm](https://img.shields.io/npm/v/libp2p-nat-mgnr.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-nat-mgnr/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-nat-mgnr.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-nat-mgnr) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-nat-mgnr.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-nat-mgnr) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr) | N/A |
| [`libp2p-utils`](//github.com/libp2p/js-libp2p-utils) | [![npm](https://img.shields.io/npm/v/libp2p-utils.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utils/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-utils.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utils) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-utils.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-utils) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-utils/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-utils) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
## Contribute

View File

@@ -17,18 +17,6 @@
* [`contentRouting.put`](#contentroutingput)
* [`contentRouting.get`](#contentroutingget)
* [`contentRouting.getMany`](#contentroutinggetmany)
* [`peerStore.addressBook.add`](#peerstoreaddressbookadd)
* [`peerStore.addressBook.delete`](#peerstoreaddressbookdelete)
* [`peerStore.addressBook.get`](#peerstoreaddressbookget)
* [`peerStore.addressBook.getMultiaddrsForPeer`](#peerstoreaddressbookgetmultiaddrsforpeer)
* [`peerStore.addressBook.set`](#peerstoreaddressbookset)
* [`peerStore.protoBook.add`](#peerstoreprotobookadd)
* [`peerStore.protoBook.delete`](#peerstoreprotobookdelete)
* [`peerStore.protoBook.get`](#peerstoreprotobookget)
* [`peerStore.protoBook.set`](#peerstoreprotobookset)
* [`peerStore.delete`](#peerstoredelete)
* [`peerStore.get`](#peerstoreget)
* [`peerStore.peers`](#peerstorepeers)
* [`pubsub.getSubscribers`](#pubsubgetsubscribers)
* [`pubsub.getTopics`](#pubsubgettopics)
* [`pubsub.publish`](#pubsubpublish)
@@ -41,8 +29,6 @@
* [`metrics.forPeer`](#metricsforpeer)
* [`metrics.forProtocol`](#metricsforprotocol)
* [Events](#events)
* [`libp2p`](#libp2p)
* [`libp2p.peerStore`](#libp2ppeerStore)
* [Types](#types)
* [`Stats`](#stats)
@@ -58,15 +44,14 @@ Creates an instance of Libp2p.
| Name | Type | Description |
|------|------|-------------|
| options | `object` | libp2p options |
| options.modules | `Array<object>` | libp2p modules to use |
| [options.addresses] | `{ listen: Array<Multiaddr> }` | Addresses to use for transport listening and to announce to the network |
| [options.config] | `object` | libp2p modules configuration and core configuration |
| [options.connectionManager] | `object` | libp2p Connection Manager configuration |
| [options.datastore] | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
| [options.dialer] | `object` | libp2p Dialer configuration
| [options.metrics] | `object` | libp2p Metrics configuration
| [options.peerId] | [`PeerId`][peer-id] | peerId instance (it will be created if not provided) |
| options | `Object` | libp2p options |
| options.modules | `Array<Object>` | libp2p modules to use |
| [options.config] | `Object` | libp2p modules configuration and core configuration |
| [options.connectionManager] | `Object` | libp2p Connection Manager configuration |
| [options.datastore] | `Object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
| [options.dialer] | `Object` | libp2p Dialer configuration
| [options.metrics] | `Object` | libp2p Metrics configuration
| [options.peerInfo] | [PeerInfo](https://github.com/libp2p/js-peer-info) | peerInfo instance (it will be created if not provided) |
For Libp2p configurations and modules details read the [Configuration Document](./CONFIGURATION.md).
@@ -88,7 +73,7 @@ const options = {}
const libp2p = await Libp2p.create(options)
```
Note: The [`PeerId`][peer-id] option is not required and will be generated if it is not provided.
Note: The `PeerInfo` option is not required and will be generated if it is not provided.
<details><summary>Alternative</summary>
As an alternative, it is possible to create a Libp2p instance with the constructor:
@@ -107,7 +92,7 @@ const libp2p = new Libp2p(options)
Required keys in the `options` object:
- `peerId`: instance of [`PeerId`][peer-id] that contains the peer Keys (optional when using `.create`).
- `peerInfo`: instance of [PeerInfo][] that contains the [PeerId][], Keys and [multiaddrs][multiaddr] of the libp2p Node (optional when using `.create`).
- `modules.transport`: An array that must include at least 1 compliant transport. See [modules that implement the transport interface](https://github.com/libp2p/js-interfaces/tree/master/src/transport#modules-that-implement-the-interface).
</details>
@@ -164,10 +149,6 @@ const libp2p = await Libp2p.create(options)
await libp2p.stop()
```
### addresses
TODO with `address-manager`.
### connections
A Getter that returns a Map of the current Connections libp2p has to other peers.
@@ -193,18 +174,18 @@ for (const [peerId, connections] of libp2p.connections) {
### dial
Dials to another peer in the network and establishes the connection.
`dial(peer, options)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peer | [`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. |
| [options] | `object` | dial options |
| peer | [PeerInfo](https://github.com/libp2p/js-peer-info), [PeerId][peer-id], [multiaddr](https://github.com/multiformats/js-multiaddr), `string` | peer to dial |
| [options] | `Object` | dial options |
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
**Note:** If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id. Moreover, if a [`PeerId`][peer-id] is given, the peer will need to have known multiaddrs for it in the PeerStore.
#### Returns
| Type | Description |
@@ -215,7 +196,7 @@ for (const [peerId, connections] of libp2p.connections) {
```js
// ...
const conn = await libp2p.dial(remotePeerId)
const conn = await libp2p.dial(remotePeerInfo)
// create a new stream within the connection
const { stream, protocol } = await conn.newStream(['/echo/1.1.0', '/echo/1.0.0'])
@@ -236,13 +217,11 @@ Dials to another peer in the network and selects a protocol to communicate with
| Name | Type | Description |
|------|------|-------------|
| peer | [`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. |
| protocols | `string|Array<string>` | A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made. (e.g '/ipfs/bitswap/1.1.0') |
| [options] | `object` | dial options |
| peer | [PeerInfo](https://github.com/libp2p/js-peer-info), [PeerId][peer-id], [multiaddr](https://github.com/multiformats/js-multiaddr), `string` | peer to dial |
| protocols | `String|Array<String>` | A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made. (e.g '/ipfs/bitswap/1.1.0') |
| [options] | `Object` | dial options |
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
**Note:** If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id. Moreover, if a [`PeerId`][peer-id] is given, the peer will need to have known multiaddrs for it in the PeerStore.
#### Returns
| Type | Description |
@@ -255,7 +234,7 @@ Dials to another peer in the network and selects a protocol to communicate with
// ...
const pipe = require('it-pipe')
const { stream, protocol } = await libp2p.dialProtocol(remotePeerId, protocols)
const { stream, protocol } = await libp2p.dialProtocol(remotePeerInfo, protocols)
// Use this new stream like any other duplex stream
pipe([1, 2, 3], stream, consume)
@@ -271,7 +250,7 @@ Attempts to gracefully close an open connection to the given peer. If the connec
| Name | Type | Description |
|------|------|-------------|
| peer | [`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | peer to hang up |
| peer | [PeerInfo](https://github.com/libp2p/js-peer-info), [PeerId][peer-id], [multiaddr](https://github.com/multiformats/js-multiaddr), `string` | peer to hang up |
#### Returns
@@ -283,7 +262,7 @@ Attempts to gracefully close an open connection to the given peer. If the connec
```js
// ...
await libp2p.hangUp(remotePeerId)
await libp2p.hangUp(remotePeerInfo)
```
### handle
@@ -298,7 +277,7 @@ In the event of a new handler for the same protocol being added, the first one i
| Name | Type | Description |
|------|------|-------------|
| protocols | `Array<string>|string` | protocols to register |
| protocols | `Array<String>|String` | protocols to register |
| handler | `function({ connection:*, stream:*, protocol:string })` | handler to call |
@@ -323,7 +302,7 @@ Unregisters all handlers with the given protocols
| Name | Type | Description |
|------|------|-------------|
| protocols | `Array<string>|string` | protocols to unregister |
| protocols | `Array<String>|String` | protocols to unregister |
#### Example
@@ -342,7 +321,7 @@ Pings a given peer and get the operation's latency.
| Name | Type | Description |
|------|------|-------------|
| peer | [`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | peer to ping |
| peer | `PeerInfo|PeerId|Multiaddr|string` | peer to ping |
#### Returns
@@ -368,20 +347,20 @@ Iterates over all peer routers in series to find the given peer. If the DHT is e
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | ID of the peer to find |
| options | `object` | operation options |
| options | `Object` | operation options |
| options.timeout | `number` | maximum time the query should run |
#### Returns
| Type | Description |
|------|-------------|
| `Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>` | Peer data of a known peer |
| `Promise<PeerInfo>` | Peer info of a known peer |
#### Example
```js
// ...
const peer = await libp2p.peerRouting.findPeer(peerId, options)
const peerInfo = await libp2p.peerRouting.findPeer(peerId, options)
```
### contentRouting.findProviders
@@ -395,8 +374,8 @@ Once a content router succeeds, the iteration will stop. If the DHT is enabled,
| Name | Type | Description |
|------|------|-------------|
| cid | [`CID`][cid] | cid to find |
| options | `object` | operation options |
| cid | [`CID`](https://github.com/multiformats/js-cid) | cid to find |
| options | `Object` | operation options |
| options.timeout | `number` | maximum time the query should run |
| options.maxNumProviders | `number` | maximum number of providers to find |
@@ -404,14 +383,14 @@ Once a content router succeeds, the iteration will stop. If the DHT is enabled,
| Type | Description |
|------|-------------|
| `AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }` | Async iterator for peer data |
| `AsyncIterator<PeerInfo>` | Async iterator for [`PeerInfo`](https://github.com/libp2p/js-peer-info) |
#### Example
```js
// Iterate over the providers found for the given cid
for await (const provider of libp2p.contentRouting.findProviders(cid)) {
console.log(provider.id, provider.multiaddrs)
console.log(provider)
}
```
@@ -425,7 +404,7 @@ Iterates over all content routers in parallel, in order to notify it is a provid
| Name | Type | Description |
|------|------|-------------|
| cid | [`CID`][cid] | cid to provide |
| cid | [`CID`](https://github.com/multiformats/js-cid) | cid to provide |
#### Returns
@@ -450,9 +429,9 @@ Writes a value to a key in the DHT.
| Name | Type | Description |
|------|------|-------------|
| key | `string` | key to add to the dht |
| key | `String` | key to add to the dht |
| value | `Buffer` | value to add to the dht |
| [options] | `object` | put options |
| [options] | `Object` | put options |
| [options.minPeers] | `number` | minimum number of peers required to successfully put (default: closestPeers.length) |
#### Returns
@@ -481,8 +460,8 @@ Queries the DHT for a value stored for a given key.
| Name | Type | Description |
|------|------|-------------|
| key | `string` | key to get from the dht |
| [options] | `object` | get options |
| key | `String` | key to get from the dht |
| [options] | `Object` | get options |
| [options.timeout] | `number` | maximum time the query should run |
#### Returns
@@ -510,9 +489,9 @@ Queries the DHT for the n values stored for the given key (without sorting).
| Name | Type | Description |
|------|------|-------------|
| key | `string` | key to get from the dht |
| key | `String` | key to get from the dht |
| nvals | `number` | number of values aimed |
| [options] | `object` | get options |
| [options] | `Object` | get options |
| [options.timeout] | `number` | maximum time the query should run |
#### Returns
@@ -530,345 +509,6 @@ const key = '/key'
const { from, val } = await libp2p.contentRouting.get(key)
```
### peerStore.addressBook.add
Adds known `multiaddrs` of a given peer. If the peer is not known, it will be set with the provided multiaddrs.
`peerStore.addressBook.add(peerId, multiaddrs)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to set |
| multiaddrs | |`Array<Multiaddr>` | [`Multiaddrs`][multiaddr] to add |
#### Returns
| Type | Description |
|------|-------------|
| `AddressBook` | Returns the Address Book component |
#### Example
```js
peerStore.addressBook.add(peerId, multiaddr)
```
### peerStore.addressBook.delete
Delete the provided peer from the book.
`peerStore.addressBook.delete(peerId)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to remove |
#### Returns
| Type | Description |
|------|-------------|
| `boolean` | true if found and removed |
#### Example
```js
peerStore.addressBook.delete(peerId)
// false
peerStore.addressBook.set(peerId, multiaddr)
peerStore.addressBook.delete(peerId)
// true
```
### peerStore.addressBook.get
Get the known [`Addresses`][address] of a provided peer.
`peerStore.addressBook.get(peerId)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to get |
#### Returns
| Type | Description |
|------|-------------|
| `Array<Address>` | Array of peer's [`Addresses`][address] containing the multiaddr and its metadata |
#### Example
```js
peerStore.addressBook.get(peerId)
// undefined
peerStore.addressBook.set(peerId, multiaddr)
peerStore.addressBook.get(peerId)
// [
// {
// multiaddr: /ip4/140.10.2.1/tcp/8000,
// ...
// },
// {
// multiaddr: /ip4/140.10.2.1/ws/8001
// ...
// },
// ]
```
## peerStore.addressBook.getMultiaddrsForPeer
Get the known `Multiaddr` of a provided peer. All returned multiaddrs will include the encapsulated `PeerId` of the peer.
`peerStore.addressBook.getMultiaddrsForPeer(peerId)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to get |
#### Returns
| Type | Description |
|------|-------------|
| `Array<Multiaddr>` | Array of peer's multiaddr |
#### Example
```js
peerStore.addressBook.getMultiaddrsForPeer(peerId)
// undefined
peerStore.addressBook.set(peerId, multiaddr)
peerStore.addressBook.getMultiaddrsForPeer(peerId)
// [
// /ip4/140.10.2.1/tcp/8000/p2p/QmW8rAgaaA6sRydK1k6vonShQME47aDxaFidbtMevWs73t
// /ip4/140.10.2.1/ws/8001/p2p/QmW8rAgaaA6sRydK1k6vonShQME47aDxaFidbtMevWs73t
// ]
```
### peerStore.addressBook.set
Set known `multiaddrs` of a given peer.
`peerStore.addressBook.set(peerId, multiaddrs)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to set |
| multiaddrs | |`Array<Multiaddr>` | [`Multiaddrs`][multiaddr] to store |
#### Returns
| Type | Description |
|------|-------------|
| `AddressBook` | Returns the Address Book component |
#### Example
```js
peerStore.addressBook.add(peerId, multiaddr)
```
### peerStore.protoBook.add
Add known `protocols` of a given peer.
`peerStore.protoBook.add(peerId, protocols)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to set |
| protocols | `Array<string>` | protocols to add |
#### Returns
| Type | Description |
|------|-------------|
| `ProtoBook` | Returns the Proto Book component |
#### Example
```js
peerStore.protoBook.add(peerId, protocols)
```
### peerStore.protoBook.delete
Delete the provided peer from the book.
`peerStore.protoBook.delete(peerId)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to remove |
#### Returns
| Type | Description |
|------|-------------|
| `boolean` | true if found and removed |
#### Example
```js
peerStore.protoBook.delete(peerId)
// false
peerStore.protoBook.set(peerId, protocols)
peerStore.protoBook.delete(peerId)
// true
```
### peerStore.protoBook.get
Get the known `protocols` of a provided peer.
`peerStore.protoBook.get(peerId)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to get |
#### Returns
| Type | Description |
|------|-------------|
| `Array<string>` | Array of peer's supported protocols |
#### Example
```js
peerStore.protoBook.get(peerId)
// undefined
peerStore.protoBook.set(peerId, [ '/proto/1.0.0', '/proto/1.1.0' ])
peerStore.protoBook.get(peerId)
// [ '/proto/1.0.0', '/proto/1.1.0' ]
```
### peerStore.protoBook.set
Set known `protocols` of a given peer.
`peerStore.protoBook.set(peerId, protocols)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to set |
| protocols | `Array<string>` | protocols to store |
#### Returns
| Type | Description |
|------|-------------|
| `ProtoBook` | Returns the Proto Book component |
#### Example
```js
peerStore.protoBook.set(peerId, protocols)
```
### peerStore.delete
Delete the provided peer from every book.
`peerStore.delete(peerId)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to remove |
#### Returns
| Type | Description |
|------|-------------|
| `boolean` | true if found and removed |
#### Example
```js
peerStore.delete(peerId)
// false
peerStore.addressBook.set(peerId, multiaddrs)
peerStore.protoBook.set(peerId, protocols)
peerStore.delete(peerId)
// true
peerStore.delete(peerId2)
// false
peerStore.addressBook.set(peerId2, multiaddrs)
peerStore.delete(peerId2)
// true
```
### peerStore.get
Get the stored information of a given peer, namely its [`PeerId`][peer-id], known [`Addresses`][address] and supported protocols.
`peerStore.get(peerId)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | peerId to get |
#### Returns
| Type | Description |
|------|-------------|
| `{ id: PeerId, addresses: Array<Address>, protocols: Array<string> }` | Peer information of the provided peer |
#### Example
```js
peerStore.get(peerId)
// false
peerStore.addressBook.set(peerId, multiaddrs)
peerStore.protoBook.set(peerId, protocols)
peerStore.get(peerId)
// {
// id: {},
// addresses: [...],
// protocols: [...]
// }
```
### peerStore.peers
Get all the stored information of every peer.
`peerStore.peers`
#### Returns
| Type | Description |
|------|-------------|
| `Map<string, { id: PeerId, addresses: Array<Address>, protocols: Array<string> }>` | Peer data of every peer known |
#### Example
```js
for (let [peerIdString, peer] of peerStore.peers.entries()) {
// peer { id, addresses, protocols }
}
```
### pubsub.getSubscribers
Gets a list of the peer-ids that are subscribed to one topic.
@@ -885,7 +525,7 @@ Gets a list of the peer-ids that are subscribed to one topic.
| Type | Description |
|------|-------------|
| `Array<string>` | peer-id subscribed to the topic |
| `Array<String>` | peer-id subscribed to the topic |
#### Example
@@ -903,7 +543,7 @@ Gets a list of topics the node is subscribed to.
| Type | Description |
|------|-------------|
| `Array<string>` | topics the node is subscribed to |
| `Array<String>` | topics the node is subscribed to |
#### Example
@@ -950,7 +590,7 @@ Subscribes the given handler to a pubsub topic.
| Name | Type | Description |
|------|------|-------------|
| topic | `string` | topic to subscribe |
| handler | `function({ from: string, data: Buffer, seqno: Buffer, topicIDs: Array<string>, signature: Buffer, key: Buffer })` | handler for new data on topic |
| handler | `function({ from: String, data: Buffer, seqno: Buffer, topicIDs: Array<String>, signature: Buffer, key: Buffer })` | handler for new data on topic |
#### Returns
@@ -980,7 +620,7 @@ Unsubscribes the given handler from a pubsub topic. If no handler is provided, a
| Name | Type | Description |
|------|------|-------------|
| topic | `string` | topic to unsubscribe |
| handler | `function(<object>)` | handler subscribed |
| handler | `function(<Object>)` | handler subscribed |
#### Returns
@@ -1009,7 +649,7 @@ Enables users to change the value of certain peers in a range of 0 to 1. Peers w
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | The peer to set the value for |
| peerId | `PeerId` | The peer to set the value for |
| value | `number` | The value of the peer from 0 to 1 |
#### Returns
@@ -1037,7 +677,7 @@ const peerIdStrings = libp2p.metrics.peers
### metrics.peers
An array of [`PeerId`][peer-id] strings of each peer currently being tracked.
An array of `PeerId` strings of each peer currently being tracked.
#### Example
@@ -1057,7 +697,7 @@ const protocols = libp2p.metrics.protocols
### metrics.forPeer
Returns the [`Stats`](#stats) object for a given [`PeerId`][peer-id] if it is being tracked.
Returns the [`Stats`](#stats) object for a given `PeerId` if it is being tracked.
`libp2p.metrics.forPeer(peerId)`
@@ -1065,7 +705,7 @@ Returns the [`Stats`](#stats) object for a given [`PeerId`][peer-id] if it is be
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | The peer to get stats for |
| peerId | `PeerId` | The peer to get stats for |
#### Returns
@@ -1076,7 +716,7 @@ Returns the [`Stats`](#stats) object for a given [`PeerId`][peer-id] if it is be
#### Example
```js
const peerStats = libp2p.metrics.forPeer(peerId)
const peerStats = libp2p.metrics.forPeer(peerInfo)
console.log(peerStats.toJSON())
```
@@ -1107,9 +747,7 @@ console.log(peerStats.toJSON())
## Events
Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events.
### libp2p
Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events.
#### An error has occurred
@@ -1124,7 +762,7 @@ Once you have a libp2p instance, you can listen to several events it emits, so t
If `autoDial` option is `true`, applications should **not** attempt to connect to the peer
unless they are performing a specific action. See [peer discovery and auto dial](./PEER_DISCOVERY.md) for more information.
- `peer`: instance of [`PeerId`][peer-id]
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### A new connection to a peer has been opened
@@ -1132,7 +770,7 @@ This event will be triggered anytime a new Connection is established to another
`libp2p.on('peer:connect', (peer) => {})`
- `peer`: instance of [`PeerId`][peer-id]
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### An existing connection to a peer has been closed
@@ -1140,29 +778,7 @@ This event will be triggered anytime we are disconnected from another peer, rega
`libp2p.on('peer:disconnect', (peer) => {})`
- `peer`: instance of [`PeerId`][peer-id]
### libp2p.peerStore
#### A new peer is added to the peerStore
`libp2p.peerStore.on('peer', (peerId) => {})`
- `peerId`: instance of [`PeerId`][peer-id]
#### Known multiaddrs for a peer change
`libp2p.peerStore.on('change:multiaddrs', ({ peerId, multiaddrs}) => {})`
- `peerId`: instance of [`PeerId`][peer-id]
- `multiaddrs`: array of known [`multiaddr`][multiaddr] for the peer
#### Known protocols for a peer change
`libp2p.peerStore.on('change:protocols', ({ peerId, protocols}) => {})`
- `peerId`: instance of [`PeerId`][peer-id]
- `protocols`: array of known, supported protocols for the peer (string identifiers)
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
## Types
@@ -1173,9 +789,9 @@ This event will be triggered anytime we are disconnected from another peer, rega
- `dataReceived<string>`: The stringified value of total incoming data for this stat.
- `dataSent<string>`: The stringified value of total outgoing data for this stat.
- `movingAverages<object>`: The properties are dependent on the configuration of the moving averages interval. Defaults are listed here.
- `['60000']<number>`: The calculated moving average at a 1 minute interval.
- `['300000']<number>`: The calculated moving average at a 5 minute interval.
- `['900000']<number>`: The calculated moving average at a 15 minute interval.
- `['60000']<Number>`: The calculated moving average at a 1 minute interval.
- `['300000']<Number>`: The calculated moving average at a 5 minute interval.
- `['900000']<Number>`: The calculated moving average at a 15 minute interval.
- `snapshot<object>`: A getter that returns a clone of the raw stats.
- `dataReceived<BigNumber>`: A [`BigNumber`](https://github.com/MikeMcl/bignumber.js/) of the amount of incoming data
- `dataSent<BigNumber>`: A [`BigNumber`](https://github.com/MikeMcl/bignumber.js/) of the amount of outgoing data
@@ -1184,8 +800,5 @@ This event will be triggered anytime we are disconnected from another peer, rega
- `['300000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 5 minute interval.
- `['900000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 15 minute interval.
[address]: https://github.com/libp2p/js-libp2p/tree/master/src/peer-store/address-book.js
[cid]: https://github.com/multiformats/js-cid
[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
[multiaddr]: https://github.com/multiformats/js-multiaddr
[peer-id]: https://github.com/libp2p/js-peer-id

View File

@@ -113,7 +113,6 @@ Some available peer discovery modules are:
- [js-libp2p-bootstrap](https://github.com/libp2p/js-libp2p-bootstrap)
- [js-libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht)
- [js-libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star)
- [discv5](https://github.com/chainsafe/discv5)
**Note**: `peer-discovery` services within transports (such as `js-libp2p-webrtc-star`) are automatically gathered from the `transport`, via it's `discovery` property. As such, they do not need to be added in the discovery modules. However, these transports can also be configured and disabled as the other ones.

View File

@@ -1,178 +0,0 @@
# Migrating to the new API
A migration guide for refactoring your application code from libp2p v0.26.x to v0.27.0.
## Table of Contents
- [Migrating from callbacks](#migrating-from-callbacks)
- [Pull Streams to Streaming Iterables](#pull-streams-to-streaming-iterables)
- [Sample API Migrations](#sample-api-migrations)
- [Registering Protocol Handlers](#registering-protocol-handlers)
- [Dialing and Sending Data](#dialing-and-sending-data)
- [Checking if a peer is connected](#checking-if-a-peer-is-connected)
- [Pinging another peer](#pinging-another-peer)
- [Pubsub](#pubsub)
- [Getting subscribers](#getting-subscribers)
- [Getting subscribed topics](#getting-subscribed-topics)
## Migrating from callbacks
Callbacks are no longer supported in the libp2p API, as the API has now fully moved to async / await. You can see a full list of the available methods in the [API readme][api]
**Before**
```js
libp2p.start((err) => {
if (err) throw err
console.log('libp2p started')
})
```
**After**
```js
await libp2p.start()
console.log('libp2p started')
```
## Pull Streams to Streaming Iterables
The libp2p API no longer supports Pull Streams and has migrated to [Streaming Iterables][streaming_iterable]. If you would like to continue using Pull Streams in your application code, or need additional time to migrate your code base, you can leverage the conversion modules [async-iterator-to-pull-stream](https://github.com/alanshaw/async-iterator-to-pull-stream) and [pull-stream-to-async-iterator](https://github.com/alanshaw/pull-stream-to-async-iterator).
For a growing list of async iterator modules, you should follow the [it-awesome repo][it_awesome].
## Sample API Migrations
### Registering Protocol Handlers
Protocol registration is very similar to how it previously was, however, the handler now takes a single parameter containing the incoming stream and its protocol. Additionally, you can now pass an array of protocols to `.handle`, but a single string is still supported.
**Before**
```js
const pull = require('pull-stream')
libp2p.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
```
**After**
```js
const pipe = require('it-pipe')
libp2p.handle(['/echo/1.0.0'], ({ protocol, stream }) => pipe(stream, stream))
```
### Dialing and Sending Data
`dialProtocol` no longer takes a callback, and will now return a [Streaming Iterable][streaming_iterable] and the protocol that was successfully negotiated. The new stream can be used with async iterator modules, see [it-awesome][it_awesome], instead of pull streams.
**Before**
```js
const pull = require('pull-stream')
libp2p.dialProtocol(peerInfo, '/echo/1.0.0', (err, conn) => {
if (err) { throw err }
pull(
pull.values(['hey']),
conn,
pull.drain((data) => {
console.log('received echo:', data.toString())
}, (err) => {
if (err) { throw err }
})
)
})
```
**After**
```js
const pipe = require('it-pipe')
const { protocol, stream } = await libp2p.dialProtocol(peerInfo, '/echo/1.0.0')
await pipe(
['hey'],
stream,
async function (source) {
for await (const data of source) {
console.log('received echo:', data.toString())
}
}
)
```
### Checking if a peer is connected
`peerInfo.isConnected` has been deprecated. libp2p now tracks all connections centrally and will no longer update the state of `peerInfo.isConnected`. Consumers should switch to using `libp2p.registrar.getConnection(peerInfo)`, which will return an open connection to that peer if one exists.
**Before**
```js
if (peerInfo.isConnected()) {
// ...do something if connected
}
```
**After**
```js
const connection = libp2p.registrar.getConnection(peerInfo)
if (connection) {
// ...do something if connected
}
```
### Pinging another peer
`libp2p.ping` will no longer callback with a `Ping` event emitter. The internal logic has been simplified to give more flexibility to the API. `libp2p.ping` will now execute a single ping and return the latency.
**Before**
```js
libp2p.ping(peerInfo, (err, ping) => {
if (err) throw err
ping.once('ping', (latency) => {
console.log('Latency is %s ms', latency)
ping.stop()
})
ping.start()
})
```
**After**
```js
const latency = await libp2p.ping(peerInfo)
console.log('Latency is %s ms', latency)
```
### Pubsub
#### Getting subscribers
`libp2p.pubsub.peers()` is now `libp2p.pubsub.getSubscribers()` and is no longer an asynchronous action.
**Before**
```js
libp2p.pubsub.peers(topic, (err, subscribers) => {
if (err) throw err
console.log('Subscribers:', subscribers)
})
```
**After**
```js
const subscribers = libp2p.pubsub.getSubscribers(topic)
console.log('Subscribers:', subscribers)
```
#### Getting subscribed topics
`libp2p.pubsub.ls()` is now `libp2p.pubsub.getTopics()` and is no longer an asynchronous action.
**Before**
```js
libp2p.pubsub.ls((err, topics) => {
if (err) throw err
console.log('Topics:', topics)
})
```
**After**
```js
const topics = libp2p.pubsub.getTopics()
console.log('Topics:', topics)
```
[api]: ../API.md
[it_awesome]: https://github.com/alanshaw/it-awesome
[streaming_iterable]: ../STREAMING_ITERABLES.md

View File

@@ -1,7 +1,3 @@
❗❗Outdated: This example is still not refactored with the `0.27.*` release.
WIP on [libp2p/js-libp2p#507](https://github.com/libp2p/js-libp2p/pull/507)
======
# Delegated Routing with Libp2p and IPFS
This example shows how to use delegated peer and content routing. The [Peer and Content Routing Example](../peer-and-content-routing) focuses

View File

@@ -17,22 +17,26 @@
"transports",
["libp2p/js-libp2p-tcp", "libp2p-tcp"],
["libp2p/js-libp2p-utp", "libp2p-utp"],
["libp2p/js-libp2p-webrtc-direct", "libp2p-webrtc-direct"],
["libp2p/js-libp2p-webrtc-star", "libp2p-webrtc-star"],
["libp2p/js-libp2p-websockets", "libp2p-websockets"],
["libp2p/js-libp2p-websocket-star", "libp2p-websocket-star"],
"secure channels",
["libp2p/js-libp2p-secio", "libp2p-secio"],
"stream multiplexers",
["libp2p/js-libp2p-mplex", "libp2p-mplex"],
["libp2p/js-libp2p-spdy", "libp2p-spdy"],
"peer discovery",
["libp2p/js-libp2p-bootstrap", "libp2p-bootstrap"],
["libp2p/js-libp2p-kad-dht", "libp2p-kad-dht"],
["libp2p/js-libp2p-mdns", "libp2p-mdns"],
["libp2p/js-libp2p-rendezvous", "libp2p-rendezvous"],
["libp2p/js-libp2p-webrtc-star", "libp2p-webrtc-star"],
["ChainSafe/discv5", "discv5"],
["libp2p/js-libp2p-websocket-star", "libp2p-websocket-star"],
"content routing",
["libp2p/js-libp2p-delegated-content-routing", "libp2p-delegated-content-routing"],

View File

@@ -1,6 +1,6 @@
{
"name": "libp2p",
"version": "0.27.5",
"version": "0.27.0-rc.0",
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js",
@@ -47,7 +47,7 @@
"bignumber.js": "^9.0.0",
"class-is": "^1.1.0",
"debug": "^4.1.1",
"err-code": "^2.0.0",
"err-code": "^1.1.2",
"hashlru": "^2.3.0",
"it-all": "^1.0.1",
"it-buffer": "^0.1.1",
@@ -57,18 +57,18 @@
"it-protocol-buffers": "^0.2.0",
"latency-monitor": "~0.2.1",
"libp2p-crypto": "^0.17.1",
"libp2p-interfaces": "^0.3.0",
"libp2p-utils": "^0.1.2",
"libp2p-interfaces": "^0.2.3",
"mafmt": "^7.0.0",
"merge-options": "^2.0.0",
"moving-average": "^1.0.0",
"multiaddr": "^7.2.1",
"multistream-select": "^0.15.0",
"mutable-proxy": "^1.0.0",
"p-any": "^3.0.0",
"p-any": "^2.1.0",
"p-fifo": "^1.0.0",
"p-settle": "^4.0.0",
"p-settle": "^3.1.0",
"peer-id": "^0.13.4",
"peer-info": "^0.17.0",
"protons": "^1.0.1",
"retimer": "^2.0.0",
"timeout-abort-controller": "^1.0.0",
@@ -76,77 +76,90 @@
},
"devDependencies": {
"@nodeutils/defaults-deep": "^1.1.0",
"abortable-iterator": "^3.0.0",
"aegir": "^21.3.0",
"abortable-iterator": "^2.1.0",
"aegir": "^20.5.1",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"cids": "^0.8.0",
"cids": "^0.7.1",
"delay": "^4.3.0",
"dirty-chai": "^2.0.1",
"interop-libp2p": "libp2p/interop#chore/update-libp2p-daemon-with-peerstore",
"ipfs-http-client": "^44.0.0",
"it-concat": "^1.0.0",
"it-pair": "^1.0.0",
"it-pushable": "^1.4.0",
"libp2p-bootstrap": "^0.11.0",
"libp2p-delegated-content-routing": "^0.5.0",
"libp2p-delegated-peer-routing": "^0.5.0",
"libp2p-floodsub": "^0.21.0",
"libp2p-gossipsub": "^0.4.0",
"libp2p-kad-dht": "^0.19.1",
"libp2p-mdns": "^0.14.0",
"libp2p-bootstrap": "^0.10.3",
"libp2p-delegated-content-routing": "^0.4.1",
"libp2p-delegated-peer-routing": "^0.4.0",
"libp2p-floodsub": "^0.20.0",
"libp2p-gossipsub": "^0.2.0",
"libp2p-kad-dht": "^0.18.2",
"libp2p-mdns": "^0.13.0",
"libp2p-mplex": "^0.9.1",
"libp2p-secio": "^0.12.1",
"libp2p-tcp": "^0.14.1",
"libp2p-webrtc-star": "^0.18.0",
"libp2p-webrtc-star": "^0.17.0",
"libp2p-websockets": "^0.13.1",
"nock": "^12.0.0",
"nock": "^10.0.6",
"p-defer": "^3.0.0",
"p-times": "^2.1.0",
"p-wait-for": "^3.1.0",
"sinon": "^9.0.0",
"sinon": "^8.1.0",
"streaming-iterables": "^4.1.0",
"wrtc": "^0.4.1"
},
"contributors": [
"David Dias <daviddias.p@gmail.com>",
"Jacob Heun <jacobheun@gmail.com>",
"Vasco Santos <vasco.santos@moxy.studio>",
"Aditya Bose <13054902+adbose@users.noreply.github.com>",
"Alan Shaw <alan.shaw@protocol.ai>",
"Alan Shaw <alan@tableflip.io>",
"Pedro Teixeira <i@pgte.me>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Alex Potsides <alex@achingbrain.net>",
"dirkmc <dirkmdev@gmail.com>",
"Volker Mische <volker.mische@gmail.com>",
"Hugo Dias <mail@hugodias.me>",
"Richard Littauer <richard.littauer@gmail.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
"Andrew Nesbitt <andrewnez@gmail.com>",
"Cayman <caymannava@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"Chris Dostert <chrisdostert@users.noreply.github.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"David Dias <daviddias.p@gmail.com>",
"Didrik Nordström <didrik.nordstrom@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Ryan Bell <ryan@piing.net>",
"Thomas Eizinger <thomas@eizinger.io>",
"Joel Gustafson <joelg@mit.edu>",
"Kevin Kwok <antimatter15@gmail.com>",
"Henrique Dias <hacdias@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Fei Liu <liu.feiwood@gmail.com>",
"Florian-Merle <florian.david.merle@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Guy Sviry <32539816+guysv@users.noreply.github.com>",
"Henrique Dias <hacdias@gmail.com>",
"Hugo Dias <mail@hugodias.me>",
"Hugo Dias <hugomrdias@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.com>",
"Jacob Heun <jacobheun@gmail.com>",
"Joel Gustafson <joelg@mit.edu>",
"John Rees <johnrees@users.noreply.github.com>",
"João Santos <joaosantos15@users.noreply.github.com>",
"Kevin Kwok <antimatter15@gmail.com>",
"Lars Gierth <lgierth@users.noreply.github.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Marcin Tojek <mtojek@users.noreply.github.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Pedro Teixeira <pedro@protocol.ai>",
"Pedro Teixeira <i@pgte.me>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"Ryan Bell <ryan@piing.net>",
"Soeren <nikorpoulsen@gmail.com>",
"Sönke Hahn <soenkehahn@gmail.com>",
"Thomas Eizinger <thomas@eizinger.io>",
"Tiago Alves <alvesjtiago@gmail.com>",
"Fei Liu <liu.feiwood@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Vasco Santos <vasco.santos@moxy.studio>",
"Vasco Santos <vasco.santos@ua.pt>",
"Volker Mische <volker.mische@gmail.com>",
"Yusef Napora <yusef@napora.org>",
"Zane Starr <zcstarr@gmail.com>",
"Didrik Nordström <didrik.nordstrom@gmail.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"a1300 <a1300@users.noreply.github.com>",
"dirkmc <dirkmdev@gmail.com>",
"ebinks <elizabethjbinks@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>",
"isan_rivkin <isanrivkin@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.com>"
"mayerwin <mayerwin@users.noreply.github.com>",
"phillmac <phillmac@users.noreply.github.com>",
"swedneck <40505480+swedneck@users.noreply.github.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>"
]
}

3
pdd/README.md Normal file
View File

@@ -0,0 +1,3 @@
# PDD Test Stories Implementation
> Implementation of the Compliance tests from https://github.com/libp2p/interop

20
pdd/package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "pdd-impl",
"version": "0.0.0",
"description": "PDD Test Stories implementation",
"repository": {
"type": "git",
"url": " "
},
"keywords": [
"PDD",
"libp2p"
],
"author": "David Dias <daviddias@ipfs.io>",
"license": "MIT",
"dependencies": {
"libp2p": "file:./..",
"libp2p-interop": "github:libp2p/interop#master",
"tape": "^4.8.0"
}
}

View File

@@ -0,0 +1,104 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const Multiplex = require('libp2p-multiplex')
const Railing = require('libp2p-railing')
const MulticastDNS = require('libp2p-mdns')
const KadDHT = require('libp2p-kad-dht')
const PeerInfo = require('peer-info')
const pull = require('pull-stream')
const waterfall = require('async/waterfall')
const series = require('async/series')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class IPFSBundle extends libp2p {
constructor (peerInfo, options) {
options = Object.assign({ bootstrap: [] }, options)
const modules = {
transport: [
new TCP(),
new WebSockets()
],
connection: {
muxer: [
Multiplex
],
crypto: [
SECIO
]
},
discovery: [
new MulticastDNS(peerInfo, 'ipfs.local'),
new Railing(options.bootstrap)
],
DHT: KadDHT
}
super(modules, peerInfo, undefined, options)
}
}
test('story 1 - peerA', (t) => {
t.plan(10)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new IPFSBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node successfully')
t.ok(node.isStarted(), 'PeerA is Running')
const peerBAddr = `/ip4/127.0.0.1/tcp/10001/p2p/${PeerB.id}`
node.handle('/time/1.0.0', (protocol, conn) => {
pull(
pull.values([Date.now().toString()]),
conn,
pull.onEnd((err) => {
t.ifErr(err)
t.pass('Sent time successfully')
})
)
})
series([
(cb) => setTimeout(cb, 5 * 1000), // time to run both scripts
(cb) => node.ping(peerBAddr, (err, p) => {
t.ifErr(err, 'initiated Ping to PeerB')
p.once('error', (err) => t.ifErr(err, 'Ping should not fail'))
p.once('ping', (time) => {
t.pass('ping PeerB successfully')
p.stop()
cb()
})
}),
(cb) => node.dial(peerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Hey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
cb()
})
)
}),
(cb) => setTimeout(cb, 2 * 1000) // time to both finish
], () => node.stop((err) => t.ifErr(err, 'PeerA has stopped')))
})
})

View File

@@ -0,0 +1,98 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const Multiplex = require('libp2p-multiplex')
const Railing = require('libp2p-railing')
const MulticastDNS = require('libp2p-mdns')
const KadDHT = require('libp2p-kad-dht')
const PeerInfo = require('peer-info')
const pull = require('pull-stream')
const waterfall = require('async/waterfall')
const series = require('async/series')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class IPFSBundle extends libp2p {
constructor (peerInfo, options) {
options = Object.assign({ bootstrap: [] }, options)
const modules = {
transport: [
new TCP(),
new WebSockets()
],
connection: {
muxer: [
Multiplex
],
crypto: [
SECIO
]
},
discovery: [
new MulticastDNS(peerInfo, 'ipfs.local'),
new Railing(options.bootstrap)
],
DHT: KadDHT
}
super(modules, peerInfo, undefined, options)
}
}
test('story 1 - peerA', (t) => {
t.plan(8)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001')
node = new IPFSBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node successfully')
t.ok(node.isStarted(), 'PeerB is Running')
const peerAAddr = `/ip4/127.0.0.1/tcp/10000/p2p/${PeerA.id}`
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
conn,
pull.onEnd((err) => t.ifErr(err, 'echo was successful'))
)
})
series([
(cb) => setTimeout(cb, 5 * 1000), // time to run both scripts
(cb) => node.ping(peerAAddr, (err, p) => {
t.ifErr(err, 'initiated Ping to PeerA')
p.once('error', (err) => t.ifErr(err, 'Ping should not fail'))
p.once('ping', (time) => {
t.pass('ping PeerA successfully')
p.stop()
cb()
})
}),
(cb) => node.dial(peerAAddr, '/time/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
pull(
pull.values([]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received time')
cb()
})
)
}),
(cb) => setTimeout(cb, 2 * 1000) // time to both finish
], () => node.stop((err) => t.ifErr(err, 'PeerB has stopped')))
})
})

View File

@@ -0,0 +1,54 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 1 - peerA', (t) => {
t.plan(6)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/p2p/${PeerB.id}`
node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Heey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
})
)
})
})
})

View File

@@ -0,0 +1,49 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 1 - peerB', (t) => {
t.plan(5)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err)
t.ok(node.isStarted(), 'PeerB is running')
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
conn,
pull.onEnd((err) => {
t.ifErr(err)
t.pass('Received End of Connection')
node.stop((err) => {
t.ifErr(err, 'PeerB has stopped')
})
})
)
})
})
})

View File

@@ -0,0 +1,54 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 2 - peerA', (t) => {
t.plan(6)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/p2p/${PeerB.id}`
node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Heey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
})
)
})
})
})

View File

@@ -0,0 +1,49 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 2 - peerB', (t) => {
t.plan(5)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err)
t.ok(node.isStarted(), 'PeerB is running')
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
pull.through(v => v, err => {
t.ifErr(err)
t.pass('Received End of Connection')
node.stop((err) => {
t.ifErr(err, 'PeerB has stopped')
})
}),
conn
)
})
})
})

View File

@@ -0,0 +1,42 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 3 - peerA', (t) => {
t.plan(4)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/ws/p2p/${PeerB.id}`
setTimeout(() => node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ok(err, 'dial failed')
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
}), 1000)
})
})

View File

@@ -0,0 +1,42 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 3 - peerB', (t) => {
t.plan(4)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerAAddr = `/ip4/127.0.0.1/tcp/10000/ws/p2p/${PeerA.id}`
setTimeout(() => node.dial(PeerAAddr, '/echo/1.0.0', (err, conn) => {
t.ok(err, 'dial failed')
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
}), 1000)
})
})

View File

@@ -1,9 +1,7 @@
'use strict'
const debug = require('debug')
const log = debug('libp2p:circuit:hop')
log.error = debug('libp2p:circuit:hop:error')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const { validateAddrs } = require('./utils')
const StreamHandler = require('./stream-handler')
@@ -16,6 +14,9 @@ const { stop } = require('./stop')
const multicodec = require('./../multicodec')
const log = debug('libp2p:circuit:hop')
log.error = debug('libp2p:circuit:hop:error')
module.exports.handleHop = async function handleHop ({
connection,
request,
@@ -41,7 +42,7 @@ module.exports.handleHop = async function handleHop ({
// Get the connection to the destination (stop) peer
const destinationPeer = new PeerId(request.dstPeer.id)
const destinationConnection = circuit._registrar.getConnection(destinationPeer)
const destinationConnection = circuit._registrar.getConnection(new PeerInfo(destinationPeer))
if (!destinationConnection && !circuit._options.hop.active) {
log('HOP request received but we are not connected to the destination peer')
return streamHandler.end({

View File

@@ -3,19 +3,20 @@
const mafmt = require('mafmt')
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const withIs = require('class-is')
const { CircuitRelay: CircuitPB } = require('./protocol')
const debug = require('debug')
const log = debug('libp2p:circuit')
log.error = debug('libp2p:circuit:error')
const toConnection = require('libp2p-utils/src/stream-to-ma-conn')
const { relay: multicodec } = require('./multicodec')
const createListener = require('./listener')
const { handleCanHop, handleHop, hop } = require('./circuit/hop')
const { handleStop } = require('./circuit/stop')
const StreamHandler = require('./circuit/stream-handler')
const toConnection = require('./stream-to-conn')
class Circuit {
/**
@@ -31,8 +32,7 @@ class Circuit {
this._registrar = libp2p.registrar
this._upgrader = upgrader
this._options = libp2p._config.relay
this.addresses = libp2p.addresses
this.peerId = libp2p.peerId
this.peerInfo = libp2p.peerInfo
this._registrar.handle(multicodec, this._onProtocol.bind(this))
}
@@ -107,7 +107,7 @@ class Circuit {
const destinationPeer = PeerId.createFromCID(destinationAddr.getPeerId())
let disconnectOnFailure = false
let relayConnection = this._registrar.getConnection(relayPeer)
let relayConnection = this._registrar.getConnection(new PeerInfo(relayPeer))
if (!relayConnection) {
relayConnection = await this._dialer.connectToPeer(relayAddr, options)
disconnectOnFailure = true
@@ -120,8 +120,8 @@ class Circuit {
request: {
type: CircuitPB.Type.HOP,
srcPeer: {
id: this.peerId.toBytes(),
addrs: this.addresses.listen.map(addr => addr.buffer)
id: this.peerInfo.id.toBytes(),
addrs: this.peerInfo.multiaddrs.toArray().map(addr => addr.buffer)
},
dstPeer: {
id: destinationPeer.toBytes(),
@@ -130,7 +130,7 @@ class Circuit {
}
})
const localAddr = relayAddr.encapsulate(`/p2p-circuit/p2p/${this.peerId.toB58String()}`)
const localAddr = relayAddr.encapsulate(`/p2p-circuit/p2p/${this.peerInfo.id.toB58String()}`)
const maConn = toConnection({
stream: virtualConnection,
remoteAddr: ma,

View File

@@ -22,7 +22,7 @@ module.exports = (circuit) => {
* @return {void}
*/
listener.listen = async (addr) => {
const addrString = String(addr).split('/p2p-circuit').find(a => a !== '')
const [addrString] = String(addr).split('/p2p-circuit').slice(-1)
const relayConn = await circuit._dialer.connectToPeer(multiaddr(addrString))
const relayedAddr = relayConn.remoteAddr.encapsulate('/p2p-circuit')

View File

@@ -0,0 +1,49 @@
'use strict'
const abortable = require('abortable-iterator')
const log = require('debug')('libp2p:circuit:stream')
// Convert a duplex iterable into a MultiaddrConnection
// https://github.com/libp2p/interface-transport#multiaddrconnection
module.exports = ({ stream, remoteAddr, localAddr }, options = {}) => {
const { sink, source } = stream
const maConn = {
async sink (source) {
if (options.signal) {
source = abortable(source, options.signal)
}
try {
await sink(source)
} catch (err) {
// If aborted we can safely ignore
if (err.type !== 'aborted') {
// If the source errored the socket will already have been destroyed by
// toIterable.duplex(). If the socket errored it will already be
// destroyed. There's nothing to do here except log the error & return.
log(err)
}
}
close()
},
source: options.signal ? abortable(source, options.signal) : source,
conn: stream,
localAddr,
remoteAddr,
timeline: { open: Date.now() },
close () {
sink([])
close()
}
}
function close () {
if (!maConn.timeline.close) {
maConn.timeline.close = Date.now()
}
}
return maConn
}

View File

@@ -4,9 +4,6 @@ const mergeOptions = require('merge-options')
const Constants = require('./constants')
const DefaultConfig = {
addresses: {
listen: []
},
connectionManager: {
minPeers: 25
},

View File

@@ -1,15 +1,11 @@
'use strict'
const errcode = require('err-code')
const assert = require('assert')
const mergeOptions = require('merge-options')
const LatencyMonitor = require('latency-monitor').default
const debug = require('debug')('libp2p:connection-manager')
const retimer = require('retimer')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
const defaultOptions = {
maxConnections: Infinity,
minConnections: 0,
@@ -40,11 +36,12 @@ class ConnectionManager {
constructor (libp2p, options) {
this._libp2p = libp2p
this._registrar = libp2p.registrar
this._peerId = libp2p.peerId.toB58String()
this._peerId = libp2p.peerInfo.id.toB58String()
this._options = mergeOptions.call({ ignoreUndefined: true }, defaultOptions, options)
if (this._options.maxConnections < this._options.minConnections) {
throw errcode(new Error('Connection Manager maxConnections must be greater than minConnections'), ERR_INVALID_PARAMETERS)
}
assert(
this._options.maxConnections > this._options.minConnections,
'Connection Manager maxConnections must be greater than minConnections'
)
debug('options: %j', this._options)

View File

@@ -24,7 +24,7 @@ module.exports = (node) => {
* @param {object} [options]
* @param {number} [options.timeout] How long the query should run
* @param {number} [options.maxNumProviders] - maximum number of providers to find
* @returns {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>}
* @returns {AsyncIterable<PeerInfo>}
*/
async * findProviders (key, options) {
if (!routers.length) {
@@ -42,8 +42,8 @@ module.exports = (node) => {
})
)
for (const peer of result) {
yield peer
for (const pInfo of result) {
yield pInfo
}
},

View File

@@ -4,12 +4,12 @@ const multiaddr = require('multiaddr')
const errCode = require('err-code')
const TimeoutController = require('timeout-abort-controller')
const anySignal = require('any-signal')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const debug = require('debug')
const log = debug('libp2p:dialer')
log.error = debug('libp2p:dialer:error')
const { DialRequest } = require('./dial-request')
const getPeer = require('../get-peer')
const { codes } = require('../errors')
const {
@@ -58,20 +58,19 @@ class Dialer {
}
/**
* Connects to a given `peer` by dialing all of its known addresses.
* Connects to a given `PeerId` or `Multiaddr` 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
* @param {PeerInfo|Multiaddr} peer The peer to dial
* @param {object} [options]
* @param {AbortSignal} [options.signal] An AbortController signal
* @returns {Promise<Connection>}
*/
async connectToPeer (peer, options = {}) {
const dialTarget = this._createDialTarget(peer)
if (!dialTarget.addrs.length) {
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
if (dialTarget.addrs.length === 0) {
throw errCode(new Error('The dial request has no addresses'), 'ERR_NO_DIAL_MULTIADDRS')
}
const pendingDial = this._pendingDials.get(dialTarget.id) || this._createPendingDial(dialTarget, options)
@@ -100,29 +99,21 @@ class Dialer {
/**
* Creates a DialTarget. The DialTarget is used to create and track
* the DialRequest to a given peer.
* If a multiaddr is received it should be the first address attempted.
* @private
* @param {PeerId|Multiaddr|string} peer A PeerId or Multiaddr
* @param {PeerInfo|Multiaddr} peer A PeerId or Multiaddr
* @returns {DialTarget}
*/
_createDialTarget (peer) {
const { id, multiaddrs } = getPeer(peer)
if (multiaddrs) {
this.peerStore.addressBook.add(id, multiaddrs)
const dialable = Dialer.getDialable(peer)
if (multiaddr.isMultiaddr(dialable)) {
return {
id: dialable.toString(),
addrs: [dialable]
}
}
let addrs = this.peerStore.addressBook.getMultiaddrsForPeer(id)
// If received a multiaddr to dial, it should be the first to use
// But, if we know other multiaddrs for the peer, we should try them too.
if (multiaddr.isMultiaddr(peer)) {
addrs = addrs.filter((addr) => !peer.equals(addr))
addrs.unshift(peer)
}
const addrs = this.peerStore.multiaddrsForPeer(dialable)
return {
id: id.toB58String(),
id: dialable.id.toB58String(),
addrs
}
}
@@ -145,7 +136,7 @@ class Dialer {
*/
_createPendingDial (dialTarget, options) {
const dialAction = (addr, options) => {
if (options.signal.aborted) throw errCode(new Error('already aborted'), codes.ERR_ALREADY_ABORTED)
if (options.signal.aborted) throw errCode(new Error('already aborted'), 'ERR_ALREADY_ABORTED')
return this.transportManager.dial(addr, options)
}
@@ -187,6 +178,37 @@ class Dialer {
log('token %d released', token)
this.tokens.push(token)
}
/**
* Converts the given `peer` into a `PeerInfo` or `Multiaddr`.
* @static
* @param {PeerInfo|PeerId|Multiaddr|string} peer
* @returns {PeerInfo|Multiaddr}
*/
static getDialable (peer) {
if (PeerInfo.isPeerInfo(peer)) return peer
if (typeof peer === 'string') {
peer = multiaddr(peer)
}
let addr
if (multiaddr.isMultiaddr(peer)) {
addr = peer
try {
peer = PeerId.createFromCID(peer.getPeerId())
} catch (err) {
// Couldn't get the PeerId, just use the address
return peer
}
}
if (PeerId.isPeerId(peer)) {
peer = new PeerInfo(peer)
}
addr && peer.multiaddrs.add(addr)
return peer
}
}
module.exports = Dialer

View File

@@ -12,7 +12,6 @@ exports.codes = {
ERR_CONNECTION_ENDED: 'ERR_CONNECTION_ENDED',
ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED',
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
ERR_DISCOVERED_SELF: 'ERR_DISCOVERED_SELF',
ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT',
@@ -20,12 +19,10 @@ exports.codes = {
ERR_HOP_REQUEST_FAILED: 'ERR_HOP_REQUEST_FAILED',
ERR_INVALID_KEY: 'ERR_INVALID_KEY',
ERR_INVALID_MESSAGE: 'ERR_INVALID_MESSAGE',
ERR_INVALID_PARAMETERS: 'ERR_INVALID_PARAMETERS',
ERR_INVALID_PEER: 'ERR_INVALID_PEER',
ERR_MUXER_UNAVAILABLE: 'ERR_MUXER_UNAVAILABLE',
ERR_TIMEOUT: 'ERR_TIMEOUT',
ERR_TRANSPORT_UNAVAILABLE: 'ERR_TRANSPORT_UNAVAILABLE',
ERR_TRANSPORT_DIAL_FAILED: 'ERR_TRANSPORT_DIAL_FAILED',
ERR_UNSUPPORTED_PROTOCOL: 'ERR_UNSUPPORTED_PROTOCOL',
ERR_INVALID_MULTIADDR: 'ERR_INVALID_MULTIADDR'
ERR_UNSUPPORTED_PROTOCOL: 'ERR_UNSUPPORTED_PROTOCOL'
}

73
src/get-peer-info.js Normal file
View File

@@ -0,0 +1,73 @@
'use strict'
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const multiaddr = require('multiaddr')
const errCode = require('err-code')
/**
* Converts the given `peer` to a `PeerInfo` instance.
* The `PeerStore` will be checked for the resulting peer, and
* the peer will be updated in the `PeerStore`.
*
* @param {PeerInfo|PeerId|Multiaddr|string} peer
* @param {PeerStore} peerStore
* @returns {PeerInfo}
*/
function getPeerInfo (peer, peerStore) {
if (typeof peer === 'string') {
peer = multiaddr(peer)
}
let addr
if (multiaddr.isMultiaddr(peer)) {
addr = peer
try {
peer = PeerId.createFromB58String(peer.getPeerId())
} catch (err) {
throw errCode(
new Error(`${peer} is not a valid peer type`),
'ERR_INVALID_MULTIADDR'
)
}
}
if (PeerId.isPeerId(peer)) {
peer = new PeerInfo(peer)
}
addr && peer.multiaddrs.add(addr)
return peerStore ? peerStore.put(peer) : peer
}
/**
* If `getPeerInfo` does not return a peer with multiaddrs,
* the `libp2p` PeerRouter will be used to attempt to find the peer.
*
* @async
* @param {PeerInfo|PeerId|Multiaddr|string} peer
* @param {Libp2p} libp2p
* @returns {Promise<PeerInfo>}
*/
function getPeerInfoRemote (peer, libp2p) {
let peerInfo
try {
peerInfo = getPeerInfo(peer, libp2p.peerStore)
} catch (err) {
throw errCode(err, 'ERR_INVALID_PEER_TYPE')
}
// If we don't have an address for the peer, attempt to find it
if (peerInfo.multiaddrs.size < 1) {
return libp2p.peerRouting.findPeer(peerInfo.id)
}
return peerInfo
}
module.exports = {
getPeerInfoRemote,
getPeerInfo
}

View File

@@ -1,40 +0,0 @@
'use strict'
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const errCode = require('err-code')
const { codes } = require('./errors')
/**
* Converts the given `peer` to a `Peer` object.
* If a multiaddr is received, the addressBook is updated.
* @param {PeerId|Multiaddr|string} peer
* @param {PeerStore} peerStore
* @returns {{ id: PeerId, multiaddrs: Array<Multiaddr> }}
*/
function getPeer (peer) {
if (typeof peer === 'string') {
peer = multiaddr(peer)
}
let addr
if (multiaddr.isMultiaddr(peer)) {
addr = peer
try {
peer = PeerId.createFromB58String(peer.getPeerId())
} catch (err) {
throw errCode(
new Error(`${peer} is not a valid peer type`),
codes.ERR_INVALID_MULTIADDR
)
}
}
return {
id: peer,
multiaddrs: addr ? [addr] : undefined
}
}
module.exports = getPeer

View File

@@ -4,8 +4,9 @@ const debug = require('debug')
const pb = require('it-protocol-buffers')
const lp = require('it-length-prefixed')
const pipe = require('it-pipe')
const { collect, take, consume } = require('streaming-iterables')
const { collect, take } = require('streaming-iterables')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const { toBuffer } = require('it-buffer')
@@ -26,6 +27,39 @@ const errCode = require('err-code')
const { codes } = require('../errors')
class IdentifyService {
/**
* Replaces the multiaddrs on the given `peerInfo`,
* with the provided `multiaddrs`
* @param {PeerInfo} peerInfo
* @param {Array<Multiaddr>|Array<Buffer>} multiaddrs
*/
static updatePeerAddresses (peerInfo, multiaddrs) {
if (multiaddrs && multiaddrs.length > 0) {
peerInfo.multiaddrs.clear()
multiaddrs.forEach(ma => {
try {
peerInfo.multiaddrs.add(ma)
} catch (err) {
log.error('could not add multiaddr', err)
}
})
}
}
/**
* Replaces the protocols on the given `peerInfo`,
* with the provided `protocols`
* @static
* @param {PeerInfo} peerInfo
* @param {Array<string>} protocols
*/
static updatePeerProtocols (peerInfo, protocols) {
if (protocols && protocols.length > 0) {
peerInfo.protocols.clear()
protocols.forEach(proto => peerInfo.protocols.add(proto))
}
}
/**
* Takes the `addr` and converts it to a Multiaddr if possible
* @param {Buffer|String} addr
@@ -47,8 +81,7 @@ class IdentifyService {
* @param {object} options
* @param {Registrar} options.registrar
* @param {Map<string, handler>} options.protocols A reference to the protocols we support
* @param {PeerId} options.peerId The peer running the identify service
* @param {{ listen: Array<Multiaddr>}} options.addresses The peer addresses
* @param {PeerInfo} options.peerInfo The peer running the identify service
*/
constructor (options) {
/**
@@ -56,11 +89,9 @@ class IdentifyService {
*/
this.registrar = options.registrar
/**
* @property {PeerId}
* @property {PeerInfo}
*/
this.peerId = options.peerId
this.addresses = options.addresses || {}
this.peerInfo = options.peerInfo
this._protocols = options.protocols
@@ -79,12 +110,11 @@ class IdentifyService {
await pipe(
[{
listenAddrs: this.addresses.listen.map((ma) => ma.buffer),
listenAddrs: this.peerInfo.multiaddrs.toArray().map((ma) => ma.buffer),
protocols: Array.from(this._protocols.keys())
}],
pb.encode(Message),
stream,
consume
stream
)
} catch (err) {
// Just log errors
@@ -103,7 +133,7 @@ class IdentifyService {
const connections = []
let connection
for (const peer of peerStore.peers.values()) {
if (peer.protocols.includes(MULTICODEC_IDENTIFY_PUSH) && (connection = this.registrar.getConnection(peer.id))) {
if (peer.protocols.has(MULTICODEC_IDENTIFY_PUSH) && (connection = this.registrar.getConnection(peer))) {
connections.push(connection)
}
}
@@ -123,7 +153,6 @@ class IdentifyService {
async identify (connection) {
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY)
const [data] = await pipe(
[],
stream,
lp.decode(),
take(1),
@@ -150,7 +179,7 @@ class IdentifyService {
} = message
const id = await PeerId.createFromPubKey(publicKey)
const peerInfo = new PeerInfo(id)
if (connection.remotePeer.toB58String() !== id.toB58String()) {
throw errCode(new Error('identified peer does not match the expected peer'), codes.ERR_INVALID_PEER)
}
@@ -158,10 +187,11 @@ class IdentifyService {
// Get the observedAddr if there is one
observedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
// Update peers data in PeerStore
this.registrar.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr)))
this.registrar.peerStore.protoBook.set(id, protocols)
// Copy the listenAddrs and protocols
IdentifyService.updatePeerAddresses(peerInfo, listenAddrs)
IdentifyService.updatePeerProtocols(peerInfo, protocols)
this.registrar.peerStore.replace(peerInfo)
// TODO: Track our observed address so that we can score it
log('received observed address of %s', observedAddr)
}
@@ -196,15 +226,15 @@ class IdentifyService {
*/
_handleIdentify ({ connection, stream }) {
let publicKey = Buffer.alloc(0)
if (this.peerId.pubKey) {
publicKey = this.peerId.pubKey.bytes
if (this.peerInfo.id.pubKey) {
publicKey = this.peerInfo.id.pubKey.bytes
}
const message = Message.encode({
protocolVersion: PROTOCOL_VERSION,
agentVersion: AGENT_VERSION,
publicKey,
listenAddrs: this.addresses.listen.map((ma) => ma.buffer),
listenAddrs: this.peerInfo.multiaddrs.toArray().map((ma) => ma.buffer),
observedAddr: connection.remoteAddr.buffer,
protocols: Array.from(this._protocols.keys())
})
@@ -212,8 +242,7 @@ class IdentifyService {
pipe(
[message],
lp.encode(),
stream,
consume
stream
)
}
@@ -226,7 +255,6 @@ class IdentifyService {
*/
async _handlePush ({ connection, stream }) {
const [data] = await pipe(
[],
stream,
lp.decode(),
take(1),
@@ -241,16 +269,20 @@ class IdentifyService {
return log.error('received invalid message', err)
}
// Update peers data in PeerStore
const id = connection.remotePeer
// Update the listen addresses
const peerInfo = new PeerInfo(connection.remotePeer)
try {
this.registrar.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr)))
IdentifyService.updatePeerAddresses(peerInfo, message.listenAddrs)
} catch (err) {
return log.error('received invalid listen addrs', err)
}
// Update the protocols
this.registrar.peerStore.protoBook.set(id, message.protocols)
IdentifyService.updatePeerProtocols(peerInfo, message.protocols)
// Update the peer in the PeerStore
this.registrar.peerStore.replace(peerInfo)
}
}

View File

@@ -5,12 +5,12 @@ const debug = require('debug')
const log = debug('libp2p')
log.error = debug('libp2p:error')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const peerRouting = require('./peer-routing')
const contentRouting = require('./content-routing')
const pubsub = require('./pubsub')
const getPeer = require('./get-peer')
const { getPeerInfo } = require('./get-peer-info')
const { validate: validateConfig } = require('./config')
const { codes } = require('./errors')
@@ -42,12 +42,9 @@ class Libp2p extends EventEmitter {
this._options = validateConfig(_options)
this.datastore = this._options.datastore
this.peerId = this._options.peerId
this.peerInfo = this._options.peerInfo
this.peerStore = new PeerStore()
// Addresses {listen, announce, noAnnounce}
this.addresses = this._options.addresses
this._modules = this._options.modules
this._config = this._options.config
this._transport = [] // Transport instances/references
@@ -59,31 +56,29 @@ class Libp2p extends EventEmitter {
// Setup the Upgrader
this.upgrader = new Upgrader({
localPeer: this.peerId,
localPeer: this.peerInfo.id,
metrics: this.metrics,
onConnection: (connection) => {
const peerId = connection.remotePeer
this.registrar.onConnect(peerId, connection)
const peerInfo = this.peerStore.put(new PeerInfo(connection.remotePeer), { silent: true })
this.registrar.onConnect(peerInfo, connection)
this.connectionManager.onConnect(connection)
this.emit('peer:connect', peerId)
this.emit('peer:connect', peerInfo)
// Run identify for every connection
if (this.identifyService) {
this.identifyService.identify(connection, peerId)
this.identifyService.identify(connection, connection.remotePeer)
.catch(log.error)
}
},
onConnectionEnd: (connection) => {
const peerId = connection.remotePeer
this.registrar.onDisconnect(peerId, connection)
const peerInfo = Dialer.getDialable(connection.remotePeer)
this.registrar.onDisconnect(peerInfo, connection)
this.connectionManager.onDisconnect(connection)
// If there are no connections to the peer, disconnect
if (!this.registrar.getConnection(peerId)) {
this.emit('peer:disconnect', peerId)
this.metrics && this.metrics.onPeerDisconnected(peerId)
if (!this.registrar.getConnection(peerInfo)) {
this.emit('peer:disconnect', peerInfo)
this.metrics && this.metrics.onPeerDisconnected(peerInfo.id)
}
}
})
@@ -138,8 +133,7 @@ class Libp2p extends EventEmitter {
// Add the identify service since we can multiplex
this.identifyService = new IdentifyService({
registrar: this.registrar,
peerId: this.peerId,
addresses: this.addresses,
peerInfo: this.peerInfo,
protocols: this.upgrader.protocols
})
this.handle(Object.values(IDENTIFY_PROTOCOLS), this.identifyService.handleMessage)
@@ -157,7 +151,7 @@ class Libp2p extends EventEmitter {
const DHT = this._modules.dht
this._dht = new DHT({
dialer: this.dialer,
peerId: this.peerId,
peerInfo: this.peerInfo,
peerStore: this.peerStore,
registrar: this.registrar,
datastore: this.datastore,
@@ -267,9 +261,10 @@ class Libp2p extends EventEmitter {
}
/**
* Dials to the provided peer. If successful, the known `Peer` data of the
* Dials to the provided peer. If successful, the `PeerInfo` of the
* peer will be added to the nodes `peerStore`
* @param {PeerId|Multiaddr|string} peer The peer to dial
*
* @param {PeerInfo|PeerId|Multiaddr|string} peer The peer to dial
* @param {object} options
* @param {AbortSignal} [options.signal]
* @returns {Promise<Connection>}
@@ -280,23 +275,26 @@ class Libp2p extends EventEmitter {
/**
* Dials to the provided peer and handshakes with the given protocol.
* If successful, the known `Peer` data of the peer will be added to the nodes `peerStore`,
* and the `Connection` will be returned
* If successful, the `PeerInfo` of the peer will be added to the nodes `peerStore`,
* and the `Connection` will be sent in the callback
*
* @async
* @param {PeerId|Multiaddr|string} peer The peer to dial
* @param {PeerInfo|PeerId|Multiaddr|string} peer The peer to dial
* @param {string[]|string} protocols
* @param {object} options
* @param {AbortSignal} [options.signal]
* @returns {Promise<Connection|*>}
*/
async dialProtocol (peer, protocols, options) {
const { id, multiaddrs } = getPeer(peer, this.peerStore)
let connection = this.registrar.getConnection(id)
const dialable = Dialer.getDialable(peer)
let connection
if (PeerInfo.isPeerInfo(dialable)) {
this.peerStore.put(dialable, { silent: true })
connection = this.registrar.getConnection(dialable)
}
if (!connection) {
connection = await this.dialer.connectToPeer(peer, options)
} else if (multiaddrs) {
this.peerStore.addressBook.add(id, multiaddrs)
connection = await this.dialer.connectToPeer(dialable, options)
}
// If a protocol was provided, create a new stream
@@ -309,28 +307,28 @@ class Libp2p extends EventEmitter {
/**
* Disconnects all connections to the given `peer`
* @param {PeerId|multiaddr|string} peer the peer to close connections to
*
* @param {PeerInfo|PeerId|multiaddr|string} peer the peer to close connections to
* @returns {Promise<void>}
*/
hangUp (peer) {
const { id } = getPeer(peer)
const peerInfo = getPeerInfo(peer, this.peerStore)
return Promise.all(
this.registrar.connections.get(id.toB58String()).map(connection => {
this.registrar.connections.get(peerInfo.id.toB58String()).map(connection => {
return connection.close()
})
)
}
/**
* Pings the given peer in order to obtain the operation latency.
* @param {PeerId|Multiaddr|string} peer The peer to ping
* Pings the given peer
* @param {PeerInfo|PeerId|Multiaddr|string} peer The peer to ping
* @returns {Promise<number>}
*/
ping (peer) {
const { id } = getPeer(peer)
async ping (peer) {
const peerInfo = await getPeerInfo(peer, this.peerStore)
return ping(this, id)
return ping(this, peerInfo)
}
/**
@@ -368,14 +366,17 @@ class Libp2p extends EventEmitter {
}
async _onStarting () {
// Listen on the addresses provided
const multiaddrs = this.addresses.listen
// Listen on the addresses supplied in the peerInfo
const multiaddrs = this.peerInfo.multiaddrs.toArray()
await this.transportManager.listen(multiaddrs)
// The addresses may change once the listener starts
// eg /ip4/0.0.0.0/tcp/0 => /ip4/192.168.1.0/tcp/58751
this.addresses.listen = this.transportManager.getAddrs()
this.peerInfo.multiaddrs.clear()
for (const ma of this.transportManager.getAddrs()) {
this.peerInfo.multiaddrs.add(ma)
}
if (this._config.pubsub.enabled) {
this.pubsub && this.pubsub.start()
@@ -398,23 +399,23 @@ class Libp2p extends EventEmitter {
* Called when libp2p has started and before it returns
* @private
*/
async _onDidStart () {
_onDidStart () {
this._isStarted = true
this.connectionManager.start()
this.peerStore.on('peer', peerId => {
this.emit('peer:discovery', peerId)
this._maybeConnect(peerId)
this.peerStore.on('peer', peerInfo => {
this.emit('peer:discovery', peerInfo)
this._maybeConnect(peerInfo)
})
// Peer discovery
await this._setupPeerDiscovery()
this._setupPeerDiscovery()
// Once we start, emit and dial any peers we may have already discovered
for (const peer of this.peerStore.peers.values()) {
this.emit('peer:discovery', peer.id)
this._maybeConnect(peer.id)
for (const peerInfo of this.peerStore.peers.values()) {
this.emit('peer:discovery', peerInfo)
this._maybeConnect(peerInfo)
}
}
@@ -422,33 +423,31 @@ class Libp2p extends EventEmitter {
* Called whenever peer discovery services emit `peer` events.
* Known peers may be emitted.
* @private
* @param {PeerDara} peer
* @param {PeerInfo} peerInfo
*/
_onDiscoveryPeer (peer) {
if (peer.id.toB58String() === this.peerId.toB58String()) {
_onDiscoveryPeer (peerInfo) {
if (peerInfo.id.toB58String() === this.peerInfo.id.toB58String()) {
log.error(new Error(codes.ERR_DISCOVERED_SELF))
return
}
peer.multiaddrs && this.peerStore.addressBook.add(peer.id, peer.multiaddrs)
peer.protocols && this.peerStore.protoBook.set(peer.id, peer.protocols)
this.peerStore.put(peerInfo)
}
/**
* Will dial to the given `peerId` if the current number of
* Will dial to the given `peerInfo` if the current number of
* connected peers is less than the configured `ConnectionManager`
* minPeers.
* @private
* @param {PeerId} peerId
* @param {PeerInfo} peerInfo
*/
async _maybeConnect (peerId) {
async _maybeConnect (peerInfo) {
// If auto dialing is on and we have no connection to the peer, check if we should dial
if (this._config.peerDiscovery.autoDial === true && !this.registrar.getConnection(peerId)) {
if (this._config.peerDiscovery.autoDial === true && !this.registrar.getConnection(peerInfo)) {
const minPeers = this._options.connectionManager.minPeers || 0
if (minPeers > this.connectionManager._connections.size) {
log('connecting to discovered peer %s', peerId.toB58String())
log('connecting to discovered peer %s', peerInfo.id.toB58String())
try {
await this.dialer.connectToPeer(peerId)
await this.dialer.connectToPeer(peerInfo)
} catch (err) {
log.error('could not connect to discovered peer', err)
}
@@ -459,10 +458,10 @@ class Libp2p extends EventEmitter {
/**
* Initializes and starts peer discovery services
*
* @async
* @private
* @returns {Promise<void>}
*/
async _setupPeerDiscovery () {
_setupPeerDiscovery () {
const setupService = (DiscoveryService) => {
let config = {
enabled: true // on by default
@@ -479,11 +478,7 @@ class Libp2p extends EventEmitter {
let discoveryService
if (typeof DiscoveryService === 'function') {
discoveryService = new DiscoveryService(Object.assign({}, config, {
peerId: this.peerId,
multiaddrs: this.addresses.listen,
libp2p: this
}))
discoveryService = new DiscoveryService(Object.assign({}, config, { peerInfo: this.peerInfo }))
} else {
discoveryService = DiscoveryService
}
@@ -505,25 +500,24 @@ class Libp2p extends EventEmitter {
}
}
await Promise.all(Array.from(this._discovery.values(), d => d.start()))
return Promise.all(Array.from(this._discovery.values(), d => d.start()))
}
}
module.exports = Libp2p
/**
* Like `new Libp2p(options)` except it will create a `PeerId`
* Like `new Libp2p(options)` except it will create a `PeerInfo`
* instance if one is not provided in options.
* @param {object} options Libp2p configuration options
* @returns {Libp2p}
*/
Libp2p.create = async function create (options = {}) {
if (options.peerId) {
module.exports.create = async (options = {}) => {
if (options.peerInfo) {
return new Libp2p(options)
}
const peerId = await PeerId.create()
const peerInfo = await PeerInfo.create()
options.peerId = peerId
options.peerInfo = peerInfo
return new Libp2p(options)
}
module.exports = Libp2p

View File

@@ -18,7 +18,7 @@ module.exports = (node) => {
* @param {String} id The id of the peer to find
* @param {object} [options]
* @param {number} [options.timeout] How long the query should run
* @returns {Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>}
* @returns {Promise<PeerInfo>}
*/
findPeer: async (id, options) => { // eslint-disable-line require-await
if (!routers.length) {

View File

@@ -1,89 +1,3 @@
# PeerStore
# Peerstore
Libp2p's PeerStore is responsible for keeping an updated register with the relevant information of the known peers. It should be the single source of truth for all peer data, where a subsystem can learn about peers' data and where someone can listen for updates. The PeerStore comprises four main components: `addressBook`, `keyBook`, `protocolBook` and `metadataBook`.
The PeerStore manages the high level operations on its inner books. Moreover, the PeerStore should be responsible for notifying interested parties of relevant events, through its Event Emitter.
## Data gathering
Several libp2p subsystems will perform operations, which will gather relevant information about peers. Some operations might not have this as an end goal, but can also gather important data.
In a libp2p node's life, it will discover peers through its discovery protocols. In a typical discovery protocol, addresses of the peer are discovered along with its peer id. Once this happens, the PeerStore should collect this information for future (or immediate) usage by other subsystems. When the information is stored, the PeerStore should inform interested parties of the peer discovered (`peer` event).
Taking into account a different scenario, a peer might perform/receive a dial request to/from a unkwown peer. In such a scenario, the PeerStore must store the peer's multiaddr once a connection is established.
After a connection is established with a peer, the Identify protocol will run automatically. A stream is created and peers exchange their information (Multiaddrs, running protocols and their public key). Once this information is obtained, it should be added to the PeerStore. In this specific case, as we are speaking to the source of truth, we should ensure the PeerStore is prioritizing these records. If the recorded `multiaddrs` or `protocols` have changed, interested parties must be informed via the `change:multiaddrs` or `change:protocols` events respectively.
In the background, the Identify Service is also waiting for protocol change notifications of peers via the IdentifyPush protocol. Peers may leverage the `identify-push` message to communicate protocol changes to all connected peers, so that their PeerStore can be updated with the updated protocols. As the `identify-push` also sends complete and updated information, the data in the PeerStore can be replaced.
(To consider: Should we not replace until we get to multiaddr confidence? we might loose true information as we will talk with older nodes on the network.)
While it is currently not supported in js-libp2p, future iterations may also support the [IdentifyDelta protocol](https://github.com/libp2p/specs/pull/176).
It is also possible to gather relevant information for peers from other protocols / subsystems. For instance, in `DHT` operations, nodes can exchange peer data as part of the `DHT` operation. In this case, we can learn additional information about a peer we already know. In this scenario the PeerStore should not replace the existing data it has, just add it.
## Data Consumption
When the PeerStore data is updated, this information might be important for different parties.
Every time a peer needs to dial another peer, it is essential that it knows the multiaddrs used by the peer, in order to perform a successful dial to it. The same is true for pinging a peer. While the `AddressBook` is going to keep its data updated, it will also emit `change:multiaddrs` events so that subsystems/users interested in knowing these changes can be notified instead of polling the `AddressBook`.
Everytime a peer starts/stops supporting a protocol, libp2p subsystems or users might need to act accordingly. `js-libp2p` registrar orchestrates known peers, established connections and protocol topologies. This way, once a protocol is supported for a peer, the topology of that protocol should be informed that a new peer may be used and the subsystem can decide if it should open a new stream with that peer or not. For these situations, the `ProtoBook` will emit `change:protocols` events whenever supported protocols of a peer change.
## PeerStore implementation
The PeerStore wraps four main components: `addressBook`, `keyBook`, `protocolBook` and `metadataBook`. Moreover, it provides a high level API for those components, as well as data events.
### Components
#### Address Book
The `addressBook` keeps the known multiaddrs of a peer. The multiaddrs of each peer may change over time and the Address Book must account for this.
`Map<string, Address>`
A `peerId.toString()` identifier mapping to a `Address` object, which should have the following structure:
```js
{
multiaddr: <Multiaddr>
}
```
#### Key Book
The `keyBook` tracks the keys of the peers.
**Not Yet Implemented**
#### Protocol Book
The `protoBook` holds the identifiers of the protocols supported by each peer. The protocols supported by each peer are dynamic and will change over time.
`Map<string, Set<string>>`
A `peerId.toString()` identifier mapping to a `Set` of protocol identifier strings.
#### Metadata Book
**Not Yet Implemented**
### API
For the complete API documentation, you should check the [API.md](../../doc/API.md).
Access to its underlying books:
- `peerStore.protoBook.*`
- `peerStore.addressBook.*`
### Events
- `peer` - emitted when a new peer is added.
- `change:multiaadrs` - emitted when a known peer has a different set of multiaddrs.
- `change:protocols` - emitted when a known peer supports a different set of protocols.
## Future Considerations
- If multiaddr TTLs are added, the PeerStore may schedule jobs to delete all addresses that exceed the TTL to prevent AddressBook bloating
- Further API methods will probably need to be added in the context of multiaddr validity and confidence.
WIP

View File

@@ -1,203 +0,0 @@
'use strict'
const errcode = require('err-code')
const debug = require('debug')
const log = debug('libp2p:peer-store:address-book')
log.error = debug('libp2p:peer-store:address-book:error')
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const Book = require('./book')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
/**
* The AddressBook is responsible for keeping the known multiaddrs
* of a peer.
*/
class AddressBook extends Book {
/**
* Address object
* @typedef {Object} Address
* @property {Multiaddr} multiaddr peer multiaddr.
*/
/**
* @constructor
* @param {PeerStore} peerStore
*/
constructor (peerStore) {
/**
* PeerStore Event emitter, used by the AddressBook to emit:
* "peer" - emitted when a peer is discovered by the node.
* "change:multiaddrs" - emitted when the known multiaddrs of a peer change.
*/
super(peerStore, 'change:multiaddrs', 'multiaddrs')
/**
* Map known peers to their known Addresses.
* @type {Map<string, Array<Address>>}
*/
this.data = new Map()
}
/**
* Set known multiaddrs of a provided peer.
* @override
* @param {PeerId} peerId
* @param {Array<Multiaddr>} multiaddrs
* @returns {AddressBook}
*/
set (peerId, multiaddrs) {
if (!PeerId.isPeerId(peerId)) {
log.error('peerId must be an instance of peer-id to store data')
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
const addresses = this._toAddresses(multiaddrs)
const id = peerId.toB58String()
const rec = this.data.get(id)
// Not replace multiaddrs
if (!addresses.length) {
return this
}
// Already knows the peer
if (rec && rec.length === addresses.length) {
const intersection = rec.filter((mi) => addresses.some((newMi) => mi.multiaddr.equals(newMi.multiaddr)))
// Are new addresses equal to the old ones?
// If yes, no changes needed!
if (intersection.length === rec.length) {
log(`the addresses provided to store are equal to the already stored for ${id}`)
return this
}
}
this.data.set(id, addresses)
this._setPeerId(peerId)
log(`stored provided multiaddrs for ${id}`)
// Notify the existance of a new peer
if (!rec) {
this._ps.emit('peer', peerId)
}
this._ps.emit('change:multiaddrs', {
peerId,
multiaddrs: addresses.map((mi) => mi.multiaddr)
})
return this
}
/**
* Add known addresses of a provided peer.
* If the peer is not known, it is set with the given addresses.
* @override
* @param {PeerId} peerId
* @param {Array<Multiaddr>} multiaddrs
* @returns {AddressBook}
*/
add (peerId, multiaddrs) {
if (!PeerId.isPeerId(peerId)) {
log.error('peerId must be an instance of peer-id to store data')
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
const addresses = this._toAddresses(multiaddrs)
const id = peerId.toB58String()
const rec = this.data.get(id)
// Add recorded uniquely to the new array (Union)
rec && rec.forEach((mi) => {
if (!addresses.find(r => r.multiaddr.equals(mi.multiaddr))) {
addresses.push(mi)
}
})
// If the recorded length is equal to the new after the unique union
// The content is the same, no need to update.
if (rec && rec.length === addresses.length) {
log(`the addresses provided to store are already stored for ${id}`)
return this
}
this._setPeerId(peerId)
this.data.set(id, addresses)
log(`added provided multiaddrs for ${id}`)
this._ps.emit('change:multiaddrs', {
peerId,
multiaddrs: addresses.map((mi) => mi.multiaddr)
})
// Notify the existance of a new peer
if (!rec) {
this._ps.emit('peer', peerId)
}
return this
}
/**
* Transforms received multiaddrs into Address.
* @param {Array<Multiaddr>} multiaddrs
* @returns {Array<Address>}
*/
_toAddresses (multiaddrs) {
if (!multiaddrs) {
log.error('multiaddrs must be provided to store data')
throw errcode(new Error('multiaddrs must be provided'), ERR_INVALID_PARAMETERS)
}
// create Address for each address
const addresses = []
multiaddrs.forEach((addr) => {
if (!multiaddr.isMultiaddr(addr)) {
log.error(`multiaddr ${addr} must be an instance of multiaddr`)
throw errcode(new Error(`multiaddr ${addr} must be an instance of multiaddr`), ERR_INVALID_PARAMETERS)
}
addresses.push({
multiaddr: addr
})
})
return addresses
}
/**
* Get the known multiaddrs for a given peer. All returned multiaddrs
* will include the encapsulated `PeerId` of the peer.
* @param {PeerId} peerId
* @returns {Array<Multiaddr>}
*/
getMultiaddrsForPeer (peerId) {
if (!PeerId.isPeerId(peerId)) {
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
const record = this.data.get(peerId.toB58String())
if (!record) {
return undefined
}
return record.map((address) => {
const multiaddr = address.multiaddr
const idString = multiaddr.getPeerId()
if (idString && idString === peerId.toB58String()) return multiaddr
return multiaddr.encapsulate(`/p2p/${peerId.toB58String()}`)
})
}
}
module.exports = AddressBook

View File

@@ -1,88 +0,0 @@
'use strict'
const errcode = require('err-code')
const PeerId = require('peer-id')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
/**
* The Book is the skeleton for the PeerStore books.
*/
class Book {
constructor (peerStore, eventName, eventProperty) {
this._ps = peerStore
this.eventName = eventName
this.eventProperty = eventProperty
/**
* Map known peers to their data.
* @type {Map<string, Array<Data>}
*/
this.data = new Map()
}
/**
* Set known data of a provided peer.
* @param {PeerId} peerId
* @param {Array<Data>|Data} data
*/
set (peerId, data) {
throw errcode(new Error('set must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
}
/**
* Add known data of a provided peer.
* @param {PeerId} peerId
* @param {Array<Data>|Data} data
*/
add (peerId, data) {
throw errcode(new Error('set must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
}
/**
* Get the known data of a provided peer.
* @param {PeerId} peerId
* @returns {Array<Data>}
*/
get (peerId) {
if (!PeerId.isPeerId(peerId)) {
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
const rec = this.data.get(peerId.toB58String())
return rec ? [...rec] : undefined
}
/**
* Deletes the provided peer from the book.
* @param {PeerId} peerId
* @returns {boolean}
*/
delete (peerId) {
if (!PeerId.isPeerId(peerId)) {
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
if (!this.data.delete(peerId.toB58String())) {
return false
}
this._ps.emit(this.eventName, {
peerId,
[this.eventProperty]: []
})
return true
}
_setPeerId (peerId) {
if (!this._ps.peerIds.get(peerId)) {
this._ps.peerIds.set(peerId.toB58String(), peerId)
}
}
}
module.exports = Book

View File

@@ -1,123 +1,235 @@
'use strict'
const errcode = require('err-code')
const assert = require('assert')
const debug = require('debug')
const log = debug('libp2p:peer-store')
log.error = debug('libp2p:peer-store:error')
const { EventEmitter } = require('events')
const PeerId = require('peer-id')
const AddressBook = require('./address-book')
const ProtoBook = require('./proto-book')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
const PeerInfo = require('peer-info')
/**
* Responsible for managing known peers, as well as their addresses, protocols and metadata.
* @fires PeerStore#peer Emitted when a new peer is added.
* @fires PeerStore#change:protocols Emitted when a known peer supports a different set of protocols.
* @fires PeerStore#change:multiaddrs Emitted when a known peer has a different set of multiaddrs.
* Responsible for managing known peers, as well as their addresses and metadata
* @fires PeerStore#peer Emitted when a peer is connected to this node
* @fires PeerStore#change:protocols
* @fires PeerStore#change:multiaddrs
*/
class PeerStore extends EventEmitter {
/**
* Peer object
* @typedef {Object} Peer
* @property {PeerId} id peer's peer-id instance.
* @property {Array<Address>} addresses peer's addresses containing its multiaddrs and metadata.
* @property {Array<string>} protocols peer's supported protocols.
*/
constructor () {
super()
/**
* AddressBook containing a map of peerIdStr to Address
* Map of peers
*
* @type {Map<string, PeerInfo>}
*/
this.addressBook = new AddressBook(this)
this.peers = new Map()
/**
* ProtoBook containing a map of peerIdStr to supported protocols.
*/
this.protoBook = new ProtoBook(this)
/**
* TODO: this should only exist until we have the key-book
* Map known peers to their peer-id.
* @type {Map<string, Array<PeerId>}
*/
this.peerIds = new Map()
// TODO: Track ourselves. We should split `peerInfo` up into its pieces so we get better
// control and observability. This will be the initial step for removing PeerInfo
// https://github.com/libp2p/go-libp2p-core/blob/master/peerstore/peerstore.go
// this.addressBook = new Map()
// this.protoBook = new Map()
}
/**
* Get all the stored information of every peer.
* @returns {Map<string, Peer>}
* Stores the peerInfo of a new peer.
* If already exist, its info is updated. If `silent` is set to
* true, no 'peer' event will be emitted. This can be useful if you
* are already in the process of dialing the peer. The peer is technically
* known, but may not have been added to the PeerStore yet.
* @param {PeerInfo} peerInfo
* @param {object} [options]
* @param {boolean} [options.silent] (Default=false)
* @return {PeerInfo}
*/
get peers () {
const peersData = new Map()
put (peerInfo, options = { silent: false }) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
// AddressBook
for (const [idStr, addresses] of this.addressBook.data.entries()) {
const id = PeerId.createFromCID(idStr)
peersData.set(idStr, {
id,
addresses,
protocols: this.protoBook.get(id) || []
let peer
// Already know the peer?
if (this.has(peerInfo.id)) {
peer = this.update(peerInfo)
} else {
peer = this.add(peerInfo)
// Emit the peer if silent = false
!options.silent && this.emit('peer', peerInfo)
}
return peer
}
/**
* Add a new peer to the store.
* @param {PeerInfo} peerInfo
* @return {PeerInfo}
*/
add (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
// Create new instance and add values to it
const newPeerInfo = new PeerInfo(peerInfo.id)
peerInfo.multiaddrs.forEach((ma) => newPeerInfo.multiaddrs.add(ma))
peerInfo.protocols.forEach((p) => newPeerInfo.protocols.add(p))
const connectedMa = peerInfo.isConnected()
connectedMa && newPeerInfo.connect(connectedMa)
const peerProxy = new Proxy(newPeerInfo, {
set: (obj, prop, value) => {
if (prop === 'multiaddrs') {
this.emit('change:multiaddrs', {
peerInfo: obj,
multiaddrs: value.toArray()
})
} else if (prop === 'protocols') {
this.emit('change:protocols', {
peerInfo: obj,
protocols: Array.from(value)
})
}
return Reflect.set(...arguments)
}
})
this.peers.set(peerInfo.id.toB58String(), peerProxy)
return peerProxy
}
/**
* Updates an already known peer.
* @param {PeerInfo} peerInfo
* @return {PeerInfo}
*/
update (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
const id = peerInfo.id.toB58String()
const recorded = this.peers.get(id)
// pass active connection state
const ma = peerInfo.isConnected()
if (ma) {
recorded.connect(ma)
}
// Verify new multiaddrs
// TODO: better track added and removed multiaddrs
const multiaddrsIntersection = [
...recorded.multiaddrs.toArray()
].filter((m) => peerInfo.multiaddrs.has(m))
if (multiaddrsIntersection.length !== peerInfo.multiaddrs.size ||
multiaddrsIntersection.length !== recorded.multiaddrs.size) {
for (const ma of peerInfo.multiaddrs.toArray()) {
recorded.multiaddrs.add(ma)
}
this.emit('change:multiaddrs', {
peerInfo: recorded,
multiaddrs: recorded.multiaddrs.toArray()
})
}
// ProtoBook
for (const [idStr, protocols] of this.protoBook.data.entries()) {
const pData = peersData.get(idStr)
// Update protocols
// TODO: better track added and removed protocols
const protocolsIntersection = new Set(
[...recorded.protocols].filter((p) => peerInfo.protocols.has(p))
)
if (!pData) {
peersData.set(idStr, {
id: PeerId.createFromCID(idStr),
addresses: [],
protocols: Array.from(protocols)
})
if (protocolsIntersection.size !== peerInfo.protocols.size ||
protocolsIntersection.size !== recorded.protocols.size) {
for (const protocol of peerInfo.protocols) {
recorded.protocols.add(protocol)
}
this.emit('change:protocols', {
peerInfo: recorded,
protocols: Array.from(recorded.protocols)
})
}
return peersData
// Add the public key if missing
if (!recorded.id.pubKey && peerInfo.id.pubKey) {
recorded.id.pubKey = peerInfo.id.pubKey
}
return recorded
}
/**
* Delete the information of the given peer in every book.
* @param {PeerId} peerId
* @returns {boolean} true if found and removed
*/
delete (peerId) {
const addressesDeleted = this.addressBook.delete(peerId)
const protocolsDeleted = this.protoBook.delete(peerId)
return addressesDeleted || protocolsDeleted
}
/**
* Get the stored information of a given peer.
* @param {PeerId} peerId
* @returns {Peer}
* Get the info to the given id.
* @param {PeerId|string} peerId b58str id
* @returns {PeerInfo}
*/
get (peerId) {
if (!PeerId.isPeerId(peerId)) {
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
// TODO: deprecate this and just accept `PeerId` instances
if (PeerId.isPeerId(peerId)) {
peerId = peerId.toB58String()
}
const id = this.peerIds.get(peerId.toB58String())
const addresses = this.addressBook.get(peerId)
const protocols = this.protoBook.get(peerId)
return this.peers.get(peerId)
}
if (!addresses && !protocols) {
return undefined
/**
* Has the info to the given id.
* @param {PeerId|string} peerId b58str id
* @returns {boolean}
*/
has (peerId) {
// TODO: deprecate this and just accept `PeerId` instances
if (PeerId.isPeerId(peerId)) {
peerId = peerId.toB58String()
}
return {
id: id || peerId,
addresses: addresses || [],
protocols: protocols || []
return this.peers.has(peerId)
}
/**
* Removes the Peer with the matching `peerId` from the PeerStore
* @param {PeerId|string} peerId b58str id
* @returns {boolean} true if found and removed
*/
remove (peerId) {
// TODO: deprecate this and just accept `PeerId` instances
if (PeerId.isPeerId(peerId)) {
peerId = peerId.toB58String()
}
return this.peers.delete(peerId)
}
/**
* Completely replaces the existing peers metadata with the given `peerInfo`
* @param {PeerInfo} peerInfo
* @returns {void}
*/
replace (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
this.remove(peerInfo.id.toB58String())
this.add(peerInfo)
// This should be cleaned up in PeerStore v2
this.emit('change:multiaddrs', {
peerInfo,
multiaddrs: peerInfo.multiaddrs.toArray()
})
this.emit('change:protocols', {
peerInfo,
protocols: Array.from(peerInfo.protocols)
})
}
/**
* Returns the known multiaddrs for a given `PeerInfo`
* @param {PeerInfo} peer
* @returns {Array<Multiaddr>}
*/
multiaddrsForPeer (peer) {
return this.put(peer, true).multiaddrs.toArray()
}
}

View File

@@ -1,128 +0,0 @@
'use strict'
const errcode = require('err-code')
const debug = require('debug')
const log = debug('libp2p:peer-store:proto-book')
log.error = debug('libp2p:peer-store:proto-book:error')
const PeerId = require('peer-id')
const Book = require('./book')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
/**
* The ProtoBook is responsible for keeping the known supported
* protocols of a peer.
* @fires ProtoBook#change:protocols
*/
class ProtoBook extends Book {
/**
* @constructor
* @param {PeerStore} peerStore
*/
constructor (peerStore) {
/**
* PeerStore Event emitter, used by the ProtoBook to emit:
* "change:protocols" - emitted when the known protocols of a peer change.
*/
super(peerStore, 'change:protocols', 'protocols')
/**
* Map known peers to their known protocols.
* @type {Map<string, Set<string>>}
*/
this.data = new Map()
}
/**
* Set known protocols of a provided peer.
* If the peer was not known before, it will be added.
* @override
* @param {PeerId} peerId
* @param {Array<string>} protocols
* @returns {ProtoBook}
*/
set (peerId, protocols) {
if (!PeerId.isPeerId(peerId)) {
log.error('peerId must be an instance of peer-id to store data')
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
if (!protocols) {
log.error('protocols must be provided to store data')
throw errcode(new Error('protocols must be provided'), ERR_INVALID_PARAMETERS)
}
const id = peerId.toB58String()
const recSet = this.data.get(id)
const newSet = new Set(protocols)
const isSetEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value))
// Already knows the peer and the recorded protocols are the same?
// If yes, no changes needed!
if (recSet && isSetEqual(recSet, newSet)) {
log(`the protocols provided to store are equal to the already stored for ${id}`)
return this
}
this.data.set(id, newSet)
this._setPeerId(peerId)
log(`stored provided protocols for ${id}`)
this._ps.emit('change:protocols', {
peerId,
protocols
})
return this
}
/**
* Adds known protocols of a provided peer.
* If the peer was not known before, it will be added.
* @override
* @param {PeerId} peerId
* @param {Array<string>} protocols
* @returns {ProtoBook}
*/
add (peerId, protocols) {
if (!PeerId.isPeerId(peerId)) {
log.error('peerId must be an instance of peer-id to store data')
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
if (!protocols) {
log.error('protocols must be provided to store data')
throw errcode(new Error('protocols must be provided'), ERR_INVALID_PARAMETERS)
}
const id = peerId.toB58String()
const recSet = this.data.get(id) || new Set()
const newSet = new Set([...recSet, ...protocols]) // Set Union
// Any new protocol added?
if (recSet.size === newSet.size) {
log(`the protocols provided to store are already stored for ${id}`)
return this
}
protocols = [...newSet]
this.data.set(id, newSet)
this._setPeerId(peerId)
log(`added provided protocols for ${id}`)
this._ps.emit('change:protocols', {
peerId,
protocols
})
return this
}
}
module.exports = ProtoBook

View File

@@ -8,18 +8,18 @@ const errCode = require('err-code')
const crypto = require('libp2p-crypto')
const pipe = require('it-pipe')
const { toBuffer } = require('it-buffer')
const { collect, take } = require('streaming-iterables')
const { collect } = require('streaming-iterables')
const { PROTOCOL, PING_LENGTH } = require('./constants')
/**
* Ping a given peer and wait for its response, getting the operation latency.
* @param {Libp2p} node
* @param {PeerId} peer
* @param {PeerInfo} peer
* @returns {Promise<Number>}
*/
async function ping (node, peer) {
log('dialing %s to %s', PROTOCOL, peer.toB58String())
log('dialing %s to %s', PROTOCOL, peer.id.toB58String())
const { stream } = await node.dialProtocol(peer, PROTOCOL)
@@ -29,7 +29,6 @@ async function ping (node, peer) {
const [result] = await pipe(
[data],
stream,
stream => take(1, stream),
toBuffer,
collect
)

View File

@@ -1,13 +1,10 @@
'use strict'
const pipe = require('it-pipe')
const errcode = require('err-code')
const assert = require('assert')
const duplexPair = require('it-pair/duplex')
const crypto = require('libp2p-crypto')
const Errors = require('./errors')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
const {
createBoxStream,
createUnboxStream,
@@ -43,9 +40,7 @@ class Protector {
* @returns {*} A protected duplex iterable
*/
async protect (connection) {
if (!connection) {
throw errcode(new Error(Errors.NO_HANDSHAKE_CONNECTION), ERR_INVALID_PARAMETERS)
}
assert(connection, Errors.NO_HANDSHAKE_CONNECTION)
// Exchange nonces
log('protecting the connection')

View File

@@ -4,7 +4,7 @@ const errCode = require('err-code')
const { messages, codes } = require('./errors')
module.exports = (node, Pubsub, config) => {
const pubsub = new Pubsub(node.peerId, node.registrar, config)
const pubsub = new Pubsub(node.peerInfo, node.registrar, config)
return {
/**

View File

@@ -1,17 +1,13 @@
'use strict'
const assert = require('assert')
const debug = require('debug')
const errcode = require('err-code')
const log = debug('libp2p:peer-store')
log.error = debug('libp2p:peer-store:error')
const PeerId = require('peer-id')
const {
ERR_INVALID_PARAMETERS
} = require('./errors')
const Topology = require('libp2p-interfaces/src/topology')
const { Connection } = require('libp2p-interfaces/src/connection')
const PeerInfo = require('peer-info')
/**
* Responsible for notifying registered protocols of events in the network.
@@ -23,7 +19,6 @@ class Registrar {
* @constructor
*/
constructor ({ peerStore }) {
// Used on topology to listen for protocol changes
this.peerStore = peerStore
/**
@@ -71,20 +66,15 @@ class Registrar {
/**
* Add a new connected peer to the record
* TODO: this should live in the ConnectionManager
* @param {PeerId} peerId
* @param {PeerInfo} peerInfo
* @param {Connection} conn
* @returns {void}
*/
onConnect (peerId, conn) {
if (!PeerId.isPeerId(peerId)) {
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
onConnect (peerInfo, conn) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
assert(Connection.isConnection(conn), 'conn must be an instance of interface-connection')
if (!Connection.isConnection(conn)) {
throw errcode(new Error('conn must be an instance of interface-connection'), ERR_INVALID_PARAMETERS)
}
const id = peerId.toB58String()
const id = peerInfo.id.toB58String()
const storedConn = this.connections.get(id)
if (storedConn) {
@@ -97,17 +87,15 @@ class Registrar {
/**
* Remove a disconnected peer from the record
* TODO: this should live in the ConnectionManager
* @param {PeerId} peerId
* @param {PeerInfo} peerInfo
* @param {Connection} connection
* @param {Error} [error]
* @returns {void}
*/
onDisconnect (peerId, connection, error) {
if (!PeerId.isPeerId(peerId)) {
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
onDisconnect (peerInfo, connection, error) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
const id = peerId.toB58String()
const id = peerInfo.id.toB58String()
let storedConn = this.connections.get(id)
if (storedConn && storedConn.length > 1) {
@@ -115,24 +103,22 @@ class Registrar {
this.connections.set(id, storedConn)
} else if (storedConn) {
for (const [, topology] of this.topologies) {
topology.disconnect(peerId, error)
topology.disconnect(peerInfo, error)
}
this.connections.delete(id)
this.connections.delete(peerInfo.id.toB58String())
}
}
/**
* Get a connection with a peer.
* @param {PeerId} peerId
* @param {PeerInfo} peerInfo
* @returns {Connection}
*/
getConnection (peerId) {
if (!PeerId.isPeerId(peerId)) {
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
}
getConnection (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
const connections = this.connections.get(peerId.toB58String())
const connections = this.connections.get(peerInfo.id.toB58String())
// Return the first, open connection
if (connections) {
return connections.find(connection => connection.stat.status === 'open')
@@ -146,9 +132,9 @@ class Registrar {
* @return {string} registrar identifier
*/
register (topology) {
if (!Topology.isTopology(topology)) {
throw errcode(new Error('topology must be an instance of interfaces/topology'), ERR_INVALID_PARAMETERS)
}
assert(
Topology.isTopology(topology),
'topology must be an instance of interfaces/topology')
// Create topology
const id = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()

View File

@@ -231,7 +231,7 @@ class Upgrader {
const { stream, protocol } = await mss.handle(Array.from(this.protocols.keys()))
log('%s: incoming stream opened on %s', direction, protocol)
if (this.metrics) this.metrics.trackStream({ stream, remotePeer, protocol })
connection.addStream(muxedStream, { protocol })
connection.addStream(stream, protocol)
this._onStream({ connection, stream, protocol })
} catch (err) {
log.error(err)
@@ -317,7 +317,7 @@ class Upgrader {
* Attempts to encrypt the incoming `connection` with the provided `cryptos`.
* @private
* @async
* @param {PeerId} localPeer The initiators PeerId
* @param {PeerId} localPeer The initiators PeerInfo
* @param {*} connection
* @param {Map<string, Crypto>} cryptos
* @returns {CryptoResult} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used
@@ -346,7 +346,7 @@ class Upgrader {
* The first `Crypto` module to succeed will be used
* @private
* @async
* @param {PeerId} localPeer The initiators PeerId
* @param {PeerId} localPeer The initiators PeerInfo
* @param {*} connection
* @param {PeerId} remotePeerId
* @param {Map<string, Crypto>} cryptos

View File

@@ -56,7 +56,7 @@ describe('content-routing', () => {
// Ring dial
await Promise.all(
nodes.map((peer, i) => peer.dial(nodes[(i + 1) % number].peerId))
nodes.map((peer, i) => peer.dial(nodes[(i + 1) % number].peerInfo))
)
})
@@ -96,9 +96,9 @@ describe('content-routing', () => {
let delegate
beforeEach(async () => {
const [peerId] = await peerUtils.createPeerId({ fixture: false })
const [peerInfo] = await peerUtils.createPeerInfo({ fixture: false })
delegate = new DelegatedContentRouter(peerId, {
delegate = new DelegatedContentRouter(peerInfo.id, {
host: '0.0.0.0',
protocol: 'http',
port: 60197
@@ -155,7 +155,10 @@ describe('content-routing', () => {
const mockApi = nock('http://0.0.0.0:60197')
// mock the refs call
.post('/api/v0/refs')
.query(true)
.query({
recursive: false,
arg: cid.toBaseEncodedString()
})
.reply(200, null, [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
@@ -171,7 +174,10 @@ describe('content-routing', () => {
const mockApi = nock('http://0.0.0.0:60197')
// mock the refs call
.post('/api/v0/refs')
.query(true)
.query({
recursive: false,
arg: cid.toBaseEncodedString()
})
.reply(502, 'Bad Gateway', ['Content-Type', 'application/json'])
await expect(node.contentRouting.provide(cid))
@@ -186,7 +192,9 @@ describe('content-routing', () => {
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findprovs')
.query(true)
.query({
arg: cid.toBaseEncodedString()
})
.reply(200, `{"Extra":"","ID":"QmWKqWXCtRXEeCQTo3FoZ7g4AfnGiauYYiczvNxFCHicbB","Responses":[{"Addrs":["/ip4/0.0.0.0/tcp/0"],"ID":"${provider}"}],"Type":4}\n`, [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
@@ -206,7 +214,9 @@ describe('content-routing', () => {
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findprovs')
.query(true)
.query({
arg: cid.toBaseEncodedString()
})
.reply(502, 'Bad Gateway', [
'X-Chunked-Output', '1'
])
@@ -227,9 +237,9 @@ describe('content-routing', () => {
let delegate
beforeEach(async () => {
const [peerId] = await peerUtils.createPeerId({ fixture: false })
const [peerInfo] = await peerUtils.createPeerInfo({ fixture: false })
delegate = new DelegatedContentRouter(peerId, {
delegate = new DelegatedContentRouter(peerInfo.id, {
host: '0.0.0.0',
protocol: 'http',
port: 60197

View File

@@ -32,13 +32,11 @@ describe('DHT subsystem is configurable', () => {
})
it('should start and stop by default once libp2p starts', async () => {
const [peerId] = await peerUtils.createPeerId(1)
const [peerInfo] = await peerUtils.createPeerInfo(1)
peerInfo.multiaddrs.add(listenAddr)
const customOptions = mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
peerInfo
})
libp2p = await create(customOptions)
@@ -52,13 +50,11 @@ describe('DHT subsystem is configurable', () => {
})
it('should not start if disabled once libp2p starts', async () => {
const [peerId] = await peerUtils.createPeerId(1)
const [peerInfo] = await peerUtils.createPeerInfo(1)
peerInfo.multiaddrs.add(listenAddr)
const customOptions = mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
peerInfo,
config: {
dht: {
enabled: false
@@ -74,13 +70,11 @@ describe('DHT subsystem is configurable', () => {
})
it('should allow a manual start', async () => {
const [peerId] = await peerUtils.createPeerId(1)
const [peerInfo] = await peerUtils.createPeerInfo(1)
peerInfo.multiaddrs.add(listenAddr)
const customOptions = mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
peerInfo,
config: {
dht: {
enabled: false

View File

@@ -17,28 +17,25 @@ const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/8000')
const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/8001')
describe('DHT subsystem operates correctly', () => {
let peerId, remotePeerId
let peerInfo, remotePeerInfo
let libp2p, remoteLibp2p
let remAddr
beforeEach(async () => {
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
[peerInfo, remotePeerInfo] = await peerUtils.createPeerInfo({ number: 2 })
peerInfo.multiaddrs.add(listenAddr)
remotePeerInfo.multiaddrs.add(remoteListenAddr)
})
describe('dht started before connect', () => {
beforeEach(async () => {
libp2p = await create(mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
peerInfo
}))
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
}
peerInfo: remotePeerInfo
}))
await Promise.all([
@@ -46,8 +43,7 @@ describe('DHT subsystem operates correctly', () => {
remoteLibp2p.start()
])
libp2p.peerStore.addressBook.set(remotePeerId, [remoteListenAddr])
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerId)[0]
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
afterEach(() => Promise.all([
@@ -71,14 +67,15 @@ describe('DHT subsystem operates correctly', () => {
const value = Buffer.from('world')
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
await Promise.all([
pWaitFor(() => libp2p._dht.routingTable.size === 1),
pWaitFor(() => remoteLibp2p._dht.routingTable.size === 1)
])
await libp2p.contentRouting.put(key, value)
const fetchedValue = await remoteLibp2p.contentRouting.get(key)
const fetchedValue = await remoteLibp2p.contentRouting.get(key)
expect(fetchedValue).to.eql(value)
})
})
@@ -86,17 +83,11 @@ describe('DHT subsystem operates correctly', () => {
describe('dht started after connect', () => {
beforeEach(async () => {
libp2p = await create(mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
peerInfo
}))
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
},
peerInfo: remotePeerInfo,
config: {
dht: {
enabled: false
@@ -107,8 +98,7 @@ describe('DHT subsystem operates correctly', () => {
await libp2p.start()
await remoteLibp2p.start()
libp2p.peerStore.addressBook.set(remotePeerId, [remoteListenAddr])
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerId)[0]
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
afterEach(() => Promise.all([

View File

@@ -14,11 +14,12 @@ const peerUtils = require('../utils/creators/peer')
const listenAddr = multiaddr('/ip4/0.0.0.0/tcp/0')
describe('Listening', () => {
let peerId
let peerInfo
let libp2p
before(async () => {
[peerId] = await peerUtils.createPeerId()
[peerInfo] = await peerUtils.createPeerInfo()
peerInfo.multiaddrs.add(listenAddr)
})
after(async () => {
@@ -27,10 +28,7 @@ describe('Listening', () => {
it('should replace wildcard host and port with actual host and port on startup', async () => {
libp2p = await create({
peerId,
addresses: {
listen: [listenAddr]
},
peerInfo,
modules: {
transport: [Transport]
}
@@ -38,7 +36,7 @@ describe('Listening', () => {
await libp2p.start()
const addrs = libp2p.addresses.listen
const addrs = libp2p.peerInfo.multiaddrs.toArray()
// Should get something like:
// /ip4/127.0.0.1/tcp/50866

View File

@@ -6,11 +6,9 @@ chai.use(require('dirty-chai'))
const { expect } = chai
const pTimes = require('p-times')
const pipe = require('it-pipe')
const peerUtils = require('../utils/creators/peer')
const baseOptions = require('../utils/base-options')
const { PROTOCOL } = require('../../src/ping/constants')
describe('ping', () => {
let nodes
@@ -20,57 +18,18 @@ describe('ping', () => {
number: 2,
config: baseOptions
})
nodes[0].peerStore.addressBook.set(nodes[1].peerId, nodes[1].addresses.listen)
nodes[1].peerStore.addressBook.set(nodes[0].peerId, nodes[0].addresses.listen)
})
it('ping once from peer0 to peer1', async () => {
const latency = await nodes[0].ping(nodes[1].peerId)
const latency = await nodes[0].ping(nodes[1].peerInfo)
expect(latency).to.be.a('Number')
})
it('ping several times for getting an average', async () => {
const latencies = await pTimes(5, () => nodes[1].ping(nodes[0].peerId))
const latencies = await pTimes(5, () => nodes[1].ping(nodes[0].peerInfo))
const averageLatency = latencies.reduce((p, c) => p + c, 0) / latencies.length
expect(averageLatency).to.be.a('Number')
})
it('only waits for the first response to arrive', async () => {
nodes[1].handle(PROTOCOL, async ({ connection, stream }) => {
let firstInvocation = true
await pipe(
stream,
function (stream) {
const output = {
[Symbol.asyncIterator]: () => output,
next: async () => {
if (firstInvocation) {
firstInvocation = false
for await (const data of stream) {
return {
value: data,
done: false
}
}
} else {
return new Promise() // never resolve
}
}
}
return output
},
stream
)
})
const latency = await nodes[0].ping(nodes[1].peerId)
expect(latency).to.be.a('Number')
})
})

View File

@@ -11,6 +11,7 @@ const Muxer = require('libp2p-mplex')
const Crypto = require('libp2p-secio')
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const delay = require('delay')
const pDefer = require('p-defer')
const pSettle = require('p-settle')
@@ -30,28 +31,23 @@ const swarmKeyBuffer = Buffer.from(require('../fixtures/swarm.key'))
const mockUpgrader = require('../utils/mockUpgrader')
const createMockConnection = require('../utils/mockConnection')
const Peers = require('../fixtures/peers')
const { createPeerId } = require('../utils/creators/peer')
const { createPeerInfo } = require('../utils/creators/peer')
const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws')
describe('Dialing (direct, TCP)', () => {
let remoteTM
let localTM
let peerStore
let remoteAddr
before(async () => {
const [remotePeerId] = await Promise.all([
PeerId.createFromJSON(Peers[0])
])
remoteTM = new TransportManager({
libp2p: {},
upgrader: mockUpgrader
})
remoteTM.add(Transport.prototype[Symbol.toStringTag], Transport)
peerStore = new PeerStore()
localTM = new TransportManager({
libp2p: {},
upgrader: mockUpgrader
@@ -60,7 +56,7 @@ describe('Dialing (direct, TCP)', () => {
await remoteTM.listen([listenAddr])
remoteAddr = remoteTM.getAddrs()[0].encapsulate(`/p2p/${remotePeerId.toB58String()}`)
remoteAddr = remoteTM.getAddrs()[0]
})
after(() => remoteTM.close())
@@ -70,7 +66,7 @@ describe('Dialing (direct, TCP)', () => {
})
it('should be able to connect to a remote node via its multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialer = new Dialer({ transportManager: localTM })
const connection = await dialer.connectToPeer(remoteAddr)
expect(connection).to.exist()
@@ -78,20 +74,37 @@ describe('Dialing (direct, TCP)', () => {
})
it('should be able to connect to a remote node via its stringified multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const connection = await dialer.connectToPeer(remoteAddr.toString())
const dialer = new Dialer({ transportManager: localTM })
const dialable = Dialer.getDialable(remoteAddr.toString())
const connection = await dialer.connectToPeer(dialable)
expect(connection).to.exist()
await connection.close()
})
it('should fail to connect to an unsupported multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialer = new Dialer({ transportManager: localTM })
await expect(dialer.connectToPeer(unsupportedAddr))
.to.eventually.be.rejectedWith(AggregateError)
.and.to.have.nested.property('._errors[0].code', ErrorCodes.ERR_TRANSPORT_UNAVAILABLE)
})
it('should be able to connect to a given peer info', async () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore: {
multiaddrsForPeer: () => [remoteAddr]
}
})
const peerId = await PeerId.createFromJSON(Peers[0])
const peerInfo = new PeerInfo(peerId)
const connection = await dialer.connectToPeer(peerInfo)
expect(connection).to.exist()
await connection.close()
})
it('should be able to connect to a given peer id', async () => {
const peerStore = new PeerStore()
const dialer = new Dialer({
@@ -100,9 +113,11 @@ describe('Dialing (direct, TCP)', () => {
})
const peerId = await PeerId.createFromJSON(Peers[0])
peerStore.addressBook.set(peerId, [remoteAddr])
const peerInfo = new PeerInfo(peerId)
peerInfo.multiaddrs.add(remoteAddr)
peerStore.put(peerInfo)
const connection = await dialer.connectToPeer(peerId)
const connection = await dialer.connectToPeer(peerInfo)
expect(connection).to.exist()
await connection.close()
})
@@ -111,15 +126,13 @@ describe('Dialing (direct, TCP)', () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore: {
addressBook: {
add: () => {},
getMultiaddrsForPeer: () => [unsupportedAddr]
}
multiaddrsForPeer: () => [unsupportedAddr]
}
})
const peerId = await PeerId.createFromJSON(Peers[0])
const peerInfo = new PeerInfo(peerId)
await expect(dialer.connectToPeer(peerId))
await expect(dialer.connectToPeer(peerInfo))
.to.eventually.be.rejectedWith(AggregateError)
.and.to.have.nested.property('._errors[0].code', ErrorCodes.ERR_TRANSPORT_UNAVAILABLE)
})
@@ -127,7 +140,6 @@ describe('Dialing (direct, TCP)', () => {
it('should abort dials on queue task timeout', async () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore,
timeout: 50
})
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
@@ -154,10 +166,7 @@ describe('Dialing (direct, TCP)', () => {
transportManager: localTM,
concurrency: 2,
peerStore: {
addressBook: {
add: () => {},
getMultiaddrsForPeer: () => addrs
}
multiaddrsForPeer: () => addrs
}
})
@@ -166,10 +175,10 @@ describe('Dialing (direct, TCP)', () => {
const deferredDial = pDefer()
sinon.stub(localTM, 'dial').callsFake(() => deferredDial.promise)
const [peerId] = await createPeerId()
const [peerInfo] = await createPeerInfo()
// Perform 3 multiaddr dials
dialer.connectToPeer(peerId)
dialer.connectToPeer(peerInfo)
// Let the call stack run
await delay(0)
@@ -188,32 +197,34 @@ describe('Dialing (direct, TCP)', () => {
})
describe('libp2p.dialer', () => {
let peerId, remotePeerId
let peerInfo
let remotePeerInfo
let libp2p
let remoteLibp2p
let remoteAddr
before(async () => {
[peerId, remotePeerId] = await Promise.all([
const [peerId, remotePeerId] = await Promise.all([
PeerId.createFromJSON(Peers[0]),
PeerId.createFromJSON(Peers[1])
])
peerInfo = new PeerInfo(peerId)
remotePeerInfo = new PeerInfo(remotePeerId)
remoteLibp2p = new Libp2p({
peerId: remotePeerId,
addresses: {
listen: [listenAddr]
},
peerInfo: remotePeerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
})
remoteLibp2p.peerInfo.multiaddrs.add(listenAddr)
remoteLibp2p.handle('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
await remoteLibp2p.start()
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${remotePeerId.toB58String()}`)
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
afterEach(async () => {
@@ -224,31 +235,9 @@ describe('Dialing (direct, TCP)', () => {
after(() => remoteLibp2p.stop())
it('should fail if no peer id is provided', async () => {
libp2p = new Libp2p({
peerId,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
})
sinon.spy(libp2p.dialer, 'connectToPeer')
try {
await libp2p.dial(remoteLibp2p.transportManager.getAddrs()[0])
} catch (err) {
expect(err).to.have.property('code', ErrorCodes.ERR_INVALID_MULTIADDR)
return
}
expect.fail('dial should have failed')
})
it('should use the dialer for connecting to a multiaddr', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -269,7 +258,7 @@ describe('Dialing (direct, TCP)', () => {
it('should use the dialer for connecting to a peer', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -278,9 +267,10 @@ describe('Dialing (direct, TCP)', () => {
})
sinon.spy(libp2p.dialer, 'connectToPeer')
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
const remotePeer = new PeerInfo(remoteLibp2p.peerInfo.id)
remotePeer.multiaddrs.add(remoteAddr)
const connection = await libp2p.dial(remotePeerId)
const connection = await libp2p.dial(remotePeer)
expect(connection).to.exist()
const { stream, protocol } = await connection.newStream('/echo/1.0.0')
expect(stream).to.exist()
@@ -291,7 +281,7 @@ describe('Dialing (direct, TCP)', () => {
it('should be able to use hangup to close connections', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -308,7 +298,7 @@ describe('Dialing (direct, TCP)', () => {
it('should be able to use hangup by address string to close connections', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -316,7 +306,7 @@ describe('Dialing (direct, TCP)', () => {
}
})
const connection = await libp2p.dial(`${remoteAddr.toString()}`)
const connection = await libp2p.dial(`${remoteAddr.toString()}/p2p/${remotePeerInfo.id.toB58String()}`)
expect(connection).to.exist()
expect(connection.stat.timeline.close).to.not.exist()
await libp2p.hangUp(connection.remotePeer)
@@ -326,7 +316,7 @@ describe('Dialing (direct, TCP)', () => {
it('should use the protectors when provided for connecting', async () => {
const protector = new Protector(swarmKeyBuffer)
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -347,9 +337,9 @@ describe('Dialing (direct, TCP)', () => {
expect(libp2p.upgrader.protector.protect.callCount).to.equal(1)
})
it('should coalesce parallel dials to the same peer (id in multiaddr)', async () => {
it('should coalesce parallel dials to the same peer (no id in multiaddr)', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -358,11 +348,36 @@ describe('Dialing (direct, TCP)', () => {
})
const dials = 10
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerId.toB58String()}`)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
const dialResults = await Promise.all([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerId)
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(remoteLibp2p.peerInfo.multiaddrs.toArray()[0])
}))
// All should succeed and we should have ten results
expect(dialResults).to.have.length(10)
for (const connection of dialResults) {
expect(Connection.isConnection(connection)).to.equal(true)
}
// We will have two connections, since the multiaddr dial doesn't have a peer id
expect(libp2p.connectionManager._connections.size).to.equal(2)
expect(remoteLibp2p.connectionManager._connections.size).to.equal(2)
})
it('should coalesce parallel dials to the same peer (id in multiaddr)', async () => {
libp2p = new Libp2p({
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
})
const dials = 10
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toB58String()}`)
const dialResults = await Promise.all([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(fullAddress)
}))
@@ -379,7 +394,7 @@ describe('Dialing (direct, TCP)', () => {
it('should coalesce parallel dials to the same error on failure', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -390,10 +405,10 @@ describe('Dialing (direct, TCP)', () => {
const error = new Error('Boom')
sinon.stub(libp2p.transportManager, 'dial').callsFake(() => Promise.reject(error))
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toB58String()}`)
const dialResults = await pSettle([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerId)
return libp2p.dial(remoteAddr)
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(fullAddress)
}))
// All should succeed and we should have ten results

View File

@@ -14,13 +14,13 @@ const Muxer = require('libp2p-mplex')
const Crypto = require('libp2p-secio')
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const AggregateError = require('aggregate-error')
const { AbortError } = require('libp2p-interfaces/src/transport/errors')
const { codes: ErrorCodes } = require('../../src/errors')
const Constants = require('../../src/constants')
const Dialer = require('../../src/dialer')
const PeerStore = require('../../src/peer-store')
const TransportManager = require('../../src/transport-manager')
const Libp2p = require('../../src')
@@ -29,15 +29,13 @@ const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
const mockUpgrader = require('../utils/mockUpgrader')
const createMockConnection = require('../utils/mockConnection')
const { createPeerId } = require('../utils/creators/peer')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws')
const remoteAddr = MULTIADDRS_WEBSOCKETS[0]
describe('Dialing (direct, WebSockets)', () => {
let localTM
let peerStore
before(() => {
peerStore = new PeerStore()
localTM = new TransportManager({
libp2p: {},
upgrader: mockUpgrader,
@@ -51,13 +49,13 @@ describe('Dialing (direct, WebSockets)', () => {
})
it('should have appropriate defaults', () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialer = new Dialer({ transportManager: localTM })
expect(dialer.concurrency).to.equal(Constants.MAX_PARALLEL_DIALS)
expect(dialer.timeout).to.equal(Constants.DIAL_TIMEOUT)
})
it('should limit the number of tokens it provides', () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialer = new Dialer({ transportManager: localTM })
const maxPerPeer = Constants.MAX_PER_PEER_DIALS
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS)
const tokens = dialer.getTokens(maxPerPeer + 1)
@@ -66,14 +64,14 @@ describe('Dialing (direct, WebSockets)', () => {
})
it('should not return tokens if non are left', () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialer = new Dialer({ transportManager: localTM })
sinon.stub(dialer, 'tokens').value([])
const tokens = dialer.getTokens(1)
expect(tokens.length).to.equal(0)
})
it('should NOT be able to return a token twice', () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialer = new Dialer({ transportManager: localTM })
const tokens = dialer.getTokens(1)
expect(tokens).to.have.length(1)
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS - 1)
@@ -86,10 +84,7 @@ describe('Dialing (direct, WebSockets)', () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore: {
addressBook: {
add: () => {},
getMultiaddrsForPeer: () => [remoteAddr]
}
multiaddrsForPeer: () => [remoteAddr]
}
})
@@ -102,10 +97,7 @@ describe('Dialing (direct, WebSockets)', () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore: {
addressBook: {
add: () => {},
getMultiaddrsForPeer: () => [remoteAddr]
}
multiaddrsForPeer: () => [remoteAddr]
}
})
@@ -115,7 +107,7 @@ describe('Dialing (direct, WebSockets)', () => {
})
it('should fail to connect to an unsupported multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialer = new Dialer({ transportManager: localTM })
await expect(dialer.connectToPeer(unsupportedAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -126,10 +118,7 @@ describe('Dialing (direct, WebSockets)', () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore: {
addressBook: {
add: () => {},
getMultiaddrsForPeer: () => [remoteAddr]
}
multiaddrsForPeer: () => [remoteAddr]
}
})
const peerId = await PeerId.createFromJSON(Peers[0])
@@ -143,10 +132,7 @@ describe('Dialing (direct, WebSockets)', () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore: {
addressBook: {
set: () => {},
getMultiaddrsForPeer: () => [unsupportedAddr]
}
multiaddrsForPeer: () => [unsupportedAddr]
}
})
const peerId = await PeerId.createFromJSON(Peers[0])
@@ -161,10 +147,7 @@ describe('Dialing (direct, WebSockets)', () => {
transportManager: localTM,
timeout: 50,
peerStore: {
addressBook: {
add: () => {},
getMultiaddrsForPeer: () => [remoteAddr]
}
multiaddrsForPeer: () => [remoteAddr]
}
})
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
@@ -186,10 +169,7 @@ describe('Dialing (direct, WebSockets)', () => {
transportManager: localTM,
concurrency: 2,
peerStore: {
addressBook: {
set: () => {},
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
}
multiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
}
})
@@ -225,10 +205,7 @@ describe('Dialing (direct, WebSockets)', () => {
transportManager: localTM,
concurrency: 2,
peerStore: {
addressBook: {
set: () => {},
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
}
multiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
}
})
@@ -266,12 +243,13 @@ describe('Dialing (direct, WebSockets)', () => {
})
describe('libp2p.dialer', () => {
let peerId
let peerInfo
let libp2p
let remoteLibp2p
before(async () => {
peerId = await PeerId.createFromJSON(Peers[0])
const peerId = await PeerId.createFromJSON(Peers[0])
peerInfo = new PeerInfo(peerId)
})
afterEach(async () => {
@@ -286,7 +264,7 @@ describe('Dialing (direct, WebSockets)', () => {
it('should create a dialer', () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -304,7 +282,7 @@ describe('Dialing (direct, WebSockets)', () => {
it('should be able to override dialer options', async () => {
const config = {
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -326,7 +304,7 @@ describe('Dialing (direct, WebSockets)', () => {
it('should use the dialer for connecting', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -335,7 +313,7 @@ describe('Dialing (direct, WebSockets)', () => {
})
sinon.spy(libp2p.dialer, 'connectToPeer')
sinon.spy(libp2p.peerStore.addressBook, 'add')
sinon.spy(libp2p.peerStore, 'put')
const connection = await libp2p.dial(remoteAddr)
expect(connection).to.exist()
@@ -344,12 +322,12 @@ describe('Dialing (direct, WebSockets)', () => {
expect(protocol).to.equal('/echo/1.0.0')
await connection.close()
expect(libp2p.dialer.connectToPeer.callCount).to.equal(1)
expect(libp2p.peerStore.addressBook.add.callCount).to.be.at.least(1)
expect(libp2p.peerStore.put.callCount).to.be.at.least(1)
})
it('should run identify automatically after connecting', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -358,27 +336,24 @@ describe('Dialing (direct, WebSockets)', () => {
})
sinon.spy(libp2p.identifyService, 'identify')
sinon.spy(libp2p.peerStore, 'replace')
sinon.spy(libp2p.upgrader, 'onConnection')
const connection = await libp2p.dial(remoteAddr)
expect(connection).to.exist()
sinon.spy(libp2p.peerStore.addressBook, 'set')
sinon.spy(libp2p.peerStore.protoBook, 'set')
// Wait for onConnection to be called
await pWaitFor(() => libp2p.upgrader.onConnection.callCount === 1)
expect(libp2p.identifyService.identify.callCount).to.equal(1)
await libp2p.identifyService.identify.firstCall.returnValue
expect(libp2p.peerStore.addressBook.set.callCount).to.equal(1)
expect(libp2p.peerStore.protoBook.set.callCount).to.equal(1)
expect(libp2p.peerStore.replace.callCount).to.equal(1)
})
it('should be able to use hangup to close connections', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -395,7 +370,7 @@ describe('Dialing (direct, WebSockets)', () => {
it('should abort pending dials on stop', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],

View File

@@ -5,37 +5,31 @@ const chai = require('chai')
chai.use(require('dirty-chai'))
chai.use(require('chai-as-promised'))
const { expect } = chai
const sinon = require('sinon')
const multiaddr = require('multiaddr')
const { collect } = require('streaming-iterables')
const pipe = require('it-pipe')
const AggregateError = require('aggregate-error')
const PeerId = require('peer-id')
const { createPeerId } = require('../utils/creators/peer')
const { createPeerInfo } = require('../utils/creators/peer')
const baseOptions = require('../utils/base-options')
const Libp2p = require('../../src')
const { codes: Errors } = require('../../src/errors')
const listenAddr = multiaddr('/ip4/0.0.0.0/tcp/0')
describe('Dialing (via relay, TCP)', () => {
let srcLibp2p
let relayLibp2p
let dstLibp2p
before(async () => {
const peerIds = await createPeerId({ number: 3 })
const peerInfos = await createPeerInfo({ number: 3 })
// Create 3 nodes, and turn HOP on for the relay
;[srcLibp2p, relayLibp2p, dstLibp2p] = peerIds.map((peerId, index) => {
;[srcLibp2p, relayLibp2p, dstLibp2p] = peerInfos.map((peerInfo, index) => {
const opts = baseOptions
index === 1 && (opts.config.relay.hop.enabled = true)
return new Libp2p({
...opts,
addresses: {
listen: [listenAddr]
},
peerId
peerInfo
})
})
@@ -44,7 +38,12 @@ describe('Dialing (via relay, TCP)', () => {
beforeEach(() => {
// Start each node
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(libp2p => libp2p.start()))
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(libp2p => {
// Reset multiaddrs and start
libp2p.peerInfo.multiaddrs.clear()
libp2p.peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
return libp2p.start()
}))
})
afterEach(() => {
@@ -52,20 +51,19 @@ describe('Dialing (via relay, TCP)', () => {
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(async libp2p => {
await libp2p.stop()
// Clear the peer stores
for (const peerIdStr of libp2p.peerStore.peers.keys()) {
const peerId = PeerId.createFromCID(peerIdStr)
libp2p.peerStore.delete(peerId)
for (const peerId of libp2p.peerStore.peers.keys()) {
libp2p.peerStore.remove(peerId)
}
}))
})
it('should be able to connect to a peer over a relay with active connections', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerId.toB58String()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerId.toB58String()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
const tcpAddrs = dstLibp2p.transportManager.getAddrs()
await dstLibp2p.transportManager.listen([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)])
@@ -73,14 +71,14 @@ describe('Dialing (via relay, TCP)', () => {
const connection = await srcLibp2p.dial(dialAddr)
expect(connection).to.exist()
expect(connection.remotePeer.toBytes()).to.eql(dstLibp2p.peerId.toBytes())
expect(connection.localPeer.toBytes()).to.eql(srcLibp2p.peerId.toBytes())
expect(connection.remotePeer.toBytes()).to.eql(dstLibp2p.peerInfo.id.toBytes())
expect(connection.localPeer.toBytes()).to.eql(srcLibp2p.peerInfo.id.toBytes())
expect(connection.remoteAddr).to.eql(dialAddr)
expect(connection.localAddr).to.eql(
relayAddr // the relay address
.encapsulate(`/p2p/${relayIdString}`) // with its peer id
.encapsulate('/p2p-circuit') // the local peer is connected over the relay
.encapsulate(`/p2p/${srcLibp2p.peerId.toB58String()}`) // and the local peer id
.encapsulate(`/p2p/${srcLibp2p.peerInfo.id.toB58String()}`) // and the local peer id
)
const { stream: echoStream } = await connection.newStream('/echo/1.0.0')
@@ -96,11 +94,11 @@ describe('Dialing (via relay, TCP)', () => {
it('should fail to connect to a peer over a relay with inactive connections', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerId.toB58String()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerId.toB58String()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -109,27 +107,28 @@ describe('Dialing (via relay, TCP)', () => {
it('should not stay connected to a relay when not already connected and HOP fails', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerId.toB58String()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerId.toB58String()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)
.and.to.have.nested.property('._errors[0].code', Errors.ERR_HOP_REQUEST_FAILED)
// We should not be connected to the relay, because we weren't before the dial
const srcToRelayConn = srcLibp2p.registrar.getConnection(relayLibp2p.peerId)
const srcToRelayConn = srcLibp2p.registrar.getConnection(relayLibp2p.peerInfo)
expect(srcToRelayConn).to.not.exist()
})
it('dialer should stay connected to an already connected relay on hop failure', async () => {
const relayIdString = relayLibp2p.peerId.toB58String()
const relayAddr = relayLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${relayIdString}`)
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerId.toB58String()}`)
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await srcLibp2p.dial(relayAddr)
@@ -137,33 +136,34 @@ describe('Dialing (via relay, TCP)', () => {
.to.eventually.be.rejectedWith(AggregateError)
.and.to.have.nested.property('._errors[0].code', Errors.ERR_HOP_REQUEST_FAILED)
const srcToRelayConn = srcLibp2p.registrar.getConnection(relayLibp2p.peerId)
const srcToRelayConn = srcLibp2p.registrar.getConnection(relayLibp2p.peerInfo)
expect(srcToRelayConn).to.exist()
expect(srcToRelayConn.stat.status).to.equal('open')
})
it('destination peer should stay connected to an already connected relay on hop failure', async () => {
const relayIdString = relayLibp2p.peerId.toB58String()
const relayAddr = relayLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${relayIdString}`)
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerId.toB58String()}`)
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
// Connect the destination peer and the relay
const tcpAddrs = dstLibp2p.transportManager.getAddrs()
await dstLibp2p.transportManager.listen([multiaddr(`${relayAddr}/p2p-circuit`)])
await dstLibp2p.transportManager.listen([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)])
expect(dstLibp2p.transportManager.getAddrs()).to.have.deep.members([...tcpAddrs, dialAddr.decapsulate('p2p')])
// Tamper with the our multiaddrs for the circuit message
srcLibp2p.addresses.listen = [{
sinon.stub(srcLibp2p.peerInfo.multiaddrs, 'toArray').returns([{
buffer: Buffer.from('an invalid multiaddr')
}]
}])
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)
.and.to.have.nested.property('._errors[0].code', Errors.ERR_HOP_REQUEST_FAILED)
const dstToRelayConn = dstLibp2p.registrar.getConnection(relayLibp2p.peerId)
const dstToRelayConn = dstLibp2p.registrar.getConnection(relayLibp2p.peerInfo)
expect(dstToRelayConn).to.exist()
expect(dstToRelayConn.stat.status).to.equal('open')
})

View File

@@ -9,9 +9,9 @@ const sinon = require('sinon')
const delay = require('delay')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const duplexPair = require('it-pair/duplex')
const multiaddr = require('multiaddr')
const pWaitFor = require('p-wait-for')
const { codes: Errors } = require('../../src/errors')
const { IdentifyService, multicodecs } = require('../../src/identify')
@@ -34,7 +34,7 @@ describe('Identify', () => {
[localPeer, remotePeer] = (await Promise.all([
PeerId.createFromJSON(Peers[0]),
PeerId.createFromJSON(Peers[1])
]))
])).map(id => new PeerInfo(id))
})
afterEach(() => {
@@ -43,39 +43,27 @@ describe('Identify', () => {
it('should be able to identify another peer', async () => {
const localIdentify = new IdentifyService({
peerId: localPeer,
addresses: {
listen: []
},
peerInfo: localPeer,
protocols,
registrar: {
peerStore: {
addressBook: {
set: () => { }
},
protoBook: {
set: () => { }
}
replace: () => {}
}
}
})
const remoteIdentify = new IdentifyService({
peerId: remotePeer,
addresses: {
listen: []
},
peerInfo: remotePeer,
protocols
})
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
const localConnectionMock = { newStream: () => {}, remotePeer }
const localConnectionMock = { newStream: () => {}, remotePeer: remotePeer.id }
const remoteConnectionMock = { remoteAddr: observedAddr }
const [local, remote] = duplexPair()
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY })
sinon.spy(localIdentify.registrar.peerStore.addressBook, 'set')
sinon.spy(localIdentify.registrar.peerStore.protoBook, 'set')
sinon.spy(localIdentify.registrar.peerStore, 'replace')
// Run identify
await Promise.all([
@@ -87,41 +75,29 @@ describe('Identify', () => {
})
])
expect(localIdentify.registrar.peerStore.addressBook.set.callCount).to.equal(1)
expect(localIdentify.registrar.peerStore.protoBook.set.callCount).to.equal(1)
expect(localIdentify.registrar.peerStore.replace.callCount).to.equal(1)
// Validate the remote peer gets updated in the peer store
const call = localIdentify.registrar.peerStore.addressBook.set.firstCall
expect(call.args[0].id.bytes).to.equal(remotePeer.bytes)
const call = localIdentify.registrar.peerStore.replace.firstCall
expect(call.args[0].id.bytes).to.equal(remotePeer.id.bytes)
})
it('should throw if identified peer is the wrong peer', async () => {
const localIdentify = new IdentifyService({
peerId: localPeer,
addresses: {
listen: []
},
peerInfo: localPeer,
protocols,
registrar: {
peerStore: {
addressBook: {
set: () => { }
},
protoBook: {
set: () => { }
}
replace: () => {}
}
}
})
const remoteIdentify = new IdentifyService({
peerId: remotePeer,
addresses: {
listen: []
},
peerInfo: remotePeer,
protocols
})
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
const localConnectionMock = { newStream: () => {}, remotePeer: localPeer }
const localConnectionMock = { newStream: () => {}, remotePeer: localPeer.id }
const remoteConnectionMock = { remoteAddr: observedAddr }
const [local, remote] = duplexPair()
@@ -129,7 +105,7 @@ describe('Identify', () => {
// Run identify
const identifyPromise = Promise.all([
localIdentify.identify(localConnectionMock, localPeer),
localIdentify.identify(localConnectionMock, localPeer.id),
remoteIdentify.handleMessage({
connection: remoteConnectionMock,
stream: remote,
@@ -144,12 +120,8 @@ describe('Identify', () => {
describe('push', () => {
it('should be able to push identify updates to another peer', async () => {
const listeningAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
const localIdentify = new IdentifyService({
peerId: localPeer,
addresses: {
listen: [listeningAddr]
},
peerInfo: localPeer,
registrar: { getConnection: () => {} },
protocols: new Map([
[multicodecs.IDENTIFY],
@@ -158,32 +130,30 @@ describe('Identify', () => {
])
})
const remoteIdentify = new IdentifyService({
peerId: remotePeer,
addresses: {
listen: []
},
peerInfo: remotePeer,
registrar: {
peerStore: {
addressBook: {
set: () => {}
},
protoBook: {
set: () => { }
}
replace: () => {}
}
}
})
// Setup peer protocols and multiaddrs
const localProtocols = new Set([multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH, '/echo/1.0.0'])
const listeningAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
sinon.stub(localPeer.multiaddrs, 'toArray').returns([listeningAddr])
sinon.stub(localPeer, 'protocols').value(localProtocols)
sinon.stub(remotePeer, 'protocols').value(new Set([multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH]))
const localConnectionMock = { newStream: () => {} }
const remoteConnectionMock = { remotePeer: localPeer }
const remoteConnectionMock = { remotePeer: localPeer.id }
const [local, remote] = duplexPair()
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_PUSH })
sinon.spy(remoteIdentify.registrar.peerStore.addressBook, 'set')
sinon.spy(remoteIdentify.registrar.peerStore.protoBook, 'set')
sinon.spy(IdentifyService, 'updatePeerAddresses')
sinon.spy(IdentifyService, 'updatePeerProtocols')
sinon.spy(remoteIdentify.registrar.peerStore, 'replace')
// Run identify
await Promise.all([
@@ -195,24 +165,25 @@ describe('Identify', () => {
})
])
expect(remoteIdentify.registrar.peerStore.addressBook.set.callCount).to.equal(1)
expect(remoteIdentify.registrar.peerStore.protoBook.set.callCount).to.equal(1)
const [peerId, multiaddrs] = remoteIdentify.registrar.peerStore.addressBook.set.firstCall.args
expect(peerId.bytes).to.eql(localPeer.bytes)
expect(multiaddrs).to.eql([listeningAddr])
const [peerId2, protocols] = remoteIdentify.registrar.peerStore.protoBook.set.firstCall.args
expect(peerId2.bytes).to.eql(localPeer.bytes)
expect(protocols).to.eql(Array.from(localProtocols))
expect(IdentifyService.updatePeerAddresses.callCount).to.equal(1)
expect(IdentifyService.updatePeerProtocols.callCount).to.equal(1)
expect(remoteIdentify.registrar.peerStore.replace.callCount).to.equal(1)
const [peerInfo] = remoteIdentify.registrar.peerStore.replace.firstCall.args
expect(peerInfo.id.bytes).to.eql(localPeer.id.bytes)
expect(peerInfo.multiaddrs.toArray()).to.eql([listeningAddr])
expect(peerInfo.protocols).to.eql(localProtocols)
})
})
describe('libp2p.dialer.identifyService', () => {
let peerId
let peerInfo
let libp2p
let remoteLibp2p
before(async () => {
peerId = await PeerId.createFromJSON(Peers[0])
const peerId = await PeerId.createFromJSON(Peers[0])
peerInfo = new PeerInfo(peerId)
})
afterEach(async () => {
@@ -228,34 +199,32 @@ describe('Identify', () => {
it('should run identify automatically after connecting', async () => {
libp2p = new Libp2p({
...baseOptions,
peerId
peerInfo
})
sinon.spy(libp2p.identifyService, 'identify')
const peerStoreSpySet = sinon.spy(libp2p.peerStore.addressBook, 'set')
const peerStoreSpyAdd = sinon.spy(libp2p.peerStore.addressBook, 'add')
sinon.spy(libp2p.peerStore, 'replace')
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
expect(connection).to.exist()
// Wait for peer store to be updated
// Dialer._createDialTarget (add), Identify (replace)
await pWaitFor(() => peerStoreSpySet.callCount === 1 && peerStoreSpyAdd.callCount === 1)
// Wait for nextTick to trigger the identify call
await delay(1)
expect(libp2p.identifyService.identify.callCount).to.equal(1)
await libp2p.identifyService.identify.firstCall.returnValue
// The connection should have no open streams
expect(connection.streams).to.have.length(0)
expect(libp2p.peerStore.replace.callCount).to.equal(1)
await connection.close()
})
it('should push protocol updates to an already connected peer', async () => {
libp2p = new Libp2p({
...baseOptions,
peerId
peerInfo
})
sinon.spy(libp2p.identifyService, 'identify')
sinon.spy(libp2p.identifyService, 'push')
sinon.spy(libp2p.peerStore, 'update')
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
expect(connection).to.exist()
@@ -278,9 +247,6 @@ describe('Identify', () => {
const results = await call.returnValue
expect(results.length).to.equal(1)
}
// Verify the streams close
await pWaitFor(() => connection.streams.length === 0)
})
})
})

View File

@@ -74,7 +74,7 @@ describe('libp2p.metrics', () => {
remoteLibp2p.handle('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
const connection = await libp2p.dial(remoteLibp2p.peerId)
const connection = await libp2p.dial(remoteLibp2p.peerInfo)
const { stream } = await connection.newStream('/echo/1.0.0')
const bytes = randomBytes(512)
@@ -109,11 +109,6 @@ describe('libp2p.metrics', () => {
enabled: true,
computeThrottleMaxQueueSize: 1, // compute after every message
movingAverageIntervals: [10]
},
config: {
peerDiscovery: {
autoDial: false
}
}
}
let remoteLibp2p
@@ -121,7 +116,7 @@ describe('libp2p.metrics', () => {
remoteLibp2p.handle('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
const connection = await libp2p.dial(remoteLibp2p.peerId)
const connection = await libp2p.dial(remoteLibp2p.peerInfo)
const { stream } = await connection.newStream('/echo/1.0.0')
const bytes = randomBytes(512)

View File

@@ -15,16 +15,18 @@ const multiaddr = require('multiaddr')
const Libp2p = require('../../src')
const baseOptions = require('../utils/base-options')
const { createPeerId } = require('../utils/creators/peer')
const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
const { createPeerInfo } = require('../utils/creators/peer')
describe('peer discovery scenarios', () => {
let peerId, remotePeerId1, remotePeerId2
let peerInfo, remotePeerInfo1, remotePeerInfo2
let libp2p
before(async () => {
[peerId, remotePeerId1, remotePeerId2] = await createPeerId({ number: 3 })
[peerInfo, remotePeerInfo1, remotePeerInfo2] = await createPeerInfo({ number: 3 })
peerInfo.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/0'))
remotePeerInfo1.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/0'))
remotePeerInfo2.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/0'))
})
afterEach(async () => {
@@ -35,15 +37,12 @@ describe('peer discovery scenarios', () => {
const deferred = defer()
const bootstrappers = [
`${listenAddr}/p2p/${remotePeerId1.toB58String()}`,
`${listenAddr}/p2p/${remotePeerId2.toB58String()}`
...remotePeerInfo1.multiaddrs.toArray().map((ma) => `${ma}/p2p/${remotePeerInfo1.id.toB58String()}`),
...remotePeerInfo2.multiaddrs.toArray().map((ma) => `${ma}/p2p/${remotePeerInfo2.id.toB58String()}`)
]
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
peerInfo,
modules: {
peerDiscovery: [Bootstrap]
},
@@ -59,12 +58,12 @@ describe('peer discovery scenarios', () => {
}))
const expectedPeers = new Set([
remotePeerId1.toB58String(),
remotePeerId2.toB58String()
remotePeerInfo1.id.toB58String(),
remotePeerInfo2.id.toB58String()
])
libp2p.on('peer:discovery', (peerId) => {
expectedPeers.delete(peerId.toB58String())
libp2p.on('peer:discovery', (peerInfo) => {
expectedPeers.delete(peerInfo.id.toB58String())
if (expectedPeers.size === 0) {
libp2p.removeAllListeners('peer:discovery')
deferred.resolve()
@@ -79,11 +78,8 @@ describe('peer discovery scenarios', () => {
it('MulticastDNS should discover all peers on the local network', async () => {
const deferred = defer()
const getConfig = (peerId) => mergeOptions(baseOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
const getConfig = (peerInfo) => mergeOptions(baseOptions, {
peerInfo,
modules: {
peerDiscovery: [MulticastDNS]
},
@@ -100,17 +96,17 @@ describe('peer discovery scenarios', () => {
}
})
libp2p = new Libp2p(getConfig(peerId))
const remoteLibp2p1 = new Libp2p(getConfig(remotePeerId1))
const remoteLibp2p2 = new Libp2p(getConfig(remotePeerId2))
libp2p = new Libp2p(getConfig(peerInfo))
const remoteLibp2p1 = new Libp2p(getConfig(remotePeerInfo1))
const remoteLibp2p2 = new Libp2p(getConfig(remotePeerInfo2))
const expectedPeers = new Set([
remotePeerId1.toB58String(),
remotePeerId2.toB58String()
remotePeerInfo1.id.toB58String(),
remotePeerInfo2.id.toB58String()
])
libp2p.on('peer:discovery', (peerId) => {
expectedPeers.delete(peerId.toB58String())
libp2p.on('peer:discovery', (peerInfo) => {
expectedPeers.delete(peerInfo.id.toB58String())
if (expectedPeers.size === 0) {
libp2p.removeAllListeners('peer:discovery')
deferred.resolve()
@@ -132,11 +128,8 @@ describe('peer discovery scenarios', () => {
it('kad-dht should discover other peers', async () => {
const deferred = defer()
const getConfig = (peerId) => mergeOptions(baseOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
const getConfig = (peerInfo) => mergeOptions(baseOptions, {
peerInfo,
modules: {
dht: KadDht
},
@@ -146,48 +139,42 @@ describe('peer discovery scenarios', () => {
},
dht: {
randomWalk: {
enabled: false,
enabled: true,
delay: 1000, // start the first query quickly
interval: 10000,
timeout: 5000
timeout: 1000
},
enabled: true
}
}
})
const localConfig = getConfig(peerId)
// Only run random walk on our local node
localConfig.config.dht.randomWalk.enabled = true
libp2p = new Libp2p(localConfig)
libp2p = new Libp2p(getConfig(peerInfo))
const remoteLibp2p1 = new Libp2p(getConfig(remotePeerInfo1))
const remoteLibp2p2 = new Libp2p(getConfig(remotePeerInfo2))
const remoteLibp2p1 = new Libp2p(getConfig(remotePeerId1))
const remoteLibp2p2 = new Libp2p(getConfig(remotePeerId2))
libp2p.on('peer:discovery', (peerId) => {
if (peerId.toB58String() === remotePeerId1.toB58String()) {
libp2p.on('peer:discovery', (peerInfo) => {
if (peerInfo.id.toB58String() === remotePeerInfo2.id.toB58String()) {
libp2p.removeAllListeners('peer:discovery')
deferred.resolve()
}
})
await Promise.all([
libp2p.start(),
remoteLibp2p1.start(),
remoteLibp2p2.start()
])
libp2p.peerStore.addressBook.set(remotePeerId1, remoteLibp2p1.addresses.listen)
remoteLibp2p2.peerStore.addressBook.set(remotePeerId1, remoteLibp2p1.addresses.listen)
// Topology:
// A -> B
// C -> B
await Promise.all([
libp2p.dial(remotePeerId1),
remoteLibp2p2.dial(remotePeerId1)
libp2p.dial(remotePeerInfo1),
remoteLibp2p2.dial(remotePeerInfo1)
])
libp2p.start()
await deferred.promise
return Promise.all([
remoteLibp2p1.stop(),

View File

@@ -9,22 +9,21 @@ const sinon = require('sinon')
const defer = require('p-defer')
const mergeOptions = require('merge-options')
const multiaddr = require('multiaddr')
const MulticastDNS = require('libp2p-mdns')
const WebRTCStar = require('libp2p-webrtc-star')
const Libp2p = require('../../src')
const baseOptions = require('../utils/base-options.browser')
const { createPeerId } = require('../utils/creators/peer')
const { EventEmitter } = require('events')
const { createPeerInfo } = require('../utils/creators/peer')
describe('peer discovery', () => {
describe('basic functions', () => {
let peerId
let remotePeerId
let peerInfo
let remotePeerInfo
let libp2p
before(async () => {
[peerId, remotePeerId] = await createPeerId({ number: 2 })
[peerInfo, remotePeerInfo] = await createPeerInfo({ number: 2 })
})
afterEach(async () => {
@@ -35,14 +34,12 @@ describe('peer discovery', () => {
it('should dial know peers on startup', async () => {
libp2p = new Libp2p({
...baseOptions,
peerId
peerInfo
})
libp2p.peerStore.addressBook.set(remotePeerId, [multiaddr('/ip4/165.1.1.1/tcp/80')])
libp2p.peerStore.add(remotePeerInfo)
const deferred = defer()
sinon.stub(libp2p.dialer, 'connectToPeer').callsFake((remotePeerId) => {
expect(remotePeerId).to.equal(remotePeerId)
sinon.stub(libp2p.dialer, 'connectToPeer').callsFake((remotePeerInfo) => {
expect(remotePeerInfo).to.equal(remotePeerInfo)
deferred.resolve()
})
const spy = sinon.spy()
@@ -50,28 +47,21 @@ describe('peer discovery', () => {
libp2p.start()
await deferred.promise
expect(spy.calledOnce).to.eql(true)
expect(spy.getCall(0).args[0].toString()).to.eql(remotePeerId.toString())
expect(spy.getCall(0).args).to.eql([remotePeerInfo])
})
it('should ignore self on discovery', async () => {
const mockDiscovery = new EventEmitter()
mockDiscovery.tag = 'mock'
mockDiscovery.start = () => {}
mockDiscovery.stop = () => {}
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerId,
peerInfo,
modules: {
peerDiscovery: [mockDiscovery]
peerDiscovery: [MulticastDNS]
}
}))
await libp2p.start()
const discoverySpy = sinon.spy()
libp2p.on('peer:discovery', discoverySpy)
libp2p._discovery.get('mock').emit('peer', { id: libp2p.peerId })
libp2p._discovery.get('mdns').emit('peer', libp2p.peerInfo)
expect(discoverySpy.called).to.eql(false)
})
@@ -88,7 +78,7 @@ describe('peer discovery', () => {
const stopSpy = sinon.spy(mockDiscovery, 'stop')
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerId,
peerInfo,
modules: {
peerDiscovery: [mockDiscovery]
}
@@ -104,15 +94,15 @@ describe('peer discovery', () => {
})
describe('discovery modules from transports', () => {
let peerId, libp2p
let peerInfo, libp2p
before(async () => {
[peerId] = await createPeerId()
[peerInfo] = await createPeerInfo()
})
it('should add discovery module if present in transports and enabled', async () => {
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerId,
peerInfo,
modules: {
transport: [WebRTCStar]
},
@@ -133,7 +123,7 @@ describe('peer discovery', () => {
it('should not add discovery module if present in transports but disabled', async () => {
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerId,
peerInfo,
modules: {
transport: [WebRTCStar]
},

View File

@@ -44,7 +44,7 @@ describe('peer-routing', () => {
// Ring dial
await Promise.all(
nodes.map((peer, i) => peer.dial(nodes[(i + 1) % number].peerId))
nodes.map((peer, i) => peer.dial(nodes[(i + 1) % number].peerInfo))
)
})
@@ -59,7 +59,7 @@ describe('peer-routing', () => {
sinon.stub(nodes[0]._dht, 'findPeer').callsFake(() => {
deferred.resolve()
return nodes[1].peerId
return nodes[1].peerInfo
})
nodes[0].peerRouting.findPeer()
@@ -104,7 +104,7 @@ describe('peer-routing', () => {
sinon.stub(delegate, 'findPeer').callsFake(() => {
deferred.resolve()
return 'fake peer-id'
return 'fake peer-info'
})
await node.peerRouting.findPeer()
@@ -115,15 +115,17 @@ describe('peer-routing', () => {
const peerKey = 'QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL'
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findpeer')
.query(true)
.query({
arg: peerKey
})
.reply(200, `{"Extra":"","ID":"some other id","Responses":null,"Type":0}\n{"Extra":"","ID":"","Responses":[{"Addrs":["/ip4/127.0.0.1/tcp/4001"],"ID":"${peerKey}"}],"Type":2}\n`, [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
])
const peer = await node.peerRouting.findPeer(peerKey)
const peerInfo = await node.peerRouting.findPeer(peerKey)
expect(peer.id).to.equal(peerKey)
expect(peerInfo.id.toB58String()).to.equal(peerKey)
expect(mockApi.isDone()).to.equal(true)
})
@@ -131,7 +133,9 @@ describe('peer-routing', () => {
const peerKey = 'key of a peer not on the network'
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findpeer')
.query(true)
.query({
arg: peerKey
})
.reply(200, '{"Extra":"","ID":"some other id","Responses":null,"Type":6}\n{"Extra":"","ID":"yet another id","Responses":null,"Type":0}\n{"Extra":"routing:not found","ID":"","Responses":null,"Type":3}\n', [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
@@ -147,7 +151,9 @@ describe('peer-routing', () => {
const peerKey = 'key of a peer not on the network'
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findpeer')
.query(true)
.query({
arg: peerKey
})
.reply(502)
await expect(node.peerRouting.findPeer(peerKey))
@@ -188,7 +194,7 @@ describe('peer-routing', () => {
sinon.stub(node._dht, 'findPeer').callsFake(() => {
dhtDeferred.resolve()
return { id: node.peerId }
return node.peerInfo
})
sinon.stub(delegate, 'findPeer').callsFake(() => {
throw new Error('the delegate should not have been called')

View File

@@ -1,364 +0,0 @@
'use strict'
/* eslint-env mocha */
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
const pDefer = require('p-defer')
const multiaddr = require('multiaddr')
const PeerStore = require('../../src/peer-store')
const peerUtils = require('../utils/creators/peer')
const {
ERR_INVALID_PARAMETERS
} = require('../../src/errors')
const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000')
const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001')
const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002')
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
describe('addressBook', () => {
let peerId
before(async () => {
[peerId] = await peerUtils.createPeerId()
})
describe('addressBook.set', () => {
let peerStore, ab
beforeEach(() => {
peerStore = new PeerStore()
ab = peerStore.addressBook
})
afterEach(() => {
peerStore.removeAllListeners()
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
ab.set('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('throwns invalid parameters error if no addresses provided', () => {
expect(() => {
ab.set(peerId)
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
expect(() => {
ab.set(peerId, 'invalid multiaddr')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('replaces the stored content by default and emit change event', () => {
const defer = pDefer()
const supportedMultiaddrs = [addr1, addr2]
peerStore.once('change:multiaddrs', ({ peerId, multiaddrs }) => {
expect(peerId).to.exist()
expect(multiaddrs).to.eql(supportedMultiaddrs)
defer.resolve()
})
ab.set(peerId, supportedMultiaddrs)
const addresses = ab.get(peerId)
const multiaddrs = addresses.map((mi) => mi.multiaddr)
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
return defer.promise
})
it('emits on set if not storing the exact same content', async () => {
const defer = pDefer()
const supportedMultiaddrsA = [addr1, addr2]
const supportedMultiaddrsB = [addr2]
let changeCounter = 0
peerStore.on('change:multiaddrs', () => {
changeCounter++
if (changeCounter > 1) {
defer.resolve()
}
})
// set 1
ab.set(peerId, supportedMultiaddrsA)
// set 2 (same content)
ab.set(peerId, supportedMultiaddrsB)
const addresses = ab.get(peerId)
const multiaddrs = addresses.map((mi) => mi.multiaddr)
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsB)
await defer.promise
})
it('does not emit on set if it is storing the exact same content', async () => {
const defer = pDefer()
const supportedMultiaddrs = [addr1, addr2]
let changeCounter = 0
peerStore.on('change:multiaddrs', () => {
changeCounter++
if (changeCounter > 1) {
defer.reject()
}
})
// set 1
ab.set(peerId, supportedMultiaddrs)
// set 2 (same content)
ab.set(peerId, supportedMultiaddrs)
// Wait 50ms for incorrect second event
setTimeout(() => {
defer.resolve()
}, 50)
await defer.promise
})
})
describe('addressBook.add', () => {
let peerStore, ab
beforeEach(() => {
peerStore = new PeerStore()
ab = peerStore.addressBook
})
afterEach(() => {
peerStore.removeAllListeners()
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
ab.add('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('throwns invalid parameters error if no addresses provided', () => {
expect(() => {
ab.add(peerId)
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
expect(() => {
ab.add(peerId, 'invalid multiaddr')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('adds the new content and emits change event', () => {
const defer = pDefer()
const supportedMultiaddrsA = [addr1, addr2]
const supportedMultiaddrsB = [addr3]
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
let changeTrigger = 2
peerStore.on('change:multiaddrs', ({ multiaddrs }) => {
changeTrigger--
if (changeTrigger === 0 && arraysAreEqual(multiaddrs, finalMultiaddrs)) {
defer.resolve()
}
})
// Replace
ab.set(peerId, supportedMultiaddrsA)
let addresses = ab.get(peerId)
let multiaddrs = addresses.map((mi) => mi.multiaddr)
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsA)
// Add
ab.add(peerId, supportedMultiaddrsB)
addresses = ab.get(peerId)
multiaddrs = addresses.map((mi) => mi.multiaddr)
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
return defer.promise
})
it('emits on add if the content to add not exists', async () => {
const defer = pDefer()
const supportedMultiaddrsA = [addr1]
const supportedMultiaddrsB = [addr2]
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
let changeCounter = 0
peerStore.on('change:multiaddrs', () => {
changeCounter++
if (changeCounter > 1) {
defer.resolve()
}
})
// set 1
ab.set(peerId, supportedMultiaddrsA)
// set 2 (content already existing)
ab.add(peerId, supportedMultiaddrsB)
const addresses = ab.get(peerId)
const multiaddrs = addresses.map((mi) => mi.multiaddr)
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
await defer.promise
})
it('does not emit on add if the content to add already exists', async () => {
const defer = pDefer()
const supportedMultiaddrsA = [addr1, addr2]
const supportedMultiaddrsB = [addr2]
let changeCounter = 0
peerStore.on('change:multiaddrs', () => {
changeCounter++
if (changeCounter > 1) {
defer.reject()
}
})
// set 1
ab.set(peerId, supportedMultiaddrsA)
// set 2 (content already existing)
ab.add(peerId, supportedMultiaddrsB)
// Wait 50ms for incorrect second event
setTimeout(() => {
defer.resolve()
}, 50)
await defer.promise
})
})
describe('addressBook.get', () => {
let peerStore, ab
beforeEach(() => {
peerStore = new PeerStore()
ab = peerStore.addressBook
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
ab.get('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('returns undefined if no multiaddrs are known for the provided peer', () => {
const addresses = ab.get(peerId)
expect(addresses).to.not.exist()
})
it('returns the multiaddrs stored', () => {
const supportedMultiaddrs = [addr1, addr2]
ab.set(peerId, supportedMultiaddrs)
const addresses = ab.get(peerId)
const multiaddrs = addresses.map((mi) => mi.multiaddr)
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
})
})
describe('addressBook.getMultiaddrsForPeer', () => {
let peerStore, ab
beforeEach(() => {
peerStore = new PeerStore()
ab = peerStore.addressBook
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
ab.getMultiaddrsForPeer('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('returns undefined if no multiaddrs are known for the provided peer', () => {
const addresses = ab.getMultiaddrsForPeer(peerId)
expect(addresses).to.not.exist()
})
it('returns the multiaddrs stored', () => {
const supportedMultiaddrs = [addr1, addr2]
ab.set(peerId, supportedMultiaddrs)
const multiaddrs = ab.getMultiaddrsForPeer(peerId)
multiaddrs.forEach((m) => {
expect(m.getPeerId()).to.equal(peerId.toB58String())
})
})
})
describe('addressBook.delete', () => {
let peerStore, ab
beforeEach(() => {
peerStore = new PeerStore()
ab = peerStore.addressBook
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
ab.delete('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('returns false if no records exist for the peer and no event is emitted', () => {
const defer = pDefer()
peerStore.on('change:multiaddrs', () => {
defer.reject()
})
const deleted = ab.delete(peerId)
expect(deleted).to.equal(false)
// Wait 50ms for incorrect invalid event
setTimeout(() => {
defer.resolve()
}, 50)
return defer.promise
})
it('returns true if the record exists and an event is emitted', () => {
const defer = pDefer()
const supportedMultiaddrs = [addr1, addr2]
ab.set(peerId, supportedMultiaddrs)
// Listen after set
peerStore.on('change:multiaddrs', ({ multiaddrs }) => {
expect(multiaddrs.length).to.eql(0)
defer.resolve()
})
const deleted = ab.delete(peerId)
expect(deleted).to.equal(true)
return defer.promise
})
})
})

View File

@@ -4,149 +4,164 @@
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
const sinon = require('sinon')
const pDefer = require('p-defer')
const PeerStore = require('../../src/peer-store')
const multiaddr = require('multiaddr')
const peerUtils = require('../utils/creators/peer')
const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000')
const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001')
const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002')
const addr4 = multiaddr('/ip4/127.0.0.1/tcp/8003')
const proto1 = '/protocol1'
const proto2 = '/protocol2'
const proto3 = '/protocol3'
const addr = multiaddr('/ip4/127.0.0.1/tcp/8000')
describe('peer-store', () => {
let peerIds
before(async () => {
peerIds = await peerUtils.createPeerId({
number: 4
})
let peerStore
beforeEach(() => {
peerStore = new PeerStore()
})
describe('empty books', () => {
let peerStore
it('should add a new peer and emit it when it does not exist', async () => {
const defer = pDefer()
beforeEach(() => {
peerStore = new PeerStore()
})
sinon.spy(peerStore, 'put')
sinon.spy(peerStore, 'add')
sinon.spy(peerStore, 'update')
it('has an empty map of peers', () => {
const peers = peerStore.peers
expect(peers.size).to.equal(0)
})
const [peerInfo] = await peerUtils.createPeerInfo()
it('returns false on trying to delete a non existant peerId', () => {
const deleted = peerStore.delete(peerIds[0])
expect(deleted).to.equal(false)
})
it('returns undefined on trying to find a non existant peerId', () => {
const peer = peerStore.get(peerIds[0])
expect(peer).to.not.exist()
})
})
describe('previously populated books', () => {
let peerStore
beforeEach(() => {
peerStore = new PeerStore()
// Add peer0 with { addr1, addr2 } and { proto1 }
peerStore.addressBook.set(peerIds[0], [addr1, addr2])
peerStore.protoBook.set(peerIds[0], [proto1])
// Add peer1 with { addr3 } and { proto2, proto3 }
peerStore.addressBook.set(peerIds[1], [addr3])
peerStore.protoBook.set(peerIds[1], [proto2, proto3])
// Add peer2 with { addr4 }
peerStore.addressBook.set(peerIds[2], [addr4])
// Add peer3 with { addr4 } and { proto2 }
peerStore.addressBook.set(peerIds[3], [addr4])
peerStore.protoBook.set(peerIds[3], [proto2])
})
it('has peers', () => {
const peers = peerStore.peers
expect(peers.size).to.equal(4)
expect(Array.from(peers.keys())).to.have.members([
peerIds[0].toB58String(),
peerIds[1].toB58String(),
peerIds[2].toB58String(),
peerIds[3].toB58String()
])
})
it('returns true on deleting a stored peer', () => {
const deleted = peerStore.delete(peerIds[0])
expect(deleted).to.equal(true)
const peers = peerStore.peers
expect(peers.size).to.equal(3)
expect(Array.from(peers.keys())).to.not.have.members([peerIds[0].toB58String()])
})
it('returns true on deleting a stored peer which is only on one book', () => {
const deleted = peerStore.delete(peerIds[2])
expect(deleted).to.equal(true)
const peers = peerStore.peers
expect(peers.size).to.equal(3)
})
it('gets the stored information of a peer in all its books', () => {
const peer = peerStore.get(peerIds[0])
peerStore.on('peer', (peer) => {
expect(peer).to.exist()
expect(peer.protocols).to.have.members([proto1])
defer.resolve()
})
peerStore.put(peerInfo)
const peerMultiaddrs = peer.addresses.map((mi) => mi.multiaddr)
expect(peerMultiaddrs).to.have.members([addr1, addr2])
// Wait for peerStore to emit the peer
await defer.promise
expect(peerStore.put.callCount).to.equal(1)
expect(peerStore.add.callCount).to.equal(1)
expect(peerStore.update.callCount).to.equal(0)
})
it('should update peer when it is already in the store', async () => {
const [peerInfo] = await peerUtils.createPeerInfo()
// Put the peer in the store
peerStore.put(peerInfo)
sinon.spy(peerStore, 'add')
sinon.spy(peerStore, 'update')
// When updating, peer event must not be emitted
peerStore.on('peer', () => {
throw new Error('should not emit twice')
})
// If no multiaddrs change, the event should not be emitted
peerStore.on('change:multiaddrs', () => {
throw new Error('should not emit change:multiaddrs')
})
// If no protocols change, the event should not be emitted
peerStore.on('change:protocols', () => {
throw new Error('should not emit change:protocols')
})
it('gets the stored information of a peer that is not present in all its books', () => {
const peers = peerStore.get(peerIds[2])
expect(peers).to.exist()
expect(peers.protocols.length).to.eql(0)
peerStore.put(peerInfo)
const peerMultiaddrs = peers.addresses.map((mi) => mi.multiaddr)
expect(peerMultiaddrs).to.have.members([addr4])
expect(peerStore.add.callCount).to.equal(0)
expect(peerStore.update.callCount).to.equal(1)
})
it('should emit the "change:multiaddrs" event when a peer has new multiaddrs', async () => {
const defer = pDefer()
const [createdPeerInfo] = await peerUtils.createPeerInfo()
// Put the peer in the store
peerStore.put(createdPeerInfo)
// When updating, "change:multiaddrs" event must not be emitted
peerStore.on('change:multiaddrs', ({ peerInfo, multiaddrs }) => {
expect(peerInfo).to.exist()
expect(peerInfo.id).to.eql(createdPeerInfo.id)
expect(peerInfo.protocols).to.eql(createdPeerInfo.protocols)
expect(multiaddrs).to.exist()
expect(multiaddrs).to.eql(createdPeerInfo.multiaddrs.toArray())
defer.resolve()
})
// If no protocols change, the event should not be emitted
peerStore.on('change:protocols', () => {
throw new Error('should not emit change:protocols')
})
it('can find all the peers supporting a protocol', () => {
const peerSupporting2 = []
createdPeerInfo.multiaddrs.add(addr)
peerStore.put(createdPeerInfo)
for (const [, peer] of peerStore.peers.entries()) {
if (peer.protocols.includes(proto2)) {
peerSupporting2.push(peer)
}
}
// Wait for peerStore to emit the event
await defer.promise
})
expect(peerSupporting2.length).to.eql(2)
expect(peerSupporting2[0].id.toB58String()).to.eql(peerIds[1].toB58String())
expect(peerSupporting2[1].id.toB58String()).to.eql(peerIds[3].toB58String())
it('should emit the "change:protocols" event when a peer has new protocols', async () => {
const defer = pDefer()
const [createdPeerInfo] = await peerUtils.createPeerInfo()
// Put the peer in the store
peerStore.put(createdPeerInfo)
// If no multiaddrs change, the event should not be emitted
peerStore.on('change:multiaddrs', () => {
throw new Error('should not emit change:multiaddrs')
})
// When updating, "change:protocols" event must be emitted
peerStore.on('change:protocols', ({ peerInfo, protocols }) => {
expect(peerInfo).to.exist()
expect(peerInfo.id).to.eql(createdPeerInfo.id)
expect(peerInfo.multiaddrs).to.eql(createdPeerInfo.multiaddrs)
expect(protocols).to.exist()
expect(protocols).to.eql(Array.from(createdPeerInfo.protocols))
defer.resolve()
})
it('can find all the peers listening on a given address', () => {
const peerListenint4 = []
createdPeerInfo.protocols.add('/new-protocol/1.0.0')
peerStore.put(createdPeerInfo)
for (const [, peer] of peerStore.peers.entries()) {
const multiaddrs = peer.addresses.map((mi) => mi.multiaddr)
// Wait for peerStore to emit the event
await defer.promise
})
if (multiaddrs.includes(addr4)) {
peerListenint4.push(peer)
}
}
it('should be able to retrieve a peer from store through its b58str id', async () => {
const [peerInfo] = await peerUtils.createPeerInfo()
const id = peerInfo.id
expect(peerListenint4.length).to.eql(2)
expect(peerListenint4[0].id.toB58String()).to.eql(peerIds[2].toB58String())
expect(peerListenint4[1].id.toB58String()).to.eql(peerIds[3].toB58String())
})
let retrievedPeer = peerStore.get(id)
expect(retrievedPeer).to.not.exist()
// Put the peer in the store
peerStore.put(peerInfo)
retrievedPeer = peerStore.get(id)
expect(retrievedPeer).to.exist()
expect(retrievedPeer.id).to.equal(peerInfo.id)
expect(retrievedPeer.multiaddrs).to.eql(peerInfo.multiaddrs)
expect(retrievedPeer.protocols).to.eql(peerInfo.protocols)
})
it('should be able to remove a peer from store through its b58str id', async () => {
const [peerInfo] = await peerUtils.createPeerInfo()
const id = peerInfo.id
let removed = peerStore.remove(id)
expect(removed).to.eql(false)
// Put the peer in the store
peerStore.put(peerInfo)
expect(peerStore.peers.size).to.equal(1)
removed = peerStore.remove(id)
expect(removed).to.eql(true)
expect(peerStore.peers.size).to.equal(0)
})
})
describe('peer-store on discovery', () => {
// TODO: implement with discovery
})

View File

@@ -1,309 +0,0 @@
'use strict'
/* eslint-env mocha */
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
const pDefer = require('p-defer')
const PeerStore = require('../../src/peer-store')
const peerUtils = require('../utils/creators/peer')
const {
ERR_INVALID_PARAMETERS
} = require('../../src/errors')
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
describe('protoBook', () => {
let peerId
before(async () => {
[peerId] = await peerUtils.createPeerId()
})
describe('protoBook.set', () => {
let peerStore, pb
beforeEach(() => {
peerStore = new PeerStore()
pb = peerStore.protoBook
})
afterEach(() => {
peerStore.removeAllListeners()
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
pb.set('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('throwns invalid parameters error if no protocols provided', () => {
expect(() => {
pb.set(peerId)
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('replaces the stored content by default and emit change event', () => {
const defer = pDefer()
const supportedProtocols = ['protocol1', 'protocol2']
peerStore.once('change:protocols', ({ peerId, protocols }) => {
expect(peerId).to.exist()
expect(protocols).to.have.deep.members(supportedProtocols)
defer.resolve()
})
pb.set(peerId, supportedProtocols)
const protocols = pb.get(peerId)
expect(protocols).to.have.deep.members(supportedProtocols)
return defer.promise
})
it('emits on set if not storing the exact same content', () => {
const defer = pDefer()
const supportedProtocolsA = ['protocol1', 'protocol2']
const supportedProtocolsB = ['protocol2']
let changeCounter = 0
peerStore.on('change:protocols', () => {
changeCounter++
if (changeCounter > 1) {
defer.resolve()
}
})
// set 1
pb.set(peerId, supportedProtocolsA)
// set 2 (same content)
pb.set(peerId, supportedProtocolsB)
const protocols = pb.get(peerId)
expect(protocols).to.have.deep.members(supportedProtocolsB)
return defer.promise
})
it('does not emit on set if it is storing the exact same content', () => {
const defer = pDefer()
const supportedProtocols = ['protocol1', 'protocol2']
let changeCounter = 0
peerStore.on('change:protocols', () => {
changeCounter++
if (changeCounter > 1) {
defer.reject()
}
})
// set 1
pb.set(peerId, supportedProtocols)
// set 2 (same content)
pb.set(peerId, supportedProtocols)
// Wait 50ms for incorrect second event
setTimeout(() => {
defer.resolve()
}, 50)
return defer.promise
})
})
describe('protoBook.add', () => {
let peerStore, pb
beforeEach(() => {
peerStore = new PeerStore()
pb = peerStore.protoBook
})
afterEach(() => {
peerStore.removeAllListeners()
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
pb.add('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('throwns invalid parameters error if no protocols provided', () => {
expect(() => {
pb.add(peerId)
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('adds the new content and emits change event', () => {
const defer = pDefer()
const supportedProtocolsA = ['protocol1', 'protocol2']
const supportedProtocolsB = ['protocol3']
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
let changeTrigger = 2
peerStore.on('change:protocols', ({ protocols }) => {
changeTrigger--
if (changeTrigger === 0 && arraysAreEqual(protocols, finalProtocols)) {
defer.resolve()
}
})
// Replace
pb.set(peerId, supportedProtocolsA)
let protocols = pb.get(peerId)
expect(protocols).to.have.deep.members(supportedProtocolsA)
// Add
pb.add(peerId, supportedProtocolsB)
protocols = pb.get(peerId)
expect(protocols).to.have.deep.members(finalProtocols)
return defer.promise
})
it('emits on add if the content to add not exists', () => {
const defer = pDefer()
const supportedProtocolsA = ['protocol1']
const supportedProtocolsB = ['protocol2']
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
let changeCounter = 0
peerStore.on('change:protocols', () => {
changeCounter++
if (changeCounter > 1) {
defer.resolve()
}
})
// set 1
pb.set(peerId, supportedProtocolsA)
// set 2 (content already existing)
pb.add(peerId, supportedProtocolsB)
const protocols = pb.get(peerId)
expect(protocols).to.have.deep.members(finalProtocols)
return defer.promise
})
it('does not emit on add if the content to add already exists', () => {
const defer = pDefer()
const supportedProtocolsA = ['protocol1', 'protocol2']
const supportedProtocolsB = ['protocol2']
let changeCounter = 0
peerStore.on('change:protocols', () => {
changeCounter++
if (changeCounter > 1) {
defer.reject()
}
})
// set 1
pb.set(peerId, supportedProtocolsA)
// set 2 (content already existing)
pb.add(peerId, supportedProtocolsB)
// Wait 50ms for incorrect second event
setTimeout(() => {
defer.resolve()
}, 50)
return defer.promise
})
})
describe('protoBook.get', () => {
let peerStore, pb
beforeEach(() => {
peerStore = new PeerStore()
pb = peerStore.protoBook
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
pb.get('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('returns undefined if no protocols are known for the provided peer', () => {
const protocols = pb.get(peerId)
expect(protocols).to.not.exist()
})
it('returns the protocols stored', () => {
const supportedProtocols = ['protocol1', 'protocol2']
pb.set(peerId, supportedProtocols)
const protocols = pb.get(peerId)
expect(protocols).to.have.deep.members(supportedProtocols)
})
})
describe('protoBook.delete', () => {
let peerStore, pb
beforeEach(() => {
peerStore = new PeerStore()
pb = peerStore.protoBook
})
it('throwns invalid parameters error if invalid PeerId is provided', () => {
expect(() => {
pb.delete('invalid peerId')
}).to.throw(ERR_INVALID_PARAMETERS)
})
it('returns false if no records exist for the peer and no event is emitted', () => {
const defer = pDefer()
peerStore.on('change:protocols', () => {
defer.reject()
})
const deleted = pb.delete(peerId)
expect(deleted).to.equal(false)
// Wait 50ms for incorrect invalid event
setTimeout(() => {
defer.resolve()
}, 50)
return defer.promise
})
it('returns true if the record exists and an event is emitted', () => {
const defer = pDefer()
const supportedProtocols = ['protocol1', 'protocol2']
pb.set(peerId, supportedProtocols)
// Listen after set
peerStore.on('change:protocols', ({ protocols }) => {
expect(protocols.length).to.eql(0)
defer.resolve()
})
const deleted = pb.delete(peerId)
expect(deleted).to.equal(true)
return defer.promise
})
})
})

View File

@@ -32,13 +32,11 @@ describe('Pubsub subsystem is configurable', () => {
})
it('should start and stop by default once libp2p starts', async () => {
const [peerId] = await peerUtils.createPeerId()
const [peerInfo] = await peerUtils.createPeerInfo()
peerInfo.multiaddrs.add(listenAddr)
const customOptions = mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
peerInfo
})
libp2p = await create(customOptions)
@@ -52,13 +50,11 @@ describe('Pubsub subsystem is configurable', () => {
})
it('should not start if disabled once libp2p starts', async () => {
const [peerId] = await peerUtils.createPeerId()
const [peerInfo] = await peerUtils.createPeerInfo()
peerInfo.multiaddrs.add(listenAddr)
const customOptions = mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
peerInfo,
config: {
pubsub: {
enabled: false
@@ -74,13 +70,11 @@ describe('Pubsub subsystem is configurable', () => {
})
it('should allow a manual start', async () => {
const [peerId] = await peerUtils.createPeerId()
const [peerInfo] = await peerUtils.createPeerInfo()
peerInfo.multiaddrs.add(listenAddr)
const customOptions = mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
peerInfo,
config: {
pubsub: {
enabled: false

View File

@@ -24,11 +24,15 @@ const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Pubsub subsystem is able to use different implementations', () => {
let peerId, remotePeerId
let peerInfo, remotePeerInfo
let libp2p, remoteLibp2p
let remAddr
beforeEach(async () => {
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
[peerInfo, remotePeerInfo] = await peerUtils.createPeerInfo({ number: 2 })
peerInfo.multiaddrs.add(listenAddr)
remotePeerInfo.multiaddrs.add(remoteListenAddr)
})
afterEach(() => Promise.all([
@@ -50,20 +54,14 @@ describe('Pubsub subsystem is able to use different implementations', () => {
const data = 'hey!'
libp2p = await create(mergeOptions(baseOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
peerInfo,
modules: {
pubsub: pubsub
}
}))
remoteLibp2p = await create(mergeOptions(baseOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
},
peerInfo: remotePeerInfo,
modules: {
pubsub: pubsub
}
@@ -74,10 +72,10 @@ describe('Pubsub subsystem is able to use different implementations', () => {
remoteLibp2p.start()
])
const libp2pId = libp2p.peerId.toB58String()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
const libp2pId = libp2p.peerInfo.id.toB58String()
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
const connection = await libp2p.dialProtocol(remotePeerId, multicodec)
const connection = await libp2p.dialProtocol(remAddr, multicodec)
expect(connection).to.exist()
libp2p.pubsub.subscribe(topic, (msg) => {

View File

@@ -19,27 +19,25 @@ const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Pubsub subsystem operates correctly', () => {
let peerId, remotePeerId
let peerInfo, remotePeerInfo
let libp2p, remoteLibp2p
let remAddr
beforeEach(async () => {
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
[peerInfo, remotePeerInfo] = await peerUtils.createPeerInfo({ number: 2 })
peerInfo.multiaddrs.add(listenAddr)
remotePeerInfo.multiaddrs.add(remoteListenAddr)
})
describe('pubsub started before connect', () => {
beforeEach(async () => {
libp2p = await create(mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
peerInfo
}))
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
}
peerInfo: remotePeerInfo
}))
await Promise.all([
@@ -47,7 +45,7 @@ describe('Pubsub subsystem operates correctly', () => {
remoteLibp2p.start()
])
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
afterEach(() => Promise.all([
@@ -60,7 +58,7 @@ describe('Pubsub subsystem operates correctly', () => {
})
it('should get notified of connected peers on dial', async () => {
const connection = await libp2p.dialProtocol(remotePeerId, subsystemMulticodecs)
const connection = await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
expect(connection).to.exist()
@@ -74,9 +72,9 @@ describe('Pubsub subsystem operates correctly', () => {
const defer = pDefer()
const topic = 'test-topic'
const data = 'hey!'
const libp2pId = libp2p.peerId.toB58String()
const libp2pId = libp2p.peerInfo.id.toB58String()
await libp2p.dialProtocol(remotePeerId, subsystemMulticodecs)
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
let subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.not.include(topic)
@@ -103,17 +101,11 @@ describe('Pubsub subsystem operates correctly', () => {
describe('pubsub started after connect', () => {
beforeEach(async () => {
libp2p = await create(mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
peerInfo
}))
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
},
peerInfo: remotePeerInfo,
config: {
pubsub: {
enabled: false
@@ -124,7 +116,7 @@ describe('Pubsub subsystem operates correctly', () => {
await libp2p.start()
await remoteLibp2p.start()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
afterEach(() => Promise.all([
@@ -137,7 +129,7 @@ describe('Pubsub subsystem operates correctly', () => {
})
it('should get notified of connected peers after starting', async () => {
const connection = await libp2p.dial(remotePeerId)
const connection = await libp2p.dial(remAddr)
expect(connection).to.exist()
expect(libp2p.pubsub._pubsub.peers.size).to.be.eql(0)
@@ -154,11 +146,11 @@ describe('Pubsub subsystem operates correctly', () => {
it('should receive pubsub messages', async function () {
this.timeout(10e3)
const defer = pDefer()
const libp2pId = libp2p.peerId.toB58String()
const libp2pId = libp2p.peerInfo.id.toB58String()
const topic = 'test-topic'
const data = 'hey!'
await libp2p.dial(remotePeerId)
await libp2p.dial(remAddr)
remoteLibp2p.pubsub.start()

View File

@@ -16,20 +16,20 @@ const peerUtils = require('../utils/creators/peer')
const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
describe('registrar on dial', () => {
let peerId
let remotePeerId
let peerInfo
let remotePeerInfo
let libp2p
let remoteLibp2p
let remoteAddr
before(async () => {
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
[peerInfo, remotePeerInfo] = await peerUtils.createPeerInfo({ number: 2 })
remoteLibp2p = new Libp2p(mergeOptions(baseOptions, {
peerId: remotePeerId
peerInfo: remotePeerInfo
}))
await remoteLibp2p.transportManager.listen([listenAddr])
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${remotePeerId.toB58String()}`)
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
after(async () => {
@@ -40,7 +40,7 @@ describe('registrar on dial', () => {
it('should inform registrar of a new connection', async () => {
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerId
peerInfo
}))
sinon.spy(remoteLibp2p.registrar, 'onConnect')
@@ -48,16 +48,16 @@ describe('registrar on dial', () => {
await libp2p.dial(remoteAddr)
expect(remoteLibp2p.registrar.onConnect.callCount).to.equal(1)
const libp2pConn = libp2p.registrar.getConnection(remotePeerId)
const libp2pConn = libp2p.registrar.getConnection(remotePeerInfo)
expect(libp2pConn).to.exist()
const remoteConn = remoteLibp2p.registrar.getConnection(peerId)
const remoteConn = remoteLibp2p.registrar.getConnection(peerInfo)
expect(remoteConn).to.exist()
})
it('should be closed on libp2p stop', async () => {
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerId
peerInfo
}))
await libp2p.dial(remoteAddr)

View File

@@ -6,6 +6,7 @@ chai.use(require('dirty-chai'))
const { expect } = chai
const pDefer = require('p-defer')
const PeerInfo = require('peer-info')
const Topology = require('libp2p-interfaces/src/topology/multicodec-topology')
const PeerStore = require('../../src/peer-store')
const Registrar = require('../../src/registrar')
@@ -82,25 +83,27 @@ describe('registrar', () => {
// Setup connections before registrar
const conn = await createMockConnection()
const remotePeerId = conn.remotePeer
const remotePeerInfo = await PeerInfo.create(conn.remotePeer)
// Add connected peer with protocol to peerStore and registrar
peerStore.protoBook.add(remotePeerId, [multicodec])
// Add protocol to peer
remotePeerInfo.protocols.add(multicodec)
registrar.onConnect(remotePeerId, conn)
// Add connected peer to peerStore and registrar
peerStore.put(remotePeerInfo)
registrar.onConnect(remotePeerInfo, conn)
expect(registrar.connections.size).to.eql(1)
const topologyProps = new Topology({
multicodecs: multicodec,
handlers: {
onConnect: (peerId, connection) => {
expect(peerId.toB58String()).to.eql(remotePeerId.toB58String())
onConnect: (peerInfo, connection) => {
expect(peerInfo.id.toB58String()).to.eql(remotePeerInfo.id.toB58String())
expect(connection.id).to.eql(conn.id)
onConnectDefer.resolve()
},
onDisconnect: (peerId) => {
expect(peerId.toB58String()).to.eql(remotePeerId.toB58String())
onDisconnect: (peerInfo) => {
expect(peerInfo.id.toB58String()).to.eql(remotePeerInfo.id.toB58String())
onDisconnectDefer.resolve()
}
@@ -114,7 +117,7 @@ describe('registrar', () => {
// Topology created
expect(topology).to.exist()
registrar.onDisconnect(remotePeerId)
registrar.onDisconnect(remotePeerInfo)
expect(registrar.connections.size).to.eql(0)
// Wait for handlers to be called
@@ -150,19 +153,21 @@ describe('registrar', () => {
// Setup connections before registrar
const conn = await createMockConnection()
const remotePeerId = conn.remotePeer
const peerInfo = await PeerInfo.create(conn.remotePeer)
// Add connected peer to peerStore and registrar
peerStore.protoBook.set(remotePeerId, [])
registrar.onConnect(remotePeerId, conn)
peerStore.put(peerInfo)
registrar.onConnect(peerInfo, conn)
// Add protocol to peer and update it
peerStore.protoBook.add(remotePeerId, [multicodec])
peerInfo.protocols.add(multicodec)
peerStore.put(peerInfo)
await onConnectDefer.promise
// Remove protocol to peer and update it
peerStore.protoBook.set(remotePeerId, [])
peerInfo.protocols.delete(multicodec)
peerStore.replace(peerInfo)
await onDisconnectDefer.promise
})
@@ -184,21 +189,22 @@ describe('registrar', () => {
registrar.register(topologyProps)
// Setup connections before registrar
const [localPeer, remotePeer] = await peerUtils.createPeerId({ number: 2 })
const [localPeer, remotePeer] = await peerUtils.createPeerInfo({ number: 2 })
const conn1 = await createMockConnection({ localPeer, remotePeer })
const conn2 = await createMockConnection({ localPeer, remotePeer })
const id = remotePeer.toB58String()
const conn1 = await createMockConnection({ localPeer: localPeer.id, remotePeer: remotePeer.id })
const conn2 = await createMockConnection({ localPeer: localPeer.id, remotePeer: remotePeer.id })
const peerInfo = await PeerInfo.create(remotePeer.id)
const id = peerInfo.id.toB58String()
// Add connection to registrar
registrar.onConnect(remotePeer, conn1)
registrar.onConnect(remotePeer, conn2)
peerStore.put(peerInfo)
registrar.onConnect(peerInfo, conn1)
registrar.onConnect(peerInfo, conn2)
expect(registrar.connections.get(id).length).to.eql(2)
conn2._stat.status = 'closed'
registrar.onDisconnect(remotePeer, conn2)
registrar.onDisconnect(peerInfo, conn2)
const peerConnections = registrar.connections.get(id)
expect(peerConnections.length).to.eql(1)

View File

@@ -11,13 +11,13 @@ module.exports.createMockConnection = async (properties = {}) => {
const localAddr = multiaddr('/ip4/127.0.0.1/tcp/8080')
const remoteAddr = multiaddr('/ip4/127.0.0.1/tcp/8081')
const [localPeer, remotePeer] = await peerUtils.createPeerId({ number: 2 })
const [localPeer, remotePeer] = await peerUtils.createPeerInfo({ number: 2 })
const openStreams = []
let streamId = 0
return new Connection({
localPeer: localPeer,
remotePeer: remotePeer,
localPeer: localPeer.id,
remotePeer: remotePeer.id,
localAddr,
remoteAddr,
stat: {

View File

@@ -16,6 +16,7 @@ const { codes: ErrorCodes } = require('../../src/errors')
const Libp2p = require('../../src')
const Peers = require('../fixtures/peers')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
describe('Transport Manager (WebSockets)', () => {
let tm
@@ -87,11 +88,12 @@ describe('Transport Manager (WebSockets)', () => {
})
describe('libp2p.transportManager', () => {
let peerId
let peerInfo
let libp2p
before(async () => {
peerId = await PeerId.createFromJSON(Peers[0])
const peerId = await PeerId.createFromJSON(Peers[0])
peerInfo = new PeerInfo(peerId)
})
afterEach(async () => {
@@ -102,7 +104,7 @@ describe('libp2p.transportManager', () => {
it('should create a TransportManager', () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport]
}
@@ -120,7 +122,7 @@ describe('libp2p.transportManager', () => {
another: 'value'
}
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [spy]
},
@@ -144,7 +146,7 @@ describe('libp2p.transportManager', () => {
it('starting and stopping libp2p should start and stop TransportManager', async () => {
libp2p = new Libp2p({
peerId,
peerInfo,
modules: {
transport: [Transport]
}

View File

@@ -8,6 +8,7 @@ const sinon = require('sinon')
const Muxer = require('libp2p-mplex')
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const pipe = require('it-pipe')
const { collect } = require('streaming-iterables')
const pSettle = require('p-settle')
@@ -346,10 +347,11 @@ describe('libp2p.upgrader', () => {
let libp2p
before(async () => {
peers = await Promise.all([
const ids = await Promise.all([
PeerId.createFromJSON(Peers[0]),
PeerId.createFromJSON(Peers[1])
])
peers = ids.map(peerId => new PeerInfo(peerId))
})
afterEach(async () => {
@@ -361,7 +363,7 @@ describe('libp2p.upgrader', () => {
it('should create an Upgrader', () => {
const protector = new Protector(swarmKeyBuffer)
libp2p = new Libp2p({
peerId: peers[0],
peerInfo: peers[0],
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -380,7 +382,7 @@ describe('libp2p.upgrader', () => {
it('should be able to register and unregister a handler', () => {
libp2p = new Libp2p({
peerId: peers[0],
peerInfo: peers[0],
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -403,7 +405,7 @@ describe('libp2p.upgrader', () => {
it('should emit connect and disconnect events', async () => {
const remotePeer = peers[1]
libp2p = new Libp2p({
peerId: peers[0],
peerInfo: peers[0],
modules: {
transport: [Transport],
streamMuxer: [Muxer],
@@ -412,12 +414,12 @@ describe('libp2p.upgrader', () => {
})
const remoteUpgrader = new Upgrader({
localPeer: remotePeer,
localPeer: remotePeer.id,
muxers: new Map([[Muxer.multicodec, Muxer]]),
cryptos: new Map([[Crypto.protocol, Crypto]])
})
const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer })
const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer: remotePeer.id })
// Spy on emit for easy verification
sinon.spy(libp2p, 'emit')
@@ -428,16 +430,15 @@ describe('libp2p.upgrader', () => {
remoteUpgrader.upgradeInbound(inbound)
])
expect(libp2p.emit.callCount).to.equal(1)
let [event, peerId] = libp2p.emit.getCall(0).args
let [event, peerInfo] = libp2p.emit.getCall(0).args
expect(event).to.equal('peer:connect')
expect(peerId.isEqual(remotePeer)).to.equal(true)
expect(peerInfo.id.isEqual(remotePeer.id)).to.equal(true)
// Close and check the disconnect event
await Promise.all(connections.map(conn => conn.close()))
expect(libp2p.emit.callCount).to.equal(2)
;([event, peerId] = libp2p.emit.getCall(1).args)
;([event, peerInfo] = libp2p.emit.getCall(1).args)
expect(event).to.equal('peer:disconnect')
expect(peerId.isEqual(remotePeer)).to.equal(true)
expect(peerInfo.id.isEqual(remotePeer.id)).to.equal(true)
})
})

View File

@@ -4,6 +4,7 @@ const pTimes = require('p-times')
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const Libp2p = require('../../../src')
const Peers = require('../../fixtures/peers')
@@ -18,36 +19,37 @@ const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
* @param {number} [properties.number] number of peers (default: 1).
* @param {boolean} [properties.fixture] use fixture for peer-id generation (default: true)
* @param {boolean} [properties.started] nodes should start (default: true)
* @param {boolean} [properties.populateAddressBooks] nodes addressBooks should be populated with other peers (default: true)
* @return {Promise<Array<Libp2p>>}
*/
async function createPeer ({ number = 1, fixture = true, started = true, populateAddressBooks = true, config = defaultOptions } = {}) {
const peerIds = await createPeerId({ number, fixture })
async function createPeer ({ number = 1, fixture = true, started = true, config = defaultOptions } = {}) {
const peerInfos = await createPeerInfo({ number, fixture })
const addresses = started ? { listen: [listenAddr] } : {}
const peers = await pTimes(number, (i) => Libp2p.create({
peerId: peerIds[i],
addresses,
peerInfo: peerInfos[i],
...config
}))
if (started) {
await Promise.all(peers.map((p) => p.start()))
populateAddressBooks && _populateAddressBooks(peers)
await Promise.all(peers.map((p) => {
p.peerInfo.multiaddrs.add(listenAddr)
return p.start()
}))
}
return peers
}
function _populateAddressBooks (peers) {
for (let i = 0; i < peers.length; i++) {
for (let j = 0; j < peers.length; j++) {
if (i !== j) {
peers[i].peerStore.addressBook.set(peers[j].peerId, peers[j].addresses.listen)
}
}
}
/**
* Create Peer-ids.
* @param {Object} [properties]
* @param {number} [properties.number] number of peers (default: 1).
* @param {boolean} [properties.fixture] use fixture for peer-id generation (default: true)
* @return {Promise<Array<PeerInfo>>}
*/
async function createPeerInfo ({ number = 1, fixture = true } = {}) {
const peerIds = await createPeerId({ number, fixture })
return pTimes(number, (i) => PeerInfo.create(peerIds[i]))
}
/**
@@ -65,4 +67,5 @@ function createPeerId ({ number = 1, fixture = true } = {}) {
}
module.exports.createPeer = createPeer
module.exports.createPeerInfo = createPeerInfo
module.exports.createPeerId = createPeerId

View File

@@ -16,13 +16,13 @@ module.exports = async (properties = {}) => {
const localAddr = multiaddr('/ip4/127.0.0.1/tcp/8080')
const remoteAddr = multiaddr('/ip4/127.0.0.1/tcp/8081')
const [localPeer, remotePeer] = await peerUtils.createPeerId({ number: 2 })
const [localPeer, remotePeer] = await peerUtils.createPeerInfo({ number: 2 })
const openStreams = []
let streamId = 0
return new Connection({
localPeer: localPeer,
remotePeer: remotePeer,
localPeer: localPeer.id,
remotePeer: remotePeer.id,
localAddr,
remoteAddr,
stat: {