@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
92 lines • 3.32 kB
JavaScript
import EventEmitter from "node:events";
import { ENR, SignableENR } from "@chainsafe/enr";
import { Thread, Worker, spawn } from "@chainsafe/threads";
import { privateKeyToProtobuf } from "@libp2p/crypto/keys";
import { chainConfigFromJson, chainConfigToJson } from "@lodestar/config";
/**
* Wrapper class abstracting the details of discv5 worker instantiation and message-passing
*/
export class Discv5Worker extends EventEmitter {
constructor(opts, workerApi) {
super();
this.opts = opts;
this.workerApi = workerApi;
this.closed = false;
this.subscription = workerApi.discovered().subscribe((enrObj) => this.onDiscovered(enrObj));
}
static async init(opts) {
const workerData = {
enr: opts.discv5.enr,
privateKeyProto: privateKeyToProtobuf(opts.privateKey),
bindAddrs: opts.discv5.bindAddrs,
config: opts.discv5.config ?? {},
bootEnrs: opts.discv5.bootEnrs,
metrics: Boolean(opts.metrics),
chainConfig: chainConfigFromJson(chainConfigToJson(opts.config)),
genesisValidatorsRoot: opts.config.genesisValidatorsRoot,
loggerOpts: opts.logger.toOpts(),
genesisTime: opts.genesisTime,
};
const worker = new Worker("./worker.js", { workerData });
const workerApi = await spawn(worker, {
// A Lodestar Node may do very expensive task at start blocking the event loop and causing
// the initialization to timeout. The number below is big enough to almost disable the timeout
timeout: 5 * 60 * 1000,
});
return new Discv5Worker(opts, workerApi);
}
async close() {
if (this.closed)
return;
this.closed = true;
this.subscription.unsubscribe();
await this.workerApi.close();
await Thread.terminate(this.workerApi);
}
onDiscovered(obj) {
const enr = this.decodeEnr(obj);
if (enr) {
this.emit("discovered", enr);
}
}
async enr() {
const obj = await this.workerApi.enr();
return new SignableENR(obj.kvs, obj.seq, this.opts.privateKey.raw);
}
setEnrValue(key, value) {
return this.workerApi.setEnrValue(key, value);
}
async kadValues() {
return this.decodeEnrs(await this.workerApi.kadValues());
}
discoverKadValues() {
return this.workerApi.discoverKadValues();
}
async findRandomNode() {
return this.decodeEnrs(await this.workerApi.findRandomNode());
}
scrapeMetrics() {
return this.workerApi.scrapeMetrics();
}
async writeProfile(durationMs, dirpath) {
return this.workerApi.writeProfile(durationMs, dirpath);
}
async writeHeapSnapshot(prefix, dirpath) {
return this.workerApi.writeHeapSnapshot(prefix, dirpath);
}
decodeEnrs(objs) {
const enrs = [];
for (const obj of objs) {
const enr = this.decodeEnr(obj);
if (enr) {
enrs.push(enr);
}
}
return enrs;
}
decodeEnr(obj) {
this.opts.metrics?.discv5.decodeEnrAttemptCount.inc(1);
return new ENR(obj.kvs, obj.seq, obj.signature);
}
}
//# sourceMappingURL=index.js.map