Predefine bootstrap node (#528)

This commit is contained in:
Franck R 2022-02-16 11:43:57 +11:00 committed by GitHub
parent 9e6cb1faaa
commit 146c67e43e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 99 additions and 92 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ran `npm audit fix`. - Ran `npm audit fix`.
- `Waku.dial` accepts protocols expected from the peer. Defaults to Waku Relay only. - `Waku.dial` accepts protocols expected from the peer. Defaults to Waku Relay only.
- Deprecated `hexToBuf` & `bufToHex` in favour of `hexToBytes` & `bytesToHex` to move towards removing the `buffer` polyfill. - Deprecated `hexToBuf` & `bufToHex` in favour of `hexToBytes` & `bytesToHex` to move towards removing the `buffer` polyfill.
- **Breaking**: Replaced `getNodesFromHostedJson` with `getPredefinedBootstrapNodes`. Now, it uses a hardcoded list of nodes.
### Removed ### Removed

View File

@ -2,7 +2,7 @@ import { useEffect, useReducer, useState } from "react";
import "./App.css"; import "./App.css";
import { import {
PageDirection, PageDirection,
getNodesFromHostedJson, getPredefinedBootstrapNodes,
Waku, Waku,
WakuMessage, WakuMessage,
} from "js-waku"; } from "js-waku";
@ -12,6 +12,7 @@ import { WakuContext } from "./WakuContext";
import { ThemeProvider } from "@livechat/ui-kit"; import { ThemeProvider } from "@livechat/ui-kit";
import { generate } from "server-name-generator"; import { generate } from "server-name-generator";
import { Message } from "./Message"; import { Message } from "./Message";
import { Fleet } from "js-waku/lib/discovery/predefined";
const themes = { const themes = {
AuthorName: { AuthorName: {
@ -184,7 +185,8 @@ async function initWaku(setter: (waku: Waku) => void) {
}, },
}, },
bootstrap: { bootstrap: {
getPeers: getNodesFromHostedJson.bind({}, selectFleetEnv()), getPeers: () =>
Promise.resolve(getPredefinedBootstrapNodes(selectFleetEnv())),
}, },
}); });
@ -197,9 +199,9 @@ async function initWaku(setter: (waku: Waku) => void) {
function selectFleetEnv() { function selectFleetEnv() {
// Works with react-scripts // Works with react-scripts
if (process?.env?.NODE_ENV === "development") { if (process?.env?.NODE_ENV === "development") {
return ["fleets", "wakuv2.test", "waku-websocket"]; return Fleet.Test;
} else { } else {
return ["fleets", "wakuv2.prod", "waku-websocket"]; return Fleet.Prod;
} }
} }

View File

@ -1,4 +1,4 @@
export { getNodesFromHostedJson } from "./lib/discovery"; export { getPredefinedBootstrapNodes } from "./lib/discovery";
export * as discovery from "./lib/discovery"; export * as discovery from "./lib/discovery";
export * as enr from "./lib/enr"; export * as enr from "./lib/enr";

View File

@ -3,7 +3,7 @@ import { Multiaddr } from "multiaddr";
import { DnsNodeDiscovery } from "./dns"; import { DnsNodeDiscovery } from "./dns";
import { getNodesFromHostedJson, getPseudoRandomSubset } from "./index"; import { getPredefinedBootstrapNodes, getPseudoRandomSubset } from "./index";
const dbg = debug("waku:discovery:bootstrap"); const dbg = debug("waku:discovery:bootstrap");
@ -57,12 +57,11 @@ export class Bootstrap {
if (opts.default) { if (opts.default) {
dbg("Use hosted list of peers."); dbg("Use hosted list of peers.");
this.getBootstrapPeers = getNodesFromHostedJson.bind( this.getBootstrapPeers = (): Promise<Multiaddr[]> => {
{}, return Promise.resolve(
undefined, getPredefinedBootstrapNodes(undefined, maxPeers)
undefined,
maxPeers
); );
};
} else if (opts.peers !== undefined && opts.peers.length > 0) { } else if (opts.peers !== undefined && opts.peers.length > 0) {
const allPeers: Multiaddr[] = opts.peers.map( const allPeers: Multiaddr[] = opts.peers.map(
(node: string) => new Multiaddr(node) (node: string) => new Multiaddr(node)

View File

@ -1,70 +0,0 @@
/**
* GET list of nodes from remote HTTP host.
*
* Default behavior 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. For example, if the GET
* request returns `{ foo: { bar: [address1, address2] } }` then `path` should be
* `[ "foo", "bar" ]`.
* @param url Remote host containing bootstrap peers in JSON format.
* @param wantedNumber The number of connections desired. Defaults to [DefaultWantedNumber].
*
* @returns An array of multiaddresses.
* @throws If the remote host is unreachable or the response cannot be parsed
* according to the passed _path_.
*/
import debug from "debug";
import { Multiaddr } from "multiaddr";
import { getPseudoRandomSubset } from "./index";
const dbg = debug("waku:discovery");
const DefaultWantedNumber = 1;
export async function getNodesFromHostedJson(
path: string[] = ["fleets", "wakuv2.prod", "waku-websocket"],
url = "https://fleets.status.im/",
wantedNumber: number = DefaultWantedNumber
): Promise<Multiaddr[]> {
if (wantedNumber <= 0) {
return [];
}
const res = await fetch(url);
let nodes = await res.json();
for (const prop of path) {
if (nodes[prop] === undefined) {
dbg(
`Failed to retrieve bootstrap nodes: ${prop} does not exist on `,
nodes
);
throw `Failed to retrieve bootstrap nodes: ${prop} does not exist on ${JSON.stringify(
nodes
)}`;
}
nodes = nodes[prop];
}
if (Array.isArray(nodes)) {
return getPseudoRandomSubset(nodes, wantedNumber).map(
(node: string) => new Multiaddr(node)
);
}
if (typeof nodes === "string") {
return [new Multiaddr(nodes)];
}
if (typeof nodes === "object") {
nodes = Object.values(nodes) as string[];
nodes = nodes.map((node: string) => new Multiaddr(node));
return getPseudoRandomSubset(nodes, wantedNumber);
}
throw `Failed to retrieve bootstrap nodes: response format is not supported: ${JSON.stringify(
nodes
)}`;
}

View File

@ -1,6 +1,8 @@
import { expect } from "chai"; import { expect } from "chai";
import { getNodesFromHostedJson, getPseudoRandomSubset } from "./index"; import { fleets } from "./predefined";
import { getPseudoRandomSubset } from "./index";
declare global { declare global {
interface Window { interface Window {
@ -51,14 +53,15 @@ describe("Discovery [live data]", function () {
} }
}); });
it("Returns nodes from default hosted JSON [live data]", async function () { it("Check pre-defined nodes against hosted JSON [live data]", async function () {
const res = await getNodesFromHostedJson( const res = await fetch("https://fleets.status.im/");
["fleets", "wakuv2.prod", "waku-websocket"], const nodes = await res.json();
"https://fleets.status.im/",
3
);
expect(res.length).to.eq(3); expect(fleets.fleets["wakuv2.prod"]["waku-websocket"]).to.deep.eq(
expect(res[0].toString()).to.not.be.undefined; nodes.fleets["wakuv2.prod"]["waku-websocket"]
);
expect(fleets.fleets["wakuv2.test"]["waku-websocket"]).to.deep.eq(
nodes.fleets["wakuv2.test"]["waku-websocket"]
);
}); });
}); });

View File

@ -1,6 +1,7 @@
import { shuffle } from "libp2p-gossipsub/src/utils"; import { shuffle } from "libp2p-gossipsub/src/utils";
export { getNodesFromHostedJson } from "./hosted_json"; export { getPredefinedBootstrapNodes } from "./predefined";
export * as predefined from "./predefined";
export { Bootstrap, BootstrapOptions } from "./bootstrap"; export { Bootstrap, BootstrapOptions } from "./bootstrap";
export { DnsClient, DnsNodeDiscovery, SearchContext } from "./dns"; export { DnsClient, DnsNodeDiscovery, SearchContext } from "./dns";
export { Endpoints, DnsOverHttps } from "./dns_over_https"; export { Endpoints, DnsOverHttps } from "./dns_over_https";

View File

@ -0,0 +1,71 @@
import { Multiaddr } from "multiaddr";
import { getPseudoRandomSubset } from "./index";
export const DefaultWantedNumber = 1;
export enum Fleet {
Prod = "prod",
Test = "test",
}
/**
* Return list of pre-defined (hardcoded) bootstrap nodes.
*
* Default behavior is to return nodes of the nim-waku Status Prod fleet.
*
* @param fleet The fleet to be returned. Defaults to production fleet.
* @param wantedNumber The number of connections desired. Defaults to [[DefaultWantedNumber]].
*
* @returns An array of multiaddresses.
*/
export function getPredefinedBootstrapNodes(
fleet: Fleet = Fleet.Prod,
wantedNumber: number = DefaultWantedNumber
): Multiaddr[] {
if (wantedNumber <= 0) {
return [];
}
let nodes;
switch (fleet) {
case Fleet.Prod:
nodes = fleets.fleets["wakuv2.prod"]["waku-websocket"];
break;
case Fleet.Test:
nodes = fleets.fleets["wakuv2.test"]["waku-websocket"];
break;
default:
nodes = fleets.fleets["wakuv2.prod"]["waku-websocket"];
}
nodes = Object.values(nodes) as string[];
nodes = nodes.map((node: string) => new Multiaddr(node));
return getPseudoRandomSubset(nodes, wantedNumber);
}
export const fleets = {
fleets: {
"wakuv2.prod": {
"waku-websocket": {
"node-01.ac-cn-hongkong-c.wakuv2.prod":
"/dns4/node-01.ac-cn-hongkong-c.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr24iDQpSN5Qa992BCjjwgrD",
"node-01.do-ams3.wakuv2.prod":
"/dns4/node-01.do-ams3.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e",
"node-01.gc-us-central1-a.wakuv2.prod":
"/dns4/node-01.gc-us-central1-a.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmVkKntsECaYfefR1V2yCR79CegLATuTPE6B9TxgxBiiiA",
},
},
"wakuv2.test": {
"waku-websocket": {
"node-01.ac-cn-hongkong-c.wakuv2.test":
"/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
"node-01.do-ams3.wakuv2.test":
"/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
"node-01.gc-us-central1-a.wakuv2.test":
"/dns4/node-01.gc-us-central1-a.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS",
},
},
},
};