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

Add execution payload header to light client header capella onwards #5027

Merged
merged 25 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions packages/api/src/beacon/client/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";
/**
* REST HTTP client for events routes
*/
export function getClient(_config: IChainForkConfig, baseUrl: string): Api {
const eventSerdes = getEventSerdes();
export function getClient(config: IChainForkConfig, baseUrl: string): Api {
const eventSerdes = getEventSerdes(config);

return {
eventstream: async (topics, signal, onEvent) => {
Expand Down
75 changes: 47 additions & 28 deletions packages/api/src/beacon/routes/events.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Epoch, phase0, capella, Slot, ssz, StringType, RootHex, altair, UintNum64} from "@lodestar/types";
import {ContainerType, Type, VectorCompositeType} from "@chainsafe/ssz";
import {FINALIZED_ROOT_DEPTH} from "@lodestar/params";
import {Epoch, phase0, capella, Slot, ssz, StringType, RootHex, altair, UintNum64, allForks} from "@lodestar/types";
import {ContainerType} from "@chainsafe/ssz";
import {IChainForkConfig} from "@lodestar/config";

import {RouteDef, TypeJson} from "../../utils/index.js";
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";
import {ApiClientResponse} from "../../interfaces.js";
Expand Down Expand Up @@ -86,9 +87,9 @@ export type EventData = {
executionOptimistic: boolean;
};
[EventType.contributionAndProof]: altair.SignedContributionAndProof;
[EventType.lightClientOptimisticUpdate]: altair.LightClientOptimisticUpdate;
[EventType.lightClientFinalityUpdate]: altair.LightClientFinalityUpdate;
[EventType.lightClientUpdate]: altair.LightClientUpdate;
[EventType.lightClientOptimisticUpdate]: allForks.LightClientOptimisticUpdate;
[EventType.lightClientFinalityUpdate]: allForks.LightClientFinalityUpdate;
[EventType.lightClientUpdate]: allForks.LightClientUpdate;
};

export type BeaconEvent = {[K in EventType]: {type: K; message: EventData[K]}}[EventType];
Expand Down Expand Up @@ -123,8 +124,12 @@ export type ReqTypes = {
// It doesn't make sense to define a getReqSerializers() here given the exotic argument of eventstream()
// The request is very simple: (topics) => {query: {topics}}, and the test will ensure compatibility server - client

export function getTypeByEvent(): {[K in EventType]: Type<EventData[K]>} {
export function getTypeByEvent(config: IChainForkConfig): {[K in EventType]: TypeJson<EventData[K]>} {
const stringType = new StringType();
const getLightClientTypeFromHeader = (data: allForks.LightClientHeader): allForks.AllForksLightClientSSZTypes => {
return config.getLightClientForkTypes(data.beacon.slot);
};

return {
[EventType.head]: new ContainerType(
{
Expand Down Expand Up @@ -178,31 +183,45 @@ export function getTypeByEvent(): {[K in EventType]: Type<EventData[K]>} {

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

[EventType.lightClientOptimisticUpdate]: new ContainerType(
{
syncAggregate: ssz.altair.SyncAggregate,
attestedHeader: ssz.altair.LightClientHeader,
signatureSlot: ssz.Slot,
},
{jsonCase: "eth2"}
),
[EventType.lightClientFinalityUpdate]: new ContainerType(
{
attestedHeader: ssz.altair.LightClientHeader,
finalizedHeader: ssz.altair.LightClientHeader,
finalityBranch: new VectorCompositeType(ssz.Bytes32, FINALIZED_ROOT_DEPTH),
syncAggregate: ssz.altair.SyncAggregate,
signatureSlot: ssz.Slot,
},
{jsonCase: "eth2"}
),
[EventType.lightClientUpdate]: ssz.altair.LightClientUpdate,
[EventType.lightClientOptimisticUpdate]: {
toJson: (data) =>
getLightClientTypeFromHeader(((data as unknown) as allForks.LightClientOptimisticUpdate).attestedHeader)[
"LightClientOptimisticUpdate"
].toJson(data),
fromJson: (data) =>
getLightClientTypeFromHeader(
// eslint-disable-next-line @typescript-eslint/naming-convention
((data as unknown) as {attested_header: allForks.LightClientHeader}).attested_header
)["LightClientOptimisticUpdate"].fromJson(data),
},
[EventType.lightClientFinalityUpdate]: {
toJson: (data) =>
getLightClientTypeFromHeader(((data as unknown) as allForks.LightClientFinalityUpdate).attestedHeader)[
"LightClientFinalityUpdate"
].toJson(data),
fromJson: (data) =>
getLightClientTypeFromHeader(
// eslint-disable-next-line @typescript-eslint/naming-convention
((data as unknown) as {attested_header: allForks.LightClientHeader}).attested_header
)["LightClientFinalityUpdate"].fromJson(data),
},
[EventType.lightClientUpdate]: {
toJson: (data) =>
getLightClientTypeFromHeader(((data as unknown) as allForks.LightClientUpdate).attestedHeader)[
"LightClientUpdate"
].toJson(data),
fromJson: (data) =>
getLightClientTypeFromHeader(
// eslint-disable-next-line @typescript-eslint/naming-convention
((data as unknown) as {attested_header: allForks.LightClientHeader}).attested_header
)["LightClientUpdate"].fromJson(data),
},
};
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function getEventSerdes() {
const typeByEvent = getTypeByEvent();
export function getEventSerdes(config: IChainForkConfig) {
const typeByEvent = getTypeByEvent(config);

return {
toJson: (event: BeaconEvent): unknown => {
Expand Down
51 changes: 29 additions & 22 deletions packages/api/src/beacon/routes/lightclient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {altair, ssz, StringType, SyncPeriod} from "@lodestar/types";
import {ForkName} from "@lodestar/params";
import {ContainerType} from "@chainsafe/ssz";
import {ssz, SyncPeriod, allForks} from "@lodestar/types";
import {ForkName, isForkLightClient} from "@lodestar/params";
import {
ArrayOf,
ReturnTypes,
Expand All @@ -17,13 +16,6 @@ import {ApiClientResponse} from "../../interfaces.js";

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

export type LightClientBootstrap = {
header: altair.LightClientHeader;
currentSyncCommittee: altair.SyncCommittee;
/** Single branch proof from state root to currentSyncCommittee */
currentSyncCommitteeBranch: Uint8Array[];
};

export type Api = {
/**
* Returns an array of best updates given a `startPeriod` and `count` number of sync committee period to return.
Expand All @@ -39,7 +31,7 @@ export type Api = {
ApiClientResponse<{
[HttpStatusCode.OK]: {
version: ForkName;
data: altair.LightClientUpdate;
data: allForks.LightClientUpdate;
}[];
}>
>;
Expand All @@ -51,15 +43,15 @@ export type Api = {
ApiClientResponse<{
[HttpStatusCode.OK]: {
version: ForkName;
data: altair.LightClientOptimisticUpdate;
data: allForks.LightClientOptimisticUpdate;
};
}>
>;
getFinalityUpdate(): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: {
version: ForkName;
data: altair.LightClientFinalityUpdate;
data: allForks.LightClientFinalityUpdate;
};
}>
>;
Expand All @@ -74,7 +66,7 @@ export type Api = {
ApiClientResponse<{
[HttpStatusCode.OK]: {
version: ForkName;
data: altair.LightClientBootstrap;
data: allForks.LightClientBootstrap;
};
}>
>;
Expand Down Expand Up @@ -138,16 +130,31 @@ export function getReqSerializers(): ReqSerializers<Api, ReqTypes> {
}

export function getReturnTypes(): ReturnTypes<Api> {
// Form a TypeJson convertor for getUpdates
const VersionedUpdate = WithVersion((fork: ForkName) =>
isForkLightClient(fork) ? ssz.allForksLightClient[fork].LightClientUpdate : ssz.altair.LightClientUpdate
);
const getUpdates = {
toJson: (updates: {version: ForkName; data: allForks.LightClientUpdate}[]) =>
updates.map((data) => VersionedUpdate.toJson(data)),
fromJson: (updates: unknown[]) => updates.map((data) => VersionedUpdate.fromJson(data)),
};

return {
getUpdates: ArrayOf(
new ContainerType({
version: new StringType<ForkName>(),
data: ssz.altair.LightClientUpdate,
})
getUpdates,
getOptimisticUpdate: WithVersion((fork: ForkName) =>
isForkLightClient(fork)
? ssz.allForksLightClient[fork].LightClientOptimisticUpdate
: ssz.altair.LightClientOptimisticUpdate
),
getFinalityUpdate: WithVersion((fork: ForkName) =>
isForkLightClient(fork)
? ssz.allForksLightClient[fork].LightClientFinalityUpdate
: ssz.altair.LightClientFinalityUpdate
),
getBootstrap: WithVersion((fork: ForkName) =>
isForkLightClient(fork) ? ssz.allForksLightClient[fork].LightClientBootstrap : ssz.altair.LightClientBootstrap
),
getOptimisticUpdate: WithVersion(() => ssz.altair.LightClientOptimisticUpdate),
getFinalityUpdate: WithVersion(() => ssz.altair.LightClientFinalityUpdate),
getBootstrap: WithVersion(() => ssz.altair.LightClientBootstrap),
getCommitteeRoot: ContainerData(ArrayOf(ssz.Root)),
};
}
2 changes: 1 addition & 1 deletion packages/api/src/beacon/server/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {ServerRoutes} from "../../utils/server/index.js";
import {ServerApi} from "../../interfaces.js";

export function getRoutes(config: IChainForkConfig, api: ServerApi<Api>): ServerRoutes<Api, ReqTypes> {
const eventSerdes = getEventSerdes();
const eventSerdes = getEventSerdes(config);

return {
// Non-JSON route. Server Sent Events (SSE)
Expand Down
2 changes: 1 addition & 1 deletion packages/api/test/unit/beacon/oapiSpec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe("eventstream event data", () => {
}
});

const eventSerdes = routes.events.getEventSerdes();
const eventSerdes = routes.events.getEventSerdes(config);
const knownTopics = new Set<string>(Object.values(routes.events.eventTypes));

for (const [topic, {value}] of Object.entries(eventstreamExamples ?? {})) {
Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/src/chain/blocks/importBlock.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {altair, capella, ssz} from "@lodestar/types";
import {capella, ssz, allForks} from "@lodestar/types";
import {MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
import {toHexString} from "@chainsafe/ssz";
import {
Expand Down Expand Up @@ -275,7 +275,7 @@ export async function importBlock(
if (blockEpoch >= this.config.ALTAIR_FORK_EPOCH) {
try {
this.lightClientServer.onImportBlockHead(
block.message as altair.BeaconBlock,
block.message as allForks.AllForksLightClient["BeaconBlock"],
postState as CachedBeaconStateAltair,
parentBlockSlot
);
Expand Down
Loading