EPF4: UPDATE 8
Lodestar is started using the beaconHandler.
The explicit command responsible for this can be found here:
.
The most important function responsible for this implementation in that file can be found here:
There are three functions in that file:
The most function we are concerned with is the beaconHandler().
Reason: It incorporates the other two functions and also contains the code for starting and stopping Lodestar.
The beaconHandler does the following:
Sets time-interval constants for periodic handling of ssz objects:
const DEFAULT_RETENTION_SSZ_OBJECTS_HOURS = 154 * 24;
const HOURS_TO_MS = 3600 * 1000;
Runs the beacon node as a whole:
export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise<void> {}
Initializes the beacon handler:
const {config, options, beaconPaths, network, version, commit, peerId, logger} = await beaconHandlerInit(args);
beaconHandlerInit
for initializing the node;Initializes directories:
mkdir(beaconPaths.dataDir); mkdir(beaconPaths.beaconDir); mkdir(beaconPaths.dbDir);
Aborts network operations:
const abortController = new AbortController();
Logs information about the following variables on the terminal:
logger.info("Lodestar", {network, version, commit});
Callback for beacon to request forced exit, for e.g. in case of irrecoverable forkchoice errors. This signal is typically sent when the user presses Ctrl + C on the terminal:
const processShutdownCallback: ProcessShutdownCallback = (err) => { logger.error("Process shutdown requested", {}, err); process.kill(process.pid, "SIGINT"); };
Logs information about preset network configs:
if (ACTIVE_PRESET === PresetName.minimal) logger.info("ACTIVE_PRESET == minimal preset");
Additional metrics registries(sets up the network's metric data):
const metricsRegistries: Registry[] = []; let networkRegistry: Registry | undefined; if (options.metrics.enabled) { networkRegistry = new Registry(); metricsRegistries.push(networkRegistry); }
Creates a new beacon database with the variables in the BeaconDb
object. Logs the information:
const db = new BeaconDb(config, await LevelDbController.create(options.db, {metrics: null, logger})); logger.info("Connected to LevelDB database", {path: options.db.name});
BeaconNode setup:
Sets up the beacon state with initBeaconState
. It returns anchorState and wsCheckpoint:
try { const {anchorState, wsCheckpoint} = await initBeaconState( options, args, config, db, logger, abortController.signal );
Create beacon chain config object for initiliazing the beacon chain:
const beaconConfig = createBeaconConfig(config, anchorState.genesisValidatorsRoot);
Initialize the beacon node using BeaconNode.init
:
const node = await BeaconNode.init({ opts: options, config: beaconConfig, db, logger, processShutdownCallback, peerId, peerStoreDir: beaconPaths.peerStoreDir, anchorState, wsCheckpoint, metricsRegistries, });
Dev debug option to have access to the BN instance
if (args.attachToGlobalThis) { (globalThis as unknown as {bn: BeaconNode}).bn = node; }
Prune invalid SSZ objects (old files) every interval
const {persistInvalidSszObjectsDir} = args; const pruneInvalidSSZObjectsInterval = persistInvalidSszObjectsDir ? setInterval(() => { try { pruneOldFilesInDir( persistInvalidSszObjectsDir, (args.persistInvalidSszObjectsRetentionHours ?? DEFAULT_RETENTION_SSZ_OBJECTS_HOURS) * HOURS_TO_MS ); } catch (e) { logger.warn("Error pruning invalid SSZ objects", {persistInvalidSszObjectsDir}, e as Error); } // Run every ~1 hour }, HOURS_TO_MS) : null;
Intercept SIGINT signal, to perform final ops before exiting:
onGracefulShutdown(async () => { if (args.persistNetworkIdentity) { try { const networkIdentity = await node.network.getNetworkIdentity(); const enrPath = path.join(beaconPaths.beaconDir, "enr"); writeFile600Perm(enrPath, networkIdentity.enr); } catch (e) { logger.warn("Unable to persist enr", {}, e as Error); } } abortController.abort();
Stops pruning ssz objects:
if (pruneInvalidSSZObjectsInterval !== null) { clearInterval(pruneInvalidSSZObjectsInterval); } }, logger.info.bind(logger));
Ensures the beacon node and database are closed gracefully when an abort signal is received:
abortController.signal.addEventListener( "abort", async () => { try { await node.close(); logger.debug("Beacon node closed");resolved process.exit(0); } catch (e) { logger.error("Error closing beacon node", {}, e as Error); await db.close(); process.exit(1); } }, {once: true} ); } catch (e) { await db.close(); if (e instanceof ErrorAborted) { logger.info(e.message); } else { throw e; } }
WIL:
abortController()
since we do not explicitly want to close node operations.node.close()
and keepind db.close()
b this means that while the node operations are still active, the database activities will be shutdown.