Skip to content
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
53 changes: 53 additions & 0 deletions packages/api/src/beacon/routes/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,34 @@ const DebugChainHeadType = new ContainerType(
{jsonCase: "eth2"}
);

const ForkChoiceNodeType = new ContainerType(
{
slot: ssz.Slot,
blockRoot: stringType,
parentRoot: stringType,
justifiedEpoch: ssz.Epoch,
finalizedEpoch: ssz.Epoch,
weight: ssz.UintNum64,
validity: new StringType<"valid" | "invalid" | "optimistic">(),
executionBlockHash: stringType,
},
{jsonCase: "eth2"}
);
const ForkChoiceResponseType = new ContainerType(
{
justifiedCheckpoint: ssz.phase0.Checkpoint,
finalizedCheckpoint: ssz.phase0.Checkpoint,
forkChoiceNodes: ArrayOf(ForkChoiceNodeType),
},
{jsonCase: "eth2"}
);

const ProtoNodeListType = ArrayOf(ProtoNodeType);
const DebugChainHeadListType = ArrayOf(DebugChainHeadType);

type ProtoNodeList = ValueOf<typeof ProtoNodeListType>;
type DebugChainHeadList = ValueOf<typeof DebugChainHeadListType>;
type ForkChoiceResponse = ValueOf<typeof ForkChoiceResponseType>;

export type Endpoints = {
/**
Expand All @@ -77,6 +100,18 @@ export type Endpoints = {
EmptyMeta
>;

/**
* Retrieves all current fork choice context
*/
getDebugForkChoice: Endpoint<
// ⏎
"GET",
EmptyArgs,
EmptyRequest,
ForkChoiceResponse,
EmptyMeta
>;

/**
* Dump all ProtoArray's nodes to debug
*/
Expand Down Expand Up @@ -115,6 +150,24 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
onlySupport: WireFormat.json,
},
},
getDebugForkChoice: {
url: "/eth/v1/debug/fork_choice",
method: "GET",
req: EmptyRequestCodec,
resp: {
data: ForkChoiceResponseType,
meta: EmptyMetaCodec,
onlySupport: WireFormat.json,
transform: {
Copy link
Member Author

@nflaig nflaig Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as per spec it's not wrapped in data container... it's too late to change it now though 😢

toResponse: (data) => ({
...(data as ForkChoiceResponse),
}),
fromResponse: (resp) => ({
data: resp as ForkChoiceResponse,
}),
},
},
},
getProtoArrayNodes: {
url: "/eth/v0/debug/forkchoice",
method: "GET",
Expand Down
1 change: 0 additions & 1 deletion packages/api/test/unit/beacon/oapiSpec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ const ignoredOperations = [
/* missing route */
"getDepositSnapshot", // Won't fix for now, see https://github.com/ChainSafe/lodestar/issues/5697
"getNextWithdrawals", // https://github.com/ChainSafe/lodestar/issues/5696
"getDebugForkChoice", // https://github.com/ChainSafe/lodestar/issues/5700
/* Must support ssz response body */
"getLightClientUpdatesByRange", // https://github.com/ChainSafe/lodestar/issues/6841
];
Expand Down
30 changes: 29 additions & 1 deletion packages/api/test/unit/beacon/testData/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,41 @@ import {ssz} from "@lodestar/types";
import {Endpoints} from "../../../../src/beacon/routes/debug.js";
import {GenericServerTestCases} from "../../../utils/genericServerTest.js";

const rootHex = toHexString(Buffer.alloc(32, 1));
const root = new Uint8Array(32).fill(1);
const rootHex = toHexString(root);

export const testData: GenericServerTestCases<Endpoints> = {
getDebugChainHeadsV2: {
args: undefined,
res: {data: [{slot: 1, root: rootHex, executionOptimistic: true}]},
},
getDebugForkChoice: {
args: undefined,
res: {
data: {
justifiedCheckpoint: {
epoch: 2,
root,
},
finalizedCheckpoint: {
epoch: 1,
root,
},
forkChoiceNodes: [
{
slot: 1,
blockRoot: rootHex,
parentRoot: rootHex,
justifiedEpoch: 1,
finalizedEpoch: 1,
weight: 1,
validity: "valid",
executionBlockHash: rootHex,
},
],
},
},
},
getProtoArrayNodes: {
args: undefined,
res: {
Expand Down
31 changes: 31 additions & 0 deletions packages/beacon-node/src/api/impl/debug/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {routes} from "@lodestar/api";
import {ApplicationMethods} from "@lodestar/api/server";
import {ExecutionStatus} from "@lodestar/fork-choice";
import {BeaconState} from "@lodestar/types";
import {ZERO_HASH_HEX} from "@lodestar/params";
import {getStateResponseWithRegen} from "../beacon/state/utils.js";
import {ApiModules} from "../types.js";
import {isOptimisticBlock} from "../../../util/forkChoice.js";
Expand All @@ -22,6 +24,35 @@ export function getDebugApi({
};
},

async getDebugForkChoice() {
return {
data: {
justifiedCheckpoint: chain.forkChoice.getJustifiedCheckpoint(),
finalizedCheckpoint: chain.forkChoice.getFinalizedCheckpoint(),
forkChoiceNodes: chain.forkChoice.getAllNodes().map((node) => ({
slot: node.slot,
blockRoot: node.blockRoot,
parentRoot: node.parentRoot,
justifiedEpoch: node.justifiedEpoch,
finalizedEpoch: node.finalizedEpoch,
weight: node.weight,
validity: (() => {
switch (node.executionStatus) {
case ExecutionStatus.Valid:
return "valid";
case ExecutionStatus.Invalid:
return "invalid";
case ExecutionStatus.Syncing:
case ExecutionStatus.PreMerge:
return "optimistic";
}
})(),
executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX,
})),
},
};
},

async getProtoArrayNodes() {
const nodes = chain.forkChoice.getAllNodes().map((node) => ({
// if node has executionPayloadNumber, it will overwrite the below default
Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/src/api/rest/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class RestApiServer {
if (err.validation) {
const {instancePath, message} = err.validation[0];
const payload: ErrorResponse = {
code: err.statusCode ?? 400,
code: 400,
message: `${instancePath.substring(instancePath.lastIndexOf("/") + 1)} ${message}`,
stacktraces,
};
Expand Down