Fix-up new bootstrap API

This commit is contained in:
Franck Royer 2022-01-13 14:28:45 +11:00
parent e47335f4c0
commit 284644b822
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
9 changed files with 80 additions and 80 deletions

View File

@ -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. - Test: Upgrade nim-waku node to v0.6.
- **Breaking**: Renamed `getBootstrapNodes` to `getNodesFromHostedJson`. - **Breaking**: Renamed `getBootstrapNodes` to `getNodesFromHostedJson`.
- Minimum node version changed to 16. - 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 ### Fixed

View File

@ -11,7 +11,7 @@ export const PrivateMessageContentTopic =
'/eth-pm-wallet/1/private-message/proto'; '/eth-pm-wallet/1/private-message/proto';
export async function initWaku(): Promise<Waku> { export async function initWaku(): Promise<Waku> {
const waku = await Waku.create({ bootstrap: true }); const waku = await Waku.create({ bootstrap: { default: true } });
// Wait to be connected to at least one peer // Wait to be connected to at least one peer
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {

View File

@ -9,7 +9,7 @@ export const PublicKeyContentTopic = '/eth-pm/1/public-key/proto';
export const PrivateMessageContentTopic = '/eth-pm/1/private-message/proto'; export const PrivateMessageContentTopic = '/eth-pm/1/private-message/proto';
export async function initWaku(): Promise<Waku> { export async function initWaku(): Promise<Waku> {
const waku = await Waku.create({ bootstrap: true }); const waku = await Waku.create({ bootstrap: { default: true } });
// Wait to be connected to at least one peer // Wait to be connected to at least one peer
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {

View File

@ -1,6 +1,11 @@
import { useEffect, useReducer, useState } from 'react'; import { useEffect, useReducer, useState } from 'react';
import './App.css'; import './App.css';
import { PageDirection, getBootstrapNodes, Waku, WakuMessage } from 'js-waku'; import {
PageDirection,
getNodesFromHostedJson,
Waku,
WakuMessage,
} from 'js-waku';
import handleCommand from './command'; import handleCommand from './command';
import Room from './Room'; import Room from './Room';
import { WakuContext } from './WakuContext'; 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); setter(waku);

View File

@ -1,4 +1,5 @@
import debug from 'debug'; import debug from 'debug';
import { Multiaddr } from 'multiaddr';
import { DnsNodeDiscovery } from './dns'; import { DnsNodeDiscovery } from './dns';
@ -6,7 +7,9 @@ import { getNodesFromHostedJson, getPseudoRandomSubset } from './index';
const dbg = debug('waku:discovery:bootstrap'); const dbg = debug('waku:discovery:bootstrap');
const DefaultMaxPeers = 1; export const DefaultMaxPeers = 1;
export type BootstrapFn = () => Promise<Multiaddr[]>;
/** /**
* Setup discovery method used to bootstrap. * 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. * The maximum of peers to connect to as part of the bootstrap process.
* *
* @default 1 * @default {{DefaultMaxPeers}}
*/ */
maxPeers?: number; 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 * The default discovery method is likely to change overtime as new discovery
* methods are implemented. * methods are implemented.
@ -36,7 +39,7 @@ export interface BootstrapOptions {
/** /**
* Getter that retrieve multiaddrs of peers to connect to. * Getter that retrieve multiaddrs of peers to connect to.
*/ */
getPeers?: () => Promise<string[]>; getPeers?: () => Promise<string[] | Multiaddr[]>;
/** /**
* An EIP-1459 ENR Tree URL. For example: * An EIP-1459 ENR Tree URL. For example:
* "enrtree://AOFTICU2XWDULNLZGRMQS4RIZPAZEHYMV4FYHAPW563HNRAOERP7C@test.nodes.vac.dev" * "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. * Parse the bootstrap options and returns an async function that returns node addresses upon invocation.
*/ */
export function parseBootstrap( export function parseBootstrap(opts: BootstrapOptions): BootstrapFn {
options: const maxPeers = opts.maxPeers ?? DefaultMaxPeers;
| BootstrapOptions
| boolean
| string[]
| (() => string[] | Promise<string[]>)
): undefined | (() => Promise<string[]>) {
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;
if (opts.default) { if (opts.default) {
dbg('Bootstrap: Use hosted list of peers.'); dbg('Bootstrap: Use hosted list of peers.');
return getNodesFromHostedJson.bind({}, undefined, undefined, maxPeers); return getNodesFromHostedJson.bind({}, undefined, undefined, maxPeers);
} else if (opts.peers !== undefined && opts.peers.length > 0) { } else if (opts.peers !== undefined && opts.peers.length > 0) {
dbg('Bootstrap: Use provided list of peers.'); dbg('Bootstrap: Use provided list of peers.');
const allPeers: string[] = opts.peers; const allPeers: Multiaddr[] = opts.peers.map(
return (): Promise<string[]> => { (node: string) => new Multiaddr(node)
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<string[]> => {
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<string[]> =>
dns
.getPeers(maxPeers, [enrUrl])
.then((peers) => peers.map((peer) => peer.toString()));
}
} else {
dbg(
'WARN: This bootstrap method will be deprecated, use `BootstrapOptions` instead'
); );
if (options === true) { const peers = getPseudoRandomSubset(allPeers, maxPeers);
return getNodesFromHostedJson; return (): Promise<Multiaddr[]> => Promise.resolve(peers);
} else if (Array.isArray(options)) { } else if (typeof opts.getPeers === 'function') {
return (): Promise<string[]> => { dbg('Bootstrap: Use provided getPeers function.');
return Promise.resolve(options as string[]); const getPeers = opts.getPeers;
};
} else if (typeof options === 'function') { return async (): Promise<Multiaddr[]> => {
return async (): Promise<string[]> => { const allPeers = await getPeers();
return options(); return getPseudoRandomSubset<string | Multiaddr>(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<Multiaddr[]> => {
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<Multiaddr[]> => Promise.resolve([]);
} }
return;
} }

View File

@ -28,7 +28,7 @@ export async function getNodesFromHostedJson(
path: string[] = ['fleets', 'wakuv2.prod', 'waku-websocket'], path: string[] = ['fleets', 'wakuv2.prod', 'waku-websocket'],
url = 'https://fleets.status.im/', url = 'https://fleets.status.im/',
wantedNumber: number = DefaultWantedNumber wantedNumber: number = DefaultWantedNumber
): Promise<string[]> { ): Promise<Multiaddr[]> {
if (wantedNumber <= 0) { if (wantedNumber <= 0) {
return []; return [];
} }
@ -54,12 +54,12 @@ export async function getNodesFromHostedJson(
if (Array.isArray(nodes)) { if (Array.isArray(nodes)) {
return getPseudoRandomSubset(nodes, wantedNumber).map( return getPseudoRandomSubset(nodes, wantedNumber).map(
(node: string) => node (node: string) => new Multiaddr(node)
); );
} }
if (typeof nodes === 'string') { if (typeof nodes === 'string') {
return [nodes]; return [new Multiaddr(nodes)];
} }
if (typeof nodes === 'object') { if (typeof nodes === 'object') {

View File

@ -3,10 +3,10 @@ import { shuffle } from 'libp2p-gossipsub/src/utils';
export { getNodesFromHostedJson } from './hosted_json'; export { getNodesFromHostedJson } from './hosted_json';
export { parseBootstrap } from './bootstrap'; export { parseBootstrap } from './bootstrap';
export function getPseudoRandomSubset( export function getPseudoRandomSubset<T>(
values: string[], values: T[],
wantedNumber: number wantedNumber: number
): string[] { ): T[] {
if (values.length <= wantedNumber) { if (values.length <= wantedNumber) {
return values; return values;
} }

View File

@ -38,7 +38,7 @@ describe('Waku Dial [node only]', function () {
waku = await Waku.create({ waku = await Waku.create({
staticNoiseKey: NOISE_KEY_1, staticNoiseKey: NOISE_KEY_1,
bootstrap: true, bootstrap: { default: true },
}); });
const connectedPeerID: PeerId = await new Promise((resolve) => { const connectedPeerID: PeerId = await new Promise((resolve) => {
@ -68,7 +68,7 @@ describe('Waku Dial [node only]', function () {
libp2p: { libp2p: {
modules: { transport: [TCP] }, modules: { transport: [TCP] },
}, },
bootstrap: [multiAddrWithId], bootstrap: { peers: [multiAddrWithId] },
}); });
const connectedPeerID: PeerId = await new Promise((resolve) => { const connectedPeerID: PeerId = await new Promise((resolve) => {
@ -102,8 +102,10 @@ describe('Waku Dial [node only]', function () {
libp2p: { libp2p: {
modules: { transport: [TCP] }, modules: { transport: [TCP] },
}, },
bootstrap: () => { bootstrap: {
return [multiAddrWithId]; getPeers: async () => {
return [multiAddrWithId];
},
}, },
}); });

View File

@ -19,6 +19,7 @@ import { Multiaddr, multiaddr } from 'multiaddr';
import PeerId from 'peer-id'; import PeerId from 'peer-id';
import { parseBootstrap } from './discovery'; import { parseBootstrap } from './discovery';
import { BootstrapOptions } from './discovery/bootstrap';
import { getPeersForProtocol } from './select_peer'; import { getPeersForProtocol } from './select_peer';
import { LightPushCodec, WakuLightPush } from './waku_light_push'; import { LightPushCodec, WakuLightPush } from './waku_light_push';
import { WakuMessage } from './waku_message'; import { WakuMessage } from './waku_message';
@ -86,12 +87,12 @@ export interface CreateOptions {
/** /**
* Use libp2p-bootstrap to discover and connect to new nodes. * 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 * Note: It overrides any other peerDiscovery modules that may have been set via
* {@link CreateOptions.libp2p}. * {@link CreateOptions.libp2p}.
*/ */
bootstrap?: boolean | string[] | (() => string[] | Promise<string[]>); bootstrap?: BootstrapOptions;
decryptionKeys?: Array<Uint8Array | string>; decryptionKeys?: Array<Uint8Array | string>;
} }