mirror of https://github.com/status-im/js-waku.git
Provide easy way to bootstrap when creating Waku node
This commit is contained in:
parent
c3855112d7
commit
140791cc91
|
@ -47,6 +47,7 @@
|
|||
"livechat",
|
||||
"mkdir",
|
||||
"multiaddr",
|
||||
"multiaddresses",
|
||||
"multiaddrs",
|
||||
"multicodecs",
|
||||
"mplex",
|
||||
|
|
|
@ -7,8 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- New `bootstrap` option for `Waku.create` to easily connect to Waku nodes upon start up.
|
||||
|
||||
### Changed
|
||||
- Renamed `discover.getStatusFleetNodes` to `discovery.getBootstrapNodes` and make it more generic to allow retrieval of bootstrap nodes from other sources.
|
||||
- Renamed `discover.getStatusFleetNodes` to `discovery.getBootstrapNodes`;
|
||||
Changed the API to allow retrieval of bootstrap nodes from other sources.
|
||||
|
||||
### Removed
|
||||
- Examples (cli-chat): The focus of this library is Web environment;
|
||||
|
|
27
README.md
27
README.md
|
@ -32,32 +32,7 @@ npm install js-waku
|
|||
```ts
|
||||
import { Waku } from 'js-waku';
|
||||
|
||||
const waku = await Waku.create();
|
||||
```
|
||||
|
||||
### Connect to a new peer
|
||||
|
||||
```ts
|
||||
// Directly dial a new peer
|
||||
await waku.dial('/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ');
|
||||
|
||||
// Or, add peer to address book so it auto dials in the background
|
||||
waku.addPeerToAddressBook(
|
||||
'16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ',
|
||||
['/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss']
|
||||
);
|
||||
```
|
||||
|
||||
You can also use `getBootstrapNodes` to connect to Waku bootstrap nodes:
|
||||
|
||||
```ts
|
||||
import { getBootstrapNodes } from 'js-waku';
|
||||
|
||||
getBootstrapNodes().then((nodes) => {
|
||||
nodes.forEach((addr) => {
|
||||
waku.dial(addr);
|
||||
});
|
||||
});
|
||||
const waku = await Waku.create({ bootstrap: true });
|
||||
```
|
||||
|
||||
### Listen for messages
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { Waku, WakuMessage } from 'js-waku';
|
||||
import { DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||
import { validatePublicKeyMessage } from './crypto';
|
||||
import { Message } from './messaging/Messages';
|
||||
|
@ -9,14 +9,7 @@ export const PublicKeyContentTopic = '/eth-dm/1/public-key/proto';
|
|||
export const DirectMessageContentTopic = '/eth-dm/1/direct-message/proto';
|
||||
|
||||
export async function initWaku(): Promise<Waku> {
|
||||
const waku = await Waku.create({});
|
||||
|
||||
// Dial all nodes it can find
|
||||
getBootstrapNodes().then((nodes) => {
|
||||
nodes.forEach((addr) => {
|
||||
waku.dial(addr);
|
||||
});
|
||||
});
|
||||
const waku = await Waku.create({ bootstrap: true });
|
||||
|
||||
// Wait to be connected to at least one peer
|
||||
await new Promise((resolve, reject) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { Waku, WakuMessage } from 'js-waku';
|
||||
import { DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||
import { validatePublicKeyMessage } from './crypto';
|
||||
import { Message } from './messaging/Messages';
|
||||
|
@ -11,14 +11,7 @@ export const DirectMessageContentTopic =
|
|||
'/eth-pm-wallet/1/direct-message/proto';
|
||||
|
||||
export async function initWaku(): Promise<Waku> {
|
||||
const waku = await Waku.create({});
|
||||
|
||||
// Dial all nodes it can find
|
||||
getBootstrapNodes().then((nodes) => {
|
||||
nodes.forEach((addr) => {
|
||||
waku.dial(addr);
|
||||
});
|
||||
});
|
||||
const waku = await Waku.create({ bootstrap: true });
|
||||
|
||||
// Wait to be connected to at least one peer
|
||||
await new Promise((resolve, reject) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import './App.css';
|
||||
import { getBootstrapNodes, StoreCodec, Waku } from 'js-waku';
|
||||
import { StoreCodec, Waku } from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import protons from 'protons';
|
||||
|
||||
|
@ -17,9 +17,6 @@ function App() {
|
|||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState('None');
|
||||
const [messages, setMessages] = React.useState([]);
|
||||
// Set to true when Waku connects to a store node
|
||||
// it does not reflect whether we then disconnected from said node.
|
||||
const [connectedToStore, setConnectedToStore] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!!waku) return;
|
||||
|
@ -27,20 +24,15 @@ function App() {
|
|||
|
||||
setWakuStatus('Starting');
|
||||
|
||||
Waku.create().then((waku) => {
|
||||
Waku.create({ bootstrap: true }).then((waku) => {
|
||||
setWaku(waku);
|
||||
setWakuStatus('Connecting');
|
||||
bootstrapWaku(waku).then(() => {
|
||||
setWakuStatus('Ready');
|
||||
});
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!waku) return;
|
||||
// This is superfluous as the try/catch block would catch the failure if
|
||||
// we are indeed not connected to any store node.
|
||||
if (!connectedToStore) return;
|
||||
if (wakuStatus !== 'Connected to Store') return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
waku.store
|
||||
|
@ -57,33 +49,27 @@ function App() {
|
|||
}, 10000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [waku, connectedToStore]);
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!waku) return;
|
||||
|
||||
// We do not handle disconnection/re-connection in this example
|
||||
if (connectedToStore) return;
|
||||
if (wakuStatus === 'Connected to Store') return;
|
||||
|
||||
const isStoreNode = ({ protocols }) => {
|
||||
if (protocols.includes(StoreCodec)) {
|
||||
// We are now connected to a store node
|
||||
setConnectedToStore(true);
|
||||
setWakuStatus('Connected to Store');
|
||||
}
|
||||
};
|
||||
|
||||
// This demonstrates how to wait for a connection to a store node.
|
||||
//
|
||||
// This is only for demonstration purposes. It is not really needed in this
|
||||
// example app as we query the store node every 10s and catch if it fails.
|
||||
// Meaning if we are not connected to a store node, then it just fails and
|
||||
// we try again 10s later.
|
||||
waku.libp2p.peerStore.on('change:protocols', isStoreNode);
|
||||
|
||||
return () => {
|
||||
waku.libp2p.peerStore.removeListener('change:protocols', isStoreNode);
|
||||
};
|
||||
}, [waku, connectedToStore]);
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
|
@ -100,15 +86,6 @@ function App() {
|
|||
|
||||
export default App;
|
||||
|
||||
async function bootstrapWaku(waku) {
|
||||
try {
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
} catch (e) {
|
||||
console.error('Failed to bootstrap to Waku network');
|
||||
}
|
||||
}
|
||||
|
||||
function decodeMessage(wakuMessage) {
|
||||
if (!wakuMessage.payload) return;
|
||||
|
||||
|
|
|
@ -82,8 +82,10 @@ export default function App() {
|
|||
const persistedNick = window.localStorage.getItem('nick');
|
||||
return persistedNick !== null ? persistedNick : generate();
|
||||
});
|
||||
const [historicalMessagesRetrieved, setHistoricalMessagesRetrieved] =
|
||||
useState(false);
|
||||
const [
|
||||
historicalMessagesRetrieved,
|
||||
setHistoricalMessagesRetrieved,
|
||||
] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('nick', nick);
|
||||
|
@ -179,16 +181,10 @@ async function initWaku(setter: (waku: Waku) => void) {
|
|||
},
|
||||
},
|
||||
},
|
||||
bootstrap: getBootstrapNodes.bind({}, selectFleetEnv()),
|
||||
});
|
||||
|
||||
setter(waku);
|
||||
|
||||
const nodes = await getBootstrapNodes(selectFleetEnv());
|
||||
await Promise.all(
|
||||
nodes.map((addr) => {
|
||||
return waku.dial(addr);
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
console.log('Issue starting waku ', e);
|
||||
}
|
||||
|
|
|
@ -38,25 +38,21 @@ In order to interact with the Waku network, you first need a Waku instance:
|
|||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
|
||||
const wakuNode = await Waku.create();
|
||||
const wakuNode = await Waku.create({ bootstrap: true });
|
||||
```
|
||||
|
||||
# Connect to Other Peers
|
||||
|
||||
The Waku instance needs to connect to other peers to communicate with the network.
|
||||
You are free to choose other methods to bootstrap and DappConnect will ship with new bootstrap mechanisms in the future.
|
||||
|
||||
For now, the easiest way is to connect to Waku bootstrap nodes:
|
||||
Passing the `bootstrap` option will connect your node to predefined Waku nodes hosted by Status.
|
||||
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
|
||||
|
||||
```js
|
||||
import { getBootstrapNodes } from 'js-waku';
|
||||
import { Waku } from 'js-waku';
|
||||
|
||||
try {
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
} catch (e) {
|
||||
console.error('Failed to bootstrap to Waku network');
|
||||
}
|
||||
const wakuNode = await Waku.create({
|
||||
bootstrap: [
|
||||
'/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm',
|
||||
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ'
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
# Use Protobuf
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"it-length-prefixed": "^5.0.2",
|
||||
"js-sha3": "^0.8.0",
|
||||
"libp2p": "^0.32.0",
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-gossipsub": "^0.10.0",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
|
@ -15055,6 +15056,39 @@
|
|||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libp2p-bootstrap": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-bootstrap/-/libp2p-bootstrap-0.13.0.tgz",
|
||||
"integrity": "sha512-8sXEZrikY+chKvMorkvOi9E/v9GvwsYr9DAEfzQZrOKQZByqhan1aXQKWrSpc4AxEv5/UopRzu1P47bkOi8wdw==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"mafmt": "^10.0.0",
|
||||
"multiaddr": "^10.0.0",
|
||||
"peer-id": "^0.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libp2p-bootstrap/node_modules/peer-id": {
|
||||
"version": "0.15.2",
|
||||
"resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.15.2.tgz",
|
||||
"integrity": "sha512-3OMbup76F28gKsQK4rGheEJHwosnJGe2+Obsf1xFaS9DpUaG9/JK0rtguWVLbrkxPclsCceci8g3/ulg8jsORA==",
|
||||
"dependencies": {
|
||||
"class-is": "^1.1.0",
|
||||
"libp2p-crypto": "^0.19.0",
|
||||
"minimist": "^1.2.5",
|
||||
"multiformats": "^9.3.0",
|
||||
"protobufjs": "^6.10.2",
|
||||
"uint8arrays": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"peer-id": "src/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libp2p-crypto": {
|
||||
"version": "0.19.6",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.19.6.tgz",
|
||||
|
@ -36622,6 +36656,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"libp2p-bootstrap": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-bootstrap/-/libp2p-bootstrap-0.13.0.tgz",
|
||||
"integrity": "sha512-8sXEZrikY+chKvMorkvOi9E/v9GvwsYr9DAEfzQZrOKQZByqhan1aXQKWrSpc4AxEv5/UopRzu1P47bkOi8wdw==",
|
||||
"requires": {
|
||||
"debug": "^4.3.1",
|
||||
"mafmt": "^10.0.0",
|
||||
"multiaddr": "^10.0.0",
|
||||
"peer-id": "^0.15.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"peer-id": {
|
||||
"version": "0.15.2",
|
||||
"resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.15.2.tgz",
|
||||
"integrity": "sha512-3OMbup76F28gKsQK4rGheEJHwosnJGe2+Obsf1xFaS9DpUaG9/JK0rtguWVLbrkxPclsCceci8g3/ulg8jsORA==",
|
||||
"requires": {
|
||||
"class-is": "^1.1.0",
|
||||
"libp2p-crypto": "^0.19.0",
|
||||
"minimist": "^1.2.5",
|
||||
"multiformats": "^9.3.0",
|
||||
"protobufjs": "^6.10.2",
|
||||
"uint8arrays": "^2.0.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libp2p-crypto": {
|
||||
"version": "0.19.6",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.19.6.tgz",
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
"it-length-prefixed": "^5.0.2",
|
||||
"js-sha3": "^0.8.0",
|
||||
"libp2p": "^0.32.0",
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-gossipsub": "^0.10.0",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
|
|
|
@ -6,6 +6,8 @@ const dbg = debug('waku:discovery');
|
|||
/**
|
||||
* GET list of nodes from remote HTTP host.
|
||||
*
|
||||
* Default behaviour is to return nodes hosted by Status.
|
||||
*
|
||||
* @param path The property path to access the node list. The result should be
|
||||
* a string, a string array or an object. If the result is an object then the
|
||||
* values of the objects are used as multiaddresses.
|
||||
|
|
|
@ -2,20 +2,98 @@ import { expect } from 'chai';
|
|||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
import TCP from 'libp2p-tcp';
|
||||
import PeerId from 'peer-id';
|
||||
|
||||
import { makeLogFileName, NimWaku, NOISE_KEY_1 } from '../test_utils/';
|
||||
import {
|
||||
makeLogFileName,
|
||||
NimWaku,
|
||||
NOISE_KEY_1,
|
||||
NOISE_KEY_2,
|
||||
} from '../test_utils/';
|
||||
|
||||
import { Waku } from './waku';
|
||||
|
||||
describe('Waku Dial', function () {
|
||||
let waku: Waku;
|
||||
let waku2: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
afterEach(async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
nimWaku ? nimWaku.stop() : null;
|
||||
waku ? await waku.stop() : null;
|
||||
|
||||
await Promise.all([waku ? waku.stop() : null, waku2 ? waku2.stop() : null]);
|
||||
});
|
||||
|
||||
describe('Bootstrap', function () {
|
||||
it('Passing an array', async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
waku = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
libp2p: {
|
||||
addresses: { listen: ['/ip4/0.0.0.0/tcp/0'] },
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
});
|
||||
|
||||
const multiAddrWithId = waku.getLocalMultiaddrWithID();
|
||||
|
||||
waku2 = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
libp2p: {
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
bootstrap: [multiAddrWithId],
|
||||
});
|
||||
|
||||
const connectedPeerID: PeerId = await new Promise((resolve) => {
|
||||
waku.libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
resolve(connection.remotePeer);
|
||||
});
|
||||
});
|
||||
|
||||
expect(connectedPeerID.toB58String()).to.eq(
|
||||
waku2.libp2p.peerId.toB58String()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Bootstrap', function () {
|
||||
it('Passing a function', async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
waku = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
libp2p: {
|
||||
addresses: { listen: ['/ip4/0.0.0.0/tcp/0'] },
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
});
|
||||
|
||||
const multiAddrWithId = waku.getLocalMultiaddrWithID();
|
||||
|
||||
waku2 = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
libp2p: {
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
bootstrap: () => {
|
||||
return [multiAddrWithId];
|
||||
},
|
||||
});
|
||||
|
||||
const connectedPeerID: PeerId = await new Promise((resolve) => {
|
||||
waku.libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
resolve(connection.remotePeer);
|
||||
});
|
||||
});
|
||||
|
||||
expect(connectedPeerID.toB58String()).to.eq(
|
||||
waku2.libp2p.peerId.toB58String()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Interop: Nim', function () {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import debug from 'debug';
|
||||
import Libp2p, { Connection, Libp2pModules, Libp2pOptions } from 'libp2p';
|
||||
import Bootstrap from 'libp2p-bootstrap';
|
||||
import { MuxedStream } from 'libp2p-interfaces/dist/src/stream-muxer/types';
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
|
@ -15,6 +17,7 @@ import Ping from 'libp2p/src/ping';
|
|||
import { Multiaddr, multiaddr } from 'multiaddr';
|
||||
import PeerId from 'peer-id';
|
||||
|
||||
import { getBootstrapNodes } from './discovery';
|
||||
import { WakuLightPush } from './waku_light_push';
|
||||
import { WakuMessage } from './waku_message';
|
||||
import { RelayCodecs, WakuRelay } from './waku_relay';
|
||||
|
@ -26,6 +29,8 @@ const websocketsTransportKey = Websockets.prototype[Symbol.toStringTag];
|
|||
const DefaultPingKeepAliveValueSecs = 0;
|
||||
const DefaultRelayKeepAliveValueSecs = 5 * 60;
|
||||
|
||||
const dbg = debug('waku:waku');
|
||||
|
||||
export interface CreateOptions {
|
||||
/**
|
||||
* The PubSub Topic to use. Defaults to {@link DefaultPubsubTopic}.
|
||||
|
@ -71,6 +76,18 @@ export interface CreateOptions {
|
|||
* This is only used for test purposes to not run out of entropy during CI runs.
|
||||
*/
|
||||
staticNoiseKey?: bytes;
|
||||
/**
|
||||
* Use libp2p-bootstrap to discover and connect to new nodes.
|
||||
*
|
||||
* You can pass:
|
||||
* - `true` to use {@link getBootstrapNodes},
|
||||
* - an array of multiaddresses,
|
||||
* - a function that returns an array of multiaddresses (or Promise of).
|
||||
*
|
||||
* Note: It overrides any other peerDiscovery modules that may have been set via
|
||||
* {@link CreateOptions.libp2p}.
|
||||
*/
|
||||
bootstrap?: boolean | string[] | (() => string[] | Promise<string[]>);
|
||||
}
|
||||
|
||||
export class Waku {
|
||||
|
@ -161,6 +178,40 @@ export class Waku {
|
|||
pubsub: WakuRelay,
|
||||
});
|
||||
|
||||
if (options?.bootstrap) {
|
||||
let bootstrap: undefined | (() => string[] | Promise<string[]>);
|
||||
|
||||
if (options.bootstrap === true) {
|
||||
bootstrap = getBootstrapNodes;
|
||||
} else if (Array.isArray(options.bootstrap)) {
|
||||
bootstrap = (): string[] => {
|
||||
return options.bootstrap as string[];
|
||||
};
|
||||
} else if (typeof options.bootstrap === 'function') {
|
||||
bootstrap = options.bootstrap;
|
||||
}
|
||||
|
||||
if (bootstrap !== undefined) {
|
||||
// Note: this overrides any other peer discover
|
||||
libp2pOpts.modules = Object.assign(libp2pOpts.modules, {
|
||||
peerDiscovery: [Bootstrap],
|
||||
});
|
||||
|
||||
try {
|
||||
const list = await bootstrap();
|
||||
|
||||
libp2pOpts.config.peerDiscovery = {
|
||||
[Bootstrap.tag]: {
|
||||
list,
|
||||
enabled: true,
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
dbg('Failed to retrieve bootstrap nodes', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: modules property is correctly set thanks to voodoo
|
||||
const libp2p = await Libp2p.create(libp2pOpts);
|
||||
|
|
Loading…
Reference in New Issue