Skip to content

Commit 1856baf

Browse files
authored
Merge 03f7396 into 5d2e1a7
2 parents 5d2e1a7 + 03f7396 commit 1856baf

File tree

205 files changed

+6093
-938
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

205 files changed

+6093
-938
lines changed

packages/api/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
},
7272
"dependencies": {
7373
"@chainsafe/persistent-merkle-tree": "^0.8.0",
74-
"@chainsafe/ssz": "^0.17.0",
74+
"@chainsafe/ssz": "^0.17.1",
7575
"@lodestar/config": "^1.21.0",
7676
"@lodestar/params": "^1.21.0",
7777
"@lodestar/types": "^1.21.0",

packages/api/src/beacon/client/events.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type ApiClient = ApiClientMethods<Endpoints>;
1313
*/
1414
export function getClient(config: ChainForkConfig, baseUrl: string): ApiClient {
1515
const definitions = getDefinitions(config);
16-
const eventSerdes = getEventSerdes();
16+
const eventSerdes = getEventSerdes(config);
1717

1818
return {
1919
eventstream: async ({topics, signal, onEvent, onError, onClose}) => {

packages/api/src/beacon/routes/beacon/block.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
SignedBlockContents,
1515
sszTypesFor,
1616
} from "@lodestar/types";
17-
import {ForkName, ForkPreExecution, isForkBlobs, isForkExecution} from "@lodestar/params";
17+
import {ForkName, ForkPreElectra, ForkPreExecution, isForkBlobs, isForkExecution} from "@lodestar/params";
1818
import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js";
1919
import {EmptyMeta, EmptyResponseCodec, EmptyResponseData, WithVersion} from "../../../utils/codecs.js";
2020
import {
@@ -101,10 +101,22 @@ export type Endpoints = {
101101
"GET",
102102
BlockArgs,
103103
{params: {block_id: string}},
104-
BeaconBlockBody["attestations"],
104+
BeaconBlockBody<ForkPreElectra>["attestations"],
105105
ExecutionOptimisticAndFinalizedMeta
106106
>;
107107

108+
/**
109+
* Get block attestations
110+
* Retrieves attestation included in requested block.
111+
*/
112+
getBlockAttestationsV2: Endpoint<
113+
"GET",
114+
BlockArgs,
115+
{params: {block_id: string}},
116+
BeaconBlockBody["attestations"],
117+
ExecutionOptimisticFinalizedAndVersionMeta
118+
>;
119+
108120
/**
109121
* Get block header
110122
* Retrieves block header for given block id.
@@ -251,6 +263,15 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
251263
meta: ExecutionOptimisticAndFinalizedCodec,
252264
},
253265
},
266+
getBlockAttestationsV2: {
267+
url: "/eth/v2/beacon/blocks/{block_id}/attestations",
268+
method: "GET",
269+
req: blockIdOnlyReq,
270+
resp: {
271+
data: WithVersion((fork) => ssz[fork].BeaconBlockBody.fields.attestations),
272+
meta: ExecutionOptimisticFinalizedAndVersionCodec,
273+
},
274+
},
254275
getBlockHeader: {
255276
url: "/eth/v1/beacon/headers/{block_id}",
256277
method: "GET",

packages/api/src/beacon/routes/beacon/pool.ts

+195-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/* eslint-disable @typescript-eslint/naming-convention */
22
import {ValueOf} from "@chainsafe/ssz";
33
import {ChainForkConfig} from "@lodestar/config";
4-
import {phase0, capella, CommitteeIndex, Slot, ssz} from "@lodestar/types";
4+
import {isForkPostElectra} from "@lodestar/params";
5+
import {phase0, capella, CommitteeIndex, Slot, ssz, electra, AttesterSlashing} from "@lodestar/types";
56
import {Schema, Endpoint, RouteDefinitions} from "../../../utils/index.js";
67
import {
78
ArrayOf,
@@ -12,19 +13,31 @@ import {
1213
EmptyRequest,
1314
EmptyResponseCodec,
1415
EmptyResponseData,
16+
WithVersion,
1517
} from "../../../utils/codecs.js";
18+
import {MetaHeader, VersionCodec, VersionMeta} from "../../../utils/metadata.js";
19+
import {toForkName} from "../../../utils/fork.js";
20+
import {fromHeaders} from "../../../utils/headers.js";
1621

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

19-
const AttestationListType = ArrayOf(ssz.phase0.Attestation);
20-
const AttesterSlashingListType = ArrayOf(ssz.phase0.AttesterSlashing);
24+
const AttestationListTypePhase0 = ArrayOf(ssz.phase0.Attestation);
25+
const AttestationListTypeElectra = ArrayOf(ssz.electra.Attestation);
26+
const AttesterSlashingListTypePhase0 = ArrayOf(ssz.phase0.AttesterSlashing);
27+
const AttesterSlashingListTypeElectra = ArrayOf(ssz.electra.AttesterSlashing);
2128
const ProposerSlashingListType = ArrayOf(ssz.phase0.ProposerSlashing);
2229
const SignedVoluntaryExitListType = ArrayOf(ssz.phase0.SignedVoluntaryExit);
2330
const SignedBLSToExecutionChangeListType = ArrayOf(ssz.capella.SignedBLSToExecutionChange);
2431
const SyncCommitteeMessageListType = ArrayOf(ssz.altair.SyncCommitteeMessage);
2532

26-
type AttestationList = ValueOf<typeof AttestationListType>;
27-
type AttesterSlashingList = ValueOf<typeof AttesterSlashingListType>;
33+
type AttestationListPhase0 = ValueOf<typeof AttestationListTypePhase0>;
34+
type AttestationListElectra = ValueOf<typeof AttestationListTypeElectra>;
35+
type AttestationList = AttestationListPhase0 | AttestationListElectra;
36+
37+
type AttesterSlashingListPhase0 = ValueOf<typeof AttesterSlashingListTypePhase0>;
38+
type AttesterSlashingListElectra = ValueOf<typeof AttesterSlashingListTypeElectra>;
39+
type AttesterSlashingList = AttesterSlashingListPhase0 | AttesterSlashingListElectra;
40+
2841
type ProposerSlashingList = ValueOf<typeof ProposerSlashingListType>;
2942
type SignedVoluntaryExitList = ValueOf<typeof SignedVoluntaryExitListType>;
3043
type SignedBLSToExecutionChangeList = ValueOf<typeof SignedBLSToExecutionChangeListType>;
@@ -39,10 +52,22 @@ export type Endpoints = {
3952
"GET",
4053
{slot?: Slot; committeeIndex?: CommitteeIndex},
4154
{query: {slot?: number; committee_index?: number}},
42-
AttestationList,
55+
AttestationListPhase0,
4356
EmptyMeta
4457
>;
4558

59+
/**
60+
* Get Attestations from operations pool
61+
* Retrieves attestations known by the node but not necessarily incorporated into any block
62+
*/
63+
getPoolAttestationsV2: Endpoint<
64+
"GET",
65+
{slot?: Slot; committeeIndex?: CommitteeIndex},
66+
{query: {slot?: number; committee_index?: number}},
67+
AttestationList,
68+
VersionMeta
69+
>;
70+
4671
/**
4772
* Get AttesterSlashings from operations pool
4873
* Retrieves attester slashings known by the node but not necessarily incorporated into any block
@@ -52,10 +77,23 @@ export type Endpoints = {
5277
"GET",
5378
EmptyArgs,
5479
EmptyRequest,
55-
AttesterSlashingList,
80+
AttesterSlashingListPhase0,
5681
EmptyMeta
5782
>;
5883

84+
/**
85+
* Get AttesterSlashings from operations pool
86+
* Retrieves attester slashings known by the node but not necessarily incorporated into any block
87+
*/
88+
getPoolAttesterSlashingsV2: Endpoint<
89+
// ⏎
90+
"GET",
91+
EmptyArgs,
92+
EmptyRequest,
93+
AttesterSlashingList,
94+
VersionMeta
95+
>;
96+
5997
/**
6098
* Get ProposerSlashings from operations pool
6199
* Retrieves proposer slashings known by the node but not necessarily incorporated into any block
@@ -105,12 +143,28 @@ export type Endpoints = {
105143
*/
106144
submitPoolAttestations: Endpoint<
107145
"POST",
108-
{signedAttestations: AttestationList},
146+
{signedAttestations: AttestationListPhase0},
109147
{body: unknown},
110148
EmptyResponseData,
111149
EmptyMeta
112150
>;
113151

152+
/**
153+
* Submit Attestation objects to node
154+
* Submits Attestation objects to the node. Each attestation in the request body is processed individually.
155+
*
156+
* If an attestation is validated successfully the node MUST publish that attestation on the appropriate subnet.
157+
*
158+
* If one or more attestations fail validation the node MUST return a 400 error with details of which attestations have failed, and why.
159+
*/
160+
submitPoolAttestationsV2: Endpoint<
161+
"POST",
162+
{signedAttestations: AttestationList},
163+
{body: unknown; headers: {[MetaHeader.Version]: string}},
164+
EmptyResponseData,
165+
EmptyMeta
166+
>;
167+
114168
/**
115169
* Submit AttesterSlashing object to node's pool
116170
* Submits AttesterSlashing object to node's pool and if passes validation node MUST broadcast it to network.
@@ -123,6 +177,18 @@ export type Endpoints = {
123177
EmptyMeta
124178
>;
125179

180+
/**
181+
* Submit AttesterSlashing object to node's pool
182+
* Submits AttesterSlashing object to node's pool and if passes validation node MUST broadcast it to network.
183+
*/
184+
submitPoolAttesterSlashingsV2: Endpoint<
185+
"POST",
186+
{attesterSlashing: AttesterSlashing},
187+
{body: unknown; headers: {[MetaHeader.Version]: string}},
188+
EmptyResponseData,
189+
EmptyMeta
190+
>;
191+
126192
/**
127193
* Submit ProposerSlashing object to node's pool
128194
* Submits ProposerSlashing object to node's pool and if passes validation node MUST broadcast it to network.
@@ -172,7 +238,7 @@ export type Endpoints = {
172238
>;
173239
};
174240

175-
export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpoints> {
241+
export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoints> {
176242
return {
177243
getPoolAttestations: {
178244
url: "/eth/v1/beacon/pool/attestations",
@@ -183,19 +249,43 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
183249
schema: {query: {slot: Schema.Uint, committee_index: Schema.Uint}},
184250
},
185251
resp: {
186-
data: AttestationListType,
252+
data: AttestationListTypePhase0,
187253
meta: EmptyMetaCodec,
188254
},
189255
},
256+
getPoolAttestationsV2: {
257+
url: "/eth/v2/beacon/pool/attestations",
258+
method: "GET",
259+
req: {
260+
writeReq: ({slot, committeeIndex}) => ({query: {slot, committee_index: committeeIndex}}),
261+
parseReq: ({query}) => ({slot: query.slot, committeeIndex: query.committee_index}),
262+
schema: {query: {slot: Schema.Uint, committee_index: Schema.Uint}},
263+
},
264+
resp: {
265+
data: WithVersion((fork) => (isForkPostElectra(fork) ? AttestationListTypeElectra : AttestationListTypePhase0)),
266+
meta: VersionCodec,
267+
},
268+
},
190269
getPoolAttesterSlashings: {
191270
url: "/eth/v1/beacon/pool/attester_slashings",
192271
method: "GET",
193272
req: EmptyRequestCodec,
194273
resp: {
195-
data: AttesterSlashingListType,
274+
data: AttesterSlashingListTypePhase0,
196275
meta: EmptyMetaCodec,
197276
},
198277
},
278+
getPoolAttesterSlashingsV2: {
279+
url: "/eth/v2/beacon/pool/attester_slashings",
280+
method: "GET",
281+
req: EmptyRequestCodec,
282+
resp: {
283+
data: WithVersion((fork) =>
284+
isForkPostElectra(fork) ? AttesterSlashingListTypeElectra : AttesterSlashingListTypePhase0
285+
),
286+
meta: VersionCodec,
287+
},
288+
},
199289
getPoolProposerSlashings: {
200290
url: "/eth/v1/beacon/pool/proposer_slashings",
201291
method: "GET",
@@ -227,16 +317,61 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
227317
url: "/eth/v1/beacon/pool/attestations",
228318
method: "POST",
229319
req: {
230-
writeReqJson: ({signedAttestations}) => ({body: AttestationListType.toJson(signedAttestations)}),
231-
parseReqJson: ({body}) => ({signedAttestations: AttestationListType.fromJson(body)}),
232-
writeReqSsz: ({signedAttestations}) => ({body: AttestationListType.serialize(signedAttestations)}),
233-
parseReqSsz: ({body}) => ({signedAttestations: AttestationListType.deserialize(body)}),
320+
writeReqJson: ({signedAttestations}) => ({body: AttestationListTypePhase0.toJson(signedAttestations)}),
321+
parseReqJson: ({body}) => ({signedAttestations: AttestationListTypePhase0.fromJson(body)}),
322+
writeReqSsz: ({signedAttestations}) => ({body: AttestationListTypePhase0.serialize(signedAttestations)}),
323+
parseReqSsz: ({body}) => ({signedAttestations: AttestationListTypePhase0.deserialize(body)}),
234324
schema: {
235325
body: Schema.ObjectArray,
236326
},
237327
},
238328
resp: EmptyResponseCodec,
239329
},
330+
submitPoolAttestationsV2: {
331+
url: "/eth/v2/beacon/pool/attestations",
332+
method: "POST",
333+
req: {
334+
writeReqJson: ({signedAttestations}) => {
335+
const fork = config.getForkName(signedAttestations[0]?.data.slot ?? 0);
336+
return {
337+
body: isForkPostElectra(fork)
338+
? AttestationListTypeElectra.toJson(signedAttestations as AttestationListElectra)
339+
: AttestationListTypePhase0.toJson(signedAttestations as AttestationListPhase0),
340+
headers: {[MetaHeader.Version]: fork},
341+
};
342+
},
343+
parseReqJson: ({body, headers}) => {
344+
const fork = toForkName(fromHeaders(headers, MetaHeader.Version));
345+
return {
346+
signedAttestations: isForkPostElectra(fork)
347+
? AttestationListTypeElectra.fromJson(body)
348+
: AttestationListTypePhase0.fromJson(body),
349+
};
350+
},
351+
writeReqSsz: ({signedAttestations}) => {
352+
const fork = config.getForkName(signedAttestations[0]?.data.slot ?? 0);
353+
return {
354+
body: isForkPostElectra(fork)
355+
? AttestationListTypeElectra.serialize(signedAttestations as AttestationListElectra)
356+
: AttestationListTypePhase0.serialize(signedAttestations as AttestationListPhase0),
357+
headers: {[MetaHeader.Version]: fork},
358+
};
359+
},
360+
parseReqSsz: ({body, headers}) => {
361+
const fork = toForkName(fromHeaders(headers, MetaHeader.Version));
362+
return {
363+
signedAttestations: isForkPostElectra(fork)
364+
? AttestationListTypeElectra.deserialize(body)
365+
: AttestationListTypePhase0.deserialize(body),
366+
};
367+
},
368+
schema: {
369+
body: Schema.ObjectArray,
370+
headers: {[MetaHeader.Version]: Schema.String},
371+
},
372+
},
373+
resp: EmptyResponseCodec,
374+
},
240375
submitPoolAttesterSlashings: {
241376
url: "/eth/v1/beacon/pool/attester_slashings",
242377
method: "POST",
@@ -251,6 +386,51 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
251386
},
252387
resp: EmptyResponseCodec,
253388
},
389+
submitPoolAttesterSlashingsV2: {
390+
url: "/eth/v2/beacon/pool/attester_slashings",
391+
method: "POST",
392+
req: {
393+
writeReqJson: ({attesterSlashing}) => {
394+
const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot));
395+
return {
396+
body: isForkPostElectra(fork)
397+
? ssz.electra.AttesterSlashing.toJson(attesterSlashing)
398+
: ssz.phase0.AttesterSlashing.toJson(attesterSlashing),
399+
headers: {[MetaHeader.Version]: fork},
400+
};
401+
},
402+
parseReqJson: ({body, headers}) => {
403+
const fork = toForkName(fromHeaders(headers, MetaHeader.Version));
404+
return {
405+
attesterSlashing: isForkPostElectra(fork)
406+
? ssz.electra.AttesterSlashing.fromJson(body)
407+
: ssz.phase0.AttesterSlashing.fromJson(body),
408+
};
409+
},
410+
writeReqSsz: ({attesterSlashing}) => {
411+
const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot));
412+
return {
413+
body: isForkPostElectra(fork)
414+
? ssz.electra.AttesterSlashing.serialize(attesterSlashing as electra.AttesterSlashing)
415+
: ssz.phase0.AttesterSlashing.serialize(attesterSlashing as phase0.AttesterSlashing),
416+
headers: {[MetaHeader.Version]: fork},
417+
};
418+
},
419+
parseReqSsz: ({body, headers}) => {
420+
const fork = toForkName(fromHeaders(headers, MetaHeader.Version));
421+
return {
422+
attesterSlashing: isForkPostElectra(fork)
423+
? ssz.electra.AttesterSlashing.deserialize(body)
424+
: ssz.phase0.AttesterSlashing.deserialize(body),
425+
};
426+
},
427+
schema: {
428+
body: Schema.Object,
429+
headers: {[MetaHeader.Version]: Schema.String},
430+
},
431+
},
432+
resp: EmptyResponseCodec,
433+
},
254434
submitPoolProposerSlashings: {
255435
url: "/eth/v1/beacon/pool/proposer_slashings",
256436
method: "POST",

0 commit comments

Comments
 (0)