From 284644b8221f4269495e3bb157698278f9047c06 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 13 Jan 2022 14:28:45 +1100 Subject: [PATCH] Fix-up new bootstrap API --- CHANGELOG.md | 2 + examples/eth-pm-wallet-encryption/src/waku.ts | 2 +- examples/eth-pm/src/waku.ts | 2 +- examples/web-chat/src/App.tsx | 11 +- src/lib/discovery/bootstrap.ts | 116 ++++++++---------- src/lib/discovery/hosted_json.ts | 6 +- src/lib/discovery/index.ts | 6 +- src/lib/waku.node.spec.ts | 10 +- src/lib/waku.ts | 5 +- 9 files changed, 80 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8901263351..4d7f5f6a86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Test: Upgrade nim-waku node to v0.6. - **Breaking**: Renamed `getBootstrapNodes` to `getNodesFromHostedJson`. - Minimum node version changed to 16. +- **Breaking**: Changed `Waku.create` bootstrap option from `{ bootstrap: boolean }` to `{ bootstrap: BootstrapOptions }`. + Replace `{ boostrap: true }` with `{ boostrap: { default: true } }` to retain same behaviour. ### Fixed diff --git a/examples/eth-pm-wallet-encryption/src/waku.ts b/examples/eth-pm-wallet-encryption/src/waku.ts index d0be5baf83..f808dff396 100644 --- a/examples/eth-pm-wallet-encryption/src/waku.ts +++ b/examples/eth-pm-wallet-encryption/src/waku.ts @@ -11,7 +11,7 @@ export const PrivateMessageContentTopic = '/eth-pm-wallet/1/private-message/proto'; export async function initWaku(): Promise { - const waku = await Waku.create({ bootstrap: true }); + const waku = await Waku.create({ bootstrap: { default: true } }); // Wait to be connected to at least one peer await new Promise((resolve, reject) => { diff --git a/examples/eth-pm/src/waku.ts b/examples/eth-pm/src/waku.ts index 8a3ba14c94..33e802bcef 100644 --- a/examples/eth-pm/src/waku.ts +++ b/examples/eth-pm/src/waku.ts @@ -9,7 +9,7 @@ export const PublicKeyContentTopic = '/eth-pm/1/public-key/proto'; export const PrivateMessageContentTopic = '/eth-pm/1/private-message/proto'; export async function initWaku(): Promise { - const waku = await Waku.create({ bootstrap: true }); + const waku = await Waku.create({ bootstrap: { default: true } }); // Wait to be connected to at least one peer await new Promise((resolve, reject) => { diff --git a/examples/web-chat/src/App.tsx b/examples/web-chat/src/App.tsx index ec42eda8eb..02a81caf75 100644 --- a/examples/web-chat/src/App.tsx +++ b/examples/web-chat/src/App.tsx @@ -1,6 +1,11 @@ import { useEffect, useReducer, useState } from 'react'; import './App.css'; -import { PageDirection, getBootstrapNodes, Waku, WakuMessage } from 'js-waku'; +import { + PageDirection, + getNodesFromHostedJson, + Waku, + WakuMessage, +} from 'js-waku'; import handleCommand from './command'; import Room from './Room'; import { WakuContext } from './WakuContext'; @@ -175,7 +180,9 @@ async function initWaku(setter: (waku: Waku) => void) { }, }, }, - bootstrap: getBootstrapNodes.bind({}, selectFleetEnv()), + bootstrap: { + getPeers: getNodesFromHostedJson.bind({}, selectFleetEnv()), + }, }); setter(waku); diff --git a/src/lib/discovery/bootstrap.ts b/src/lib/discovery/bootstrap.ts index 6ba0860bc0..14a004edb7 100644 --- a/src/lib/discovery/bootstrap.ts +++ b/src/lib/discovery/bootstrap.ts @@ -1,4 +1,5 @@ import debug from 'debug'; +import { Multiaddr } from 'multiaddr'; import { DnsNodeDiscovery } from './dns'; @@ -6,7 +7,9 @@ import { getNodesFromHostedJson, getPseudoRandomSubset } from './index'; const dbg = debug('waku:discovery:bootstrap'); -const DefaultMaxPeers = 1; +export const DefaultMaxPeers = 1; + +export type BootstrapFn = () => Promise; /** * Setup discovery method used to bootstrap. @@ -17,11 +20,11 @@ export interface BootstrapOptions { /** * The maximum of peers to connect to as part of the bootstrap process. * - * @default 1 + * @default {{DefaultMaxPeers}} */ maxPeers?: number; /** - * Use the default discovery method. + * Use the default discovery method. Overrides all other options but `maxPeers` * * The default discovery method is likely to change overtime as new discovery * methods are implemented. @@ -36,7 +39,7 @@ export interface BootstrapOptions { /** * Getter that retrieve multiaddrs of peers to connect to. */ - getPeers?: () => Promise; + getPeers?: () => Promise; /** * An EIP-1459 ENR Tree URL. For example: * "enrtree://AOFTICU2XWDULNLZGRMQS4RIZPAZEHYMV4FYHAPW563HNRAOERP7C@test.nodes.vac.dev" @@ -47,69 +50,54 @@ export interface BootstrapOptions { /** * Parse the bootstrap options and returns an async function that returns node addresses upon invocation. */ -export function parseBootstrap( - options: - | BootstrapOptions - | boolean - | string[] - | (() => string[] | Promise) -): undefined | (() => Promise) { - if ( - Object.keys(options).includes('default') || - Object.keys(options).includes('maxPeers') || - Object.keys(options).includes('peers') || - Object.keys(options).includes('getPeers') || - Object.keys(options).includes('enrUrl') - ) { - const opts = options as unknown as BootstrapOptions; - const maxPeers = opts.maxPeers || DefaultMaxPeers; +export function parseBootstrap(opts: BootstrapOptions): BootstrapFn { + const maxPeers = opts.maxPeers ?? DefaultMaxPeers; - if (opts.default) { - dbg('Bootstrap: Use hosted list of peers.'); + if (opts.default) { + dbg('Bootstrap: Use hosted list of peers.'); - return getNodesFromHostedJson.bind({}, undefined, undefined, maxPeers); - } else if (opts.peers !== undefined && opts.peers.length > 0) { - dbg('Bootstrap: Use provided list of peers.'); + return getNodesFromHostedJson.bind({}, undefined, undefined, maxPeers); + } else if (opts.peers !== undefined && opts.peers.length > 0) { + dbg('Bootstrap: Use provided list of peers.'); - const allPeers: string[] = opts.peers; - return (): Promise => { - const peers = getPseudoRandomSubset(allPeers, maxPeers); - return Promise.resolve(peers); - }; - } else if (typeof opts.getPeers === 'function') { - dbg('Bootstrap: Use provided getPeers function.'); - const getPeers = opts.getPeers; - - return async (): Promise => { - const allPeers = await getPeers(); - return getPseudoRandomSubset(allPeers, maxPeers); - }; - } else if (opts.enrUrl) { - const enrUrl = opts.enrUrl; - dbg('Bootstrap: Use provided EIP-1459 ENR Tree URL.'); - - const dns = DnsNodeDiscovery.dnsOverHttp(); - // TODO: The `toString` is incorrect. - return (): Promise => - dns - .getPeers(maxPeers, [enrUrl]) - .then((peers) => peers.map((peer) => peer.toString())); - } - } else { - dbg( - 'WARN: This bootstrap method will be deprecated, use `BootstrapOptions` instead' + const allPeers: Multiaddr[] = opts.peers.map( + (node: string) => new Multiaddr(node) ); - if (options === true) { - return getNodesFromHostedJson; - } else if (Array.isArray(options)) { - return (): Promise => { - return Promise.resolve(options as string[]); - }; - } else if (typeof options === 'function') { - return async (): Promise => { - return options(); - }; - } + const peers = getPseudoRandomSubset(allPeers, maxPeers); + return (): Promise => Promise.resolve(peers); + } else if (typeof opts.getPeers === 'function') { + dbg('Bootstrap: Use provided getPeers function.'); + const getPeers = opts.getPeers; + + return async (): Promise => { + const allPeers = await getPeers(); + return getPseudoRandomSubset(allPeers, maxPeers).map( + (node) => new Multiaddr(node) + ); + }; + } else if (opts.enrUrl) { + const enrUrl = opts.enrUrl; + dbg('Bootstrap: Use provided EIP-1459 ENR Tree URL.'); + + const dns = DnsNodeDiscovery.dnsOverHttp(); + + return async (): Promise => { + const enrs = await dns.getPeers(maxPeers, [enrUrl]); + const addresses: Multiaddr[] = []; + enrs.forEach((enr) => { + if (!enr.multiaddrs) return; + + enr.multiaddrs.forEach((ma: Multiaddr) => { + // Only return secure websocket addresses + if (ma.protoNames().includes('wss')) { + addresses.push(ma); + } + }); + }); + return addresses; + }; + } else { + dbg('No bootstrap method specified, no peer will be returned'); + return (): Promise => Promise.resolve([]); } - return; } diff --git a/src/lib/discovery/hosted_json.ts b/src/lib/discovery/hosted_json.ts index bfabea3aca..111675e20d 100644 --- a/src/lib/discovery/hosted_json.ts +++ b/src/lib/discovery/hosted_json.ts @@ -28,7 +28,7 @@ export async function getNodesFromHostedJson( path: string[] = ['fleets', 'wakuv2.prod', 'waku-websocket'], url = 'https://fleets.status.im/', wantedNumber: number = DefaultWantedNumber -): Promise { +): Promise { if (wantedNumber <= 0) { return []; } @@ -54,12 +54,12 @@ export async function getNodesFromHostedJson( if (Array.isArray(nodes)) { return getPseudoRandomSubset(nodes, wantedNumber).map( - (node: string) => node + (node: string) => new Multiaddr(node) ); } if (typeof nodes === 'string') { - return [nodes]; + return [new Multiaddr(nodes)]; } if (typeof nodes === 'object') { diff --git a/src/lib/discovery/index.ts b/src/lib/discovery/index.ts index 5513e332c0..e3c9b429d4 100644 --- a/src/lib/discovery/index.ts +++ b/src/lib/discovery/index.ts @@ -3,10 +3,10 @@ import { shuffle } from 'libp2p-gossipsub/src/utils'; export { getNodesFromHostedJson } from './hosted_json'; export { parseBootstrap } from './bootstrap'; -export function getPseudoRandomSubset( - values: string[], +export function getPseudoRandomSubset( + values: T[], wantedNumber: number -): string[] { +): T[] { if (values.length <= wantedNumber) { return values; } diff --git a/src/lib/waku.node.spec.ts b/src/lib/waku.node.spec.ts index ce50591170..4e2a3cffd5 100644 --- a/src/lib/waku.node.spec.ts +++ b/src/lib/waku.node.spec.ts @@ -38,7 +38,7 @@ describe('Waku Dial [node only]', function () { waku = await Waku.create({ staticNoiseKey: NOISE_KEY_1, - bootstrap: true, + bootstrap: { default: true }, }); const connectedPeerID: PeerId = await new Promise((resolve) => { @@ -68,7 +68,7 @@ describe('Waku Dial [node only]', function () { libp2p: { modules: { transport: [TCP] }, }, - bootstrap: [multiAddrWithId], + bootstrap: { peers: [multiAddrWithId] }, }); const connectedPeerID: PeerId = await new Promise((resolve) => { @@ -102,8 +102,10 @@ describe('Waku Dial [node only]', function () { libp2p: { modules: { transport: [TCP] }, }, - bootstrap: () => { - return [multiAddrWithId]; + bootstrap: { + getPeers: async () => { + return [multiAddrWithId]; + }, }, }); diff --git a/src/lib/waku.ts b/src/lib/waku.ts index de942c89e7..f2cf1f85e8 100644 --- a/src/lib/waku.ts +++ b/src/lib/waku.ts @@ -19,6 +19,7 @@ import { Multiaddr, multiaddr } from 'multiaddr'; import PeerId from 'peer-id'; import { parseBootstrap } from './discovery'; +import { BootstrapOptions } from './discovery/bootstrap'; import { getPeersForProtocol } from './select_peer'; import { LightPushCodec, WakuLightPush } from './waku_light_push'; import { WakuMessage } from './waku_message'; @@ -86,12 +87,12 @@ export interface CreateOptions { /** * Use libp2p-bootstrap to discover and connect to new nodes. * - * See [BootstrapOptions] for available parameters. + * See [[BootstrapOptions]] for available parameters. * * Note: It overrides any other peerDiscovery modules that may have been set via * {@link CreateOptions.libp2p}. */ - bootstrap?: boolean | string[] | (() => string[] | Promise); + bootstrap?: BootstrapOptions; decryptionKeys?: Array; }