@lodestar/api 1.50.0-dev.335476095e → 1.50.0-dev.3430a7cf04

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/lib/beacon/client/events.d.ts.map +1 -1
  2. package/lib/beacon/client/events.js +2 -1
  3. package/lib/beacon/client/events.js.map +1 -1
  4. package/lib/beacon/routes/beacon/block.d.ts.map +1 -1
  5. package/lib/beacon/routes/beacon/block.js +3 -3
  6. package/lib/beacon/routes/beacon/block.js.map +1 -1
  7. package/lib/beacon/routes/beacon/index.d.ts +1 -1
  8. package/lib/beacon/routes/beacon/index.d.ts.map +1 -1
  9. package/lib/beacon/routes/beacon/index.js.map +1 -1
  10. package/lib/beacon/routes/beacon/state.d.ts +30 -5
  11. package/lib/beacon/routes/beacon/state.d.ts.map +1 -1
  12. package/lib/beacon/routes/beacon/state.js +25 -4
  13. package/lib/beacon/routes/beacon/state.js.map +1 -1
  14. package/lib/beacon/routes/debug.d.ts +24 -10
  15. package/lib/beacon/routes/debug.d.ts.map +1 -1
  16. package/lib/beacon/routes/debug.js +19 -18
  17. package/lib/beacon/routes/debug.js.map +1 -1
  18. package/lib/beacon/routes/events.d.ts +2 -0
  19. package/lib/beacon/routes/events.d.ts.map +1 -1
  20. package/lib/beacon/routes/events.js.map +1 -1
  21. package/lib/beacon/routes/lodestar.d.ts.map +1 -1
  22. package/lib/beacon/routes/lodestar.js +5 -5
  23. package/lib/beacon/routes/lodestar.js.map +1 -1
  24. package/lib/index.d.ts +1 -1
  25. package/lib/index.d.ts.map +1 -1
  26. package/lib/index.js.map +1 -1
  27. package/lib/utils/client/error.d.ts +8 -1
  28. package/lib/utils/client/error.d.ts.map +1 -1
  29. package/lib/utils/client/error.js +4 -1
  30. package/lib/utils/client/error.js.map +1 -1
  31. package/lib/utils/client/response.d.ts +1 -1
  32. package/lib/utils/client/response.d.ts.map +1 -1
  33. package/lib/utils/client/response.js +11 -7
  34. package/lib/utils/client/response.js.map +1 -1
  35. package/lib/utils/fork.d.ts +2 -1
  36. package/lib/utils/fork.d.ts.map +1 -1
  37. package/lib/utils/fork.js +7 -1
  38. package/lib/utils/fork.js.map +1 -1
  39. package/package.json +7 -7
  40. package/src/beacon/client/events.ts +3 -0
  41. package/src/beacon/routes/beacon/block.ts +10 -5
  42. package/src/beacon/routes/beacon/index.ts +1 -0
  43. package/src/beacon/routes/beacon/state.ts +50 -8
  44. package/src/beacon/routes/debug.ts +22 -18
  45. package/src/beacon/routes/events.ts +2 -0
  46. package/src/beacon/routes/lodestar.ts +5 -4
  47. package/src/index.ts +1 -1
  48. package/src/utils/client/error.ts +7 -1
  49. package/src/utils/client/response.ts +13 -9
  50. package/src/utils/fork.ts +10 -0
@@ -6,6 +6,7 @@ import {
6
6
  BuilderStatus,
7
7
  CommitteeIndex,
8
8
  Epoch,
9
+ GeneralValidatorStatus,
9
10
  RootHex,
10
11
  Slot,
11
12
  StringType,
@@ -16,7 +17,8 @@ import {
16
17
  phase0,
17
18
  ssz,
18
19
  } from "@lodestar/types";
19
- import {JsonOnlyReq} from "../../../utils/codecs.js";
20
+ import {JsonOnlyReq, WithVersion} from "../../../utils/codecs.js";
21
+ import {getPostElectraForkTypes} from "../../../utils/fork.js";
20
22
  import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js";
21
23
  import {
22
24
  ExecutionOptimisticAndFinalizedCodec,
@@ -43,6 +45,12 @@ export type BuilderId = string | number;
43
45
 
44
46
  export type {BuilderStatus, ValidatorStatus};
45
47
 
48
+ /**
49
+ * Beacon API `status` filter: oneOf [ValidatorStatus, enum [active, pending, exited, withdrawal]].
50
+ * https://github.com/ethereum/beacon-APIs/blob/master/apis/beacon/states/validators.yaml
51
+ */
52
+ export type ValidatorStatusFilter = ValidatorStatus | GeneralValidatorStatus;
53
+
46
54
  export const RandaoResponseType = new ContainerType({
47
55
  randao: ssz.Root,
48
56
  });
@@ -91,6 +99,10 @@ export const EpochSyncCommitteeResponseType = new ContainerType(
91
99
  },
92
100
  {jsonCase: "eth2"}
93
101
  );
102
+ export const PtcResponseType = new ContainerType({
103
+ slot: ssz.Slot,
104
+ validators: ssz.gloas.PayloadTimelinessCommittee,
105
+ });
94
106
  export const ValidatorResponseListType = ArrayOf(ValidatorResponseType);
95
107
  export const BuilderResponseListType = ArrayOf(BuilderResponseType);
96
108
  export const ValidatorIdentitiesType = ArrayOf(ValidatorIdentityType);
@@ -104,6 +116,7 @@ export type BuilderResponse = ValueOf<typeof BuilderResponseType>;
104
116
  export type EpochCommitteeResponse = ValueOf<typeof EpochCommitteeResponseType>;
105
117
  export type ValidatorBalance = ValueOf<typeof ValidatorBalanceType>;
106
118
  export type EpochSyncCommitteeResponse = ValueOf<typeof EpochSyncCommitteeResponseType>;
119
+ export type PtcResponse = ValueOf<typeof PtcResponseType>;
107
120
 
108
121
  export type ValidatorResponseList = ValueOf<typeof ValidatorResponseListType>;
109
122
  export type BuilderResponseList = ValueOf<typeof BuilderResponseListType>;
@@ -191,9 +204,9 @@ export type Endpoints = {
191
204
  /** Either hex encoded public key (with 0x prefix) or validator index */
192
205
  validatorIds?: ValidatorId[];
193
206
  /** [Validator status specification](https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ) */
194
- statuses?: ValidatorStatus[];
207
+ statuses?: ValidatorStatusFilter[];
195
208
  },
196
- {params: {state_id: string}; query: {id?: ValidatorId[]; status?: ValidatorStatus[]}},
209
+ {params: {state_id: string}; query: {id?: ValidatorId[]; status?: ValidatorStatusFilter[]}},
197
210
  ValidatorResponseList,
198
211
  ExecutionOptimisticAndFinalizedMeta
199
212
  >;
@@ -208,9 +221,9 @@ export type Endpoints = {
208
221
  /** Either hex encoded public key (with 0x prefix) or validator index */
209
222
  validatorIds?: ValidatorId[];
210
223
  /** [Validator status specification](https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ) */
211
- statuses?: ValidatorStatus[];
224
+ statuses?: ValidatorStatusFilter[];
212
225
  },
213
- {params: {state_id: string}; body: {ids?: string[]; statuses?: ValidatorStatus[]}},
226
+ {params: {state_id: string}; body: {ids?: string[]; statuses?: ValidatorStatusFilter[]}},
214
227
  ValidatorResponseList,
215
228
  ExecutionOptimisticAndFinalizedMeta
216
229
  >;
@@ -316,6 +329,19 @@ export type Endpoints = {
316
329
  ExecutionOptimisticAndFinalizedMeta
317
330
  >;
318
331
 
332
+ /**
333
+ * Get the payload timeliness committee for a slot from the given state.
334
+ *
335
+ * Defaults to the state's slot. Validator indices are returned in committee order and may contain duplicates.
336
+ */
337
+ getStatePtc: Endpoint<
338
+ "GET",
339
+ StateArgs & {slot?: Slot},
340
+ {params: {state_id: string}; query: {slot?: number}},
341
+ PtcResponse,
342
+ ExecutionOptimisticAndFinalizedMeta
343
+ >;
344
+
319
345
  /**
320
346
  * Get State Pending Deposits
321
347
  *
@@ -444,6 +470,22 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
444
470
  meta: ExecutionOptimisticAndFinalizedCodec,
445
471
  },
446
472
  },
473
+ getStatePtc: {
474
+ url: "/eth/v1/beacon/states/{state_id}/ptc",
475
+ method: "GET",
476
+ req: {
477
+ writeReq: ({stateId, slot}) => ({params: {state_id: stateId.toString()}, query: {slot}}),
478
+ parseReq: ({params, query}) => ({stateId: params.state_id, slot: query.slot}),
479
+ schema: {
480
+ params: {state_id: Schema.StringRequired},
481
+ query: {slot: Schema.Uint},
482
+ },
483
+ },
484
+ resp: {
485
+ data: PtcResponseType,
486
+ meta: ExecutionOptimisticAndFinalizedCodec,
487
+ },
488
+ },
447
489
  getStateFinalityCheckpoints: {
448
490
  url: "/eth/v1/beacon/states/{state_id}/finality_checkpoints",
449
491
  method: "GET",
@@ -642,7 +684,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
642
684
  method: "GET",
643
685
  req: stateIdOnlyReq,
644
686
  resp: {
645
- data: ssz.electra.PendingDeposits,
687
+ data: WithVersion((fork) => getPostElectraForkTypes(fork).PendingDeposits),
646
688
  meta: ExecutionOptimisticFinalizedAndVersionCodec,
647
689
  },
648
690
  },
@@ -651,7 +693,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
651
693
  method: "GET",
652
694
  req: stateIdOnlyReq,
653
695
  resp: {
654
- data: ssz.electra.PendingPartialWithdrawals,
696
+ data: WithVersion((fork) => getPostElectraForkTypes(fork).PendingPartialWithdrawals),
655
697
  meta: ExecutionOptimisticFinalizedAndVersionCodec,
656
698
  },
657
699
  },
@@ -660,7 +702,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
660
702
  method: "GET",
661
703
  req: stateIdOnlyReq,
662
704
  resp: {
663
- data: ssz.electra.PendingConsolidations,
705
+ data: WithVersion((fork) => getPostElectraForkTypes(fork).PendingConsolidations),
664
706
  meta: ExecutionOptimisticFinalizedAndVersionCodec,
665
707
  },
666
708
  },
@@ -80,40 +80,52 @@ const ForkChoiceResponseType = new ContainerType(
80
80
 
81
81
  const ForkChoiceNodeV2ExtraDataType = new ContainerType(
82
82
  {
83
+ attestationScore: ssz.Gwei,
83
84
  executionOptimistic: ssz.Boolean,
85
+ gasLimit: new OptionalType(ssz.UintNum64),
84
86
  timestamp: ssz.UintNum64,
87
+ stateRoot: stringType,
85
88
  target: stringType,
86
- justifiedEpoch: ssz.Epoch,
87
- finalizedEpoch: ssz.Epoch,
88
89
  unrealizedJustifiedEpoch: ssz.Epoch,
90
+ unrealizedJustifiedRoot: stringType,
89
91
  unrealizedFinalizedEpoch: ssz.Epoch,
90
- payloadAttesterCount: new OptionalType(ssz.UintNum64),
91
- payloadAvailabilityYesCount: new OptionalType(ssz.UintNum64),
92
- payloadDataAvailabilityYesCount: new OptionalType(ssz.UintNum64),
93
- gasLimit: new OptionalType(ssz.UintNum64),
92
+ unrealizedFinalizedRoot: stringType,
94
93
  },
95
94
  {jsonCase: "eth2"}
96
95
  );
96
+ const payloadStatusType = new StringType<"pending" | "empty" | "full">();
97
97
  const ForkChoiceNodeV2Type = new ContainerType(
98
98
  {
99
- payloadStatus: new StringType<"pending" | "empty" | "full">(),
100
99
  slot: ssz.Slot,
101
100
  blockRoot: stringType,
101
+ payloadStatus: payloadStatusType,
102
102
  parentRoot: stringType,
103
+ parentPayloadStatus: new OptionalType(payloadStatusType),
104
+ justifiedCheckpoint: ssz.phase0.Checkpoint,
105
+ finalizedCheckpoint: ssz.phase0.Checkpoint,
103
106
  weight: ssz.Gwei,
104
107
  validity: new StringType<"valid" | "invalid" | "optimistic">(),
105
108
  executionBlockHash: stringType,
109
+ payloadAttesterCount: ssz.UintNum64,
110
+ payloadAvailabilityYesCount: ssz.UintNum64,
111
+ payloadDataAvailabilityYesCount: ssz.UintNum64,
106
112
  extraData: ForkChoiceNodeV2ExtraDataType,
107
113
  },
108
114
  {jsonCase: "eth2"}
109
115
  );
110
116
  const ForkChoiceExtraDataType = new ContainerType(
111
117
  {
112
- unrealizedJustifiedCheckpoint: ssz.phase0.Checkpoint,
113
- unrealizedFinalizedCheckpoint: ssz.phase0.Checkpoint,
118
+ head: new ContainerType(
119
+ {
120
+ blockRoot: stringType,
121
+ payloadStatus: payloadStatusType,
122
+ },
123
+ {jsonCase: "eth2"}
124
+ ),
114
125
  proposerBoostRoot: stringType,
115
126
  previousProposerBoostRoot: stringType,
116
- headRoot: stringType,
127
+ unrealizedJustifiedCheckpoint: ssz.phase0.Checkpoint,
128
+ unrealizedFinalizedCheckpoint: ssz.phase0.Checkpoint,
117
129
  },
118
130
  {jsonCase: "eth2"}
119
131
  );
@@ -255,14 +267,6 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
255
267
  data: ForkChoiceResponseV2Type,
256
268
  meta: EmptyMetaCodec,
257
269
  onlySupport: WireFormat.json,
258
- transform: {
259
- toResponse: (data) => ({
260
- ...(data as ForkChoiceResponseV2),
261
- }),
262
- fromResponse: (resp) => ({
263
- data: resp as ForkChoiceResponseV2,
264
- }),
265
- },
266
270
  },
267
271
  },
268
272
  getProtoArrayNodes: {
@@ -270,6 +270,8 @@ type EventstreamArgs = {
270
270
  topics: EventType[];
271
271
  signal: AbortSignal;
272
272
  onEvent: (event: BeaconEvent) => void;
273
+ /** Called every time the connection is established, including reconnects */
274
+ onOpen?: () => void;
273
275
  onError?: (err: Error) => void;
274
276
  onClose?: () => void;
275
277
  };
@@ -11,6 +11,7 @@ import {
11
11
  Slot,
12
12
  ValidatorIndex,
13
13
  ssz,
14
+ sszTypesFor,
14
15
  } from "@lodestar/types";
15
16
  import {
16
17
  EmptyArgs,
@@ -672,13 +673,13 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
672
673
  if (signedBlocks.length === 0) throw new Error("No blocks provided.");
673
674
  const fork = config.getForkName(signedBlocks[0].message.slot);
674
675
  return {
675
- body: ArrayOf(ssz[fork].SignedBeaconBlock).toJson(signedBlocks as SignedBeaconBlock<typeof fork>[]),
676
+ body: ArrayOf(sszTypesFor(fork).SignedBeaconBlock).toJson(signedBlocks),
676
677
  headers: {[MetaHeader.Version]: fork},
677
678
  };
678
679
  },
679
680
  parseReqJson: ({body, headers}) => {
680
681
  const fork = toForkName(fromHeaders(headers, MetaHeader.Version));
681
- const signedBlocks = ArrayOf(ssz[fork].SignedBeaconBlock).fromJson(body) as SignedBeaconBlock[];
682
+ const signedBlocks = ArrayOf(sszTypesFor(fork).SignedBeaconBlock).fromJson(body);
682
683
  assertBlocksMatchFork(signedBlocks, fork);
683
684
  return {signedBlocks};
684
685
  },
@@ -686,13 +687,13 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
686
687
  if (signedBlocks.length === 0) throw new Error("No blocks provided.");
687
688
  const fork = config.getForkName(signedBlocks[0].message.slot);
688
689
  return {
689
- body: ArrayOf(ssz[fork].SignedBeaconBlock).serialize(signedBlocks as SignedBeaconBlock<typeof fork>[]),
690
+ body: ArrayOf(sszTypesFor(fork).SignedBeaconBlock).serialize(signedBlocks),
690
691
  headers: {[MetaHeader.Version]: fork},
691
692
  };
692
693
  },
693
694
  parseReqSsz: ({body, headers}) => {
694
695
  const fork = toForkName(fromHeaders(headers, MetaHeader.Version));
695
- const signedBlocks = ArrayOf(ssz[fork].SignedBeaconBlock).deserialize(body) as SignedBeaconBlock[];
696
+ const signedBlocks = ArrayOf(sszTypesFor(fork).SignedBeaconBlock).deserialize(body);
696
697
  assertBlocksMatchFork(signedBlocks, fork);
697
698
  return {signedBlocks};
698
699
  },
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Re-exporting beacon only for backwards compatibility
2
2
  export * from "./beacon/index.js";
3
- export {ApiError} from "./utils/client/error.js";
3
+ export {ApiError, type ApiFailure} from "./utils/client/error.js";
4
4
  export type {
5
5
  ApiClientMethods,
6
6
  HttpClientModules,
@@ -1,10 +1,16 @@
1
+ /** Failure of a single item of a batch request, `index` refers to the submitted array */
2
+ export type ApiFailure = {index: number; message: string};
3
+
1
4
  export class ApiError extends Error {
2
5
  status: number;
3
6
  operationId: string;
7
+ /** Set if the server rejected only some items of a batch request */
8
+ failures?: ApiFailure[];
4
9
 
5
- constructor(message: string, status: number, operationId: string) {
10
+ constructor(message: string, status: number, operationId: string, failures?: ApiFailure[]) {
6
11
  super(`${operationId} failed with status ${status}: ${message}`);
7
12
  this.status = status;
8
13
  this.operationId = operationId;
14
+ this.failures = failures;
9
15
  }
10
16
  }
@@ -2,7 +2,7 @@ import {HeadersExtra, HttpHeader, parseContentTypeHeader} from "../headers.js";
2
2
  import {HttpStatusCode} from "../httpStatusCode.js";
3
3
  import {Endpoint} from "../types.js";
4
4
  import {WireFormat, getWireFormat} from "../wireFormat.js";
5
- import {ApiError} from "./error.js";
5
+ import {ApiError, ApiFailure} from "./error.js";
6
6
  import {RouteDefinitionExtra} from "./request.js";
7
7
 
8
8
  export type RawBody =
@@ -162,7 +162,8 @@ export class ApiResponse<E extends Endpoint> extends Response {
162
162
  return null;
163
163
  }
164
164
 
165
- return new ApiError(this.getErrorMessage(), this.status, this.definition.operationId);
165
+ const {message, failures} = this.parseErrorBody();
166
+ return new ApiError(message, this.status, this.definition.operationId, failures);
166
167
  }
167
168
 
168
169
  async errorBody(): Promise<string> {
@@ -187,19 +188,22 @@ export class ApiResponse<E extends Endpoint> extends Response {
187
188
  return this._errorBody;
188
189
  }
189
190
 
190
- private getErrorMessage(): string {
191
+ private parseErrorBody(): {message: string; failures?: ApiFailure[]} {
191
192
  const errBody = this.resolvedErrorBody();
192
193
  try {
193
- const errJson = JSON.parse(errBody) as {message?: string; failures?: {message: string}[]};
194
+ const errJson = JSON.parse(errBody) as {message?: string; failures?: ApiFailure[]};
194
195
  if (errJson.message) {
195
- if (errJson.failures) {
196
- return `${errJson.message}\n` + errJson.failures.map((e) => e.message).join("\n");
196
+ if (Array.isArray(errJson.failures)) {
197
+ return {
198
+ message: `${errJson.message}\n` + errJson.failures.map((e) => e.message).join("\n"),
199
+ failures: errJson.failures,
200
+ };
197
201
  }
198
- return errJson.message;
202
+ return {message: errJson.message};
199
203
  }
200
- return errBody;
204
+ return {message: errBody};
201
205
  } catch (_e) {
202
- return errBody || this.statusText;
206
+ return {message: errBody || this.statusText};
203
207
  }
204
208
  }
205
209
  }
package/src/utils/fork.ts CHANGED
@@ -3,10 +3,12 @@ import {
3
3
  ForkPostAltair,
4
4
  ForkPostBellatrix,
5
5
  ForkPostDeneb,
6
+ ForkPostElectra,
6
7
  ForkPostGloas,
7
8
  isForkPostAltair,
8
9
  isForkPostBellatrix,
9
10
  isForkPostDeneb,
11
+ isForkPostElectra,
10
12
  isForkPostGloas,
11
13
  } from "@lodestar/params";
12
14
  import {SSZTypesFor, sszTypesFor} from "@lodestar/types";
@@ -45,6 +47,14 @@ export function getPostDenebForkTypes(fork: ForkName): SSZTypesFor<ForkPostDeneb
45
47
  return sszTypesFor(fork);
46
48
  }
47
49
 
50
+ export function getPostElectraForkTypes(fork: ForkName): SSZTypesFor<ForkPostElectra> {
51
+ if (!isForkPostElectra(fork)) {
52
+ throw Error(`Invalid fork=${fork} for post-electra fork types`);
53
+ }
54
+
55
+ return sszTypesFor(fork);
56
+ }
57
+
48
58
  export function getPostGloasForkTypes(fork: ForkName): SSZTypesFor<ForkPostGloas> {
49
59
  if (!isForkPostGloas(fork)) {
50
60
  throw Error(`Invalid fork=${fork} for post-gloas fork types`);