Skip to content

Commit

Permalink
chore: simplify LightClient usage (#6506)
Browse files Browse the repository at this point in the history
* chore: simplify LightClient usage

* chore: lint

* chore: lint
  • Loading branch information
jeluard authored and philknows committed Mar 6, 2024
1 parent c931a4c commit 3875463
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 64 deletions.
2 changes: 1 addition & 1 deletion packages/beacon-node/test/e2e/chain/lightclient.test.ts
Expand Up @@ -131,7 +131,7 @@ describe("chain / lightclient", function () {
});

loggerLC.info("Initialized lightclient", {headSlot: lightclient.getHead().beacon.slot});
lightclient.start();
void lightclient.start();

return new Promise<void>((resolve, reject) => {
bn.chain.emitter.on(routes.events.EventType.head, async (head) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cmds/lightclient/handler.ts
Expand Up @@ -33,5 +33,5 @@ export async function lightclientHandler(args: ILightClientArgs & GlobalArgs): P
transport: new LightClientRestTransport(api),
});

client.start();
void client.start();
}
54 changes: 8 additions & 46 deletions packages/light-client/README.md
Expand Up @@ -51,78 +51,40 @@ lodestar lightclient \
For this example we will assume there is a running beacon node at `https://beacon-node.your-domain.com`

```ts
import type {Api} from "@lodestar/api/beacon";
import {ApiError} from "@lodestar/api";
import type {Bytes32} from "@lodestar/types";
import {getClient} from "@lodestar/api";
import {createChainForkConfig} from "@lodestar/config";
import {networksChainConfig} from "@lodestar/config/networks";
import {
type GenesisData,
Lightclient,
LightclientEvent,
RunStatusCode
} from "@lodestar/light-client";
import {getClient} from "@lodestar/api";
import {Lightclient, LightclientEvent} from "@lodestar/light-client";
import {LightClientRestTransport} from "@lodestar/light-client/transport";
import {getLcLoggerConsole} from "@lodestar/light-client/utils";

async function getGenesisData(api: Pick<Api, "beacon">): Promise<GenesisData> {
const res = await api.beacon.getGenesis();
ApiError.assert(res);

return {
genesisTime: Number(res.response.data.genesisTime),
genesisValidatorsRoot: res.response.data.genesisValidatorsRoot,
};
}

async function getSyncCheckpoint(api: Pick<Api, "beacon">): Promise<Bytes32> {
const res = await api.beacon.getStateFinalityCheckpoints("head");
ApiError.assert(res);
return res.response.data.finalized.root;
}
import {getFinalizedSyncCheckpoint, getGenesisData, getLcLoggerConsole} from "@lodestar/light-client/utils";

const config = createChainForkConfig(networksChainConfig.mainnet);

const logger = getLcLoggerConsole({logDebug: Boolean(process.env.DEBUG)});

const api = getClient({urls: ["https://beacon-node.your-domain.com"]}, {config});

const transport = new LightClientRestTransport(api);

const lightclient = await Lightclient.initializeFromCheckpointRoot({
config,
logger,
transport,
transport: new LightClientRestTransport(api),
genesisData: await getGenesisData(api),
checkpointRoot: await getSyncCheckpoint(api),
checkpointRoot: await getFinalizedSyncCheckpoint(api),
opts: {
allowForcedUpdates: true,
updateHeadersOnForcedUpdate: true,
}
});

// Wait for the lightclient to start
await new Promise<void>((resolve) => {
const lightclientStarted = (status: RunStatusCode): void => {
if (status === RunStatusCode.started) {
lightclient?.emitter.off(LightclientEvent.statusChange, lightclientStarted);
resolve();
}
};
lightclient?.emitter.on(LightclientEvent.statusChange, lightclientStarted);
logger.info("Initiating lightclient");
lightclient?.start();
});
await lightclient.start();

logger.info("Lightclient synced");

lightclient.emitter.on(LightclientEvent.lightClientFinalityHeader, async (finalityUpdate) => {
console.log(finalityUpdate);
logger.info(finalityUpdate);
});

lightclient.emitter.on(LightclientEvent.lightClientOptimisticHeader, async (optimisticUpdate) => {
console.log(optimisticUpdate);
logger.info(optimisticUpdate);
});
```

Expand Down
19 changes: 16 additions & 3 deletions packages/light-client/src/index.ts
Expand Up @@ -167,10 +167,23 @@ export class Lightclient {
return new Lightclient({...args, bootstrap});
}

start(): void {
this.runLoop().catch((e) => {
this.logger.error("Error on runLoop", {}, e as Error);
/**
* @returns a `Promise` that will resolve once `LightclientEvent.statusChange` with `RunStatusCode.started` value is emitted
*/
start(): Promise<void> {
const startPromise = new Promise<void>((resolve) => {
const lightclientStarted = (status: RunStatusCode): void => {
if (status === RunStatusCode.started) {
this.emitter.off(LightclientEvent.statusChange, lightclientStarted);
resolve();
}
};
this.emitter.on(LightclientEvent.statusChange, lightclientStarted);
});

void this.runLoop();

return startPromise;
}

stop(): void {
Expand Down
20 changes: 19 additions & 1 deletion packages/light-client/src/utils/utils.ts
@@ -1,8 +1,10 @@
import bls from "@chainsafe/bls";
import type {PublicKey} from "@chainsafe/bls/types";
import {BitArray} from "@chainsafe/ssz";
import {altair, Root, ssz} from "@lodestar/types";
import {Api, ApiError} from "@lodestar/api";
import {altair, Bytes32, Root, ssz} from "@lodestar/types";
import {BeaconBlockHeader} from "@lodestar/types/phase0";
import {GenesisData} from "../index.js";
import {SyncCommitteeFast} from "../types.js";

export function sumBits(bits: BitArray): number {
Expand Down Expand Up @@ -78,3 +80,19 @@ export function isEmptyHeader(header: BeaconBlockHeader): boolean {
// Thanks https://github.com/iliakan/detect-node/blob/master/index.esm.js
export const isNode =
Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]";

export async function getGenesisData(api: Pick<Api, "beacon">): Promise<GenesisData> {
const res = await api.beacon.getGenesis();
ApiError.assert(res);

return {
genesisTime: res.response.data.genesisTime,
genesisValidatorsRoot: res.response.data.genesisValidatorsRoot,
};
}

export async function getFinalizedSyncCheckpoint(api: Pick<Api, "beacon">): Promise<Bytes32> {
const res = await api.beacon.getStateFinalityCheckpoints("head");
ApiError.assert(res);
return res.response.data.finalized.root;
}
2 changes: 1 addition & 1 deletion packages/light-client/test/unit/sync.node.test.ts
Expand Up @@ -104,7 +104,7 @@ describe("sync", () => {
resolve();
}
});
lightclient.start();
void lightclient.start();
});

// Wait for lightclient to subscribe to header updates
Expand Down
14 changes: 3 additions & 11 deletions packages/prover/src/proof_provider/proof_provider.ts
Expand Up @@ -96,18 +96,10 @@ export class ProofProvider {
});

assertLightClient(this.lightClient);

this.logger.info("Initiating lightclient");
// Wait for the lightclient to start
await new Promise<void>((resolve) => {
const lightClientStarted = (status: RunStatusCode): void => {
if (status === RunStatusCode.started) {
this.lightClient?.emitter.off(LightclientEvent.statusChange, lightClientStarted);
resolve();
}
};
this.lightClient?.emitter.on(LightclientEvent.statusChange, lightClientStarted);
this.logger.info("Initiating lightclient");
this.lightClient?.start();
});
await this.lightClient?.start();
this.logger.info("Lightclient synced", this.getStatus());
this.registerEvents();

Expand Down

0 comments on commit 3875463

Please sign in to comment.