@lodestar/api 1.50.0-dev.1f129c79a1 → 1.50.0-dev.20062ed60e
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.
- package/lib/beacon/client/events.d.ts.map +1 -1
- package/lib/beacon/client/events.js +2 -1
- package/lib/beacon/client/events.js.map +1 -1
- package/lib/beacon/routes/beacon/block.d.ts.map +1 -1
- package/lib/beacon/routes/beacon/block.js +3 -3
- package/lib/beacon/routes/beacon/block.js.map +1 -1
- package/lib/beacon/routes/beacon/index.d.ts +28 -2
- package/lib/beacon/routes/beacon/index.d.ts.map +1 -1
- package/lib/beacon/routes/beacon/index.js +23 -1
- package/lib/beacon/routes/beacon/index.js.map +1 -1
- package/lib/beacon/routes/beacon/state.d.ts +30 -5
- package/lib/beacon/routes/beacon/state.d.ts.map +1 -1
- package/lib/beacon/routes/beacon/state.js +25 -4
- package/lib/beacon/routes/beacon/state.js.map +1 -1
- package/lib/beacon/routes/debug.d.ts +24 -10
- package/lib/beacon/routes/debug.d.ts.map +1 -1
- package/lib/beacon/routes/debug.js +19 -18
- package/lib/beacon/routes/debug.js.map +1 -1
- package/lib/beacon/routes/events.d.ts +18 -5
- package/lib/beacon/routes/events.d.ts.map +1 -1
- package/lib/beacon/routes/events.js +28 -5
- package/lib/beacon/routes/events.js.map +1 -1
- package/lib/beacon/routes/lodestar.d.ts.map +1 -1
- package/lib/beacon/routes/lodestar.js +5 -5
- package/lib/beacon/routes/lodestar.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/utils/client/error.d.ts +8 -1
- package/lib/utils/client/error.d.ts.map +1 -1
- package/lib/utils/client/error.js +4 -1
- package/lib/utils/client/error.js.map +1 -1
- package/lib/utils/client/response.d.ts +1 -1
- package/lib/utils/client/response.d.ts.map +1 -1
- package/lib/utils/client/response.js +11 -7
- package/lib/utils/client/response.js.map +1 -1
- package/lib/utils/fork.d.ts +2 -1
- package/lib/utils/fork.d.ts.map +1 -1
- package/lib/utils/fork.js +7 -1
- package/lib/utils/fork.js.map +1 -1
- package/package.json +7 -7
- package/src/beacon/client/events.ts +3 -0
- package/src/beacon/routes/beacon/block.ts +10 -5
- package/src/beacon/routes/beacon/index.ts +40 -1
- package/src/beacon/routes/beacon/state.ts +50 -8
- package/src/beacon/routes/debug.ts +22 -18
- package/src/beacon/routes/events.ts +39 -12
- package/src/beacon/routes/lodestar.ts +5 -4
- package/src/index.ts +1 -1
- package/src/utils/client/error.ts +7 -1
- package/src/utils/client/response.ts +13 -9
- package/src/utils/fork.ts +10 -0
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ChainSafe/lodestar/issues"
|
|
13
13
|
},
|
|
14
|
-
"version": "1.50.0-dev.
|
|
14
|
+
"version": "1.50.0-dev.20062ed60e",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -75,11 +75,11 @@
|
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
77
|
"@chainsafe/persistent-merkle-tree": "^1.3.1",
|
|
78
|
-
"@chainsafe/ssz": "^1.8.
|
|
79
|
-
"@lodestar/config": "^1.50.0-dev.
|
|
80
|
-
"@lodestar/params": "^1.50.0-dev.
|
|
81
|
-
"@lodestar/types": "^1.50.0-dev.
|
|
82
|
-
"@lodestar/utils": "^1.50.0-dev.
|
|
78
|
+
"@chainsafe/ssz": "^1.8.1",
|
|
79
|
+
"@lodestar/config": "^1.50.0-dev.20062ed60e",
|
|
80
|
+
"@lodestar/params": "^1.50.0-dev.20062ed60e",
|
|
81
|
+
"@lodestar/types": "^1.50.0-dev.20062ed60e",
|
|
82
|
+
"@lodestar/utils": "^1.50.0-dev.20062ed60e",
|
|
83
83
|
"eventsource": "^2.0.2",
|
|
84
84
|
"qs": "^6.14.2"
|
|
85
85
|
},
|
|
@@ -96,5 +96,5 @@
|
|
|
96
96
|
"api",
|
|
97
97
|
"blockchain"
|
|
98
98
|
],
|
|
99
|
-
"gitHead": "
|
|
99
|
+
"gitHead": "ec866a47abbc8e41a6b314235496afd0212f38c8"
|
|
100
100
|
}
|
|
@@ -21,6 +21,7 @@ export function getClient(config: ChainForkConfig, baseUrl: string): ApiClient {
|
|
|
21
21
|
topics,
|
|
22
22
|
signal,
|
|
23
23
|
onEvent,
|
|
24
|
+
onOpen,
|
|
24
25
|
onError,
|
|
25
26
|
onClose,
|
|
26
27
|
}): Promise<ApiResponse<Endpoints["eventstream"]>> => {
|
|
@@ -39,6 +40,8 @@ export function getClient(config: ChainForkConfig, baseUrl: string): ApiClient {
|
|
|
39
40
|
};
|
|
40
41
|
signal.addEventListener("abort", close, {once: true});
|
|
41
42
|
|
|
43
|
+
eventSource.onopen = () => onOpen?.();
|
|
44
|
+
|
|
42
45
|
for (const topic of topics) {
|
|
43
46
|
eventSource.addEventListener(topic, (event: MessageEvent) => {
|
|
44
47
|
try {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
ForkPostGloas,
|
|
6
6
|
ForkPreBellatrix,
|
|
7
7
|
ForkPreDeneb,
|
|
8
|
+
ForkPreGloas,
|
|
8
9
|
isForkPostBellatrix,
|
|
9
10
|
isForkPostDeneb,
|
|
10
11
|
isForkPostGloas,
|
|
@@ -296,7 +297,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
|
|
|
296
297
|
method: "GET",
|
|
297
298
|
req: blockIdOnlyReq,
|
|
298
299
|
resp: {
|
|
299
|
-
data: WithVersion((fork) =>
|
|
300
|
+
data: WithVersion((fork) => sszTypesFor(fork).SignedBeaconBlock),
|
|
300
301
|
meta: ExecutionOptimisticFinalizedAndVersionCodec,
|
|
301
302
|
},
|
|
302
303
|
},
|
|
@@ -362,7 +363,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
|
|
|
362
363
|
body:
|
|
363
364
|
isForkPostDeneb(fork) && !isForkPostGloas(fork)
|
|
364
365
|
? sszTypesFor(fork).SignedBlockContents.toJson(
|
|
365
|
-
signedBlockContents as SignedBlockContents<ForkPostDeneb>
|
|
366
|
+
signedBlockContents as SignedBlockContents<ForkPostDeneb & ForkPreGloas>
|
|
366
367
|
)
|
|
367
368
|
: sszTypesFor(fork).SignedBeaconBlock.toJson(
|
|
368
369
|
signedBlockContents.signedBlock as SignedBeaconBlock<ForkPreDeneb | ForkPostGloas>
|
|
@@ -380,7 +381,9 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
|
|
|
380
381
|
signedBlockContents:
|
|
381
382
|
isForkPostDeneb(forkName) && !isForkPostGloas(forkName)
|
|
382
383
|
? sszTypesFor(forkName).SignedBlockContents.fromJson(body)
|
|
383
|
-
: {signedBlock:
|
|
384
|
+
: ({signedBlock: sszTypesFor(forkName).SignedBeaconBlock.fromJson(body)} as SignedBlockContents<
|
|
385
|
+
ForkPreDeneb | ForkPostGloas
|
|
386
|
+
>),
|
|
384
387
|
broadcastValidation: query.broadcast_validation as BroadcastValidation,
|
|
385
388
|
builderUrl: fromHeaders(headers, MetaHeader.BuilderUrl, false),
|
|
386
389
|
};
|
|
@@ -393,7 +396,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
|
|
|
393
396
|
body:
|
|
394
397
|
isForkPostDeneb(fork) && !isForkPostGloas(fork)
|
|
395
398
|
? sszTypesFor(fork).SignedBlockContents.serialize(
|
|
396
|
-
signedBlockContents as SignedBlockContents<ForkPostDeneb>
|
|
399
|
+
signedBlockContents as SignedBlockContents<ForkPostDeneb & ForkPreGloas>
|
|
397
400
|
)
|
|
398
401
|
: sszTypesFor(fork).SignedBeaconBlock.serialize(
|
|
399
402
|
signedBlockContents.signedBlock as SignedBeaconBlock<ForkPreDeneb | ForkPostGloas>
|
|
@@ -411,7 +414,9 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
|
|
|
411
414
|
signedBlockContents:
|
|
412
415
|
isForkPostDeneb(forkName) && !isForkPostGloas(forkName)
|
|
413
416
|
? sszTypesFor(forkName).SignedBlockContents.deserialize(body)
|
|
414
|
-
: {signedBlock:
|
|
417
|
+
: ({signedBlock: sszTypesFor(forkName).SignedBeaconBlock.deserialize(body)} as SignedBlockContents<
|
|
418
|
+
ForkPreDeneb | ForkPostGloas
|
|
419
|
+
>),
|
|
415
420
|
broadcastValidation: query.broadcast_validation as BroadcastValidation,
|
|
416
421
|
builderUrl: fromHeaders(headers, MetaHeader.BuilderUrl, false),
|
|
417
422
|
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import {ValueOf} from "@chainsafe/ssz";
|
|
1
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {phase0, ssz} from "@lodestar/types";
|
|
3
|
+
import {ArrayOf, Root, Slot, phase0, ssz} from "@lodestar/types";
|
|
4
|
+
import {fromHex, toRootHex} from "@lodestar/utils";
|
|
3
5
|
import {EmptyArgs, EmptyMeta, EmptyMetaCodec, EmptyRequest, EmptyRequestCodec} from "../../../utils/codecs.js";
|
|
6
|
+
import {VersionCodec, VersionMeta} from "../../../utils/metadata.js";
|
|
7
|
+
import {Schema} from "../../../utils/schema.js";
|
|
4
8
|
import {Endpoint, RouteDefinitions} from "../../../utils/types.js";
|
|
5
9
|
import * as block from "./block.js";
|
|
6
10
|
import * as pool from "./pool.js";
|
|
@@ -27,8 +31,13 @@ export type {
|
|
|
27
31
|
ValidatorIdentities,
|
|
28
32
|
ValidatorResponse,
|
|
29
33
|
ValidatorStatus,
|
|
34
|
+
ValidatorStatusFilter,
|
|
30
35
|
} from "./state.js";
|
|
31
36
|
|
|
37
|
+
const SignedProposerPreferencesListType = ArrayOf(ssz.gloas.SignedProposerPreferences);
|
|
38
|
+
|
|
39
|
+
type SignedProposerPreferencesList = ValueOf<typeof SignedProposerPreferencesListType>;
|
|
40
|
+
|
|
32
41
|
export type Endpoints = block.Endpoints &
|
|
33
42
|
pool.Endpoints &
|
|
34
43
|
state.Endpoints &
|
|
@@ -41,6 +50,18 @@ export type Endpoints = block.Endpoints &
|
|
|
41
50
|
phase0.Genesis,
|
|
42
51
|
EmptyMeta
|
|
43
52
|
>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get proposer preferences
|
|
56
|
+
* Retrieves the signed proposer preferences known by the node for upcoming proposal slots.
|
|
57
|
+
*/
|
|
58
|
+
getProposerPreferences: Endpoint<
|
|
59
|
+
"GET",
|
|
60
|
+
{slot?: Slot; dependentRoot?: Root},
|
|
61
|
+
{query: {slot?: number; dependent_root?: string}},
|
|
62
|
+
SignedProposerPreferencesList,
|
|
63
|
+
VersionMeta
|
|
64
|
+
>;
|
|
44
65
|
};
|
|
45
66
|
|
|
46
67
|
export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoints> {
|
|
@@ -54,6 +75,24 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoi
|
|
|
54
75
|
meta: EmptyMetaCodec,
|
|
55
76
|
},
|
|
56
77
|
},
|
|
78
|
+
getProposerPreferences: {
|
|
79
|
+
url: "/eth/v1/beacon/proposer_preferences",
|
|
80
|
+
method: "GET",
|
|
81
|
+
req: {
|
|
82
|
+
writeReq: ({slot, dependentRoot}) => ({
|
|
83
|
+
query: {slot, dependent_root: dependentRoot && toRootHex(dependentRoot)},
|
|
84
|
+
}),
|
|
85
|
+
parseReq: ({query}) => ({
|
|
86
|
+
slot: query.slot,
|
|
87
|
+
dependentRoot: query.dependent_root ? fromHex(query.dependent_root) : undefined,
|
|
88
|
+
}),
|
|
89
|
+
schema: {query: {slot: Schema.Uint, dependent_root: Schema.String}},
|
|
90
|
+
},
|
|
91
|
+
resp: {
|
|
92
|
+
data: SignedProposerPreferencesListType,
|
|
93
|
+
meta: VersionCodec,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
57
96
|
...block.getDefinitions(config),
|
|
58
97
|
...pool.getDefinitions(config),
|
|
59
98
|
...state.getDefinitions(config),
|
|
@@ -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?:
|
|
207
|
+
statuses?: ValidatorStatusFilter[];
|
|
195
208
|
},
|
|
196
|
-
{params: {state_id: string}; query: {id?: ValidatorId[]; status?:
|
|
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?:
|
|
224
|
+
statuses?: ValidatorStatusFilter[];
|
|
212
225
|
},
|
|
213
|
-
{params: {state_id: string}; body: {ids?: string[]; statuses?:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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: {
|
|
@@ -69,10 +69,31 @@ const headV2 = new ContainerType(
|
|
|
69
69
|
},
|
|
70
70
|
{typeName: "HeadV2", jsonCase: "eth2"}
|
|
71
71
|
);
|
|
72
|
+
const phase0Block = new ContainerType(
|
|
73
|
+
{
|
|
74
|
+
slot: ssz.Slot,
|
|
75
|
+
block: stringType,
|
|
76
|
+
executionOptimistic: ssz.Boolean,
|
|
77
|
+
},
|
|
78
|
+
{typeName: "Block", jsonCase: "eth2"}
|
|
79
|
+
);
|
|
80
|
+
const gloasBlock = new ContainerType(
|
|
81
|
+
{
|
|
82
|
+
slot: ssz.Slot,
|
|
83
|
+
block: stringType,
|
|
84
|
+
blockHash: stringType,
|
|
85
|
+
builderIndex: ssz.BuilderIndex,
|
|
86
|
+
executionOptimistic: ssz.Boolean,
|
|
87
|
+
},
|
|
88
|
+
{typeName: "BlockGloas", jsonCase: "eth2"}
|
|
89
|
+
);
|
|
72
90
|
type FuluDataColumnSidecarSSE = ValueOf<typeof fuluDataColumnSidecarSSE>;
|
|
73
91
|
type GloasDataColumnSidecarSSE = ValueOf<typeof gloasDataColumnSidecarSSE>;
|
|
74
92
|
type DataColumnSidecarSSE = FuluDataColumnSidecarSSE | GloasDataColumnSidecarSSE;
|
|
75
93
|
type HeadV2 = ValueOf<typeof headV2>;
|
|
94
|
+
type Phase0BlockSSE = ValueOf<typeof phase0Block>;
|
|
95
|
+
type GloasBlockSSE = ValueOf<typeof gloasBlock>;
|
|
96
|
+
type BlockSSE = Phase0BlockSSE | GloasBlockSSE;
|
|
76
97
|
|
|
77
98
|
export enum EventType {
|
|
78
99
|
/**
|
|
@@ -182,11 +203,7 @@ export type EventData = {
|
|
|
182
203
|
version: ForkName;
|
|
183
204
|
data: HeadV2;
|
|
184
205
|
};
|
|
185
|
-
[EventType.block]:
|
|
186
|
-
slot: Slot;
|
|
187
|
-
block: RootHex;
|
|
188
|
-
executionOptimistic: boolean;
|
|
189
|
-
};
|
|
206
|
+
[EventType.block]: BlockSSE;
|
|
190
207
|
[EventType.blockGossip]: {
|
|
191
208
|
slot: Slot;
|
|
192
209
|
block: RootHex;
|
|
@@ -253,6 +270,8 @@ type EventstreamArgs = {
|
|
|
253
270
|
topics: EventType[];
|
|
254
271
|
signal: AbortSignal;
|
|
255
272
|
onEvent: (event: BeaconEvent) => void;
|
|
273
|
+
/** Called every time the connection is established, including reconnects */
|
|
274
|
+
onOpen?: () => void;
|
|
256
275
|
onError?: (err: Error) => void;
|
|
257
276
|
onClose?: () => void;
|
|
258
277
|
};
|
|
@@ -330,14 +349,22 @@ export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: Type
|
|
|
330
349
|
),
|
|
331
350
|
[EventType.headV2]: WithVersion(() => headV2),
|
|
332
351
|
|
|
333
|
-
[EventType.block]:
|
|
334
|
-
{
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
352
|
+
[EventType.block]: {
|
|
353
|
+
toJson: (data) => {
|
|
354
|
+
const fork = config.getForkName(data.slot);
|
|
355
|
+
if (isForkPostGloas(fork)) {
|
|
356
|
+
return gloasBlock.toJson(data as GloasBlockSSE);
|
|
357
|
+
}
|
|
358
|
+
return phase0Block.toJson(data);
|
|
338
359
|
},
|
|
339
|
-
|
|
340
|
-
|
|
360
|
+
fromJson: (data) => {
|
|
361
|
+
const fork = config.getForkName(Number((data as BlockSSE).slot));
|
|
362
|
+
if (isForkPostGloas(fork)) {
|
|
363
|
+
return gloasBlock.fromJson(data);
|
|
364
|
+
}
|
|
365
|
+
return phase0Block.fromJson(data);
|
|
366
|
+
},
|
|
367
|
+
},
|
|
341
368
|
[EventType.blockGossip]: new ContainerType(
|
|
342
369
|
{
|
|
343
370
|
slot: ssz.Slot,
|
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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?:
|
|
194
|
+
const errJson = JSON.parse(errBody) as {message?: string; failures?: ApiFailure[]};
|
|
194
195
|
if (errJson.message) {
|
|
195
|
-
if (errJson.failures) {
|
|
196
|
-
return
|
|
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`);
|