@lodestar/beacon-node 1.43.0-dev.a45ba75824 → 1.43.0-dev.a58ad80359
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/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +0 -1
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +2 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- 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 +14 -18
- 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 +15 -6
- 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 +29 -17
- 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/types.d.ts +2 -1
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +8 -0
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +5 -6
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +16 -7
- package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +10 -6
- 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/errors/proposerPreferences.d.ts +8 -1
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/errors/proposerPreferences.js +1 -0
- package/lib/chain/errors/proposerPreferences.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/produceBlock/produceBlockBody.d.ts +1 -0
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +2 -7
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +1 -4
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +1 -4
- package/lib/chain/regen/regen.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 +8 -7
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.js +11 -10
- package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +11 -8
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +39 -17
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -0
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +14 -0
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/node/nodejs.js +2 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/node/notifier.js +1 -7
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/constants.d.ts +3 -1
- package/lib/sync/constants.d.ts.map +1 -1
- package/lib/sync/constants.js +3 -4
- package/lib/sync/constants.js.map +1 -1
- package/lib/sync/range/batch.d.ts +12 -3
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +163 -33
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +13 -2
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +38 -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 +14 -3
- package/lib/sync/range/range.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 +138 -10
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +29 -8
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +87 -31
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +8 -6
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/debug/index.ts +0 -1
- package/src/api/impl/validator/index.ts +2 -1
- package/src/chain/blocks/blockInput/blockInput.ts +4 -1
- package/src/chain/blocks/importBlock.ts +14 -21
- package/src/chain/blocks/importExecutionPayload.ts +21 -11
- package/src/chain/blocks/index.ts +18 -9
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +31 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -0
- package/src/chain/blocks/types.ts +2 -1
- package/src/chain/blocks/utils/chainSegment.ts +8 -0
- package/src/chain/blocks/verifyBlock.ts +7 -5
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -6
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +14 -6
- package/src/chain/chain.ts +29 -9
- package/src/chain/errors/proposerPreferences.ts +9 -1
- package/src/chain/initState.ts +9 -1
- package/src/chain/prepareNextSlot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +3 -7
- package/src/chain/regen/queued.ts +2 -7
- package/src/chain/regen/regen.ts +2 -7
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +66 -20
- package/src/chain/seenCache/seenProposerPreferences.ts +14 -11
- package/src/chain/validation/executionPayloadBid.ts +11 -8
- package/src/chain/validation/proposerPreferences.ts +37 -18
- package/src/network/processor/gossipHandlers.ts +18 -0
- package/src/node/nodejs.ts +2 -2
- package/src/node/notifier.ts +1 -8
- package/src/sync/constants.ts +4 -4
- package/src/sync/range/batch.ts +187 -38
- package/src/sync/range/chain.ts +52 -5
- package/src/sync/range/range.ts +16 -3
- package/src/sync/sync.ts +13 -1
- package/src/sync/unknownBlock.ts +170 -10
- package/src/sync/utils/downloadByRange.ts +149 -33
- package/src/util/sszBytes.ts +8 -6
|
@@ -8,7 +8,9 @@ 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,
|
|
@@ -45,6 +47,22 @@ export type DownloadByRangeRequests = {
|
|
|
45
47
|
blobsRequest?: deneb.BlobSidecarsByRangeRequest;
|
|
46
48
|
columnsRequest?: fulu.DataColumnSidecarsByRangeRequest;
|
|
47
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;
|
|
48
66
|
};
|
|
49
67
|
|
|
50
68
|
export type DownloadByRangeResponses = {
|
|
@@ -60,6 +78,8 @@ export type DownloadAndCacheByRangeProps = DownloadByRangeRequests & {
|
|
|
60
78
|
logger: Logger;
|
|
61
79
|
peerIdStr: string;
|
|
62
80
|
batchBlocks?: IBlockInput[];
|
|
81
|
+
/** Required when `parentPayloadRequest` is set; supplies the data needed to validate the parent's columns. */
|
|
82
|
+
parentPayloadCommitments?: ParentPayloadCommitments;
|
|
63
83
|
peerDasMetrics?: BeaconMetrics["peerDas"] | null;
|
|
64
84
|
};
|
|
65
85
|
|
|
@@ -201,23 +221,17 @@ export function cacheByRangeResponses({
|
|
|
201
221
|
});
|
|
202
222
|
}
|
|
203
223
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null = null;
|
|
224
|
+
let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null =
|
|
225
|
+
existingPayloadEnvelopes !== null ? new Map(existingPayloadEnvelopes) : null;
|
|
207
226
|
if (downloadedPayloadEnvelopes !== null) {
|
|
208
|
-
payloadEnvelopes
|
|
209
|
-
|
|
227
|
+
payloadEnvelopes ??= new Map();
|
|
210
228
|
for (const [slot, envelope] of downloadedPayloadEnvelopes) {
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
// No block to pair this envelope with; drop silently
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const payloadInput = seenPayloadEnvelopeInputCache.get(blockInput.blockRootHex);
|
|
229
|
+
const envelopeBlockRootHex = toRootHex(envelope.message.beaconBlockRoot);
|
|
230
|
+
const payloadInput = seenPayloadEnvelopeInputCache.get(envelopeBlockRootHex);
|
|
218
231
|
if (payloadInput === undefined) {
|
|
219
232
|
// Unreachable given the loop above seeded an entry for every gloas block in the batch.
|
|
220
|
-
|
|
233
|
+
// for the parent block, it's populated at BeaconChain init
|
|
234
|
+
throw new Error(`Missing PayloadEnvelopeInput for block ${envelopeBlockRootHex}`);
|
|
221
235
|
}
|
|
222
236
|
|
|
223
237
|
if (!payloadInput.hasPayloadEnvelope()) {
|
|
@@ -307,6 +321,8 @@ export async function downloadByRange({
|
|
|
307
321
|
blobsRequest,
|
|
308
322
|
columnsRequest,
|
|
309
323
|
envelopesRequest,
|
|
324
|
+
parentPayloadRequest,
|
|
325
|
+
parentPayloadCommitments,
|
|
310
326
|
peerDasMetrics,
|
|
311
327
|
}: DownloadAndCacheByRangeProps): Promise<
|
|
312
328
|
WarnResult<
|
|
@@ -323,6 +339,7 @@ export async function downloadByRange({
|
|
|
323
339
|
blobsRequest,
|
|
324
340
|
columnsRequest,
|
|
325
341
|
envelopesRequest,
|
|
342
|
+
parentPayloadRequest,
|
|
326
343
|
});
|
|
327
344
|
} catch (err) {
|
|
328
345
|
throw new DownloadByRangeError({
|
|
@@ -339,6 +356,8 @@ export async function downloadByRange({
|
|
|
339
356
|
blobsRequest,
|
|
340
357
|
columnsRequest,
|
|
341
358
|
envelopesRequest,
|
|
359
|
+
parentPayloadRequest,
|
|
360
|
+
parentPayloadCommitments,
|
|
342
361
|
peerDasMetrics,
|
|
343
362
|
...response,
|
|
344
363
|
});
|
|
@@ -354,14 +373,15 @@ export async function requestByRange({
|
|
|
354
373
|
blobsRequest,
|
|
355
374
|
columnsRequest,
|
|
356
375
|
envelopesRequest,
|
|
376
|
+
parentPayloadRequest,
|
|
357
377
|
}: DownloadByRangeRequests & {
|
|
358
378
|
network: INetwork;
|
|
359
379
|
peerIdStr: PeerIdStr;
|
|
360
380
|
}): Promise<DownloadByRangeResponses> {
|
|
361
381
|
let blocks: undefined | SignedBeaconBlock[];
|
|
362
382
|
let blobSidecars: undefined | deneb.BlobSidecars;
|
|
363
|
-
|
|
364
|
-
|
|
383
|
+
const columnSidecars: DataColumnSidecar[] = [];
|
|
384
|
+
const payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[] = [];
|
|
365
385
|
|
|
366
386
|
const requests: Promise<unknown>[] = [];
|
|
367
387
|
|
|
@@ -384,7 +404,7 @@ export async function requestByRange({
|
|
|
384
404
|
if (columnsRequest) {
|
|
385
405
|
requests.push(
|
|
386
406
|
network.sendDataColumnSidecarsByRange(peerIdStr, columnsRequest).then((columnResponse) => {
|
|
387
|
-
columnSidecars
|
|
407
|
+
columnSidecars.push(...columnResponse);
|
|
388
408
|
})
|
|
389
409
|
);
|
|
390
410
|
}
|
|
@@ -392,11 +412,34 @@ export async function requestByRange({
|
|
|
392
412
|
if (envelopesRequest) {
|
|
393
413
|
requests.push(
|
|
394
414
|
network.sendExecutionPayloadEnvelopesByRange(peerIdStr, envelopesRequest).then((envelopeResponse) => {
|
|
395
|
-
payloadEnvelopes
|
|
415
|
+
payloadEnvelopes.push(...envelopeResponse);
|
|
396
416
|
})
|
|
397
417
|
);
|
|
398
418
|
}
|
|
399
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
|
+
|
|
400
443
|
await Promise.all(requests);
|
|
401
444
|
|
|
402
445
|
return {
|
|
@@ -417,6 +460,8 @@ export async function validateResponses({
|
|
|
417
460
|
blobsRequest,
|
|
418
461
|
columnsRequest,
|
|
419
462
|
envelopesRequest,
|
|
463
|
+
parentPayloadRequest,
|
|
464
|
+
parentPayloadCommitments,
|
|
420
465
|
blocks,
|
|
421
466
|
blobSidecars,
|
|
422
467
|
columnSidecars,
|
|
@@ -426,6 +471,7 @@ export async function validateResponses({
|
|
|
426
471
|
DownloadByRangeResponses & {
|
|
427
472
|
config: ChainForkConfig;
|
|
428
473
|
batchBlocks?: IBlockInput[];
|
|
474
|
+
parentPayloadCommitments?: ParentPayloadCommitments;
|
|
429
475
|
peerDasMetrics?: BeaconMetrics["peerDas"] | null;
|
|
430
476
|
}): Promise<
|
|
431
477
|
WarnResult<
|
|
@@ -446,6 +492,11 @@ export async function validateResponses({
|
|
|
446
492
|
);
|
|
447
493
|
}
|
|
448
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
|
+
|
|
449
500
|
const validatedResponses: ValidatedResponses = {};
|
|
450
501
|
let warnings: DownloadByRangeError[] | null = null;
|
|
451
502
|
|
|
@@ -457,21 +508,30 @@ export async function validateResponses({
|
|
|
457
508
|
validatedResponses.validatedBlocks = result.result;
|
|
458
509
|
}
|
|
459
510
|
|
|
511
|
+
const needsEnvelopeValidation = !!envelopesRequest || parentPayloadCommitments !== undefined;
|
|
460
512
|
const dataRequest = blobsRequest ?? columnsRequest;
|
|
461
|
-
if (!dataRequest && !
|
|
513
|
+
if (!dataRequest && !needsEnvelopeValidation) {
|
|
462
514
|
return {result: {responses: validatedResponses, payloadEnvelopes: null}, warnings};
|
|
463
515
|
}
|
|
464
516
|
|
|
465
517
|
if (!dataRequest) {
|
|
466
|
-
// Only envelope validation needed
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
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
|
|
473
524
|
);
|
|
525
|
+
if (parentValidated) {
|
|
526
|
+
validatedResponses.validatedColumnSidecars = [parentValidated];
|
|
527
|
+
}
|
|
474
528
|
}
|
|
529
|
+
const validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
|
|
530
|
+
validatedResponses.validatedBlocks ?? [],
|
|
531
|
+
batchBlocks,
|
|
532
|
+
payloadEnvelopes ?? [],
|
|
533
|
+
parentPayloadCommitments
|
|
534
|
+
);
|
|
475
535
|
return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
|
|
476
536
|
}
|
|
477
537
|
|
|
@@ -530,19 +590,64 @@ export async function validateResponses({
|
|
|
530
590
|
warnings = validatedColumnSidecarsResult.warnings;
|
|
531
591
|
}
|
|
532
592
|
|
|
533
|
-
//
|
|
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
|
+
|
|
534
608
|
let validatedPayloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null = null;
|
|
535
|
-
if (
|
|
609
|
+
if (needsEnvelopeValidation) {
|
|
536
610
|
validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
|
|
537
611
|
validatedResponses.validatedBlocks ?? [],
|
|
538
612
|
batchBlocks,
|
|
539
|
-
payloadEnvelopes ?? []
|
|
613
|
+
payloadEnvelopes ?? [],
|
|
614
|
+
parentPayloadCommitments
|
|
540
615
|
);
|
|
541
616
|
}
|
|
542
617
|
|
|
543
618
|
return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
|
|
544
619
|
}
|
|
545
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
|
+
|
|
546
651
|
/**
|
|
547
652
|
* Should not be called directly. Only exported for unit testing purposes
|
|
548
653
|
*
|
|
@@ -1153,14 +1258,18 @@ export class DownloadByRangeError extends LodestarError<DownloadByRangeErrorType
|
|
|
1153
1258
|
|
|
1154
1259
|
/**
|
|
1155
1260
|
* Validates SignedExecutionPayloadEnvelopes received for a range request.
|
|
1156
|
-
*
|
|
1157
|
-
*
|
|
1158
|
-
*
|
|
1261
|
+
*
|
|
1262
|
+
* Three categories of envelope slots:
|
|
1263
|
+
* - In-batch slot whose block we have: verify envelope.beaconBlockRoot matches.
|
|
1264
|
+
* - Dangling-parent envelope (only when `parentPayloadCommitments` is set, i.e. the first
|
|
1265
|
+
* batch of a `SyncChain`): keep if `envelope.beaconBlockRoot === parentPayloadCommitments.blockRoot`.
|
|
1266
|
+
* - Other "orphan" envelopes (e.g. unrelated slots): ignored.
|
|
1159
1267
|
*/
|
|
1160
1268
|
export function validateEnvelopesByRangeResponse(
|
|
1161
1269
|
validatedBlocks: ValidatedBlock[],
|
|
1162
1270
|
batchBlocks: IBlockInput[] | undefined,
|
|
1163
|
-
payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[]
|
|
1271
|
+
payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[],
|
|
1272
|
+
parentPayloadCommitments?: ParentPayloadCommitments
|
|
1164
1273
|
): Map<Slot, gloas.SignedExecutionPayloadEnvelope> {
|
|
1165
1274
|
// Build a map of slot -> blockRoot for all blocks in the batch
|
|
1166
1275
|
const batchBlockRoots = new Map<Slot, Uint8Array>();
|
|
@@ -1179,8 +1288,15 @@ export function validateEnvelopesByRangeResponse(
|
|
|
1179
1288
|
const slot = payloadEnvelope.message.payload.slotNumber;
|
|
1180
1289
|
const batchBlockRoot = batchBlockRoots.get(slot);
|
|
1181
1290
|
|
|
1182
|
-
// Envelopes for slots not in the batch are silently ignored (orphaned payloads)
|
|
1183
1291
|
if (batchBlockRoot === undefined) {
|
|
1292
|
+
// Keep the requested dangling-parent envelope only when its beaconBlockRoot matches
|
|
1293
|
+
// exactly. All other unrelated envelopes are dropped.
|
|
1294
|
+
if (
|
|
1295
|
+
parentPayloadCommitments !== undefined &&
|
|
1296
|
+
byteArrayEquals(payloadEnvelope.message.beaconBlockRoot, parentPayloadCommitments.blockRoot)
|
|
1297
|
+
) {
|
|
1298
|
+
payloadEnvelopeMap.set(slot, payloadEnvelope);
|
|
1299
|
+
}
|
|
1184
1300
|
continue;
|
|
1185
1301
|
}
|
|
1186
1302
|
|
package/src/util/sszBytes.ts
CHANGED
|
@@ -558,9 +558,10 @@ export function getBeaconBlockRootFromDataColumnSidecarSerialized(data: Uint8Arr
|
|
|
558
558
|
* └─ ExecutionPayloadEnvelope (starts at byte 100):
|
|
559
559
|
* ├─ 4 bytes: payload offset
|
|
560
560
|
* ├─ 4 bytes: executionRequests offset
|
|
561
|
-
* ├─ 8 bytes: builderIndex
|
|
562
|
-
* ├─ 32 bytes: beaconBlockRoot
|
|
563
|
-
*
|
|
561
|
+
* ├─ 8 bytes: builderIndex (offset 108-115)
|
|
562
|
+
* ├─ 32 bytes: beaconBlockRoot (offset 116-147)
|
|
563
|
+
* ├─ 32 bytes: parentBeaconBlockRoot (offset 148-179) — new in Gloas alpha.6 (consensus-specs#5152)
|
|
564
|
+
* └─ variable: payload data (starts at envelope + 80)
|
|
564
565
|
* └─ ExecutionPayload fixed portion includes slotNumber at offset 532
|
|
565
566
|
*/
|
|
566
567
|
const SIGNED_EXECUTION_PAYLOAD_ENVELOPE_MESSAGE_OFFSET = 4;
|
|
@@ -576,12 +577,13 @@ const BEACON_BLOCK_ROOT_OFFSET_IN_SIGNED_EXECUTION_PAYLOAD_ENVELOPE =
|
|
|
576
577
|
EXECUTION_PAYLOAD_ENVELOPE_REQUESTS_OFFSET +
|
|
577
578
|
EXECUTION_PAYLOAD_ENVELOPE_BUILDER_INDEX_SIZE; // 116
|
|
578
579
|
|
|
579
|
-
// Envelope fixed portion
|
|
580
|
+
// Envelope fixed portion: payload_offset(4) + requests_offset(4) + builderIndex(8) + beaconBlockRoot(32) + parentBeaconBlockRoot(32) = 80
|
|
580
581
|
const EXECUTION_PAYLOAD_ENVELOPE_FIXED_SIZE =
|
|
581
582
|
EXECUTION_PAYLOAD_ENVELOPE_PAYLOAD_OFFSET +
|
|
582
583
|
EXECUTION_PAYLOAD_ENVELOPE_REQUESTS_OFFSET +
|
|
583
584
|
EXECUTION_PAYLOAD_ENVELOPE_BUILDER_INDEX_SIZE +
|
|
584
|
-
ROOT_SIZE
|
|
585
|
+
ROOT_SIZE +
|
|
586
|
+
ROOT_SIZE; // 80
|
|
585
587
|
|
|
586
588
|
// slotNumber offset within ExecutionPayload fixed portion:
|
|
587
589
|
// parentHash(32) + feeRecipient(20) + stateRoot(32) + receiptsRoot(32) + logsBloom(256) +
|
|
@@ -595,7 +597,7 @@ const ENVELOPE_START_IN_SIGNED =
|
|
|
595
597
|
SIGNED_EXECUTION_PAYLOAD_ENVELOPE_MESSAGE_OFFSET + SIGNED_EXECUTION_PAYLOAD_ENVELOPE_SIGNATURE_SIZE; // 100
|
|
596
598
|
|
|
597
599
|
const SLOT_OFFSET_IN_SIGNED_EXECUTION_PAYLOAD_ENVELOPE =
|
|
598
|
-
ENVELOPE_START_IN_SIGNED + EXECUTION_PAYLOAD_ENVELOPE_FIXED_SIZE + SLOT_NUMBER_OFFSET_IN_EXECUTION_PAYLOAD; // 100 +
|
|
600
|
+
ENVELOPE_START_IN_SIGNED + EXECUTION_PAYLOAD_ENVELOPE_FIXED_SIZE + SLOT_NUMBER_OFFSET_IN_EXECUTION_PAYLOAD; // 100 + 80 + 532 = 712
|
|
599
601
|
|
|
600
602
|
export function getSlotFromExecutionPayloadEnvelopeSerialized(data: Uint8Array): Slot | null {
|
|
601
603
|
if (data.length < SLOT_OFFSET_IN_SIGNED_EXECUTION_PAYLOAD_ENVELOPE + SLOT_SIZE) {
|