Skip to content

Commit

Permalink
fix: infer returned type for getBlock apis
Browse files Browse the repository at this point in the history
  • Loading branch information
twoeths committed Sep 1, 2023
1 parent f463598 commit f91f152
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 27 deletions.
34 changes: 19 additions & 15 deletions packages/api/src/beacon/routes/beacon/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
ContainerData,
} from "../../../utils/index.js";
import {HttpStatusCode} from "../../../utils/client/httpStatusCode.js";
import {ApiClientResponse} from "../../../interfaces.js";
import {ApiClientResponse, ResponseFormat} from "../../../interfaces.js";
import {
SignedBlockContents,
SignedBlindedBlockContents,
Expand All @@ -31,7 +31,6 @@ import {
// See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes

export type BlockId = RootHex | Slot | "head" | "genesis" | "finalized";
export type BlockFormat = "json" | "ssz";
export const mimeTypeSSZ = "application/octet-stream";

/**
Expand Down Expand Up @@ -62,32 +61,37 @@ export type Api = {
* @param blockId Block identifier.
* Can be one of: "head" (canonical head in node's view), "genesis", "finalized", \<slot\>, \<hex encoded blockRoot with 0x prefix\>.
*/
getBlock(
getBlock<T extends ResponseFormat = "json">(
blockId: BlockId,
format?: BlockFormat
): Promise<ApiClientResponse<{[HttpStatusCode.OK]: Uint8Array | {data: allForks.SignedBeaconBlock}}>>;
format?: T
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: allForks.SignedBeaconBlock}},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND,
T
>
>;

/**
* Get block
* Retrieves block details for given block id.
* @param blockId Block identifier.
* Can be one of: "head" (canonical head in node's view), "genesis", "finalized", \<slot\>, \<hex encoded blockRoot with 0x prefix\>.
*/
getBlockV2(
getBlockV2<T extends ResponseFormat = "json">(
blockId: BlockId,
format?: BlockFormat
format?: T
): Promise<
ApiClientResponse<
{
[HttpStatusCode.OK]:
| Uint8Array
| {
data: allForks.SignedBeaconBlock;
executionOptimistic: ExecutionOptimistic;
version: ForkName;
};
[HttpStatusCode.OK]: {
data: allForks.SignedBeaconBlock;
executionOptimistic: ExecutionOptimistic;
version: ForkName;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND,
T
>
>;

Expand Down
11 changes: 9 additions & 2 deletions packages/api/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ import {Resolves} from "./utils/types.js";

/* eslint-disable @typescript-eslint/no-explicit-any */

export type ResponseFormat = "json" | "ssz";
export type APIClientHandler = (...args: any) => PromiseLike<ApiClientResponse>;
export type APIServerHandler = (...args: any) => PromiseLike<unknown>;

export type ApiClientSuccessResponse<S extends keyof any, T> = {ok: true; status: S; response: T; error?: never};
export type ApiClientSuccessResponse<S extends keyof any, R, T> = {
ok: true;
status: S;
response: T extends "ssz" ? Uint8Array : R;
error?: never;
};
export type ApiClientErrorResponse<S extends Exclude<HttpStatusCode, HttpSuccessCodes>> = {
ok: false;
status: S;
Expand All @@ -16,8 +22,9 @@ export type ApiClientErrorResponse<S extends Exclude<HttpStatusCode, HttpSuccess
export type ApiClientResponse<
S extends Partial<{[K in HttpSuccessCodes]: unknown}> = {[K in HttpSuccessCodes]: unknown},
E extends Exclude<HttpStatusCode, HttpSuccessCodes> = Exclude<HttpStatusCode, HttpSuccessCodes>,
T extends ResponseFormat = "json",
> =
| {[K in keyof S]: ApiClientSuccessResponse<K, S[K]>}[keyof S]
| {[K in keyof S]: ApiClientSuccessResponse<K, S[K], T>}[keyof S]
| {[K in E]: ApiClientErrorResponse<K>}[E]
| ApiClientErrorResponse<HttpStatusCode.INTERNAL_SERVER_ERROR>;

Expand Down
7 changes: 5 additions & 2 deletions packages/api/src/utils/client/httpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ export class ApiError extends Error {
this.operationId = operationId;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
static assert(res: ApiClientResponse, message?: string): asserts res is ApiClientSuccessResponse<any, unknown> {
static assert(
res: ApiClientResponse,
message?: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): asserts res is ApiClientSuccessResponse<any, unknown, unknown> {
if (!res.ok) {
throw new ApiError([message, res.error.message].join(" - "), res.error.code, res.error.operationId);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/beacon-node/src/api/impl/beacon/blocks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {fromHexString, toHexString} from "@chainsafe/ssz";
import {routes, ServerApi, isSignedBlockContents, isSignedBlindedBlockContents} from "@lodestar/api";
import {routes, ServerApi, isSignedBlockContents, isSignedBlindedBlockContents, ResponseFormat} from "@lodestar/api";
import {computeTimeAtSlot} from "@lodestar/state-transition";
import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
import {sleep, toHex} from "@lodestar/utils";
Expand Down Expand Up @@ -243,7 +243,7 @@ export function getBeaconBlockApi({
};
},

async getBlock(blockId, format?: routes.beacon.block.BlockFormat) {
async getBlock(blockId, format?: ResponseFormat) {
const {block} = await resolveBlockId(chain, blockId);
if (format === "ssz") {
// Casting to any otherwise Typescript doesn't like the multi-type return
Expand All @@ -255,7 +255,7 @@ export function getBeaconBlockApi({
};
},

async getBlockV2(blockId, format?: routes.beacon.block.BlockFormat) {
async getBlockV2(blockId, format?: ResponseFormat) {
const {block, executionOptimistic} = await resolveBlockId(chain, blockId);
if (format === "ssz") {
// Casting to any otherwise Typescript doesn't like the multi-type return
Expand Down
6 changes: 4 additions & 2 deletions packages/beacon-node/test/sim/mergemock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {LogLevel, sleep} from "@lodestar/utils";
import {TimestampFormatCode} from "@lodestar/logger";
import {SLOTS_PER_EPOCH} from "@lodestar/params";
import {ChainConfig} from "@lodestar/config";
import {Epoch, bellatrix} from "@lodestar/types";
import {Epoch, allForks, bellatrix} from "@lodestar/types";
import {ValidatorProposerConfig, BuilderSelection} from "@lodestar/validator";
import {routes} from "@lodestar/api";

Expand Down Expand Up @@ -210,7 +210,9 @@ describe("executionEngine / ExecutionEngineHttp", function () {
let builderBlocks = 0;
await new Promise<void>((resolve, _reject) => {
bn.chain.emitter.on(routes.events.EventType.block, async (blockData) => {
const {data: fullOrBlindedBlock} = await bn.api.beacon.getBlockV2(blockData.block);
const {data: fullOrBlindedBlock} = (await bn.api.beacon.getBlockV2(blockData.block)) as {
data: allForks.SignedBeaconBlock;
};
if (fullOrBlindedBlock !== undefined) {
const blockFeeRecipient = toHexString(
(fullOrBlindedBlock as bellatrix.SignedBeaconBlock).message.body.executionPayload.feeRecipient
Expand Down
7 changes: 5 additions & 2 deletions packages/beacon-node/test/sim/withdrawal-interop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TimestampFormatCode} from "@lodestar/logger";
import {SLOTS_PER_EPOCH, ForkName} from "@lodestar/params";
import {ChainConfig} from "@lodestar/config";
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
import {Epoch, capella, Slot} from "@lodestar/types";
import {Epoch, capella, Slot, allForks} from "@lodestar/types";
import {ValidatorProposerConfig} from "@lodestar/validator";

import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js";
Expand Down Expand Up @@ -369,7 +369,10 @@ async function retrieveCanonicalWithdrawals(bn: BeaconNode, fromSlot: Slot, toSl
});

if (block) {
if ((block.data as capella.SignedBeaconBlock).message.body.executionPayload?.withdrawals.length > 0) {
if (
((block as {data: allForks.SignedBeaconBlock}).data as capella.SignedBeaconBlock).message.body.executionPayload
?.withdrawals.length > 0
) {
withdrawalsBlocks++;
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/state-transition/test/perf/analyzeBlocks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {getClient, ApiError} from "@lodestar/api";
import {config} from "@lodestar/config/default";
import {allForks} from "@lodestar/types";
import {getInfuraBeaconUrl} from "../utils/infura.js";

// Analyze how Ethereum Consensus blocks are in a target network to prepare accurate performance states and blocks
Expand Down Expand Up @@ -52,7 +53,7 @@ async function run(): Promise<void> {
}
ApiError.assert(result.value);

const block = result.value.response.data;
const block = (result.value.response as {data: allForks.SignedBeaconBlock}).data;

blocks++;
attestations += block.message.body.attestations.length;
Expand Down

0 comments on commit f91f152

Please sign in to comment.