mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-03-25 11:51:04 +00:00
* docs: update chat example and add info to its readme * docs: update echo example * docs: update libp2p in browser example * docs: update pubsub example * docs: update peer and content routing examples * docs: update discovery mechanisms example * docs: update encrypted comms example * docs: update protocol and stream muxing example * feat: add config validation * test: update CI configs, use only node 8
183 lines
6.9 KiB
Markdown
183 lines
6.9 KiB
Markdown
# Peer Discovery Mechanisms
|
|
|
|
A Peer Discovery module enables libp2p to find peers to connect to. Think of these mechanisms as ways to join the rest of the network, as railing points.
|
|
|
|
With these system, a libp2p node can both have a set of nodes to always connect on boot (bootstraper nodes), discover nodes through locality (e.g connected in the same LAN) or through serendipity (random walks on a DHT).
|
|
|
|
These mechanisms save configuration and enable a node to operate without any explicit dials, it will just work.
|
|
|
|
## 1. Bootstrap list of Peers when booting a node
|
|
|
|
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex and SECIO. You can see the complete example at [1.js](./1.js).
|
|
|
|
First, we create our libp2p bundle.
|
|
|
|
```JavaScript
|
|
const Bootstrap = require('libp2p-railing')
|
|
class MyBundle extends libp2p {
|
|
constructor (peerInfo) {
|
|
const defaults = {
|
|
modules: {
|
|
transport: [ TCP ],
|
|
streamMuxer: [ Mplex ],
|
|
connEncryption: [ SECIO ],
|
|
peerDiscovery: [ Bootstrap ]
|
|
},
|
|
config: {
|
|
peerDiscovery: {
|
|
bootstrap: {
|
|
interval: 2000,
|
|
enabled: true,
|
|
list: bootstrapers
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
super(defaultsDeep(_options, defaults))
|
|
}
|
|
}
|
|
```
|
|
|
|
In this bundle, we use a `bootstrappers` array listing peers to connect _on boot_. Here is the list used by js-ipfs and go-ipfs.
|
|
|
|
```JavaScript
|
|
const bootstrapers = [
|
|
'/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
'/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
|
|
'/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
|
'/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
|
'/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
|
'/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
|
|
'/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
|
'/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
|
|
'/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx'
|
|
]
|
|
```
|
|
|
|
Now, once we create and start the node, we can listen for events such as `peer:discovery` and `peer:connect`, these events tell us when we found a peer, independently of the discovery mechanism used and when we actually dialed to that peer.
|
|
|
|
```JavaScript
|
|
let node
|
|
|
|
waterfall([
|
|
(cb) => PeerInfo.create(cb),
|
|
(peerInfo, cb) => {
|
|
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
|
node = new MyBundle({
|
|
peerInfo
|
|
})
|
|
node.start(cb)
|
|
}
|
|
], (err) => {
|
|
if (err) { throw err }
|
|
|
|
// Emitted when a peer has been found
|
|
node.on('peer:discovery', (peer) => {
|
|
console.log('Discovered:', peer.id.toB58String())
|
|
// Note how we need to dial, even if just to warm up the Connection (by not
|
|
// picking any protocol) in order to get a full Connection. The Peer Discovery
|
|
// doesn't make any decisions for you.
|
|
node.dial(peer, () => {})
|
|
})
|
|
|
|
// Once the dial is complete, this event is emitted.
|
|
node.on('peer:connect', (peer) => {
|
|
console.log('Connection established to:', peer.id.toB58String())
|
|
})
|
|
})
|
|
```
|
|
|
|
From running [1.js](./1.js), you should see the following:
|
|
|
|
```bash
|
|
> node 1.js
|
|
Discovered: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
|
Discovered: QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
|
|
Discovered: QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM
|
|
Discovered: QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm
|
|
Discovered: QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
|
|
Discovered: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
|
|
Discovered: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
|
|
Discovered: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
|
|
Discovered: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
|
|
Connection established to: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
|
|
Connection established to: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
|
|
Connection established to: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
|
|
Connection established to: QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm
|
|
Connection established to: QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM
|
|
Connection established to: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
|
|
Connection established to: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
|
Connection established to: QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
|
|
Connection established to: QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
|
|
```
|
|
|
|
## 2. MulticastDNS to find other peers in the network
|
|
|
|
For this example, we need `libp2p-mdns`, go ahead and `npm install` it. You can find the complete solution at [2.js](./2.js).
|
|
|
|
Update your libp2p bundle to include MulticastDNS.
|
|
|
|
```JavaScript
|
|
class MyBundle extends libp2p {
|
|
constructor (peerInfo) {
|
|
const defaults = {
|
|
modules: {
|
|
transport: [ TCP ],
|
|
streamMuxer: [ Mplex ],
|
|
connEncryption: [ SECIO ],
|
|
peerDiscovery: [ MulticastDNS ]
|
|
},
|
|
config: {
|
|
peerDiscovery: {
|
|
mdns: {
|
|
// Run at 1s so we can observe more quickly, default is 10s
|
|
interval: 1000,
|
|
enabled: true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
super(defaultsDeep(_options, defaults))
|
|
}
|
|
}
|
|
```
|
|
|
|
To observe it working, spawn two nodes.
|
|
|
|
```JavaScript
|
|
parallel([
|
|
(cb) => createNode(cb),
|
|
(cb) => createNode(cb)
|
|
], (err, nodes) => {
|
|
if (err) { throw err }
|
|
|
|
const node1 = nodes[0]
|
|
const node2 = nodes[1]
|
|
|
|
node1.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
|
|
node2.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
|
|
})
|
|
```
|
|
|
|
If you run this example, you will see a continuous stream of each peer discovering each other.
|
|
|
|
```bash
|
|
> node 2.js
|
|
Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
|
|
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
|
|
Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
|
|
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
|
|
Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
|
|
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
|
|
```
|
|
|
|
## 3. Where to find other Peer Discovery Mechanisms
|
|
|
|
There are plenty more Peer Discovery Mechanisms out there, you can:
|
|
|
|
- Find one in [libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star). Yes, a transport with discovery capabilities! This happens because WebRTC requires a rendezvous point for peers to exchange [SDP](https://tools.ietf.org/html/rfc4317) offer, which means we have one or more points that can introduce peers to each other. Think of it as MulticastDNS for the Web, as in MulticastDNS only works in LAN.
|
|
- Any DHT will offer you a discovery capability. You can simple _random-walk_ the routing tables to find other peers to connect to.
|
|
- You can create your own Discovery service, a registry, a list, a radio beacon, you name it!
|