Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: simplify discv5 initialization #5456

Merged
merged 5 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions packages/beacon-node/src/network/discv5/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,16 @@ import EventEmitter from "events";
import {PeerId} from "@libp2p/interface-peer-id";
import StrictEventEmitter from "strict-event-emitter-types";
import {exportToProtobuf} from "@libp2p/peer-id-factory";
import {
createKeypairFromPeerId,
ENR,
ENRData,
IDiscv5DiscoveryInputOptions,
IKeypair,
SignableENR,
} from "@chainsafe/discv5";
import {createKeypairFromPeerId, ENR, ENRData, IKeypair, SignableENR} from "@chainsafe/discv5";
import {spawn, Thread, Worker} from "@chainsafe/threads";
import {chainConfigFromJson, chainConfigToJson, BeaconConfig} from "@lodestar/config";
import {Logger} from "@lodestar/utils";
import {NetworkCoreMetrics} from "../core/metrics.js";
import {Discv5WorkerApi, Discv5WorkerData} from "./types.js";
import {Discv5WorkerApi, Discv5WorkerData, LodestarDiscv5Opts} from "./types.js";

export type Discv5Opts = {
peerId: PeerId;
discv5: Omit<IDiscv5DiscoveryInputOptions, "metrics" | "searchInterval" | "enabled">;
discv5: LodestarDiscv5Opts;
logger: Logger;
config: BeaconConfig;
metrics?: NetworkCoreMetrics;
Expand Down Expand Up @@ -52,10 +45,10 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter<E
if (this.status.status === "started") return;

const workerData: Discv5WorkerData = {
enr: (this.opts.discv5.enr as SignableENR).toObject(),
enr: this.opts.discv5.enr,
peerIdProto: exportToProtobuf(this.opts.peerId),
bindAddr: this.opts.discv5.bindAddr,
config: this.opts.discv5,
config: this.opts.discv5.config,
bootEnrs: this.opts.discv5.bootEnrs as string[],
metrics: Boolean(this.opts.metrics),
chainConfig: chainConfigFromJson(chainConfigToJson(this.opts.config)),
Expand Down
9 changes: 8 additions & 1 deletion packages/beacon-node/src/network/discv5/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@ import {ChainConfig} from "@lodestar/config";
// TODO export IDiscv5Config so we don't need this convoluted type
type Discv5Config = Parameters<(typeof Discv5)["create"]>[0]["config"];

export type LodestarDiscv5Opts = {
config?: Discv5Config;
enr: string;
bindAddr: string;
bootEnrs: string[];
};

/** discv5 worker constructor data */
export interface Discv5WorkerData {
enr: SignableENRData;
enr: string;
peerIdProto: Uint8Array;
bindAddr: string;
config: Discv5Config;
Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/src/network/discv5/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const config = createBeaconConfig(workerData.chainConfig, workerData.genesisVali

// Initialize discv5
const discv5 = Discv5.create({
enr: new SignableENR(workerData.enr.kvs, workerData.enr.seq, keypair),
enr: SignableENR.decodeTxt(workerData.enr, keypair),
peerId,
multiaddr: multiaddr(workerData.bindAddr),
config: workerData.config,
Expand Down
14 changes: 3 additions & 11 deletions packages/beacon-node/src/network/nodejs/util.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {PeerId} from "@libp2p/interface-peer-id";
import {Registry} from "prom-client";
import {ENR, SignableENR} from "@chainsafe/discv5";
import {ENR} from "@chainsafe/discv5";
import {Libp2p} from "../interface.js";
import {Eth2PeerDataStore} from "../peers/datastore.js";
import {defaultDiscv5Options, defaultNetworkOptions, NetworkOptions} from "../options.js";
import {defaultNetworkOptions, NetworkOptions} from "../options.js";
import {createNodejsLibp2p as _createNodejsLibp2p} from "./bundle.js";

export type NodeJsLibp2pOpts = {
Expand All @@ -27,13 +27,8 @@ export async function createNodeJsLibp2p(
const peerId = await Promise.resolve(peerIdOrPromise);
const localMultiaddrs = networkOpts.localMultiaddrs || defaultNetworkOptions.localMultiaddrs;
const bootMultiaddrs = networkOpts.bootMultiaddrs || defaultNetworkOptions.bootMultiaddrs;
const enr = networkOpts.discv5?.enr;
const {peerStoreDir, disablePeerDiscovery} = nodeJsLibp2pOpts;

if (enr !== undefined && typeof enr !== "string" && !(enr instanceof SignableENR)) {
throw Error("network.discv5.enr must be an instance of SignableENR");
}

let datastore: undefined | Eth2PeerDataStore = undefined;
if (peerStoreDir) {
datastore = new Eth2PeerDataStore(peerStoreDir);
Expand All @@ -45,10 +40,7 @@ export async function createNodeJsLibp2p(
if (!networkOpts.bootMultiaddrs) {
networkOpts.bootMultiaddrs = [];
}
if (!networkOpts.discv5) {
networkOpts.discv5 = defaultDiscv5Options;
}
for (const enrOrStr of networkOpts.discv5.bootEnrs) {
for (const enrOrStr of networkOpts.discv5?.bootEnrs ?? []) {
const enr = typeof enrOrStr === "string" ? ENR.decodeTxt(enrOrStr) : enrOrStr;
const fullMultiAddr = await enr.getFullMultiaddr("tcp");
const multiaddrWithPeerId = fullMultiAddr?.toString();
Expand Down
12 changes: 2 additions & 10 deletions packages/beacon-node/src/network/options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {generateKeypair, IDiscv5DiscoveryInputOptions, KeypairType, SignableENR} from "@chainsafe/discv5";
import {Eth2GossipsubOpts} from "./gossip/gossipsub.js";
import {defaultGossipHandlerOpts} from "./processor/gossipHandlers.js";
import {PeerManagerOpts} from "./peers/index.js";
Expand All @@ -20,22 +19,15 @@ export interface NetworkOptions
version?: string;
}

export const defaultDiscv5Options: IDiscv5DiscoveryInputOptions = {
bindAddr: "/ip4/0.0.0.0/udp/9000",
enr: SignableENR.createV4(generateKeypair(KeypairType.Secp256k1)),
bootEnrs: [],
enrUpdate: true,
enabled: true,
};

export const defaultNetworkOptions: NetworkOptions = {
maxPeers: 55, // Allow some room above targetPeers for new inbound peers
targetPeers: 50,
discv5FirstQueryDelayMs: 1000,
localMultiaddrs: ["/ip4/0.0.0.0/tcp/9000"],
bootMultiaddrs: [],
mdns: false,
discv5: defaultDiscv5Options,
/** disabled by default */
discv5: null,
wemeetagain marked this conversation as resolved.
Show resolved Hide resolved
rateLimitMultiplier: 1,
// TODO: this value is 12 per spec, however lodestar has performance issue if there are too many mesh peers
// see https://github.com/ChainSafe/lodestar/issues/5420
Expand Down
5 changes: 3 additions & 2 deletions packages/beacon-node/src/network/peers/discover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import {Multiaddr} from "@multiformats/multiaddr";
import {PeerInfo} from "@libp2p/interface-peer-info";
import {BeaconConfig} from "@lodestar/config";
import {Logger, pruneSetToMax, sleep} from "@lodestar/utils";
import {ENR, IDiscv5DiscoveryInputOptions} from "@chainsafe/discv5";
import {ENR} from "@chainsafe/discv5";
import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
import {NetworkCoreMetrics} from "../core/metrics.js";
import {Libp2p} from "../interface.js";
import {ENRKey, SubnetType} from "../metadata.js";
import {getConnectionsMap, getDefaultDialer, prettyPrintPeerId} from "../util.js";
import {Discv5Worker} from "../discv5/index.js";
import {LodestarDiscv5Opts} from "../discv5/types.js";
import {IPeerRpcScoreStore, ScoreState} from "./score.js";
import {deserializeEnrSubnets, zeroAttnets, zeroSyncnets} from "./utils/enrSubnetsDeserialize.js";

Expand All @@ -21,7 +22,7 @@ const MAX_CACHED_ENR_AGE_MS = 5 * 60 * 1000;
export type PeerDiscoveryOpts = {
maxPeers: number;
discv5FirstQueryDelayMs: number;
discv5: Omit<IDiscv5DiscoveryInputOptions, "metrics" | "searchInterval" | "enabled">;
discv5: LodestarDiscv5Opts;
connectToDiscv5Bootnodes?: boolean;
};

Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/src/network/peers/peerManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {Connection} from "@libp2p/interface-connection";
import {PeerId} from "@libp2p/interface-peer-id";
import {IDiscv5DiscoveryInputOptions} from "@chainsafe/discv5";
import {BitArray} from "@chainsafe/ssz";
import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
import {BeaconConfig} from "@lodestar/config";
Expand All @@ -17,6 +16,7 @@ import {SubnetType} from "../metadata.js";
import {Eth2Gossipsub} from "../gossip/gossipsub.js";
import {StatusCache} from "../statusCache.js";
import {IClock} from "../../util/clock.js";
import {LodestarDiscv5Opts} from "../discv5/types.js";
import {PeersData, PeerData} from "./peersData.js";
import {PeerDiscovery, SubnetDiscvQueryMs} from "./discover.js";
import {IPeerRpcScoreStore, ScoreState, updateGossipsubScores} from "./score.js";
Expand Down Expand Up @@ -74,7 +74,7 @@ export type PeerManagerOpts = {
/**
* If null, Don't run discv5 queries, nor connect to cached peers in the peerStore
*/
discv5: IDiscv5DiscoveryInputOptions | null;
discv5: LodestarDiscv5Opts | null;
/**
* If set to true, connect to Discv5 bootnodes. If not set or false, do not connect
*/
Expand Down
3 changes: 1 addition & 2 deletions packages/beacon-node/test/e2e/network/mdns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ describe.skip("mdns", function () {
localMultiaddrs: [],
discv5FirstQueryDelayMs: 0,
discv5: {
enr,
enr: enr.encodeTxt(),
bindAddr: bindAddrUdp,
bootEnrs: [],
enabled: true,
},
};
}
Expand Down
8 changes: 4 additions & 4 deletions packages/beacon-node/test/unit/network/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ describe("createNodeJsLibp2p", () => {
"enr:-LK4QDiPGwNomqUqNDaM3iHYvtdX7M5qngson6Qb2xGIg1LwC8-Nic0aQwO0rVbJt5xp32sRE3S1YqvVrWO7OgVNv0kBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpA7CIeVAAAgCf__________gmlkgnY0gmlwhBKNA4qJc2VjcDI1NmsxoQKbBS4ROQ_sldJm5tMgi36qm5I5exKJFb4C8dDVS_otAoN0Y3CCIyiDdWRwgiMo",
];
const bootMultiaddrs: string[] = [];
const keypair = generateKeypair(KeypairType.Secp256k1);
await createNodeJsLibp2p(
peerId,
{
connectToDiscv5Bootnodes: true,
discv5: {
enabled: false,
enr: SignableENR.createV4(generateKeypair(KeypairType.Secp256k1)),
enr: SignableENR.createV4(keypair).encodeTxt(),
bindAddr: "/ip4/127.0.0.1/udp/0",
bootEnrs: enrWithTcp,
},
Expand All @@ -74,13 +74,13 @@ describe("createNodeJsLibp2p", () => {
"enr:-Ku4QCFQW96tEDYPjtaueW3WIh1CB0cJnvw_ibx5qIFZGqfLLj-QajMX6XwVs2d4offuspwgH3NkIMpWtCjCytVdlywGh2F0dG5ldHOIEAIAAgABAUyEZXRoMpCi7FS9AQAAAAAiAQAAAAAAgmlkgnY0gmlwhFA4VK6Jc2VjcDI1NmsxoQNGH1sJJS86-0x9T7qQewz9Wn9zlp6bYxqqrR38JQ49yIN1ZHCCIyg",
];
const bootMultiaddrs: string[] = [];
const keypair = generateKeypair(KeypairType.Secp256k1);
await createNodeJsLibp2p(
peerId,
{
connectToDiscv5Bootnodes: true,
discv5: {
enabled: false,
enr: SignableENR.createV4(generateKeypair(KeypairType.Secp256k1)),
enr: SignableENR.createV4(keypair).encodeTxt(),
bindAddr: "/ip4/127.0.0.1/udp/0",
bootEnrs: enrWithoutTcp,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cmds/beacon/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export async function beaconHandlerInit(args: BeaconArgs & GlobalArgs) {
const logger = initLogger(args, beaconPaths.dataDir, config);
const {peerId, enr} = await initPeerIdAndEnr(args, beaconPaths.beaconDir, logger);
// Inject ENR to beacon options
beaconNodeOptions.set({network: {discv5: {enr, enrUpdate: !enr.ip && !enr.ip6}}});
beaconNodeOptions.set({network: {discv5: {enr: enr.encodeTxt(), config: {enrUpdate: !enr.ip && !enr.ip6}}}});
// Add simple version string for libp2p agent version
beaconNodeOptions.set({network: {version: version.split("/")[0]}});

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/options/beaconNodeOptions/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function parseArgs(args: NetworkArgs): IBeaconNodeOptions["network"] {
}
return {
discv5: {
enabled: args["discv5"] ?? true,
config: {},
bindAddr: `/ip4/${listenAddress}/udp/${udpPort}`,
// TODO: Okay to set to empty array?
bootEnrs: args["bootnodes"] ?? [],
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/test/unit/cmds/beacon.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {createFromJSON, createSecp256k1PeerId} from "@libp2p/peer-id-factory";
import {multiaddr} from "@multiformats/multiaddr";
import {chainConfig} from "@lodestar/config/default";
import {chainConfigToJson} from "@lodestar/config";
import {createKeypairFromPeerId, SignableENR} from "@chainsafe/discv5";
import {createKeypairFromPeerId, ENR, SignableENR} from "@chainsafe/discv5";
import {exportToJSON} from "../../../src/config/peerId.js";
import {beaconHandlerInit} from "../../../src/cmds/beacon/handler.js";
import {initPeerIdAndEnr, isLocalMultiAddr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js";
Expand Down Expand Up @@ -43,7 +43,7 @@ describe("cmds / beacon / args handler", () => {
nat: true,
});

const enr = options.network.discv5?.enr as SignableENR;
const enr = ENR.decodeTxt(options.network.discv5?.enr as string);

expect(enr.ip).to.equal(enrIp, "wrong enr.ip");
expect(enr.tcp).to.equal(enrTcp, "wrong enr.tcp");
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/unit/options/beaconNodeOptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ describe("options / beaconNodeOptions", () => {
},
network: {
discv5: {
enabled: true,
config: {},
bindAddr: "/ip4/127.0.0.1/udp/9002",
bootEnrs: ["enr:-somedata"],
},
Expand Down