@lodestar/beacon-node 1.43.0-dev.87cbe69c66 → 1.43.0-dev.8ad5d8be4c
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/chain/blocks/blockInput/blockInput.d.ts +3 -0
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +4 -1
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +0 -16
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +4 -0
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +12 -1
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +6 -7
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +11 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +23 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +16 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +1 -3
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +29 -26
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +5 -4
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +25 -10
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +6 -1
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/prepareNextSlot.js +1 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +14 -10
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +51 -17
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.d.ts +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.js +6 -11
- package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +4 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +5 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +749 -2
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/interface.d.ts +1 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +1 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +3 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +45 -1
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.d.ts.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts +9 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts.map +1 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.js +61 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.js.map +1 -0
- package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/index.js +5 -0
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/interface.d.ts +1 -1
- package/lib/network/reqresp/interface.js +1 -1
- package/lib/network/reqresp/protocols.d.ts +1 -0
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +5 -0
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.d.ts.map +1 -1
- package/lib/network/reqresp/rateLimit.js +4 -0
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/reqresp/score.d.ts.map +1 -1
- package/lib/network/reqresp/score.js +1 -0
- package/lib/network/reqresp/score.js.map +1 -1
- package/lib/network/reqresp/types.d.ts +3 -0
- package/lib/network/reqresp/types.d.ts.map +1 -1
- package/lib/network/reqresp/types.js +3 -0
- package/lib/network/reqresp/types.js.map +1 -1
- package/lib/sync/constants.d.ts +7 -1
- package/lib/sync/constants.d.ts.map +1 -1
- package/lib/sync/constants.js +7 -4
- package/lib/sync/constants.js.map +1 -1
- package/lib/sync/range/batch.d.ts +32 -6
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +215 -41
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +16 -2
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +77 -4
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +54 -5
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/range/utils/peerBalancer.d.ts +2 -1
- package/lib/sync/range/utils/peerBalancer.d.ts.map +1 -1
- package/lib/sync/range/utils/peerBalancer.js +8 -4
- package/lib/sync/range/utils/peerBalancer.js.map +1 -1
- package/lib/sync/sync.d.ts.map +1 -1
- package/lib/sync/sync.js +13 -0
- package/lib/sync/sync.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +7 -0
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +127 -10
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +36 -9
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +89 -42
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/rateLimit.d.ts +2 -0
- package/lib/sync/utils/rateLimit.d.ts.map +1 -0
- package/lib/sync/utils/rateLimit.js +15 -0
- package/lib/sync/utils/rateLimit.js.map +1 -0
- package/package.json +16 -16
- package/src/chain/blocks/blockInput/blockInput.ts +4 -1
- package/src/chain/blocks/importBlock.ts +0 -18
- package/src/chain/blocks/importExecutionPayload.ts +18 -6
- package/src/chain/blocks/index.ts +5 -7
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +31 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -0
- package/src/chain/blocks/utils/chainSegment.ts +30 -27
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +7 -4
- package/src/chain/chain.ts +29 -9
- package/src/chain/initState.ts +9 -1
- package/src/chain/prepareNextSlot.ts +1 -1
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +66 -20
- package/src/chain/seenCache/seenProposerPreferences.ts +7 -12
- package/src/metrics/metrics/lodestar.ts +6 -0
- package/src/network/interface.ts +1 -0
- package/src/network/network.ts +12 -0
- package/src/network/processor/gossipHandlers.ts +53 -1
- package/src/network/reqresp/ReqRespBeaconNode.ts +1 -0
- package/src/network/reqresp/handlers/beaconBlocksByHead.ts +91 -0
- package/src/network/reqresp/handlers/index.ts +5 -0
- package/src/network/reqresp/interface.ts +1 -1
- package/src/network/reqresp/protocols.ts +6 -0
- package/src/network/reqresp/rateLimit.ts +4 -0
- package/src/network/reqresp/score.ts +1 -0
- package/src/network/reqresp/types.ts +5 -0
- package/src/sync/constants.ts +8 -4
- package/src/sync/range/batch.ts +256 -47
- package/src/sync/range/chain.ts +94 -5
- package/src/sync/range/range.ts +68 -5
- package/src/sync/range/utils/peerBalancer.ts +9 -3
- package/src/sync/sync.ts +13 -1
- package/src/sync/unknownBlock.ts +157 -10
- package/src/sync/utils/downloadByRange.ts +156 -44
- package/src/sync/utils/rateLimit.ts +16 -0
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
isForkPostGloas,
|
|
9
9
|
} from "@lodestar/params";
|
|
10
10
|
import {
|
|
11
|
+
ColumnIndex,
|
|
11
12
|
DataColumnSidecar,
|
|
13
|
+
RootHex,
|
|
12
14
|
SignedBeaconBlock,
|
|
13
15
|
Slot,
|
|
14
16
|
deneb,
|
|
15
17
|
fulu,
|
|
16
18
|
gloas,
|
|
17
|
-
isGloasBeaconBlock,
|
|
18
19
|
isGloasDataColumnSidecar,
|
|
19
20
|
phase0,
|
|
20
21
|
} from "@lodestar/types";
|
|
@@ -46,6 +47,22 @@ export type DownloadByRangeRequests = {
|
|
|
46
47
|
blobsRequest?: deneb.BlobSidecarsByRangeRequest;
|
|
47
48
|
columnsRequest?: fulu.DataColumnSidecarsByRangeRequest;
|
|
48
49
|
envelopesRequest?: gloas.ExecutionPayloadEnvelopesByRangeRequest;
|
|
50
|
+
/**
|
|
51
|
+
* Post-Gloas only. Fetches the dangling-parent's payload envelope and/or its missing sampled
|
|
52
|
+
* data columns by-root. Set by `Batch` for the first batch of a `SyncChain` after the first
|
|
53
|
+
* block's parentRoot is known.
|
|
54
|
+
*/
|
|
55
|
+
parentPayloadRequest?: {
|
|
56
|
+
blockRoot?: Uint8Array;
|
|
57
|
+
columns?: ColumnIndex[];
|
|
58
|
+
envelopeBlockRoot?: Uint8Array;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type ParentPayloadCommitments = {
|
|
63
|
+
blockRoot: Uint8Array;
|
|
64
|
+
blockRootHex: RootHex;
|
|
65
|
+
kzgCommitments: deneb.BlobKzgCommitments;
|
|
49
66
|
};
|
|
50
67
|
|
|
51
68
|
export type DownloadByRangeResponses = {
|
|
@@ -61,6 +78,8 @@ export type DownloadAndCacheByRangeProps = DownloadByRangeRequests & {
|
|
|
61
78
|
logger: Logger;
|
|
62
79
|
peerIdStr: string;
|
|
63
80
|
batchBlocks?: IBlockInput[];
|
|
81
|
+
/** Required when `parentPayloadRequest` is set; supplies the data needed to validate the parent's columns. */
|
|
82
|
+
parentPayloadCommitments?: ParentPayloadCommitments;
|
|
64
83
|
peerDasMetrics?: BeaconMetrics["peerDas"] | null;
|
|
65
84
|
};
|
|
66
85
|
|
|
@@ -202,23 +221,17 @@ export function cacheByRangeResponses({
|
|
|
202
221
|
});
|
|
203
222
|
}
|
|
204
223
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null = null;
|
|
224
|
+
let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null =
|
|
225
|
+
existingPayloadEnvelopes !== null ? new Map(existingPayloadEnvelopes) : null;
|
|
208
226
|
if (downloadedPayloadEnvelopes !== null) {
|
|
209
|
-
payloadEnvelopes
|
|
210
|
-
|
|
227
|
+
payloadEnvelopes ??= new Map();
|
|
211
228
|
for (const [slot, envelope] of downloadedPayloadEnvelopes) {
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
// No block to pair this envelope with; drop silently
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const payloadInput = seenPayloadEnvelopeInputCache.get(blockInput.blockRootHex);
|
|
229
|
+
const envelopeBlockRootHex = toRootHex(envelope.message.beaconBlockRoot);
|
|
230
|
+
const payloadInput = seenPayloadEnvelopeInputCache.get(envelopeBlockRootHex);
|
|
219
231
|
if (payloadInput === undefined) {
|
|
220
232
|
// Unreachable given the loop above seeded an entry for every gloas block in the batch.
|
|
221
|
-
|
|
233
|
+
// for the parent block, it's populated at BeaconChain init
|
|
234
|
+
throw new Error(`Missing PayloadEnvelopeInput for block ${envelopeBlockRootHex}`);
|
|
222
235
|
}
|
|
223
236
|
|
|
224
237
|
if (!payloadInput.hasPayloadEnvelope()) {
|
|
@@ -308,6 +321,8 @@ export async function downloadByRange({
|
|
|
308
321
|
blobsRequest,
|
|
309
322
|
columnsRequest,
|
|
310
323
|
envelopesRequest,
|
|
324
|
+
parentPayloadRequest,
|
|
325
|
+
parentPayloadCommitments,
|
|
311
326
|
peerDasMetrics,
|
|
312
327
|
}: DownloadAndCacheByRangeProps): Promise<
|
|
313
328
|
WarnResult<
|
|
@@ -324,6 +339,7 @@ export async function downloadByRange({
|
|
|
324
339
|
blobsRequest,
|
|
325
340
|
columnsRequest,
|
|
326
341
|
envelopesRequest,
|
|
342
|
+
parentPayloadRequest,
|
|
327
343
|
});
|
|
328
344
|
} catch (err) {
|
|
329
345
|
throw new DownloadByRangeError({
|
|
@@ -340,6 +356,8 @@ export async function downloadByRange({
|
|
|
340
356
|
blobsRequest,
|
|
341
357
|
columnsRequest,
|
|
342
358
|
envelopesRequest,
|
|
359
|
+
parentPayloadRequest,
|
|
360
|
+
parentPayloadCommitments,
|
|
343
361
|
peerDasMetrics,
|
|
344
362
|
...response,
|
|
345
363
|
});
|
|
@@ -355,13 +373,14 @@ export async function requestByRange({
|
|
|
355
373
|
blobsRequest,
|
|
356
374
|
columnsRequest,
|
|
357
375
|
envelopesRequest,
|
|
376
|
+
parentPayloadRequest,
|
|
358
377
|
}: DownloadByRangeRequests & {
|
|
359
378
|
network: INetwork;
|
|
360
379
|
peerIdStr: PeerIdStr;
|
|
361
380
|
}): Promise<DownloadByRangeResponses> {
|
|
362
381
|
let blocks: undefined | SignedBeaconBlock[];
|
|
363
382
|
let blobSidecars: undefined | deneb.BlobSidecars;
|
|
364
|
-
|
|
383
|
+
const columnSidecars: DataColumnSidecar[] = [];
|
|
365
384
|
const payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[] = [];
|
|
366
385
|
|
|
367
386
|
const requests: Promise<unknown>[] = [];
|
|
@@ -370,17 +389,6 @@ export async function requestByRange({
|
|
|
370
389
|
requests.push(
|
|
371
390
|
network.sendBeaconBlocksByRange(peerIdStr, blocksRequest).then((blockResponse) => {
|
|
372
391
|
blocks = blockResponse;
|
|
373
|
-
const firstBlock = blockResponse.at(0);
|
|
374
|
-
if (firstBlock && isGloasBeaconBlock(firstBlock.message)) {
|
|
375
|
-
return network
|
|
376
|
-
.sendExecutionPayloadEnvelopesByRoot(peerIdStr, [
|
|
377
|
-
firstBlock.message.body.signedExecutionPayloadBid.message.parentBlockRoot,
|
|
378
|
-
])
|
|
379
|
-
.then((envelopeResponse) => {
|
|
380
|
-
payloadEnvelopes?.unshift(...envelopeResponse);
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
return undefined;
|
|
384
392
|
})
|
|
385
393
|
);
|
|
386
394
|
}
|
|
@@ -396,7 +404,7 @@ export async function requestByRange({
|
|
|
396
404
|
if (columnsRequest) {
|
|
397
405
|
requests.push(
|
|
398
406
|
network.sendDataColumnSidecarsByRange(peerIdStr, columnsRequest).then((columnResponse) => {
|
|
399
|
-
columnSidecars
|
|
407
|
+
columnSidecars.push(...columnResponse);
|
|
400
408
|
})
|
|
401
409
|
);
|
|
402
410
|
}
|
|
@@ -404,11 +412,34 @@ export async function requestByRange({
|
|
|
404
412
|
if (envelopesRequest) {
|
|
405
413
|
requests.push(
|
|
406
414
|
network.sendExecutionPayloadEnvelopesByRange(peerIdStr, envelopesRequest).then((envelopeResponse) => {
|
|
407
|
-
payloadEnvelopes
|
|
415
|
+
payloadEnvelopes.push(...envelopeResponse);
|
|
408
416
|
})
|
|
409
417
|
);
|
|
410
418
|
}
|
|
411
419
|
|
|
420
|
+
// Only happens on the 1st batch of a SyncChain — fetches whichever pieces of the
|
|
421
|
+
// dangling-parent's payload are still missing from the seen-cache entry.
|
|
422
|
+
if (parentPayloadRequest?.envelopeBlockRoot) {
|
|
423
|
+
requests.push(
|
|
424
|
+
network
|
|
425
|
+
.sendExecutionPayloadEnvelopesByRoot(peerIdStr, [parentPayloadRequest.envelopeBlockRoot])
|
|
426
|
+
.then((envelopeResponse) => {
|
|
427
|
+
payloadEnvelopes.push(...envelopeResponse);
|
|
428
|
+
})
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
if (parentPayloadRequest?.blockRoot && parentPayloadRequest.columns && parentPayloadRequest.columns.length > 0) {
|
|
432
|
+
requests.push(
|
|
433
|
+
network
|
|
434
|
+
.sendDataColumnSidecarsByRoot(peerIdStr, [
|
|
435
|
+
{blockRoot: parentPayloadRequest.blockRoot, columns: parentPayloadRequest.columns},
|
|
436
|
+
])
|
|
437
|
+
.then((columnResponse) => {
|
|
438
|
+
columnSidecars.push(...columnResponse);
|
|
439
|
+
})
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
412
443
|
await Promise.all(requests);
|
|
413
444
|
|
|
414
445
|
return {
|
|
@@ -429,6 +460,8 @@ export async function validateResponses({
|
|
|
429
460
|
blobsRequest,
|
|
430
461
|
columnsRequest,
|
|
431
462
|
envelopesRequest,
|
|
463
|
+
parentPayloadRequest,
|
|
464
|
+
parentPayloadCommitments,
|
|
432
465
|
blocks,
|
|
433
466
|
blobSidecars,
|
|
434
467
|
columnSidecars,
|
|
@@ -438,6 +471,7 @@ export async function validateResponses({
|
|
|
438
471
|
DownloadByRangeResponses & {
|
|
439
472
|
config: ChainForkConfig;
|
|
440
473
|
batchBlocks?: IBlockInput[];
|
|
474
|
+
parentPayloadCommitments?: ParentPayloadCommitments;
|
|
441
475
|
peerDasMetrics?: BeaconMetrics["peerDas"] | null;
|
|
442
476
|
}): Promise<
|
|
443
477
|
WarnResult<
|
|
@@ -458,6 +492,11 @@ export async function validateResponses({
|
|
|
458
492
|
);
|
|
459
493
|
}
|
|
460
494
|
|
|
495
|
+
// `parentPayloadRequest` and `parentPayloadCommitments` must be supplied together
|
|
496
|
+
if ((parentPayloadRequest === undefined) !== (parentPayloadCommitments === undefined)) {
|
|
497
|
+
throw new Error("Coding error: parentPayloadRequest and parentPayloadCommitments must be both set or both unset");
|
|
498
|
+
}
|
|
499
|
+
|
|
461
500
|
const validatedResponses: ValidatedResponses = {};
|
|
462
501
|
let warnings: DownloadByRangeError[] | null = null;
|
|
463
502
|
|
|
@@ -469,21 +508,30 @@ export async function validateResponses({
|
|
|
469
508
|
validatedResponses.validatedBlocks = result.result;
|
|
470
509
|
}
|
|
471
510
|
|
|
511
|
+
const needsEnvelopeValidation = !!envelopesRequest || parentPayloadCommitments !== undefined;
|
|
472
512
|
const dataRequest = blobsRequest ?? columnsRequest;
|
|
473
|
-
if (!dataRequest && !
|
|
513
|
+
if (!dataRequest && !needsEnvelopeValidation) {
|
|
474
514
|
return {result: {responses: validatedResponses, payloadEnvelopes: null}, warnings};
|
|
475
515
|
}
|
|
476
516
|
|
|
477
517
|
if (!dataRequest) {
|
|
478
|
-
// Only envelope validation needed
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
payloadEnvelopes ?? []
|
|
518
|
+
// Only envelope and/or parent-by-root validation needed
|
|
519
|
+
if (parentPayloadCommitments !== undefined) {
|
|
520
|
+
const parentValidated = await validateParentPayloadColumns(
|
|
521
|
+
parentPayloadCommitments,
|
|
522
|
+
columnSidecars ?? [],
|
|
523
|
+
peerDasMetrics
|
|
485
524
|
);
|
|
525
|
+
if (parentValidated) {
|
|
526
|
+
validatedResponses.validatedColumnSidecars = [parentValidated];
|
|
527
|
+
}
|
|
486
528
|
}
|
|
529
|
+
const validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
|
|
530
|
+
validatedResponses.validatedBlocks ?? [],
|
|
531
|
+
batchBlocks,
|
|
532
|
+
payloadEnvelopes ?? [],
|
|
533
|
+
parentPayloadCommitments
|
|
534
|
+
);
|
|
487
535
|
return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
|
|
488
536
|
}
|
|
489
537
|
|
|
@@ -542,19 +590,64 @@ export async function validateResponses({
|
|
|
542
590
|
warnings = validatedColumnSidecarsResult.warnings;
|
|
543
591
|
}
|
|
544
592
|
|
|
545
|
-
//
|
|
593
|
+
// Parent columns (by-root): KZG-validate against parent's bid commitments and append.
|
|
594
|
+
if (parentPayloadCommitments !== undefined) {
|
|
595
|
+
const parentValidated = await validateParentPayloadColumns(
|
|
596
|
+
parentPayloadCommitments,
|
|
597
|
+
columnSidecars ?? [],
|
|
598
|
+
peerDasMetrics
|
|
599
|
+
);
|
|
600
|
+
if (parentValidated) {
|
|
601
|
+
validatedResponses.validatedColumnSidecars = [
|
|
602
|
+
...(validatedResponses.validatedColumnSidecars ?? []),
|
|
603
|
+
parentValidated,
|
|
604
|
+
];
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
546
608
|
let validatedPayloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null = null;
|
|
547
|
-
if (
|
|
609
|
+
if (needsEnvelopeValidation) {
|
|
548
610
|
validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
|
|
549
611
|
validatedResponses.validatedBlocks ?? [],
|
|
550
612
|
batchBlocks,
|
|
551
|
-
payloadEnvelopes ?? []
|
|
613
|
+
payloadEnvelopes ?? [],
|
|
614
|
+
parentPayloadCommitments
|
|
552
615
|
);
|
|
553
616
|
}
|
|
554
617
|
|
|
555
618
|
return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
|
|
556
619
|
}
|
|
557
620
|
|
|
621
|
+
async function validateParentPayloadColumns(
|
|
622
|
+
parentPayloadCommitments: ParentPayloadCommitments,
|
|
623
|
+
columnSidecars: DataColumnSidecar[],
|
|
624
|
+
peerDasMetrics?: BeaconMetrics["peerDas"] | null
|
|
625
|
+
): Promise<ValidatedColumnSidecars | null> {
|
|
626
|
+
const parentColumns: gloas.DataColumnSidecar[] = [];
|
|
627
|
+
for (const cs of columnSidecars) {
|
|
628
|
+
if (isGloasDataColumnSidecar(cs) && byteArrayEquals(cs.beaconBlockRoot, parentPayloadCommitments.blockRoot)) {
|
|
629
|
+
parentColumns.push(cs);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (parentColumns.length === 0) {
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
parentColumns.sort((a, b) => a.index - b.index);
|
|
638
|
+
const parentSlot = parentColumns[0].slot;
|
|
639
|
+
|
|
640
|
+
await validateGloasBlockDataColumnSidecars(
|
|
641
|
+
parentSlot,
|
|
642
|
+
parentPayloadCommitments.blockRoot,
|
|
643
|
+
parentPayloadCommitments.kzgCommitments,
|
|
644
|
+
parentColumns,
|
|
645
|
+
peerDasMetrics
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
return {blockRoot: parentPayloadCommitments.blockRoot, columnSidecars: parentColumns};
|
|
649
|
+
}
|
|
650
|
+
|
|
558
651
|
/**
|
|
559
652
|
* Should not be called directly. Only exported for unit testing purposes
|
|
560
653
|
*
|
|
@@ -1062,6 +1155,9 @@ export enum DownloadByRangeErrorCode {
|
|
|
1062
1155
|
|
|
1063
1156
|
/** Envelope beaconBlockRoot does not match the block's root */
|
|
1064
1157
|
INVALID_ENVELOPE_BEACON_BLOCK_ROOT = "DOWNLOAD_BY_RANGE_ERROR_INVALID_ENVELOPE_BEACON_BLOCK_ROOT",
|
|
1158
|
+
|
|
1159
|
+
/** Block segment + envelopes failed chain-segment linearity / FULL-chain checks */
|
|
1160
|
+
INVALID_CHAIN_SEGMENT = "DOWNLOAD_BY_RANGE_ERROR_INVALID_CHAIN_SEGMENT",
|
|
1065
1161
|
}
|
|
1066
1162
|
|
|
1067
1163
|
export type DownloadByRangeErrorType =
|
|
@@ -1159,20 +1255,29 @@ export type DownloadByRangeErrorType =
|
|
|
1159
1255
|
slot: Slot;
|
|
1160
1256
|
expected: string;
|
|
1161
1257
|
actual: string;
|
|
1258
|
+
}
|
|
1259
|
+
| {
|
|
1260
|
+
code: DownloadByRangeErrorCode.INVALID_CHAIN_SEGMENT;
|
|
1261
|
+
slot: Slot;
|
|
1262
|
+
reason: string;
|
|
1162
1263
|
};
|
|
1163
1264
|
|
|
1164
1265
|
export class DownloadByRangeError extends LodestarError<DownloadByRangeErrorType> {}
|
|
1165
1266
|
|
|
1166
1267
|
/**
|
|
1167
1268
|
* Validates SignedExecutionPayloadEnvelopes received for a range request.
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1269
|
+
*
|
|
1270
|
+
* Three categories of envelope slots:
|
|
1271
|
+
* - In-batch slot whose block we have: verify envelope.beaconBlockRoot matches.
|
|
1272
|
+
* - Dangling-parent envelope (only when `parentPayloadCommitments` is set, i.e. the first
|
|
1273
|
+
* batch of a `SyncChain`): keep if `envelope.beaconBlockRoot === parentPayloadCommitments.blockRoot`.
|
|
1274
|
+
* - Other "orphan" envelopes (e.g. unrelated slots): ignored.
|
|
1171
1275
|
*/
|
|
1172
1276
|
export function validateEnvelopesByRangeResponse(
|
|
1173
1277
|
validatedBlocks: ValidatedBlock[],
|
|
1174
1278
|
batchBlocks: IBlockInput[] | undefined,
|
|
1175
|
-
payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[]
|
|
1279
|
+
payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[],
|
|
1280
|
+
parentPayloadCommitments?: ParentPayloadCommitments
|
|
1176
1281
|
): Map<Slot, gloas.SignedExecutionPayloadEnvelope> {
|
|
1177
1282
|
// Build a map of slot -> blockRoot for all blocks in the batch
|
|
1178
1283
|
const batchBlockRoots = new Map<Slot, Uint8Array>();
|
|
@@ -1191,8 +1296,15 @@ export function validateEnvelopesByRangeResponse(
|
|
|
1191
1296
|
const slot = payloadEnvelope.message.payload.slotNumber;
|
|
1192
1297
|
const batchBlockRoot = batchBlockRoots.get(slot);
|
|
1193
1298
|
|
|
1194
|
-
// Envelopes for slots not in the batch are silently ignored (orphaned payloads or a parent payload)
|
|
1195
1299
|
if (batchBlockRoot === undefined) {
|
|
1300
|
+
// Keep the requested dangling-parent envelope only when its beaconBlockRoot matches
|
|
1301
|
+
// exactly. All other unrelated envelopes are dropped.
|
|
1302
|
+
if (
|
|
1303
|
+
parentPayloadCommitments !== undefined &&
|
|
1304
|
+
byteArrayEquals(payloadEnvelope.message.beaconBlockRoot, parentPayloadCommitments.blockRoot)
|
|
1305
|
+
) {
|
|
1306
|
+
payloadEnvelopeMap.set(slot, payloadEnvelope);
|
|
1307
|
+
}
|
|
1196
1308
|
continue;
|
|
1197
1309
|
}
|
|
1198
1310
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
|
|
2
|
+
import {RATE_LIMITED_PEER_BACKOFF_MS} from "../constants.js";
|
|
3
|
+
|
|
4
|
+
export function getRateLimitedUntilMs(e: unknown): number | null {
|
|
5
|
+
if (!(e instanceof RequestError)) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
switch (e.type.code) {
|
|
10
|
+
case RequestErrorCode.RESP_RATE_LIMITED:
|
|
11
|
+
case RequestErrorCode.REQUEST_SELF_RATE_LIMITED:
|
|
12
|
+
return e.type.rateLimitedUntilMs ?? Date.now() + RATE_LIMITED_PEER_BACKOFF_MS;
|
|
13
|
+
default:
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|