Skip to content

Commit

Permalink
Fix lightclient API to support SSZ (ChainSafe#5128)
Browse files Browse the repository at this point in the history
  • Loading branch information
maschad committed Mar 7, 2023
1 parent 5a671b1 commit 23c2c60
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 13 deletions.
18 changes: 17 additions & 1 deletion packages/api/src/beacon/routes/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "../../utils/index.js";
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";
import {ApiClientResponse} from "../../interfaces.js";
import {EncodingFormat} from "./shared.js";

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

Expand All @@ -29,14 +30,24 @@ export type Api = {
/**
* Get deposit contract address.
* Retrieve Eth1 deposit contract address and chain ID.
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
*/
getDepositContract(): Promise<ApiClientResponse<{[HttpStatusCode.OK]: {data: DepositContract}}>>;
getDepositContract(format?: "json"): Promise<ApiClientResponse<{[HttpStatusCode.OK]: {data: DepositContract}}>>;
getDepositContract(format: "ssz"): Promise<ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array}>>;
getDepositContract(
format?: EncodingFormat
): Promise<ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array | {data: DepositContract}}>>;

/**
* Get scheduled upcoming forks.
* Retrieve all scheduled upcoming forks this node is aware of.
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
*/
getForkSchedule(): Promise<ApiClientResponse<{[HttpStatusCode.OK]: {data: phase0.Fork[]}}>>;
getForkSchedule(format: "ssz"): Promise<ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array}>>;
getForkSchedule(
format?: EncodingFormat
): Promise<ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array | {data: phase0.Fork[]}}>>;

/**
* Retrieve specification configuration used on this node. The configuration should include:
Expand All @@ -47,8 +58,13 @@ export type Api = {
* Values are returned with following format:
* - any value starting with 0x in the spec is returned as a hex string
* - numeric values are returned as a quoted integer
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
*/
getSpec(): Promise<ApiClientResponse<{[HttpStatusCode.OK]: {data: Record<string, string>}}>>;
getSpec(format: "ssz"): Promise<ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array}>>;
getSpec(
format?: EncodingFormat
): Promise<ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array | {data: Record<string, string>}}>>;
};

/**
Expand Down
4 changes: 1 addition & 3 deletions packages/api/src/beacon/routes/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ import {
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";
import {ApiClientResponse} from "../../interfaces.js";
import {ExecutionOptimistic, StateId} from "./beacon/state.js";
import {EncodingFormat, mimeTypeSSZ} from "./shared.js";

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

export type EncodingFormat = "json" | "ssz";
export const mimeTypeSSZ = "application/octet-stream";

const stringType = new StringType();
const protoNodeSszType = new ContainerType(
{
Expand Down
116 changes: 107 additions & 9 deletions packages/api/src/beacon/routes/lightclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@ import {
} from "../../utils/index.js";
import {HttpStatusCode} from "../../utils/client/httpStatusCode.js";
import {ApiClientResponse} from "../../interfaces.js";
import {EncodingFormat} from "./shared.js";

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

export type Api = {
/**
* Returns an array of best updates given a `startPeriod` and `count` number of sync committee period to return.
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
* Best is defined by (in order of priority):
* - Is finalized update
* - Has most bits
* - Oldest update
*/
getUpdates(
startPeriod: SyncPeriod,
count: number
count: number,
format?: "json"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: {
Expand All @@ -35,33 +38,92 @@ export type Api = {
}[];
}>
>;
getUpdates(
startPeriod: SyncPeriod,
count: number,
format: "ssz"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array;
}>
>;
getUpdates(
startPeriod: SyncPeriod,
count: number,
format: EncodingFormat
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array | {version: ForkName; data: allForks.LightClientUpdate}[];
}>
>;
/**
* 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.
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
*/
getOptimisticUpdate(): Promise<
getOptimisticUpdate(
format?: "json"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: {
version: ForkName;
data: allForks.LightClientOptimisticUpdate;
};
}>
>;
getFinalityUpdate(): Promise<
getOptimisticUpdate(
format: "ssz"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array;
}>
>;
getOptimisticUpdate(
format: EncodingFormat
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array | {version: ForkName; data: allForks.LightClientOptimisticUpdate};
}>
>;
/**
* Returns the latest finality update available. Clients should use the SSE type `light_client_finality_update`
* unless to get the very first finality update after syncing, or if SSE are not supported by the server.
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
* */
getFinalityUpdate(
format?: "json"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: {
version: ForkName;
data: allForks.LightClientFinalityUpdate;
};
}>
>;
getFinalityUpdate(
format: "ssz"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array;
}>
>;
getFinalityUpdate(
format: EncodingFormat
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array | {version: ForkName; data: allForks.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.
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
*/
getBootstrap(
blockRoot: string
blockRoot: string,
format?: "json"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: {
Expand All @@ -70,19 +132,55 @@ export type Api = {
};
}>
>;
getBootstrap(
blockRoot: string,
format: "ssz"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array;
}>
>;
getBootstrap(
blockRoot: string,
format: EncodingFormat
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array | {version: ForkName; data: allForks.LightClientBootstrap};
}>
>;
/**
* Returns an array of sync committee hashes based on the provided period and count
* Depending on `Accept` header it can be returned either as json or as bytes serialized by SSZ
*/
getCommitteeRoot(
startPeriod: SyncPeriod,
count: number
count: number,
format?: "json"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: {
data: Uint8Array[];
};
}>
>;
getCommitteeRoot(
startPeriod: SyncPeriod,
count: number,
format: "ssz"
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array;
}>
>;
getCommitteeRoot(
startPeriod: SyncPeriod,
count: number,
format: EncodingFormat
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: Uint8Array | {data: Uint8Array[]};
}>
>;
};

/**
Expand All @@ -98,7 +196,7 @@ export const routesData: RoutesData<Api> = {

/* eslint-disable @typescript-eslint/naming-convention */
export type ReqTypes = {
getUpdates: {query: {start_period: number; count: number}};
getUpdates: {query: {start_period: number; count: number; format: EncodingFormat}};
getOptimisticUpdate: ReqEmpty;
getFinalityUpdate: ReqEmpty;
getBootstrap: {params: {block_root: string}};
Expand All @@ -108,9 +206,9 @@ export type ReqTypes = {
export function getReqSerializers(): ReqSerializers<Api, ReqTypes> {
return {
getUpdates: {
writeReq: (start_period, count) => ({query: {start_period, count}}),
parseReq: ({query}) => [query.start_period, query.count],
schema: {query: {start_period: Schema.UintRequired, count: Schema.UintRequired}},
writeReq: (start_period, count, format) => ({query: {start_period, count, format}}),
parseReq: ({query}) => [query.start_period, query.count, query.format],
schema: {query: {start_period: Schema.UintRequired, count: Schema.UintRequired, format: Schema.StringRequired}},
},

getOptimisticUpdate: reqEmpty,
Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/beacon/routes/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type EncodingFormat = "json" | "ssz";
export const mimeTypeSSZ = "application/octet-stream";

0 comments on commit 23c2c60

Please sign in to comment.