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

Serve Lightclient related data via p2p #4365

Merged
merged 127 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from 118 commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
ebc175e
rename to LightClientBootstrap to keep consistent with spec
dadepo Aug 1, 2022
be219f1
updating types in preparation to start serving LightClientBootstrap v…
dadepo Aug 2, 2022
25718c4
should be able to serve LightClientBootstrap via p2p
dadepo Aug 3, 2022
32399cb
aligning types in preparation to be able to serve light client update…
dadepo Aug 3, 2022
765a76c
added a comment to take care of error handling for light client boots…
dadepo Aug 3, 2022
8d190d1
fix type error
dadepo Aug 4, 2022
f826c1e
handle error when lighclientBootstrap cannot be returned
dadepo Aug 4, 2022
2d36d3f
Add ability to serve LightclientUpdate via p2p req/resp
dadepo Aug 4, 2022
3e9f991
Aligning types in prep for being able to serve LightClientFinalityUpd…
dadepo Aug 4, 2022
201406d
Added ability to serve LightClientFinalityUpdate via p2p req/resp
dadepo Aug 4, 2022
7ded1a4
Serving lightclientFinalityUpdate via p2p
dadepo Aug 4, 2022
9fce4bc
fix check types
dadepo Aug 4, 2022
0ec2171
fix failing lightclient.test.ts test
dadepo Aug 5, 2022
24d597d
fix check-types check
dadepo Aug 5, 2022
c86ba5c
fix check-types check
dadepo Aug 5, 2022
0236dfd
merged in unstable
dadepo Aug 5, 2022
4bf866e
initial changes to have light_client_optimistic_update and light_clie…
dadepo Aug 8, 2022
9bf6216
adding placeholder for validating lightclient's gossip messages
dadepo Aug 10, 2022
8dc7c49
Added some validation to LightClientFinalityUpdate
dadepo Aug 11, 2022
86a7e1a
merging in unstable
dadepo Sep 4, 2022
58fa587
added more gossip validation
dadepo Sep 7, 2022
d3a40c2
Merge branch 'unstable' into dadepo/p2p-lightclient
dadepo Sep 7, 2022
01bdd0d
fix check-types errors
dadepo Sep 7, 2022
526b2b7
temp disable test
dadepo Sep 7, 2022
0bd729a
Unit tests should now be passing
dadepo Sep 7, 2022
fc982d9
explicitly binding this to function passed to the chain event emitter…
dadepo Sep 8, 2022
ba2b77f
merged in master and resolved conflicts
dadepo Sep 16, 2022
ff39614
removed TODO comment after processing it
dadepo Sep 16, 2022
e4c56e3
undo removal of space
dadepo Sep 16, 2022
9a41c36
LightClientOptimisticUpdate has no request
dadepo Sep 16, 2022
2bea643
update to return corrosponding ssz type to lightclient gossip type
dadepo Sep 18, 2022
d2fbf82
turn runtime error to compile time error
dadepo Sep 18, 2022
56965c6
extend gossipsub.test to include tests for LightClientOptimisticUpdat…
dadepo Sep 18, 2022
34686ea
Merge branch 'unstable' into dadepo/p2p-lightclient
dadepo Sep 19, 2022
ab45631
Fix build failure
dadepo Sep 19, 2022
209743e
Also unsubscribe lightclient's gossip global topics
dadepo Sep 19, 2022
3a8ff23
Logging topics for debugging in CI
dadepo Sep 19, 2022
b326ecd
debugging in CI
dadepo Sep 19, 2022
350217e
do not override zeroProtoBlock
dadepo Sep 19, 2022
18f4194
removing cli debugging changes
dadepo Sep 19, 2022
b77c7ac
run the network.test within altair
dadepo Sep 19, 2022
b958625
split lightclient gossip validation to seperate files
dadepo Sep 19, 2022
9fc30d1
adding tests for validateLightClientOptimisticUpdate
dadepo Sep 20, 2022
d28aced
undo unintended changes
dadepo Sep 20, 2022
a28bc04
Added Light Client Finality Update validation
dadepo Sep 20, 2022
abf4f4c
Merge branch 'unstable' into dadepo/p2p-lightclient
dadepo Sep 20, 2022
f79d7a8
corrected type name to be aligned with spec
dadepo Sep 20, 2022
d6c5035
extend onRequest with light client
dadepo Sep 20, 2022
098b3d8
fix test
dadepo Sep 20, 2022
20a5d2f
properly setting signatureSlot
dadepo Sep 20, 2022
3fd9b22
wrapped getting onLightclientUpdate via res/req in a try catch
dadepo Sep 21, 2022
d8d4301
Align light client objects naming with spec
dadepo Sep 21, 2022
c701a4a
remove comment
dadepo Sep 21, 2022
c78f458
process some TODO
dadepo Sep 21, 2022
c94a638
Add ability to request lightClientBootstrap via Req/Resp
dadepo Sep 22, 2022
4b5db07
added ability to request light client optimistic and finality update …
dadepo Sep 22, 2022
113e678
Add ability to request light client update message via Req/Res channel
dadepo Sep 22, 2022
bb41a01
renabled skipped test
dadepo Sep 26, 2022
2d6a640
process LightClientUpdate via SSE also
dadepo Sep 26, 2022
e46277f
undo unintended committed changes
dadepo Sep 26, 2022
c5ca43c
remove unnecessary promise resolve
dadepo Sep 26, 2022
cd4b595
remove unnecessary promise resolve
dadepo Sep 26, 2022
253ff23
Merge branch 'unstable' into dadepo/p2p-lightclient
dadepo Sep 26, 2022
b44db38
temp undo commit cd4b595 and c5ca43c
dadepo Sep 26, 2022
c7394ba
Revert "temp undo commit cd4b595 and c5ca43c"
dadepo Sep 26, 2022
d79efff
yield LightClientUpdate instead of LightClientUpdates
dadepo Sep 27, 2022
e61f3fe
removed unused type
dadepo Sep 27, 2022
28ef184
merged in unstable and resolved conflicts
dadepo Sep 27, 2022
30fb2f6
Merge branch 'unstable' into dadepo/p2p-lightclient
dadepo Sep 29, 2022
1138a7a
fix compilation in tests
dadepo Sep 29, 2022
2a90961
improve error handling for getOptimisticUpdate
dadepo Sep 30, 2022
a9f014e
improve error handling for getFinalityUpdate
dadepo Sep 30, 2022
1549d10
avoid voiding promise. Fix lint errors
dadepo Sep 30, 2022
66dfe39
Switch to debug level to prevent unnecessary PublishError.Insufficien…
dadepo Sep 30, 2022
d3f8db6
Adding back promises to api client functions
dadepo Sep 30, 2022
f47a952
resolved confilict/merged in unstable
dadepo Oct 2, 2022
a607a93
merged in unstable and resolved conflicts
dadepo Oct 2, 2022
9d0418e
Merge branch 'unstable' into dadepo/p2p-lightclient
dadepo Oct 2, 2022
0594956
Merge branch 'unstable' into dadepo/p2p-lightclient
dadepo Oct 4, 2022
ee55152
Move setting of latestForwardedFinalitySlot and latestForwardedOptimi…
dadepo Oct 5, 2022
43c4745
Use correct version for Res/Req
dadepo Oct 5, 2022
0667b4e
Use correct version for Res/Req
dadepo Oct 5, 2022
2c4a98b
use one event stream
dadepo Oct 5, 2022
5145b81
removed redundant async
dadepo Oct 5, 2022
fc0305b
Fix tests due to removal of async
dadepo Oct 5, 2022
0007665
Fixed test
dadepo Oct 5, 2022
95a57f6
Do not forward if local light client updates do not exist yet
dadepo Oct 5, 2022
b3ea614
fix lightClientOptimisticUpdate.test and wait 1/3 slot before publishing
dadepo Oct 6, 2022
4369c14
Added tests for scenarios where validation does not fail for validate…
dadepo Oct 6, 2022
fd36f64
Remove redefinition of Root. Removed utility functions in test
dadepo Oct 6, 2022
f94a81e
Passing in syncAggregate and signatureSlot instead of whole block
dadepo Oct 6, 2022
630e702
Make getUpdates more flexible
dadepo Oct 6, 2022
c47daff
use strong equality check
dadepo Oct 6, 2022
62cc4b2
do not publish events if sync committee is below MIN_SYNC_COMMITTEE_P…
dadepo Oct 9, 2022
6c2fc68
doGetUpdate => getUpdate. private => public
dadepo Oct 9, 2022
df9f48f
Allow gaps in light client updates instead of throwing
dadepo Oct 17, 2022
824700c
Address pr comments
wemeetagain Oct 19, 2022
50fe56f
Remove light client latest cached slot
wemeetagain Oct 19, 2022
639f636
Revert "Remove light client latest cached slot"
wemeetagain Oct 19, 2022
351f786
Use simple for loop
wemeetagain Oct 20, 2022
b61b154
Remove trailing slash from lightclient apis
wemeetagain Oct 20, 2022
4d843bc
Fix finality update gossip validation
wemeetagain Oct 20, 2022
c696ee7
fixing failing tests
dadepo Oct 21, 2022
649c453
invalid with not matching local when no local update yet
dadepo Oct 21, 2022
6994e79
Limit REST getUpdates response to MAX_REQUEST_LIGHT_CLIENT_UPDATES
dadepo Oct 21, 2022
22517ff
unbind listeners on close
dadepo Oct 21, 2022
1011e6f
removed the need to bind to this
dadepo Oct 23, 2022
16dcb0c
fix lint
dadepo Oct 23, 2022
003a233
wait one third before publishing lc updates in on onSyncAggregate
dadepo Oct 23, 2022
53755ea
Revert "wait one third before publishing lc updates in on onSyncAggre…
dadepo Oct 24, 2022
9e1e901
update waiting logic before publishing lc update to network
dadepo Oct 24, 2022
1e77b4e
making use of abort signal when sleeping
dadepo Oct 24, 2022
cc4f5bb
only publish lc updates if node has atleast one sync committee member
dadepo Oct 24, 2022
797a50d
Remove stray comment
wemeetagain Oct 26, 2022
6c6cefd
Use strict equals
wemeetagain Oct 26, 2022
81c78d1
More consistent naming
wemeetagain Oct 26, 2022
bfc675e
Reorg reqresp methods
wemeetagain Oct 26, 2022
3806324
Add light client server error
wemeetagain Oct 28, 2022
4d2f972
Fix seconds to miliseconds typo
dapplion Oct 28, 2022
207a306
Remove need for -1 default
dapplion Oct 28, 2022
c060b8a
Remove unnecessary arrow function
dapplion Oct 28, 2022
5165506
Allow to publish to zero peers
dapplion Oct 28, 2022
fb7eb09
Use spec name LightClientUpdatesByRange
dapplion Oct 28, 2022
53f4096
Clarify FINALITY_UPDATE_RECEIVED_TOO_EARLY math
dapplion Oct 28, 2022
0971596
De-duplicate updateReceivedToEarly condition
dapplion Oct 28, 2022
e73bde4
Update emit comments
dapplion Oct 28, 2022
6ea5c53
Fix typo in updateReceivedTooEarly
dapplion Oct 28, 2022
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
32 changes: 13 additions & 19 deletions packages/api/src/beacon/routes/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@ import {RouteDef, TypeJson} from "../../utils/index.js";

// See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes

export type LightclientOptimisticHeaderUpdate = {
dapplion marked this conversation as resolved.
Show resolved Hide resolved
syncAggregate: altair.SyncAggregate;
attestedHeader: phase0.BeaconBlockHeader;
};

export type LightclientFinalizedUpdate = {
attestedHeader: phase0.BeaconBlockHeader;
finalizedHeader: phase0.BeaconBlockHeader;
finalityBranch: Uint8Array[];
syncAggregate: altair.SyncAggregate;
};

export enum EventType {
/**
* The node has finished processing, resulting in a new head. previous_duty_dependent_root is
Expand All @@ -38,9 +26,11 @@ export enum EventType {
/** The node has received a valid sync committee SignedContributionAndProof (from P2P or API) */
contributionAndProof = "contribution_and_proof",
/** New or better optimistic header update available */
lightclientOptimisticUpdate = "light_client_optimistic_update",
/** New or better finalized update available */
lightclientFinalizedUpdate = "light_client_finalized_update",
lightClientOptimisticUpdate = "light_client_optimistic_update",
/** New or better finality update available */
lightClientFinalityUpdate = "light_client_finality_update",
/** New or better light client update available */
lightClientUpdate = "light_client_update",
}

export type EventData = {
Expand Down Expand Up @@ -77,8 +67,9 @@ export type EventData = {
executionOptimistic: boolean;
};
[EventType.contributionAndProof]: altair.SignedContributionAndProof;
[EventType.lightclientOptimisticUpdate]: LightclientOptimisticHeaderUpdate;
[EventType.lightclientFinalizedUpdate]: LightclientFinalizedUpdate;
[EventType.lightClientOptimisticUpdate]: altair.LightClientOptimisticUpdate;
[EventType.lightClientFinalityUpdate]: altair.LightClientFinalityUpdate;
[EventType.lightClientUpdate]: altair.LightClientUpdate;
};

export type BeaconEvent = {[K in EventType]: {type: K; message: EventData[K]}}[EventType];
Expand Down Expand Up @@ -163,22 +154,25 @@ export function getTypeByEvent(): {[K in EventType]: Type<EventData[K]>} {

[EventType.contributionAndProof]: ssz.altair.SignedContributionAndProof,

[EventType.lightclientOptimisticUpdate]: new ContainerType(
[EventType.lightClientOptimisticUpdate]: new ContainerType(
{
syncAggregate: ssz.altair.SyncAggregate,
attestedHeader: ssz.phase0.BeaconBlockHeader,
signatureSlot: ssz.Slot,
},
{jsonCase: "eth2"}
),
[EventType.lightclientFinalizedUpdate]: new ContainerType(
[EventType.lightClientFinalityUpdate]: new ContainerType(
{
attestedHeader: ssz.phase0.BeaconBlockHeader,
finalizedHeader: ssz.phase0.BeaconBlockHeader,
finalityBranch: new VectorCompositeType(ssz.Bytes32, FINALIZED_ROOT_DEPTH),
syncAggregate: ssz.altair.SyncAggregate,
signatureSlot: ssz.Slot,
},
{jsonCase: "eth2"}
),
[EventType.lightClientUpdate]: ssz.altair.LightClientUpdate,
};
}

Expand Down
52 changes: 10 additions & 42 deletions packages/api/src/beacon/routes/lightclient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {ContainerType, JsonPath, VectorCompositeType} from "@chainsafe/ssz";
import {JsonPath} from "@chainsafe/ssz";
import {Proof} from "@chainsafe/persistent-merkle-tree";
import {FINALIZED_ROOT_DEPTH} from "@lodestar/params";
import {altair, phase0, ssz, SyncPeriod} from "@lodestar/types";
import {
ArrayOf,
Expand All @@ -14,14 +13,10 @@ import {
ReqEmpty,
} from "../../utils/index.js";
import {queryParseProofPathsArr, querySerializeProofPathsArr} from "../../utils/serdes.js";
import {LightclientOptimisticHeaderUpdate, LightclientFinalizedUpdate} from "./events.js";

// Re-export for convenience when importing routes.lightclient.LightclientOptimisticHeaderUpdate
export {LightclientOptimisticHeaderUpdate, LightclientFinalizedUpdate};

// See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes

export type LightclientSnapshotWithProof = {
export type LightClientBootstrap = {
header: phase0.BeaconBlockHeader;
currentSyncCommittee: altair.SyncCommittee;
/** Single branch proof from state root to currentSyncCommittee */
Expand All @@ -46,14 +41,14 @@ export type Api = {
* Returns the latest optimistic head update available. Clients should use the SSE type `light_client_optimistic_update`
* unless to get the very first head update after syncing, or if SSE are not supported by the server.
*/
getOptimisticUpdate(): Promise<{data: LightclientOptimisticHeaderUpdate}>;
getFinalityUpdate(): Promise<{data: LightclientFinalizedUpdate}>;
getOptimisticUpdate(): Promise<{data: altair.LightClientOptimisticUpdate}>;
getFinalityUpdate(): Promise<{data: altair.LightClientFinalityUpdate}>;
/**
* Fetch a bootstrapping state with a proof to a trusted block root.
* The trusted block root should be fetched with similar means to a weak subjectivity checkpoint.
* Only block roots for checkpoints are guaranteed to be available.
*/
getBootstrap(blockRoot: string): Promise<{data: LightclientSnapshotWithProof}>;
getBootstrap(blockRoot: string): Promise<{data: LightClientBootstrap}>;
};

/**
Expand All @@ -62,8 +57,8 @@ export type Api = {
export const routesData: RoutesData<Api> = {
getStateProof: {url: "/eth/v1/beacon/light_client/proof/{state_id}", method: "GET"},
getUpdates: {url: "/eth/v1/beacon/light_client/updates", method: "GET"},
getOptimisticUpdate: {url: "/eth/v1/beacon/light_client/optimistic_update/", method: "GET"},
getFinalityUpdate: {url: "/eth/v1/beacon/light_client/finality_update/", method: "GET"},
getOptimisticUpdate: {url: "/eth/v1/beacon/light_client/optimistic_update", method: "GET"},
getFinalityUpdate: {url: "/eth/v1/beacon/light_client/finality_update", method: "GET"},
getBootstrap: {url: "/eth/v1/beacon/light_client/bootstrap/{block_root}", method: "GET"},
};

Expand Down Expand Up @@ -102,39 +97,12 @@ export function getReqSerializers(): ReqSerializers<Api, ReqTypes> {
}

export function getReturnTypes(): ReturnTypes<Api> {
const lightclientSnapshotWithProofType = new ContainerType(
dapplion marked this conversation as resolved.
Show resolved Hide resolved
{
header: ssz.phase0.BeaconBlockHeader,
currentSyncCommittee: ssz.altair.SyncCommittee,
currentSyncCommitteeBranch: new VectorCompositeType(ssz.Root, 5),
},
{jsonCase: "eth2"}
);

const lightclientHeaderUpdate = new ContainerType(
{
syncAggregate: ssz.altair.SyncAggregate,
attestedHeader: ssz.phase0.BeaconBlockHeader,
},
{jsonCase: "eth2"}
);

const lightclientFinalizedUpdate = new ContainerType(
{
attestedHeader: ssz.phase0.BeaconBlockHeader,
finalizedHeader: ssz.phase0.BeaconBlockHeader,
finalityBranch: new VectorCompositeType(ssz.Bytes32, FINALIZED_ROOT_DEPTH),
syncAggregate: ssz.altair.SyncAggregate,
},
{jsonCase: "eth2"}
);

return {
// Just sent the proof JSON as-is
getStateProof: sameType(),
getUpdates: ContainerData(ArrayOf(ssz.altair.LightClientUpdate)),
getOptimisticUpdate: ContainerData(lightclientHeaderUpdate),
getFinalityUpdate: ContainerData(lightclientFinalizedUpdate),
getBootstrap: ContainerData(lightclientSnapshotWithProofType),
getOptimisticUpdate: ContainerData(ssz.altair.LightClientOptimisticUpdate),
getFinalityUpdate: ContainerData(ssz.altair.LightClientFinalityUpdate),
getBootstrap: ContainerData(ssz.altair.LightClientBootstrap),
};
}
7 changes: 5 additions & 2 deletions packages/api/test/unit/beacon/testData/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,17 @@ export const eventTestData: EventData = {
signature:
"0xac118511474a94f857300b315c50585c32a713e4452e26a6bb98cdb619936370f126ed3b6bb64469259ee92e69791d9e12d324ce6fd90081680ce72f39d85d50b0ff977260a8667465e613362c6d6e6e745e1f9323ec1d6f16041c4e358839ac",
}),
[EventType.lightclientOptimisticUpdate]: {
[EventType.lightClientOptimisticUpdate]: {
syncAggregate: ssz.altair.SyncAggregate.defaultValue(),
attestedHeader: ssz.phase0.BeaconBlockHeader.defaultValue(),
signatureSlot: ssz.Slot.defaultValue(),
},
[EventType.lightclientFinalizedUpdate]: {
[EventType.lightClientFinalityUpdate]: {
attestedHeader: ssz.phase0.BeaconBlockHeader.defaultValue(),
finalizedHeader: ssz.phase0.BeaconBlockHeader.defaultValue(),
finalityBranch: [root],
syncAggregate: ssz.altair.SyncAggregate.defaultValue(),
signatureSlot: ssz.Slot.defaultValue(),
},
[EventType.lightClientUpdate]: ssz.altair.LightClientUpdate.defaultValue(),
};
4 changes: 3 additions & 1 deletion packages/api/test/unit/beacon/testData/lightclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const root = Uint8Array.from(Buffer.alloc(32, 1));
const lightClientUpdate = ssz.altair.LightClientUpdate.defaultValue();
const syncAggregate = ssz.altair.SyncAggregate.defaultValue();
const header = ssz.phase0.BeaconBlockHeader.defaultValue();
const signatureSlot = ssz.Slot.defaultValue();

export const testData: GenericServerTestCases<Api> = {
getStateProof: {
Expand Down Expand Up @@ -41,7 +42,7 @@ export const testData: GenericServerTestCases<Api> = {
},
getOptimisticUpdate: {
args: [],
res: {data: {syncAggregate, attestedHeader: header}},
res: {data: {syncAggregate, attestedHeader: header, signatureSlot}},
},
getFinalityUpdate: {
args: [],
Expand All @@ -51,6 +52,7 @@ export const testData: GenericServerTestCases<Api> = {
attestedHeader: header,
finalizedHeader: lightClientUpdate.finalizedHeader,
finalityBranch: lightClientUpdate.finalityBranch,
signatureSlot: lightClientUpdate.attestedHeader.slot + 1,
},
},
},
Expand Down
10 changes: 6 additions & 4 deletions packages/beacon-node/src/api/impl/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ const chainEventMap = {
[routes.events.EventType.finalizedCheckpoint]: ChainEvent.finalized as const,
[routes.events.EventType.chainReorg]: ChainEvent.forkChoiceReorg as const,
[routes.events.EventType.contributionAndProof]: ChainEvent.contributionAndProof as const,
[routes.events.EventType.lightclientOptimisticUpdate]: ChainEvent.lightclientOptimisticUpdate as const,
[routes.events.EventType.lightclientFinalizedUpdate]: ChainEvent.lightclientFinalizedUpdate as const,
[routes.events.EventType.lightClientOptimisticUpdate]: ChainEvent.lightClientOptimisticUpdate as const,
[routes.events.EventType.lightClientFinalityUpdate]: ChainEvent.lightClientFinalityUpdate as const,
[routes.events.EventType.lightClientUpdate]: ChainEvent.lightClientUpdate as const,
};

export function getEventsApi({chain, config}: Pick<ApiModules, "chain" | "config">): routes.events.Api {
Expand Down Expand Up @@ -60,8 +61,9 @@ export function getEventsApi({chain, config}: Pick<ApiModules, "chain" | "config
},
],
[routes.events.EventType.contributionAndProof]: (contributionAndProof) => [contributionAndProof],
[routes.events.EventType.lightclientOptimisticUpdate]: (headerUpdate) => [headerUpdate],
[routes.events.EventType.lightclientFinalizedUpdate]: (headerUpdate) => [headerUpdate],
[routes.events.EventType.lightClientOptimisticUpdate]: (headerUpdate) => [headerUpdate],
[routes.events.EventType.lightClientFinalityUpdate]: (headerUpdate) => [headerUpdate],
[routes.events.EventType.lightClientUpdate]: (headerUpdate) => [headerUpdate],
};

return {
Expand Down
22 changes: 16 additions & 6 deletions packages/beacon-node/src/api/impl/lightclient/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {routes} from "@lodestar/api";
import {fromHexString} from "@chainsafe/ssz";
import {ProofType, Tree} from "@chainsafe/persistent-merkle-tree";
import {SyncPeriod} from "@lodestar/types";
import {MAX_REQUEST_LIGHT_CLIENT_UPDATES} from "@lodestar/params";
import {ApiModules} from "../types.js";
import {resolveStateId} from "../beacon/state/utils.js";
import {IApiOptions} from "../../options.js";
Expand Down Expand Up @@ -41,19 +43,27 @@ export function getLightclientApi(
};
},

// eslint-disable-next-line @typescript-eslint/naming-convention
async getUpdates(start_period, count) {
const periods = Array.from({length: count}, (_ignored, i) => i + start_period);
const updates = await Promise.all(periods.map((period) => chain.lightClientServer.getUpdates(period)));
async getUpdates(startPeriod: SyncPeriod, count: number) {
const maxAllowedCount = Math.min(MAX_REQUEST_LIGHT_CLIENT_UPDATES, count);
const periods = Array.from({length: maxAllowedCount}, (_ignored, i) => i + startPeriod);
const updates = await Promise.all(periods.map((period) => chain.lightClientServer.getUpdate(period)));
return {data: updates};
},

async getOptimisticUpdate() {
return {data: await chain.lightClientServer.getOptimisticUpdate()};
const data = chain.lightClientServer.getOptimisticUpdate();
if (data === null) {
throw Error("No optimistic update available");
}
return {data};
},

async getFinalityUpdate() {
return {data: await chain.lightClientServer.getFinalityUpdate()};
const data = chain.lightClientServer.getFinalityUpdate();
if (data === null) {
throw Error("No finality update available");
}
return {data};
},

async getBootstrap(blockRoot) {
Expand Down
13 changes: 9 additions & 4 deletions packages/beacon-node/src/chain/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,15 @@ export enum ChainEvent {
/**
* A new lightclient optimistic header update is available to be broadcasted to connected light-clients
*/
lightclientOptimisticUpdate = "lightclient:header_update",
lightClientOptimisticUpdate = "lightclient:header_update",
/**
* A new lightclient finalized header update is available to be broadcasted to connected light-clients
*/
lightclientFinalizedUpdate = "lightclient:finalized_update",
lightClientFinalityUpdate = "lightclient:finality_update",
/**
* A new lightclient update is available to be broadcasted to connected light-clients
*/
lightClientUpdate = "lightclient:update",
}

export type HeadEventData = routes.events.EventData[routes.events.EventType.head];
Expand All @@ -114,8 +118,9 @@ export interface IChainEvents {
[ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithHex) => void;
[ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithHex) => void;

[ChainEvent.lightclientOptimisticUpdate]: (optimisticUpdate: routes.events.LightclientOptimisticHeaderUpdate) => void;
[ChainEvent.lightclientFinalizedUpdate]: (finalizedUpdate: routes.events.LightclientFinalizedUpdate) => void;
[ChainEvent.lightClientOptimisticUpdate]: (optimisticUpdate: altair.LightClientOptimisticUpdate) => void;
[ChainEvent.lightClientFinalityUpdate]: (finalizedUpdate: altair.LightClientFinalityUpdate) => void;
[ChainEvent.lightClientUpdate]: (update: altair.LightClientUpdate) => void;
}

/**
Expand Down
30 changes: 30 additions & 0 deletions packages/beacon-node/src/chain/errors/lightClientError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {LodestarError} from "@lodestar/utils";
import {GossipActionError} from "./gossipValidation.js";

export enum LightClientErrorCode {
FINALITY_UPDATE_ALREADY_FORWARDED = "FINALITY_UPDATE_ALREADY_FORWARDED",
OPTIMISTIC_UPDATE_ALREADY_FORWARDED = "OPTIMISTIC_UPDATE_ALREADY_FORWARDED",
FINALITY_UPDATE_RECEIVED_TOO_EARLY = "FINALITY_UPDATE_RECEIVED_TOO_EARLY",
OPTIMISTIC_UPDATE_RECEIVED_TOO_EARLY = "OPTIMISTIC_UPDATE_RECEIVED_TOO_EARLY",
FINALITY_UPDATE_NOT_MATCHING_LOCAL = "FINALITY_UPDATE_NOT_MATCHING_LOCAL",
OPTIMISTIC_UPDATE_NOT_MATCHING_LOCAL = "OPTIMISTIC_UPDATE_NOT_MATCHING_LOCAL",
}
export type LightClientErrorType =
| {code: LightClientErrorCode.FINALITY_UPDATE_ALREADY_FORWARDED}
| {code: LightClientErrorCode.OPTIMISTIC_UPDATE_ALREADY_FORWARDED}
| {code: LightClientErrorCode.FINALITY_UPDATE_RECEIVED_TOO_EARLY}
| {code: LightClientErrorCode.OPTIMISTIC_UPDATE_RECEIVED_TOO_EARLY}
| {code: LightClientErrorCode.FINALITY_UPDATE_NOT_MATCHING_LOCAL}
| {code: LightClientErrorCode.OPTIMISTIC_UPDATE_NOT_MATCHING_LOCAL};

export class LightClientError extends GossipActionError<LightClientErrorType> {}

// Errors for the light client server

export enum LightClientServerErrorCode {
RESOURCE_UNAVAILABLE = "RESOURCE_UNAVALIABLE",
}

export type LightClientServerErrorType = {code: LightClientServerErrorCode.RESOURCE_UNAVAILABLE};

export class LightClientServerError extends LodestarError<LightClientServerErrorType> {}
Loading