diff --git a/CHANGELOG.md b/CHANGELOG.md index e48fc42054..b9501170fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ran `npm audit fix`. - `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. +- **Breaking**: Replaced `getNodesFromHostedJson` with `getPredefinedBootstrapNodes`. Now, it uses a hardcoded list of nodes. ### Removed diff --git a/examples/web-chat/src/App.tsx b/examples/web-chat/src/App.tsx index 958c4dec0e..da1947165e 100644 --- a/examples/web-chat/src/App.tsx +++ b/examples/web-chat/src/App.tsx @@ -2,7 +2,7 @@ import { useEffect, useReducer, useState } from "react"; import "./App.css"; import { PageDirection, - getNodesFromHostedJson, + getPredefinedBootstrapNodes, Waku, WakuMessage, } from "js-waku"; @@ -12,6 +12,7 @@ import { WakuContext } from "./WakuContext"; import { ThemeProvider } from "@livechat/ui-kit"; import { generate } from "server-name-generator"; import { Message } from "./Message"; +import { Fleet } from "js-waku/lib/discovery/predefined"; const themes = { AuthorName: { @@ -184,7 +185,8 @@ async function initWaku(setter: (waku: Waku) => void) { }, }, bootstrap: { - getPeers: getNodesFromHostedJson.bind({}, selectFleetEnv()), + getPeers: () => + Promise.resolve(getPredefinedBootstrapNodes(selectFleetEnv())), }, }); @@ -197,9 +199,9 @@ async function initWaku(setter: (waku: Waku) => void) { function selectFleetEnv() { // Works with react-scripts if (process?.env?.NODE_ENV === "development") { - return ["fleets", "wakuv2.test", "waku-websocket"]; + return Fleet.Test; } else { - return ["fleets", "wakuv2.prod", "waku-websocket"]; + return Fleet.Prod; } } diff --git a/src/index.ts b/src/index.ts index 0938485c5c..8624fd92fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -export { getNodesFromHostedJson } from "./lib/discovery"; +export { getPredefinedBootstrapNodes } from "./lib/discovery"; export * as discovery from "./lib/discovery"; export * as enr from "./lib/enr"; diff --git a/src/lib/discovery/bootstrap.ts b/src/lib/discovery/bootstrap.ts index bc56cd14c9..a830ed2931 100644 --- a/src/lib/discovery/bootstrap.ts +++ b/src/lib/discovery/bootstrap.ts @@ -3,7 +3,7 @@ import { Multiaddr } from "multiaddr"; import { DnsNodeDiscovery } from "./dns"; -import { getNodesFromHostedJson, getPseudoRandomSubset } from "./index"; +import { getPredefinedBootstrapNodes, getPseudoRandomSubset } from "./index"; const dbg = debug("waku:discovery:bootstrap"); @@ -57,12 +57,11 @@ export class Bootstrap { if (opts.default) { dbg("Use hosted list of peers."); - this.getBootstrapPeers = getNodesFromHostedJson.bind( - {}, - undefined, - undefined, - maxPeers - ); + this.getBootstrapPeers = (): Promise => { + return Promise.resolve( + getPredefinedBootstrapNodes(undefined, maxPeers) + ); + }; } else if (opts.peers !== undefined && opts.peers.length > 0) { const allPeers: Multiaddr[] = opts.peers.map( (node: string) => new Multiaddr(node) diff --git a/src/lib/discovery/hosted_json.ts b/src/lib/discovery/hosted_json.ts deleted file mode 100644 index 2f827ff0b4..0000000000 --- a/src/lib/discovery/hosted_json.ts +++ /dev/null @@ -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 { - 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 - )}`; -} diff --git a/src/lib/discovery/index.spec.ts b/src/lib/discovery/index.spec.ts index 437024cec5..63862250ff 100644 --- a/src/lib/discovery/index.spec.ts +++ b/src/lib/discovery/index.spec.ts @@ -1,6 +1,8 @@ import { expect } from "chai"; -import { getNodesFromHostedJson, getPseudoRandomSubset } from "./index"; +import { fleets } from "./predefined"; + +import { getPseudoRandomSubset } from "./index"; declare global { interface Window { @@ -51,14 +53,15 @@ describe("Discovery [live data]", function () { } }); - it("Returns nodes from default hosted JSON [live data]", async function () { - const res = await getNodesFromHostedJson( - ["fleets", "wakuv2.prod", "waku-websocket"], - "https://fleets.status.im/", - 3 - ); + it("Check pre-defined nodes against hosted JSON [live data]", async function () { + const res = await fetch("https://fleets.status.im/"); + const nodes = await res.json(); - expect(res.length).to.eq(3); - expect(res[0].toString()).to.not.be.undefined; + expect(fleets.fleets["wakuv2.prod"]["waku-websocket"]).to.deep.eq( + nodes.fleets["wakuv2.prod"]["waku-websocket"] + ); + expect(fleets.fleets["wakuv2.test"]["waku-websocket"]).to.deep.eq( + nodes.fleets["wakuv2.test"]["waku-websocket"] + ); }); }); diff --git a/src/lib/discovery/index.ts b/src/lib/discovery/index.ts index e1c03ec154..7b927f76dd 100644 --- a/src/lib/discovery/index.ts +++ b/src/lib/discovery/index.ts @@ -1,6 +1,7 @@ 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 { DnsClient, DnsNodeDiscovery, SearchContext } from "./dns"; export { Endpoints, DnsOverHttps } from "./dns_over_https"; diff --git a/src/lib/discovery/predefined.ts b/src/lib/discovery/predefined.ts new file mode 100644 index 0000000000..de74409ad3 --- /dev/null +++ b/src/lib/discovery/predefined.ts @@ -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", + }, + }, + }, +};