Compare commits

..

1 Commits

Author SHA1 Message Date
4c1b376c65 fix: event handlers error 2020-10-07 18:22:54 +02:00
26 changed files with 185 additions and 491 deletions

View File

@ -7,7 +7,7 @@ stages:
node_js: node_js:
- 'lts/*' - 'lts/*'
- '14' - 'stable'
os: os:
- linux - linux

View File

@ -1,35 +1,3 @@
<a name="0.29.3"></a>
## [0.29.3](https://github.com/libp2p/js-libp2p/compare/v0.29.2...v0.29.3) (2020-11-04)
### Features
* resolve multiaddrs before dial ([#782](https://github.com/libp2p/js-libp2p/issues/782)) ([093c0ea](https://github.com/libp2p/js-libp2p/commit/093c0ea))
<a name="0.29.2"></a>
## [0.29.2](https://github.com/libp2p/js-libp2p/compare/v0.29.1...v0.29.2) (2020-10-23)
### Bug Fixes
* cleanup open streams on conn close ([#791](https://github.com/libp2p/js-libp2p/issues/791)) ([06f26e5](https://github.com/libp2p/js-libp2p/commit/06f26e5))
<a name="0.29.1"></a>
## [0.29.1](https://github.com/libp2p/js-libp2p/compare/v0.29.0...v0.29.1) (2020-10-22)
### Bug Fixes
* catch error in upgrader close call ([e04224a](https://github.com/libp2p/js-libp2p/commit/e04224a))
* ensure streams are closed on connection close ([4c6be91](https://github.com/libp2p/js-libp2p/commit/4c6be91))
* flakey identify test firefox ([#774](https://github.com/libp2p/js-libp2p/issues/774)) ([60d437f](https://github.com/libp2p/js-libp2p/commit/60d437f))
<a name="0.29.0"></a> <a name="0.29.0"></a>
# [0.29.0](https://github.com/libp2p/js-libp2p/compare/v0.28.10...v0.29.0) (2020-08-27) # [0.29.0](https://github.com/libp2p/js-libp2p/compare/v0.28.10...v0.29.0) (2020-08-27)

View File

@ -24,7 +24,7 @@
<a href="https://github.com/feross/standard"><img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square"></a> <a href="https://github.com/feross/standard"><img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square"></a>
<a href="https://github.com/RichardLitt/standard-readme"><img src="https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square" /></a> <a href="https://github.com/RichardLitt/standard-readme"><img src="https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square" /></a>
<a href=""><img src="https://img.shields.io/badge/npm-%3E%3D6.0.0-orange.svg?style=flat-square" /></a> <a href=""><img src="https://img.shields.io/badge/npm-%3E%3D6.0.0-orange.svg?style=flat-square" /></a>
<a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D12.0.0-orange.svg?style=flat-square" /></a> <a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D10.0.0-orange.svg?style=flat-square" /></a>
<br> <br>
</p> </p>

View File

@ -48,8 +48,6 @@
* [`pubsub.unsubscribe`](#pubsubunsubscribe) * [`pubsub.unsubscribe`](#pubsubunsubscribe)
* [`pubsub.on`](#pubsubon) * [`pubsub.on`](#pubsubon)
* [`pubsub.removeListener`](#pubsubremovelistener) * [`pubsub.removeListener`](#pubsubremovelistener)
* [`pubsub.topicValidators.set`](#pubsubtopicvalidatorsset)
* [`pubsub.topicValidators.delete`](#pubsubtopicvalidatorsdelete)
* [`connectionManager.get`](#connectionmanagerget) * [`connectionManager.get`](#connectionmanagerget)
* [`connectionManager.setPeerValue`](#connectionmanagersetpeervalue) * [`connectionManager.setPeerValue`](#connectionmanagersetpeervalue)
* [`connectionManager.size`](#connectionmanagersize) * [`connectionManager.size`](#connectionmanagersize)

View File

@ -465,7 +465,6 @@ Dialing in libp2p can be configured to limit the rate of dialing, and how long d
| maxParallelDials | `number` | How many multiaddrs we can dial in parallel. | | maxParallelDials | `number` | How many multiaddrs we can dial in parallel. |
| maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. | | maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. |
| dialTimeout | `number` | Second dial timeout per peer in ms. | | dialTimeout | `number` | Second dial timeout per peer in ms. |
| resolvers | `object` | Dial [Resolvers](https://github.com/multiformats/js-multiaddr/blob/master/src/resolvers/index.js) for resolving multiaddrs |
The below configuration example shows how the dialer should be configured, with the current defaults: The below configuration example shows how the dialer should be configured, with the current defaults:
@ -475,8 +474,6 @@ const TCP = require('libp2p-tcp')
const MPLEX = require('libp2p-mplex') const MPLEX = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise') const { NOISE } = require('libp2p-noise')
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
const node = await Libp2p.create({ const node = await Libp2p.create({
modules: { modules: {
transport: [TCP], transport: [TCP],
@ -486,10 +483,7 @@ const node = await Libp2p.create({
dialer: { dialer: {
maxParallelDials: 100, maxParallelDials: 100,
maxDialsPerPeer: 4, maxDialsPerPeer: 4,
dialTimeout: 30e3, dialTimeout: 30e3
resolvers: {
dnsaddr: dnsaddrResolver
}
} }
``` ```

View File

@ -204,8 +204,8 @@ const Bootstrap = require('libp2p-bootstrap')
// Known peers addresses // Known peers addresses
const bootstrapMultiaddrs = [ const bootstrapMultiaddrs = [
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb', '/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN' '/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3'
] ]
const node = await Libp2p.create({ const node = await Libp2p.create({

View File

@ -1,7 +0,0 @@
# Circuit Relay
> Circuit Switching for libp2p, also known as TURN or Relay in Networking literature.
If you are looking for information about libp2p's circuit relay, you should read its [spec](https://github.com/libp2p/specs/tree/master/relay).

View File

@ -1,3 +0,0 @@
# Delegate Nodes
[TODO](https://github.com/libp2p/js-libp2p/pull/718)

View File

@ -1,38 +0,0 @@
# Production
Nowadays, you can run JavaScript code in several different environments, some of them with their own particularities. Moreover, you can use `js-libp2p` for a wide range of use cases. Different environments and different use cases mean different configurations and challenges in the network.
Libp2p nodes can vary from nodes behind an application, to infrastructure nodes that enable the network to operate and to be efficient. In this context, the Libp2p project provides public infrastructure to boost the network, enable nodes connectivity and improve constrained nodes performance. This public infrastructure should be leveraged for learning the concepts and experimenting. When an application on top of libp2p aims to move into production, its own infrastructure should be setup as the public nodes will be intensively used by others and its availability is not guaranteed.
This guide aims to guide you from using the public infrastructure into setting up your own.
## Table of Contents
* [Production](#production)
* [Star servers](#star-servers)
* [Delegate nodes](#delegate-nodes)
* [Circuit Relay](#circuit-relay)
## `webrtc-star` servers
While the libp2p core codebase aims to work in multiple environments, there are some limitations that are not possible to overcome at the time of writing. Regarding `webRTC`, at the time of writing a set of star servers are needed to act as a rendezvous point, where peers can learn about other peers (`peer-discovery`), as well as exchange their SDP offers (signaling data).
You can read on how to setup your own set of delegated nodes in [libp2p/js-libp2p-webrtc-star/DEPLOYMENT.md](https://github.com/libp2p/js-libp2p-webrtc-star/blob/master/DEPLOYMENT.md).
It is worth pointing out that with new discovery protocols on the way, as well as support for distributed signaling, the star servers should be deprecated on the long run.
## Delegate nodes
Libp2p nodes in scenarios such as browser environment and constrained devices will not be an efficient node in the libp2p DHT overlay, as a consequence of their known limitations regarding connectivity and performance.
Aiming to support these type of nodes to find other peers and content in the network, delegate nodes can be setup. With a set of well known libp2p delegate nodes, nodes with limitations in the network can leverage them to perform peer and content routing calls.
You can read on how to setup your own set of delegated nodes in [DELEGATE_NODES.md](./DELEGATE_NODES.md).
## Circuit Relay
Libp2p nodes acting as circuit relay aim to establish connectivity between libp2p nodes (e.g. IPFS nodes) that wouldn't otherwise be able to establish a direct connection to each other.
A relay is needed in situations where nodes are behind NAT, reverse proxies, firewalls and/or simply don't support the same transports (e.g. go-libp2p vs. browser-libp2p). The circuit relay protocol exists to overcome those scenarios. Nodes with the `auto-relay` feature enabled can automatically bind themselves on a relay to listen for connections on their behalf.
You can read on how to setup your own set of delegated nodes in [CIRCUIT_RELAY.md](./CIRCUIT_RELAY.md).

View File

@ -31,11 +31,12 @@ document.addEventListener('DOMContentLoaded', async () => {
[Bootstrap.tag]: { [Bootstrap.tag]: {
enabled: true, enabled: true,
list: [ list: [
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN', '/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb', '/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp', '/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa', '/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt' '/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64'
] ]
} }
} }

View File

@ -8,7 +8,7 @@ const { NOISE } = require('libp2p-noise')
const createNode = async () => { const createNode = async () => {
const node = await Libp2p.create({ const node = await Libp2p.create({
addresses: { addresses: {
// To signal the addresses we want to be available, we use // To signall the addresses we want to be available, we use
// the multiaddr format, a self describable address // the multiaddr format, a self describable address
listen: ['/ip4/0.0.0.0/tcp/0'] listen: ['/ip4/0.0.0.0/tcp/0']
}, },

View File

@ -12,7 +12,7 @@ const concat = require('it-concat')
const createNode = async () => { const createNode = async () => {
const node = await Libp2p.create({ const node = await Libp2p.create({
addresses: { addresses: {
// To signal the addresses we want to be available, we use // To signall the addresses we want to be available, we use
// the multiaddr format, a self describable address // the multiaddr format, a self describable address
listen: ['/ip4/0.0.0.0/tcp/0'] listen: ['/ip4/0.0.0.0/tcp/0']
}, },

View File

@ -16,7 +16,7 @@ const createNode = async (transports, addresses = []) => {
const node = await Libp2p.create({ const node = await Libp2p.create({
addresses: { addresses: {
listen: addresses listen: addresses.map((a) => a)
}, },
modules: { modules: {
transport: transports, transport: transports,

View File

@ -13,10 +13,10 @@ When using libp2p, you need properly configure it, that is, pick your set of mod
You will need 4 dependencies total, so go ahead and install all of them with: You will need 4 dependencies total, so go ahead and install all of them with:
```bash ```bash
> npm install libp2p libp2p-tcp libp2p-noise > npm install libp2p libp2p-tcp libp2p-noise peer-info
``` ```
Then, in your favorite text editor create a file with the `.js` extension. I've called mine `1.js`. Then, on your favorite text editor create a file with the `.js` extension. I've called mine `1.js`.
First thing is to create our own libp2p node! Insert: First thing is to create our own libp2p node! Insert:
@ -30,7 +30,7 @@ const { NOISE } = require('libp2p-noise')
const createNode = async () => { const createNode = async () => {
const node = await Libp2p.create({ const node = await Libp2p.create({
addresses: { addresses: {
// To signal the addresses we want to be available, we use // To signall the addresses we want to be available, we use
// the multiaddr format, a self describable address // the multiaddr format, a self describable address
listen: ['/ip4/0.0.0.0/tcp/0'] listen: ['/ip4/0.0.0.0/tcp/0']
}, },
@ -77,41 +77,20 @@ That `QmW2cKTakTYqbQkUzBTEGXgWYFj1YEPeUndE1YWs6CBzDQ` is the PeerId that was cre
Now that we have our `createNode` function, let's create two nodes and make them dial to each other! You can find the complete solution at [2.js](./2.js). Now that we have our `createNode` function, let's create two nodes and make them dial to each other! You can find the complete solution at [2.js](./2.js).
For this step, we will need some more dependencies. For this step, we will need one more dependency.
```bash ```bash
> npm install it-pipe it-concat libp2p-mplex > npm install it-pipe it-buffer
``` ```
And we also need to import the modules on our .js file: And we also need to import the module on our .js file:
```js ```js
const pipe = require('it-pipe') const pipe = require('it-pipe')
const concat = require('it-concat') const { toBuffer } = require('it-buffer')
const MPLEX = require('libp2p-mplex')
``` ```
We are going to reuse the `createNode` function from step 1, but this time add a stream multiplexer from `libp2p-mplex`. We are going to reuse the `createNode` function from step 1, but this time to make things simpler, we will create another function to print the addrs to avoid duplicating code.
```js
const createNode = async () => {
const node = await Libp2p.create({
addresses: {
// To signal the addresses we want to be available, we use
// the multiaddr format, a self describable address
listen: ['/ip4/0.0.0.0/tcp/0']
},
modules: {
transport: [TCP],
connEncryption: [NOISE],
streamMuxer: [MPLEX] // <--- Add this line
}
})
await node.start()
return node
}
```
We will also make things simpler by creating another function to print the multiaddresses to avoid duplicating code.
```JavaScript ```JavaScript
function printAddrs (node, number) { function printAddrs (node, number) {
@ -120,7 +99,7 @@ function printAddrs (node, number) {
} }
``` ```
Then add, Then,
```js ```js
;(async () => { ;(async () => {
@ -132,15 +111,18 @@ Then add,
printAddrs(node1, '1') printAddrs(node1, '1')
printAddrs(node2, '2') printAddrs(node2, '2')
node2.handle('/print', async ({ stream }) => { node2.handle('/print', ({ stream }) => {
const result = await pipe( pipe(
stream, stream,
concat async function (source) {
for await (const msg of source) {
console.log(msg.toString())
}
}
) )
console.log(result.toString())
}) })
node1.peerStore.addressBook.set(node2.peerId, node2.multiaddrs) node1.peerStore.addressBook.set(node2.peerId, node2.multiaddrs)
const { stream } = await node1.dialProtocol(node2.peerId, '/print') const { stream } = await node1.dialProtocol(node2.peerId, '/print')
await pipe( await pipe(
@ -149,9 +131,8 @@ Then add,
) )
})(); })();
``` ```
For more information refer to the [docs](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md).
The result should look like: The result should be look like:
```bash ```bash
> node 2.js > node 2.js
@ -166,29 +147,29 @@ Hello p2p world!
## 3. Using multiple transports ## 3. Using multiple transports
Next, we want nodes to have multiple transports available to increase their chances of having a common transport in the network to communicate over. A simple scenario is a node running in the browser only having access to HTTP, WebSockets and WebRTC since the browser doesn't let you open any other kind of transport. For this node to dial to some other node, that other node needs to share a common transport. Next, we want to be available in multiple transports to increase our chances of having common transports in the network. A simple scenario, a node running in the browser only has access to HTTP, WebSockets and WebRTC since the browser doesn't let you open any other kind of transport, for this node to dial to some other node, that other node needs to share a common transport.
What we are going to do in this step is to create 3 nodes: one with TCP, another with TCP+WebSockets and another one with just WebSockets. The full solution can be found on [3.js](./3.js). What we are going to do in this step is to create 3 nodes, one with TCP, another with TCP+WebSockets and another one with just WebSockets. The full solution can be found on [3.js](./3.js).
In this example, we will need to also install `libp2p-websockets`: In this example, we will need to also install `libp2p-websockets`, go ahead and install:
```bash ```bash
> npm install libp2p-websockets > npm install libp2p-websockets
``` ```
We want to create 3 nodes: one with TCP, one with TCP+WebSockets and one with just WebSockets. We need to update our `createNode` function to accept WebSocket connections as well. Moreover, let's upgrade our function to enable us to pick the addresses over which a node will start a listener: We want to create 3 nodes, one with TCP, one with TCP+WebSockets and one with just WebSockets. We need to update our `createNode` function to contemplate WebSockets as well. Moreover, let's upgrade our function to enable us to pick the addrs in which a node will start a listener:
```JavaScript ```JavaScript
// ... // ...
const createNode = async (transports, addresses = []) => { const createNode = async (transports, multiaddrs = []) => {
if (!Array.isArray(addresses)) { if (!Array.isArray(multiaddrs)) {
addresses = [addresses] multiaddrs = [multiaddrs]
} }
const node = await Libp2p.create({ const node = await Libp2p.create({
addresses: { addresses: {
listen: addresses listen: multiaddrs.map((a) => multiaddr(a))
}, },
modules: { modules: {
transport: transports, transport: transports,
@ -250,7 +231,7 @@ try {
} }
``` ```
`print` is a function that prints each piece of data from a stream onto a new line but factored into its own function to save lines: `print` is a function created using the code from 2.js, but factored into its own function to save lines, here it is:
```JavaScript ```JavaScript
function print ({ stream }) { function print ({ stream }) {
@ -265,7 +246,7 @@ function print ({ stream }) {
} }
``` ```
If everything was set correctly, you now should see something similar to the following after running the script: If everything was set correctly, you now should see the following after you run the script:
```Bash ```Bash
> node 3.js > node 3.js
@ -284,13 +265,13 @@ node 3 failed to dial to node 1 with:
Error: No transport available for address /ip4/127.0.0.1/tcp/51482 Error: No transport available for address /ip4/127.0.0.1/tcp/51482
``` ```
As expected, we created 3 nodes: node 1 with TCP, node 2 with TCP+WebSockets and node 3 with just WebSockets. node 1 -> node 2 and node 2 -> node 3 managed to dial correctly because they shared a common transport; however, node 3 -> node 1 failed because they didn't share any. As expected, we created 3 nodes, node 1 with TCP, node 2 with TCP+WebSockets and node 3 with just WebSockets. node 1 -> node 2 and node 2 -> node 3 managed to dial correctly because they shared a common transport, however, node 3 -> node 1 failed because they didn't share any.
## 4. How to create a new libp2p transport ## 4. How to create a new libp2p transport
Today there are already several transports available and plenty to come. You can find these at [interface-transport implementations](https://github.com/libp2p/js-interfaces/tree/master/src/transport#modules-that-implement-the-interface) list. Today there are already several transports available and plenty to come, you can find these at [interface-transport implementations](https://github.com/libp2p/js-interfaces/tree/master/src/transport#modules-that-implement-the-interface) list.
Adding more transports is done through the same way as you added TCP and WebSockets. Some transports might offer extra functionalities, but as far as libp2p is concerned, if it follows the interface defined in the [spec](https://github.com/libp2p/js-interfaces/tree/master/src/transport#api) it will be able to use it. Adding more transports is done through the same way as you added TCP and WebSockets. Some transports might offer extra functionalities, but as far as libp2p is concerned, if it follows the interface defined at the [spec](https://github.com/libp2p/js-interfaces/tree/master/src/transport#api) it will be able to use it.
If you decide to implement a transport yourself, please consider adding to the list so that others can use it as well. If you decide to implement a transport yourself, please consider adding to the list so that others can use it as well.

View File

@ -1,6 +1,6 @@
{ {
"name": "libp2p", "name": "libp2p",
"version": "0.29.3", "version": "0.29.0",
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack", "description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>", "leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js", "main": "src/index.js",
@ -64,7 +64,7 @@
"mafmt": "^8.0.0", "mafmt": "^8.0.0",
"merge-options": "^2.0.0", "merge-options": "^2.0.0",
"moving-average": "^1.0.0", "moving-average": "^1.0.0",
"multiaddr": "^8.1.0", "multiaddr": "^8.0.0",
"multicodec": "^2.0.0", "multicodec": "^2.0.0",
"multistream-select": "^1.0.0", "multistream-select": "^1.0.0",
"mutable-proxy": "^1.0.0", "mutable-proxy": "^1.0.0",
@ -73,6 +73,7 @@
"p-fifo": "^1.0.0", "p-fifo": "^1.0.0",
"p-settle": "^4.0.1", "p-settle": "^4.0.1",
"peer-id": "^0.14.2", "peer-id": "^0.14.2",
"proper-event-emitter": "^1.0.0",
"protons": "^2.0.0", "protons": "^2.0.0",
"retimer": "^2.0.0", "retimer": "^2.0.0",
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
@ -105,7 +106,7 @@
"libp2p-gossipsub": "^0.6.0", "libp2p-gossipsub": "^0.6.0",
"libp2p-kad-dht": "^0.20.0", "libp2p-kad-dht": "^0.20.0",
"libp2p-mdns": "^0.15.0", "libp2p-mdns": "^0.15.0",
"libp2p-mplex": "^0.10.1", "libp2p-mplex": "^0.10.0",
"libp2p-noise": "^2.0.0", "libp2p-noise": "^2.0.0",
"libp2p-secio": "^0.13.1", "libp2p-secio": "^0.13.1",
"libp2p-tcp": "^0.15.1", "libp2p-tcp": "^0.15.1",
@ -132,41 +133,39 @@
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>", "Maciej Krüger <mkg20001@gmail.com>",
"Hugo Dias <mail@hugodias.me>", "Hugo Dias <mail@hugodias.me>",
"dirkmc <dirkmdev@gmail.com>",
"Volker Mische <volker.mische@gmail.com>", "Volker Mische <volker.mische@gmail.com>",
"dirkmc <dirkmdev@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>", "Richard Littauer <richard.littauer@gmail.com>",
"Elven <mon.samuel@qq.com>", "ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
"Andrew Nesbitt <andrewnez@gmail.com>", "Andrew Nesbitt <andrewnez@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>", "Giovanni T. Parra <fiatjaf@gmail.com>",
"Ryan Bell <ryan@piing.net>", "Ryan Bell <ryan@piing.net>",
"Thomas Eizinger <thomas@eizinger.io>", "Thomas Eizinger <thomas@eizinger.io>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
"Didrik Nordström <didrik@betamos.se>", "Didrik Nordström <didrik@betamos.se>",
"Henrique Dias <hacdias@gmail.com>", "Francis Gulotta <wizard@roborooter.com>",
"Fei Liu <liu.feiwood@gmail.com>", "Florian-Merle <florian.david.merle@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.com>",
"Ethan Lam <elmemphis2000@gmail.com>",
"Joel Gustafson <joelg@mit.edu>", "Joel Gustafson <joelg@mit.edu>",
"Julien Bouquillon <contact@revolunet.com>", "Julien Bouquillon <contact@revolunet.com>",
"Kevin Kwok <antimatter15@gmail.com>", "Kevin Kwok <antimatter15@gmail.com>",
"Felipe Martins <felipebrasil93@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>", "Nuno Nogueira <nunofmn@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>", "Fei Liu <liu.feiwood@gmail.com>",
"RasmusErik Voel Jensen <github@solsort.com>", "RasmusErik Voel Jensen <github@solsort.com>",
"Diogo Silva <fsdiogo@gmail.com>", "Dmitriy Ryajov <dryajov@gmail.com>",
"robertkiel <robert.kiel@validitylabs.org>",
"Soeren <nikorpoulsen@gmail.com>", "Soeren <nikorpoulsen@gmail.com>",
"Sönke Hahn <soenkehahn@gmail.com>", "Sönke Hahn <soenkehahn@gmail.com>",
"Tiago Alves <alvesjtiago@gmail.com>", "Tiago Alves <alvesjtiago@gmail.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>", "Diogo Silva <fsdiogo@gmail.com>",
"Yusef Napora <yusef@napora.org>", "Yusef Napora <yusef@napora.org>",
"Zane Starr <zcstarr@gmail.com>", "Zane Starr <zcstarr@gmail.com>",
"Cindy Wu <ciindy.wu@gmail.com>", "Daijiro Wachi <daijiro.wachi@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>", "Chris Bratlien <chrisbratlien@gmail.com>",
"ebinks <elizabethjbinks@gmail.com>", "ebinks <elizabethjbinks@gmail.com>",
"Bernd Strehl <bernd.strehl@gmail.com>", "Bernd Strehl <bernd.strehl@gmail.com>",
"isan_rivkin <isanrivkin@gmail.com>", "isan_rivkin <isanrivkin@gmail.com>",
"Florian-Merle <florian.david.merle@gmail.com>", "Henrique Dias <hacdias@gmail.com>",
"Francis Gulotta <wizard@roborooter.com>", "robertkiel <robert.kiel@validitylabs.org>",
"Felipe Martins <felipebrasil93@gmail.com>" "Irakli Gozalishvili <rfobic@gmail.com>"
] ]
} }

View File

@ -1,6 +1,6 @@
'use strict' 'use strict'
const EventEmitter = require('events') const EventEmitter = require('proper-event-emitter')
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const debug = require('debug') const debug = require('debug')

View File

@ -1,8 +1,6 @@
'use strict' 'use strict'
const mergeOptions = require('merge-options') const mergeOptions = require('merge-options')
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
const Constants = require('./constants') const Constants = require('./constants')
const { FaultTolerance } = require('./transport-manager') const { FaultTolerance } = require('./transport-manager')
@ -22,10 +20,7 @@ const DefaultConfig = {
dialer: { dialer: {
maxParallelDials: Constants.MAX_PARALLEL_DIALS, maxParallelDials: Constants.MAX_PARALLEL_DIALS,
maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS, maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,
dialTimeout: Constants.DIAL_TIMEOUT, dialTimeout: Constants.DIAL_TIMEOUT
resolvers: {
dnsaddr: dnsaddrResolver
}
}, },
metrics: { metrics: {
enabled: false enabled: false

View File

@ -9,7 +9,7 @@ const mergeOptions = require('merge-options')
const LatencyMonitor = require('./latency-monitor') const LatencyMonitor = require('./latency-monitor')
const retimer = require('retimer') const retimer = require('retimer')
const { EventEmitter } = require('events') const EventEmitter = require('proper-event-emitter')
const PeerId = require('peer-id') const PeerId = require('peer-id')
@ -199,6 +199,7 @@ class ConnectionManager extends EventEmitter {
const storedConn = this.connections.get(peerIdStr) const storedConn = this.connections.get(peerIdStr)
this.emit('peer:connect', connection) this.emit('peer:connect', connection)
if (storedConn) { if (storedConn) {
storedConn.push(connection) storedConn.push(connection)
} else { } else {

View File

@ -27,15 +27,13 @@ class Dialer {
* @param {number} [options.concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials. * @param {number} [options.concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
* @param {number} [options.perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer. * @param {number} [options.perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
* @param {number} [options.timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take. * @param {number} [options.timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
* @param {object} [options.resolvers = {}] - multiaddr resolvers to use when dialing
*/ */
constructor ({ constructor ({
transportManager, transportManager,
peerStore, peerStore,
concurrency = MAX_PARALLEL_DIALS, concurrency = MAX_PARALLEL_DIALS,
timeout = DIAL_TIMEOUT, timeout = DIAL_TIMEOUT,
perPeerLimit = MAX_PER_PEER_DIALS, perPeerLimit = MAX_PER_PEER_DIALS
resolvers = {}
}) { }) {
this.transportManager = transportManager this.transportManager = transportManager
this.peerStore = peerStore this.peerStore = peerStore
@ -44,10 +42,6 @@ class Dialer {
this.perPeerLimit = perPeerLimit this.perPeerLimit = perPeerLimit
this.tokens = [...new Array(concurrency)].map((_, index) => index) this.tokens = [...new Array(concurrency)].map((_, index) => index)
this._pendingDials = new Map() this._pendingDials = new Map()
for (const [key, value] of Object.entries(resolvers)) {
multiaddr.resolvers.set(key, value)
}
} }
/** /**
@ -75,7 +69,7 @@ class Dialer {
* @returns {Promise<Connection>} * @returns {Promise<Connection>}
*/ */
async connectToPeer (peer, options = {}) { async connectToPeer (peer, options = {}) {
const dialTarget = await this._createDialTarget(peer) const dialTarget = this._createDialTarget(peer)
if (!dialTarget.addrs.length) { if (!dialTarget.addrs.length) {
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES) throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
@ -111,28 +105,22 @@ class Dialer {
* *
* @private * @private
* @param {PeerId|Multiaddr|string} peer - A PeerId or Multiaddr * @param {PeerId|Multiaddr|string} peer - A PeerId or Multiaddr
* @returns {Promise<DialTarget>} * @returns {DialTarget}
*/ */
async _createDialTarget (peer) { _createDialTarget (peer) {
const { id, multiaddrs } = getPeer(peer) const { id, multiaddrs } = getPeer(peer)
if (multiaddrs) { if (multiaddrs) {
this.peerStore.addressBook.add(id, multiaddrs) this.peerStore.addressBook.add(id, multiaddrs)
} }
let knownAddrs = this.peerStore.addressBook.getMultiaddrsForPeer(id) || [] let addrs = this.peerStore.addressBook.getMultiaddrsForPeer(id) || []
// If received a multiaddr to dial, it should be the first to use // 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. // But, if we know other multiaddrs for the peer, we should try them too.
if (multiaddr.isMultiaddr(peer)) { if (multiaddr.isMultiaddr(peer)) {
knownAddrs = knownAddrs.filter((addr) => !peer.equals(addr)) addrs = addrs.filter((addr) => !peer.equals(addr))
knownAddrs.unshift(peer) addrs.unshift(peer)
}
const addrs = []
for (const a of knownAddrs) {
const resolvedAddrs = await this._resolve(a)
resolvedAddrs.forEach(ra => addrs.push(ra))
} }
return { return {
@ -202,52 +190,6 @@ class Dialer {
log('token %d released', token) log('token %d released', token)
this.tokens.push(token) this.tokens.push(token)
} }
/**
* Resolve multiaddr recursively.
*
* @param {Multiaddr} ma
* @returns {Promise<Array<Multiaddr>>}
*/
async _resolve (ma) {
// TODO: recursive logic should live in multiaddr once dns4/dns6 support is in place
// Now only supporting resolve for dnsaddr
const resolvableProto = ma.protoNames().includes('dnsaddr')
// Multiaddr is not resolvable? End recursion!
if (!resolvableProto) {
return [ma]
}
const resolvedMultiaddrs = await this._resolveRecord(ma)
const recursiveMultiaddrs = await Promise.all(resolvedMultiaddrs.map((nm) => {
return this._resolve(nm)
}))
return recursiveMultiaddrs.flat().reduce((array, newM) => {
if (!array.find(m => m.equals(newM))) {
array.push(newM)
}
return array
}, []) // Unique addresses
}
/**
* Resolve a given multiaddr. If this fails, an empty array will be returned
*
* @param {Multiaddr} ma
* @returns {Promise<Array<Multiaddr>>}
*/
async _resolveRecord (ma) {
try {
ma = multiaddr(ma.toString()) // Use current multiaddr module
const multiaddrs = await ma.resolve()
return multiaddrs
} catch (_) {
log.error(`multiaddr ${ma} could not be resolved`)
return []
}
}
} }
module.exports = Dialer module.exports = Dialer

View File

@ -1,6 +1,6 @@
'use strict' 'use strict'
const { EventEmitter } = require('events') const EventEmitter = require('proper-event-emitter')
const debug = require('debug') const debug = require('debug')
const globalThis = require('ipfs-utils/src/globalthis') const globalThis = require('ipfs-utils/src/globalthis')
const log = debug('libp2p') const log = debug('libp2p')
@ -134,8 +134,7 @@ class Libp2p extends EventEmitter {
peerStore: this.peerStore, peerStore: this.peerStore,
concurrency: this._options.dialer.maxParallelDials, concurrency: this._options.dialer.maxParallelDials,
perPeerLimit: this._options.dialer.maxDialsPerPeer, perPeerLimit: this._options.dialer.maxDialsPerPeer,
timeout: this._options.dialer.dialTimeout, timeout: this._options.dialer.dialTimeout
resolvers: this._options.dialer.resolvers
}) })
this._modules.transport.forEach((Transport) => { this._modules.transport.forEach((Transport) => {

View File

@ -5,7 +5,7 @@ const debug = require('debug')
const log = debug('libp2p:peer-store') const log = debug('libp2p:peer-store')
log.error = debug('libp2p:peer-store:error') log.error = debug('libp2p:peer-store:error')
const { EventEmitter } = require('events') const EventEmitter = require('proper-event-emitter')
const PeerId = require('peer-id') const PeerId = require('peer-id')
const AddressBook = require('./address-book') const AddressBook = require('./address-book')

View File

@ -5,7 +5,6 @@ const log = debug('libp2p:upgrader')
log.error = debug('libp2p:upgrader:error') log.error = debug('libp2p:upgrader:error')
const Multistream = require('multistream-select') const Multistream = require('multistream-select')
const { Connection } = require('libp2p-interfaces/src/connection') const { Connection } = require('libp2p-interfaces/src/connection')
const ConnectionStatus = require('libp2p-interfaces/src/connection/status')
const PeerId = require('peer-id') const PeerId = require('peer-id')
const pipe = require('it-pipe') const pipe = require('it-pipe')
const errCode = require('err-code') const errCode = require('err-code')
@ -269,19 +268,9 @@ class Upgrader {
maConn.timeline = new Proxy(_timeline, { maConn.timeline = new Proxy(_timeline, {
set: (...args) => { set: (...args) => {
if (connection && args[1] === 'close' && args[2] && !_timeline.close) { if (connection && args[1] === 'close' && args[2] && !_timeline.close) {
// Wait for close to finish before notifying of the closure connection.stat.status = 'closed'
(async () => {
try {
if (connection.stat.status === ConnectionStatus.OPEN) {
await connection.close()
}
} catch (err) {
log.error(err)
} finally {
this.onConnectionEnd(connection) this.onConnectionEnd(connection)
} }
})()
}
return Reflect.set(...args) return Reflect.set(...args)
} }
@ -306,13 +295,7 @@ class Upgrader {
}, },
newStream: newStream || errConnectionNotMultiplexed, newStream: newStream || errConnectionNotMultiplexed,
getStreams: () => muxer ? muxer.streams : errConnectionNotMultiplexed, getStreams: () => muxer ? muxer.streams : errConnectionNotMultiplexed,
close: async (err) => { close: err => maConn.close(err)
await maConn.close(err)
// Ensure remaining streams are aborted
if (muxer) {
muxer.streams.map(stream => stream.abort(err))
}
}
}) })
this.onConnection(connection) this.onConnection(connection)

View File

@ -0,0 +1,98 @@
'use strict'
/* eslint-env mocha */
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
const errCode = require('err-code')
const { isNode, isWebWorker } = require('ipfs-utils/src/env')
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const peerUtils = require('../utils/creators/peer')
const mockConnection = require('../utils/mockConnection')
const baseOptions = require('../utils/base-options.browser')
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
const relayAddr = MULTIADDRS_WEBSOCKETS[0]
const code = 'HANDLER_ERROR'
const errorMsg = 'handle error'
describe('event handlers error', () => {
// TODO: Need a way of catching the error in the process and absorb it
if (isWebWorker) {
return
}
let libp2p
let peerId
before(async () => {
peerId = await PeerId.create()
})
beforeEach(async () => {
[libp2p] = await peerUtils.createPeer({
config: {
modules: baseOptions.modules,
addresses: {
listen: [multiaddr(`${relayAddr}/p2p-circuit`)]
}
},
started: true
})
})
afterEach(async () => {
libp2p && await libp2p.stop()
})
it('should throw on "peer:connect" event handler error', async () => {
const p = catchGlobalError()
libp2p.connectionManager.on('peer:connect', () => {
throw errCode(new Error(errorMsg), code)
})
const connection = await mockConnection()
libp2p.connectionManager.onConnect(connection)
await p
})
it('should throw on "peer:discovery" event handler error', async () => {
const p = catchGlobalError()
libp2p.on('peer:discovery', () => {
throw errCode(new Error(errorMsg), code)
})
const ma = multiaddr('/ip4/127.0.0.1/tcp/0')
libp2p.peerStore.addressBook.add(peerId, [ma])
await p
})
})
const catchGlobalError = () => {
return new Promise((resolve) => {
if (isNode) {
const originalException = process.listeners('uncaughtException').pop()
originalException && process.removeListener('uncaughtException', originalException)
process.once('uncaughtException', (err) => {
expect(err).to.exist()
expect(err.code).to.eql(code)
originalException && process.listeners('uncaughtException').push(originalException)
resolve()
})
} else {
window.onerror = () => {
resolve()
}
}
})
}

View File

@ -11,9 +11,7 @@ const PeerId = require('peer-id')
const delay = require('delay') const delay = require('delay')
const pDefer = require('p-defer') const pDefer = require('p-defer')
const pSettle = require('p-settle') const pSettle = require('p-settle')
const pWaitFor = require('p-wait-for')
const pipe = require('it-pipe') const pipe = require('it-pipe')
const pushable = require('it-pushable')
const AggregateError = require('aggregate-error') const AggregateError = require('aggregate-error')
const { Connection } = require('libp2p-interfaces/src/connection') const { Connection } = require('libp2p-interfaces/src/connection')
const { AbortError } = require('libp2p-interfaces/src/transport/errors') const { AbortError } = require('libp2p-interfaces/src/transport/errors')
@ -158,9 +156,9 @@ describe('Dialing (direct, TCP)', () => {
it('should dial to the max concurrency', async () => { it('should dial to the max concurrency', async () => {
const addrs = [ const addrs = [
multiaddr('/ip4/0.0.0.0/tcp/8000'), '/ip4/0.0.0.0/tcp/8000',
multiaddr('/ip4/0.0.0.0/tcp/8001'), '/ip4/0.0.0.0/tcp/8001',
multiaddr('/ip4/0.0.0.0/tcp/8002') '/ip4/0.0.0.0/tcp/8002'
] ]
const dialer = new Dialer({ const dialer = new Dialer({
transportManager: localTM, transportManager: localTM,
@ -301,50 +299,6 @@ describe('Dialing (direct, TCP)', () => {
expect(libp2p.dialer.connectToPeer.callCount).to.equal(1) expect(libp2p.dialer.connectToPeer.callCount).to.equal(1)
}) })
it('should close all streams when the connection closes', async () => {
libp2p = new Libp2p({
peerId,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
})
// register some stream handlers to simulate several protocols
libp2p.handle('/stream-count/1', ({ stream }) => pipe(stream, stream))
libp2p.handle('/stream-count/2', ({ stream }) => pipe(stream, stream))
remoteLibp2p.handle('/stream-count/3', ({ stream }) => pipe(stream, stream))
remoteLibp2p.handle('/stream-count/4', ({ stream }) => pipe(stream, stream))
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
const connection = await libp2p.dial(remotePeerId)
// Create local to remote streams
const { stream } = await connection.newStream('/echo/1.0.0')
await connection.newStream('/stream-count/3')
await libp2p.dialProtocol(remoteLibp2p.peerId, '/stream-count/4')
// Partially write to the echo stream
const source = pushable()
stream.sink(source)
source.push('hello')
// Create remote to local streams
await remoteLibp2p.dialProtocol(libp2p.peerId, '/stream-count/1')
await remoteLibp2p.dialProtocol(libp2p.peerId, '/stream-count/2')
// Verify stream count
const remoteConn = remoteLibp2p.connectionManager.get(libp2p.peerId)
expect(connection.streams).to.have.length(5)
expect(remoteConn.streams).to.have.length(5)
// Close the connection and verify all streams have been closed
await connection.close()
await pWaitFor(() => connection.streams.length === 0)
await pWaitFor(() => remoteConn.streams.length === 0)
})
it('should be able to use hangup to close connections', async () => { it('should be able to use hangup to close connections', async () => {
libp2p = new Libp2p({ libp2p = new Libp2p({
peerId, peerId,

View File

@ -263,6 +263,7 @@ describe('Dialing (direct, WebSockets)', () => {
describe('libp2p.dialer', () => { describe('libp2p.dialer', () => {
let libp2p let libp2p
let remoteLibp2p
afterEach(async () => { afterEach(async () => {
sinon.restore() sinon.restore()
@ -270,6 +271,10 @@ describe('Dialing (direct, WebSockets)', () => {
libp2p = null libp2p = null
}) })
after(async () => {
remoteLibp2p && await remoteLibp2p.stop()
})
it('should create a dialer', () => { it('should create a dialer', () => {
libp2p = new Libp2p({ libp2p = new Libp2p({
peerId, peerId,

View File

@ -1,176 +0,0 @@
'use strict'
/* eslint-env mocha */
const { expect } = require('aegir/utils/chai')
const sinon = require('sinon')
const multiaddr = require('multiaddr')
const { Resolver } = require('multiaddr/src/resolvers/dns')
const { codes: ErrorCodes } = require('../../src/errors')
const peerUtils = require('../utils/creators/peer')
const baseOptions = require('../utils/base-options.browser')
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
const relayAddr = MULTIADDRS_WEBSOCKETS[0]
const getDnsaddrStub = (peerId) => [
[`dnsaddr=/dnsaddr/ams-1.bootstrap.libp2p.io/p2p/${peerId}`],
[`dnsaddr=/dnsaddr/ams-2.bootstrap.libp2p.io/p2p/${peerId}`],
[`dnsaddr=/dnsaddr/lon-1.bootstrap.libp2p.io/p2p/${peerId}`],
[`dnsaddr=/dnsaddr/nrt-1.bootstrap.libp2p.io/p2p/${peerId}`],
[`dnsaddr=/dnsaddr/nyc-1.bootstrap.libp2p.io/p2p/${peerId}`],
[`dnsaddr=/dnsaddr/sfo-2.bootstrap.libp2p.io/p2p/${peerId}`]
]
const relayedAddr = (peerId) => `${relayAddr}/p2p-circuit/p2p/${peerId}`
const getDnsRelayedAddrStub = (peerId) => [
[`dnsaddr=${relayedAddr(peerId)}`]
]
describe('Dialing (resolvable addresses)', () => {
let libp2p, remoteLibp2p
beforeEach(async () => {
[libp2p, remoteLibp2p] = await peerUtils.createPeer({
number: 2,
config: {
modules: baseOptions.modules,
addresses: {
listen: [multiaddr(`${relayAddr}/p2p-circuit`)]
},
config: {
peerDiscovery: {
autoDial: false
}
}
},
started: true,
populateAddressBooks: false
})
})
afterEach(async () => {
sinon.restore()
await Promise.all([libp2p, remoteLibp2p].map(n => n.stop()))
})
it('resolves dnsaddr to ws local address', async () => {
const remoteId = remoteLibp2p.peerId.toB58String()
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
// Transport spy
const transport = libp2p.transportManager._transports.get('Circuit')
sinon.spy(transport, 'dial')
// Resolver stub
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
stub.onCall(0).returns(Promise.resolve(getDnsRelayedAddrStub(remoteId)))
// Dial with address resolve
const connection = await libp2p.dial(dialAddr)
expect(connection).to.exist()
expect(connection.remoteAddr.equals(relayedAddrFetched))
const dialArgs = transport.dial.firstCall.args
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
})
it('resolves a dnsaddr recursively', async () => {
const remoteId = remoteLibp2p.peerId.toB58String()
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
// Transport spy
const transport = libp2p.transportManager._transports.get('Circuit')
sinon.spy(transport, 'dial')
// Resolver stub
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
let firstCall = false
stub.callsFake(() => {
if (!firstCall) {
firstCall = true
// Return an array of dnsaddr
return Promise.resolve(getDnsaddrStub(remoteId))
}
return Promise.resolve(getDnsRelayedAddrStub(remoteId))
})
// Dial with address resolve
const connection = await libp2p.dial(dialAddr)
expect(connection).to.exist()
expect(connection.remoteAddr.equals(relayedAddrFetched))
const dialArgs = transport.dial.firstCall.args
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
})
// TODO: Temporary solution does not resolve dns4/dns6
// Resolver just returns the received multiaddrs
it('stops recursive resolve if finds dns4/dns6 and dials it', async () => {
const remoteId = remoteLibp2p.peerId.toB58String()
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
// Stub resolver
const dnsMa = multiaddr(`/dns4/ams-1.remote.libp2p.io/tcp/443/wss/p2p/${remoteId}`)
const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt')
stubResolve.returns(Promise.resolve([
[`dnsaddr=${dnsMa}`]
]))
// Stub transport
const transport = libp2p.transportManager._transports.get('WebSockets')
const stubTransport = sinon.stub(transport, 'dial')
stubTransport.callsFake((multiaddr) => {
expect(multiaddr.equals(dnsMa)).to.eql(true)
})
await libp2p.dial(dialAddr)
})
it('resolves a dnsaddr recursively not failing if one address fails to resolve', async () => {
const remoteId = remoteLibp2p.peerId.toB58String()
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
// Transport spy
const transport = libp2p.transportManager._transports.get('Circuit')
sinon.spy(transport, 'dial')
// Resolver stub
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
stub.onCall(0).callsFake(() => Promise.resolve(getDnsaddrStub(remoteId)))
stub.onCall(1).callsFake(() => Promise.reject(new Error()))
stub.callsFake(() => Promise.resolve(getDnsRelayedAddrStub(remoteId)))
// Dial with address resolve
const connection = await libp2p.dial(dialAddr)
expect(connection).to.exist()
expect(connection.remoteAddr.equals(relayedAddrFetched))
const dialArgs = transport.dial.firstCall.args
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
})
it('fails to dial if resolve fails and there are no addresses to dial', async () => {
const remoteId = remoteLibp2p.peerId.toB58String()
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
// Stub resolver
const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt')
stubResolve.returns(Promise.reject(new Error()))
// Stub transport
const transport = libp2p.transportManager._transports.get('WebSockets')
const spy = sinon.spy(transport, 'dial')
await expect(libp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(Error)
.and.to.have.nested.property('.code', ErrorCodes.ERR_NO_VALID_ADDRESSES)
expect(spy.callCount).to.eql(0)
})
})