Skip to content

3.1 Code Lodestar CLI Beacon Node

From lodestar documentation:

It's codebase start with packages/beacon-node folder.

From CLI#

packages/cli/src/cmds/beacon/index.ts

export const beacon: ICliCommand<IBeaconArgs, IGlobalArgs> = {
  command: "beacon",
  // ...
  // Below points to beaconHandler
  handler: beaconHandler,
};

beaconHandler is the main function defined in handler.ts. It starts the database and initialize the node:

const node = await BeaconNode.init({
  opts: options,
  config: beaconConfig,
  db, // a 'level' db connection.
  logger,
  processShutdownCallback, // used during fatal error to shutdown the node.
  libp2p: await createNodeJsLibp2p(peerId, options.network, {
    peerStoreDir: beaconPaths.peerStoreDir,
    metrics: options.metrics.enabled,
    metricsRegistry: networkRegistry,
  }), // initialize p2p network, which will be used later for gossipsub. peerId is created or retrieved from file.
  anchorState, // the trusted state to not roll back beyond.
  wsCheckpoint, // weak subjectivity checkpoints.
  metricsRegistries,
});

Some concepts in this section of the code:

Deep dive into BeaconNode.init#

In https://github.com/ChainSafe/lodestar/blob/v1.5.1/packages/beacon-node/src/node/nodejs.ts L126:

const chain = new BeaconChain(); // responsible for managing blocks
await chain.loadFromDisk();

const network = new Network(); // handles p2p connections, subnets.
await network.start();

const sync = new BeaconSync(); // handles addPeer, removePeer, and stops/continues participating in gossipsub based on sync status.

const api = getApi(); // corresponds to these specs: https://ethereum.github.io/beacon-APIs/

const restApi = new BeaconRestApiServer(); // registers routes for the 'api' that's created before.

For more details:

CKZG, after deneb#

If post deneb (EIP-4844) upgrade, initialize KZG ^ce21ec

if (config.EIP4844_FORK_EPOCH < Infinity) {
  // TODO DENEB: "c-kzg" is not installed by default, so if the library is not installed this will throw
  // See "Not able to build lodestar from source" https://github.com/ChainSafe/lodestar/issues/4886
  await initCKZG();
  loadEthereumTrustedSetup();
}

Create chain#

Initialize database, and creates BeaconChain instance.

await db.start();
await db.pruneHotDb();
const chain = new BeaconChain(opts.chain, {
      // ...
      /* a queued JSON-RPC client to interact with execution client. */
      executionEngine: initializeExecutionEngine(opts.executionEngine, {metrics, signal}),
      executionBuilder: opts.executionBuilder.enabled
        ? initializeExecutionBuilder(opts.executionBuilder, config)
        : undefined, // an HTTP client to interact with MEV boosters.
    });
  • Queue. A queue is used to guarantee the order of requests.
  • The executionEngine is the execution client usually running on another port on the same host.

Create network, the most important step.#

Code: https://github.com/ChainSafe/lodestar/blob/v1.5.1/packages/beacon-node/src/network/network.ts

Compared to execution client, the consensus client upgraded network by:

  • using 'discv5' as discovery protocol to find peers.
  • using ENR (EIP-778). Particularly, it introduces seqNumber to version the metadata.

    Note: execution client uses 'Enode', see [[4.1 Code * Geth * CLI#About Bootnodes]]

The constructor:

  • this.gossip = new Eth2Gossipsub, read more in [[3.3 Code * Lodestar * Gossip Handling]]

The start function:

  async start(): Promise<void> {
    await this.discovery?.start();
    this.libp2p.connectionManager.addEventListener(Libp2pEvent.peerConnect, this.onLibp2pPeerConnect);
    this.libp2p.connectionManager.addEventListener(Libp2pEvent.peerDisconnect, this.onLibp2pPeerDisconnect);
    this.networkEventBus.on(NetworkEvent.reqRespRequest, this.onRequest);

    this.heartbeat(); // will soon make it periodic
    this.intervals = [
      setInterval(this.pingAndStatusTimeouts.bind(this), CHECK_PING_STATUS_INTERVAL), // check whether peers 'seqNumber' is still the same, if not, update.
      setInterval(this.heartbeat.bind(this), HEARTBEAT_INTERVAL_MS), // check whether sufficient peers are connected
      setInterval(
        this.updateGossipsubScores.bind(this),
        this.gossipsub.scoreParams.decayInterval ?? HEARTBEAT_INTERVAL_MS
      ), // update peer scoring
    ];
  }

Peer Scoring

Peer scoring is introduced in gossipsub 1.1. Although lodestar implemented it, the only spec I could find is saying that it is under investigation: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-gossip-domain-gossipsub