@lodestar/beacon-node 1.41.0-dev.b90dff673d → 1.41.0-dev.bb16850567
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/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +9 -0
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -2
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +5 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +0 -1
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +0 -9
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/interface.d.ts +4 -4
- package/lib/chain/archiveStore/interface.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +4 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +38 -0
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +12 -8
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
- package/lib/chain/chain.d.ts +3 -3
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +20 -9
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +6 -2
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +9 -1
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/errors.d.ts +11 -1
- package/lib/chain/regen/errors.d.ts.map +1 -1
- package/lib/chain/regen/errors.js +2 -0
- package/lib/chain/regen/errors.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +12 -6
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/queued.d.ts +11 -6
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +40 -8
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +5 -0
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +33 -6
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/stateCache/datastore/db.d.ts +4 -5
- package/lib/chain/stateCache/datastore/db.d.ts.map +1 -1
- package/lib/chain/stateCache/datastore/db.js +32 -10
- package/lib/chain/stateCache/datastore/db.js.map +1 -1
- package/lib/chain/stateCache/datastore/file.d.ts +1 -1
- package/lib/chain/stateCache/datastore/file.d.ts.map +1 -1
- package/lib/chain/stateCache/datastore/file.js +5 -5
- package/lib/chain/stateCache/datastore/file.js.map +1 -1
- package/lib/chain/stateCache/datastore/types.d.ts +1 -1
- package/lib/chain/stateCache/datastore/types.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +7 -4
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +8 -3
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +33 -14
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +217 -119
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +15 -8
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts +2 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +124 -107
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +2 -2
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/metrics/metrics/beacon.d.ts +2 -1
- package/lib/metrics/metrics/beacon.d.ts.map +1 -1
- package/lib/metrics/metrics/beacon.js +9 -3
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +5 -5
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +16 -14
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/discv5/utils.d.ts +1 -1
- package/lib/network/discv5/utils.d.ts.map +1 -1
- package/lib/network/discv5/utils.js +5 -4
- package/lib/network/discv5/utils.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +9 -6
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/libp2p/index.d.ts +1 -1
- package/lib/network/libp2p/index.d.ts.map +1 -1
- package/lib/network/libp2p/index.js +35 -17
- package/lib/network/libp2p/index.js.map +1 -1
- package/lib/network/metadata.d.ts +1 -0
- package/lib/network/metadata.d.ts.map +1 -1
- package/lib/network/metadata.js +1 -0
- package/lib/network/metadata.js.map +1 -1
- package/lib/network/options.d.ts +2 -0
- package/lib/network/options.d.ts.map +1 -1
- package/lib/network/options.js +3 -0
- package/lib/network/options.js.map +1 -1
- package/lib/network/peers/discover.d.ts +2 -0
- package/lib/network/peers/discover.d.ts.map +1 -1
- package/lib/network/peers/discover.js +41 -10
- package/lib/network/peers/discover.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +1 -0
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +6 -3
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +6 -5
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +1 -1
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/lib/util/dataColumns.d.ts.map +1 -1
- package/lib/util/dataColumns.js +5 -1
- package/lib/util/dataColumns.js.map +1 -1
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +17 -8
- package/lib/util/execution.js.map +1 -1
- package/package.json +28 -27
- package/src/api/impl/beacon/blocks/index.ts +11 -0
- package/src/api/impl/beacon/state/utils.ts +2 -2
- package/src/api/impl/validator/index.ts +7 -3
- package/src/chain/archiveStore/archiveStore.ts +0 -10
- package/src/chain/archiveStore/interface.ts +4 -4
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +8 -5
- package/src/chain/archiveStore/utils/archiveBlocks.ts +59 -1
- package/src/chain/blocks/importBlock.ts +12 -7
- package/src/chain/blocks/verifyBlocksSignatures.ts +1 -1
- package/src/chain/chain.ts +27 -14
- package/src/chain/interface.ts +2 -2
- package/src/chain/prepareNextSlot.ts +6 -2
- package/src/chain/produceBlock/produceBlockBody.ts +8 -1
- package/src/chain/regen/errors.ts +6 -1
- package/src/chain/regen/interface.ts +12 -6
- package/src/chain/regen/queued.ts +48 -12
- package/src/chain/regen/regen.ts +37 -7
- package/src/chain/stateCache/datastore/db.ts +33 -10
- package/src/chain/stateCache/datastore/file.ts +6 -5
- package/src/chain/stateCache/datastore/types.ts +3 -2
- package/src/chain/stateCache/fifoBlockStateCache.ts +10 -4
- package/src/chain/stateCache/persistentCheckpointsCache.ts +248 -139
- package/src/chain/stateCache/types.ts +18 -8
- package/src/chain/validation/dataColumnSidecar.ts +146 -126
- package/src/chain/validation/voluntaryExit.ts +2 -1
- package/src/metrics/metrics/beacon.ts +9 -3
- package/src/metrics/metrics/lodestar.ts +16 -14
- package/src/network/discv5/utils.ts +5 -4
- package/src/network/gossip/gossipsub.ts +12 -7
- package/src/network/libp2p/index.ts +40 -18
- package/src/network/metadata.ts +1 -0
- package/src/network/options.ts +5 -1
- package/src/network/peers/discover.ts +46 -11
- package/src/sync/range/range.ts +1 -0
- package/src/sync/utils/downloadByRange.ts +12 -3
- package/src/sync/utils/downloadByRoot.ts +1 -1
- package/src/util/dataColumns.ts +6 -2
- package/src/util/execution.ts +23 -12
- package/lib/chain/archiveStore/utils/archivePayloads.d.ts +0 -7
- package/lib/chain/archiveStore/utils/archivePayloads.d.ts.map +0 -1
- package/lib/chain/archiveStore/utils/archivePayloads.js +0 -10
- package/lib/chain/archiveStore/utils/archivePayloads.js.map +0 -1
- package/src/chain/archiveStore/utils/archivePayloads.ts +0 -15
|
@@ -2,7 +2,11 @@ import {routes} from "@lodestar/api";
|
|
|
2
2
|
import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
|
|
3
3
|
import {Epoch, RootHex, phase0} from "@lodestar/types";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Checkpoint hex representation for state cache keys.
|
|
7
|
+
* Extends CheckpointWithHex (from fork-choice) with payloadPresent.
|
|
8
|
+
*/
|
|
9
|
+
export type CheckpointHexPayload = {epoch: Epoch; rootHex: RootHex; payloadPresent: boolean};
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* Lodestar currently keeps two state caches around.
|
|
@@ -31,6 +35,8 @@ export interface BlockStateCache {
|
|
|
31
35
|
size: number;
|
|
32
36
|
prune(headStateRootHex: RootHex): void;
|
|
33
37
|
deleteAllBeforeEpoch(finalizedEpoch: Epoch): void;
|
|
38
|
+
/** Upgrade cache capacity for Gloas fork (2x states for block + payload states) */
|
|
39
|
+
upgradeToGloas(): void;
|
|
34
40
|
dumpSummary(): routes.lodestar.StateCacheItem[];
|
|
35
41
|
/** Expose beacon states stored in cache. Use with caution */
|
|
36
42
|
getStates(): IterableIterator<CachedBeaconStateAllForks>;
|
|
@@ -59,13 +65,17 @@ export interface BlockStateCache {
|
|
|
59
65
|
*/
|
|
60
66
|
export interface CheckpointStateCache {
|
|
61
67
|
init?: () => Promise<void>;
|
|
62
|
-
getOrReload(cp:
|
|
63
|
-
getStateOrBytes(cp:
|
|
64
|
-
get(cpOrKey:
|
|
65
|
-
add(cp: phase0.Checkpoint, state: CachedBeaconStateAllForks): void;
|
|
66
|
-
getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null;
|
|
67
|
-
getOrReloadLatest(
|
|
68
|
-
|
|
68
|
+
getOrReload(cp: CheckpointHexPayload): Promise<CachedBeaconStateAllForks | null>;
|
|
69
|
+
getStateOrBytes(cp: CheckpointHexPayload): Promise<CachedBeaconStateAllForks | Uint8Array | null>;
|
|
70
|
+
get(cpOrKey: CheckpointHexPayload | string): CachedBeaconStateAllForks | null;
|
|
71
|
+
add(cp: phase0.Checkpoint, state: CachedBeaconStateAllForks, payloadPresent: boolean): void;
|
|
72
|
+
getLatest(rootHex: RootHex, maxEpoch: Epoch, payloadPresent: boolean): CachedBeaconStateAllForks | null;
|
|
73
|
+
getOrReloadLatest(
|
|
74
|
+
rootHex: RootHex,
|
|
75
|
+
maxEpoch: Epoch,
|
|
76
|
+
payloadPresent: boolean
|
|
77
|
+
): Promise<CachedBeaconStateAllForks | null>;
|
|
78
|
+
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch, payloadPresent: boolean): number | null;
|
|
69
79
|
prune(finalizedEpoch: Epoch, justifiedEpoch: Epoch): void;
|
|
70
80
|
pruneFinalized(finalizedEpoch: Epoch): void;
|
|
71
81
|
processState(blockRootHex: RootHex, state: CachedBeaconStateAllForks): Promise<number>;
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "@lodestar/state-transition";
|
|
13
13
|
import {DataColumnSidecar, Root, Slot, SubnetID, fulu, ssz} from "@lodestar/types";
|
|
14
14
|
import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
15
|
+
import {BeaconMetrics} from "../../metrics/metrics/beacon.js";
|
|
15
16
|
import {Metrics} from "../../metrics/metrics.js";
|
|
16
17
|
import {kzg} from "../../util/kzg.js";
|
|
17
18
|
import {
|
|
@@ -177,6 +178,7 @@ export async function validateGossipDataColumnSidecar(
|
|
|
177
178
|
});
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
// single data column is being verified here
|
|
180
182
|
const kzgProofTimer = metrics?.peerDas.dataColumnSidecarKzgProofsVerificationTime.startTimer();
|
|
181
183
|
// 11) [REJECT] The sidecar's column data is valid as verified by verify_data_column_sidecar_kzg_proofs
|
|
182
184
|
try {
|
|
@@ -297,159 +299,177 @@ export async function validateBlockDataColumnSidecars(
|
|
|
297
299
|
blockSlot: Slot,
|
|
298
300
|
blockRoot: Root,
|
|
299
301
|
blockBlobCount: number,
|
|
300
|
-
dataColumnSidecars: fulu.DataColumnSidecars
|
|
302
|
+
dataColumnSidecars: fulu.DataColumnSidecars,
|
|
303
|
+
metrics?: BeaconMetrics["peerDas"] | null
|
|
301
304
|
): Promise<void> {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
+
metrics?.dataColumnSidecarProcessingRequests.inc(dataColumnSidecars.length);
|
|
306
|
+
const verificationTimer = metrics?.dataColumnSidecarGossipVerificationTime.startTimer();
|
|
307
|
+
try {
|
|
308
|
+
if (dataColumnSidecars.length === 0) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
305
311
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
312
|
+
if (blockBlobCount === 0) {
|
|
313
|
+
throw new DataColumnSidecarValidationError(
|
|
314
|
+
{
|
|
315
|
+
code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_COUNT,
|
|
316
|
+
slot: blockSlot,
|
|
317
|
+
expected: 0,
|
|
318
|
+
actual: dataColumnSidecars.length,
|
|
319
|
+
},
|
|
320
|
+
"Block has no blob commitments but data column sidecars were provided"
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
// Hash the first sidecar block header and compare the rest via (cheaper) equality
|
|
324
|
+
const firstSidecarSignedBlockHeader = dataColumnSidecars[0].signedBlockHeader;
|
|
325
|
+
const firstSidecarBlockHeader = firstSidecarSignedBlockHeader.message;
|
|
326
|
+
const firstBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(firstSidecarBlockHeader);
|
|
327
|
+
if (!byteArrayEquals(blockRoot, firstBlockRoot)) {
|
|
328
|
+
throw new DataColumnSidecarValidationError(
|
|
329
|
+
{
|
|
330
|
+
code: DataColumnSidecarErrorCode.INCORRECT_BLOCK,
|
|
331
|
+
slot: blockSlot,
|
|
332
|
+
columnIndex: 0,
|
|
333
|
+
expected: toRootHex(blockRoot),
|
|
334
|
+
actual: toRootHex(firstBlockRoot),
|
|
335
|
+
},
|
|
336
|
+
"DataColumnSidecar doesn't match corresponding block"
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (chain !== null) {
|
|
341
|
+
const rootHex = toRootHex(blockRoot);
|
|
342
|
+
const slot = firstSidecarSignedBlockHeader.message.slot;
|
|
343
|
+
const signature = firstSidecarSignedBlockHeader.signature;
|
|
344
|
+
if (!chain.seenBlockInputCache.isVerifiedProposerSignature(slot, rootHex, signature)) {
|
|
345
|
+
const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(
|
|
346
|
+
chain.config,
|
|
347
|
+
firstSidecarSignedBlockHeader
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
if (
|
|
351
|
+
!(await chain.bls.verifySignatureSets([signatureSet], {
|
|
352
|
+
verifyOnMainThread: true,
|
|
353
|
+
}))
|
|
354
|
+
) {
|
|
355
|
+
throw new DataColumnSidecarValidationError({
|
|
356
|
+
code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
|
|
357
|
+
blockRoot: rootHex,
|
|
358
|
+
slot: blockSlot,
|
|
359
|
+
index: dataColumnSidecars[0].index,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
chain.seenBlockInputCache.markVerifiedProposerSignature(slot, rootHex, signature);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
333
366
|
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
const
|
|
367
|
+
const commitments: Uint8Array[] = [];
|
|
368
|
+
const cellIndices: number[] = [];
|
|
369
|
+
const cells: Uint8Array[] = [];
|
|
370
|
+
const proofs: Uint8Array[] = [];
|
|
371
|
+
for (let i = 0; i < dataColumnSidecars.length; i++) {
|
|
372
|
+
const columnSidecar = dataColumnSidecars[i];
|
|
340
373
|
|
|
341
374
|
if (
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}))
|
|
375
|
+
i !== 0 &&
|
|
376
|
+
!ssz.phase0.SignedBeaconBlockHeader.equals(firstSidecarSignedBlockHeader, columnSidecar.signedBlockHeader)
|
|
345
377
|
) {
|
|
346
378
|
throw new DataColumnSidecarValidationError({
|
|
347
|
-
code: DataColumnSidecarErrorCode.
|
|
348
|
-
blockRoot: rootHex,
|
|
379
|
+
code: DataColumnSidecarErrorCode.INCORRECT_HEADER_ROOT,
|
|
349
380
|
slot: blockSlot,
|
|
350
|
-
|
|
381
|
+
expected: toRootHex(blockRoot),
|
|
382
|
+
actual: toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(columnSidecar.signedBlockHeader.message)),
|
|
351
383
|
});
|
|
352
384
|
}
|
|
353
385
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
386
|
+
if (columnSidecar.index >= NUMBER_OF_COLUMNS) {
|
|
387
|
+
throw new DataColumnSidecarValidationError(
|
|
388
|
+
{
|
|
389
|
+
code: DataColumnSidecarErrorCode.INVALID_INDEX,
|
|
390
|
+
slot: blockSlot,
|
|
391
|
+
columnIndex: columnSidecar.index,
|
|
392
|
+
},
|
|
393
|
+
"DataColumnSidecar has invalid index"
|
|
394
|
+
);
|
|
395
|
+
}
|
|
357
396
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
397
|
+
if (columnSidecar.column.length !== blockBlobCount) {
|
|
398
|
+
throw new DataColumnSidecarValidationError({
|
|
399
|
+
code: DataColumnSidecarErrorCode.INCORRECT_CELL_COUNT,
|
|
400
|
+
slot: blockSlot,
|
|
401
|
+
columnIndex: columnSidecar.index,
|
|
402
|
+
expected: blockBlobCount,
|
|
403
|
+
actual: columnSidecar.column.length,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
364
406
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
});
|
|
375
|
-
}
|
|
407
|
+
if (columnSidecar.column.length !== columnSidecar.kzgCommitments.length) {
|
|
408
|
+
throw new DataColumnSidecarValidationError({
|
|
409
|
+
code: DataColumnSidecarErrorCode.INCORRECT_KZG_COMMITMENTS_COUNT,
|
|
410
|
+
slot: blockSlot,
|
|
411
|
+
columnIndex: columnSidecar.index,
|
|
412
|
+
expected: columnSidecar.column.length,
|
|
413
|
+
actual: columnSidecar.kzgCommitments.length,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
376
416
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
code: DataColumnSidecarErrorCode.INVALID_INDEX,
|
|
417
|
+
if (columnSidecar.column.length !== columnSidecar.kzgProofs.length) {
|
|
418
|
+
throw new DataColumnSidecarValidationError({
|
|
419
|
+
code: DataColumnSidecarErrorCode.INCORRECT_KZG_PROOF_COUNT,
|
|
381
420
|
slot: blockSlot,
|
|
382
421
|
columnIndex: columnSidecar.index,
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
422
|
+
expected: columnSidecar.column.length,
|
|
423
|
+
actual: columnSidecar.kzgProofs.length,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
387
426
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
427
|
+
const inclusionProofTimer = metrics?.dataColumnSidecarInclusionProofVerificationTime.startTimer();
|
|
428
|
+
const validInclusionProof = verifyDataColumnSidecarInclusionProof(columnSidecar);
|
|
429
|
+
inclusionProofTimer?.();
|
|
430
|
+
if (!validInclusionProof) {
|
|
431
|
+
throw new DataColumnSidecarValidationError(
|
|
432
|
+
{
|
|
433
|
+
code: DataColumnSidecarErrorCode.INCLUSION_PROOF_INVALID,
|
|
434
|
+
slot: blockSlot,
|
|
435
|
+
columnIndex: columnSidecar.index,
|
|
436
|
+
},
|
|
437
|
+
"DataColumnSidecar has invalid inclusion proof"
|
|
438
|
+
);
|
|
439
|
+
}
|
|
397
440
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
columnIndex: columnSidecar.index,
|
|
403
|
-
expected: columnSidecar.column.length,
|
|
404
|
-
actual: columnSidecar.kzgCommitments.length,
|
|
405
|
-
});
|
|
441
|
+
commitments.push(...columnSidecar.kzgCommitments);
|
|
442
|
+
cellIndices.push(...Array.from({length: columnSidecar.column.length}, () => columnSidecar.index));
|
|
443
|
+
cells.push(...columnSidecar.column);
|
|
444
|
+
proofs.push(...columnSidecar.kzgProofs);
|
|
406
445
|
}
|
|
407
446
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
447
|
+
let reason: string | undefined;
|
|
448
|
+
// batch verification for the cases: downloadByRange and downloadByRoot
|
|
449
|
+
const kzgVerificationTimer = metrics?.kzgVerificationDataColumnBatchTime.startTimer();
|
|
450
|
+
try {
|
|
451
|
+
const valid = await kzg.asyncVerifyCellKzgProofBatch(commitments, cellIndices, cells, proofs);
|
|
452
|
+
if (!valid) {
|
|
453
|
+
reason = "Invalid KZG proof batch";
|
|
454
|
+
}
|
|
455
|
+
} catch (e) {
|
|
456
|
+
reason = (e as Error).message;
|
|
457
|
+
} finally {
|
|
458
|
+
kzgVerificationTimer?.();
|
|
416
459
|
}
|
|
417
|
-
|
|
418
|
-
if (!verifyDataColumnSidecarInclusionProof(columnSidecar)) {
|
|
460
|
+
if (reason !== undefined) {
|
|
419
461
|
throw new DataColumnSidecarValidationError(
|
|
420
462
|
{
|
|
421
|
-
code: DataColumnSidecarErrorCode.
|
|
463
|
+
code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF_BATCH,
|
|
422
464
|
slot: blockSlot,
|
|
423
|
-
|
|
465
|
+
reason,
|
|
424
466
|
},
|
|
425
|
-
"DataColumnSidecar has invalid
|
|
467
|
+
"DataColumnSidecar has invalid KZG proof batch"
|
|
426
468
|
);
|
|
427
469
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
cells.push(...columnSidecar.column);
|
|
432
|
-
proofs.push(...columnSidecar.kzgProofs);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
let reason: string | undefined;
|
|
436
|
-
try {
|
|
437
|
-
const valid = await kzg.asyncVerifyCellKzgProofBatch(commitments, cellIndices, cells, proofs);
|
|
438
|
-
if (!valid) {
|
|
439
|
-
reason = "Invalid KZG proof batch";
|
|
440
|
-
}
|
|
441
|
-
} catch (e) {
|
|
442
|
-
reason = (e as Error).message;
|
|
443
|
-
}
|
|
444
|
-
if (reason !== undefined) {
|
|
445
|
-
throw new DataColumnSidecarValidationError(
|
|
446
|
-
{
|
|
447
|
-
code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF_BATCH,
|
|
448
|
-
slot: blockSlot,
|
|
449
|
-
reason,
|
|
450
|
-
},
|
|
451
|
-
"DataColumnSidecar has invalid KZG proof batch"
|
|
452
|
-
);
|
|
470
|
+
metrics?.dataColumnSidecarProcessingSuccesses.inc();
|
|
471
|
+
} finally {
|
|
472
|
+
verificationTimer?.();
|
|
453
473
|
}
|
|
454
474
|
}
|
|
455
475
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BeaconStateView,
|
|
2
3
|
VoluntaryExitValidity,
|
|
3
4
|
getVoluntaryExitSignatureSet,
|
|
4
5
|
getVoluntaryExitValidity,
|
|
@@ -59,7 +60,7 @@ async function validateVoluntaryExit(
|
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
const signatureSet = getVoluntaryExitSignatureSet(chain.config, state
|
|
63
|
+
const signatureSet = getVoluntaryExitSignatureSet(chain.config, new BeaconStateView(state), voluntaryExit);
|
|
63
64
|
if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}))) {
|
|
64
65
|
throw new VoluntaryExitError(GossipAction.REJECT, {
|
|
65
66
|
code: VoluntaryExitErrorCode.INVALID_SIGNATURE,
|
|
@@ -333,11 +333,13 @@ export function createBeaconMetrics(register: RegistryMetricCreator) {
|
|
|
333
333
|
help: "Time taken to verify data_column sidecar inclusion proof",
|
|
334
334
|
buckets: [0.002, 0.004, 0.006, 0.008, 0.01, 0.05, 1, 2],
|
|
335
335
|
}),
|
|
336
|
+
// single verification
|
|
336
337
|
dataColumnSidecarKzgProofsVerificationTime: register.histogram({
|
|
337
338
|
name: "beacon_data_column_sidecar_kzg_proofs_verification_seconds",
|
|
338
|
-
help: "Time taken to verify data_column sidecar kzg proofs",
|
|
339
|
+
help: "Time taken to verify single data_column sidecar kzg proofs",
|
|
339
340
|
buckets: [0.01, 0.02, 0.03, 0.04, 0.05, 0.1, 0.2, 0.5, 1],
|
|
340
341
|
}),
|
|
342
|
+
// batch verification
|
|
341
343
|
kzgVerificationDataColumnBatchTime: register.histogram({
|
|
342
344
|
name: "beacon_kzg_verification_data_column_batch_seconds",
|
|
343
345
|
help: "Runtime of batched data column kzg verification",
|
|
@@ -361,10 +363,14 @@ export function createBeaconMetrics(register: RegistryMetricCreator) {
|
|
|
361
363
|
help: "Duration of engine_getBlobsV2 requests",
|
|
362
364
|
buckets: [0.01, 0.05, 0.1, 0.5, 1, 2.5, 5, 7.5],
|
|
363
365
|
}),
|
|
364
|
-
|
|
365
|
-
name: "
|
|
366
|
+
custodyGroupCount: register.gauge({
|
|
367
|
+
name: "beacon_custody_groups",
|
|
366
368
|
help: "Total number of custody groups within a node",
|
|
367
369
|
}),
|
|
370
|
+
custodyGroupsBackfilled: register.gauge({
|
|
371
|
+
name: "beacon_custody_groups_backfilled",
|
|
372
|
+
help: "Total number of custody groups backfilled by a node",
|
|
373
|
+
}),
|
|
368
374
|
reconstructedColumns: register.counter({
|
|
369
375
|
name: "beacon_data_availability_reconstructed_columns_total",
|
|
370
376
|
help: "Total count of reconstructed columns",
|
|
@@ -836,20 +836,23 @@ export function createLodestarMetrics(
|
|
|
836
836
|
buckets: [0.5, 1, 2, 4, 6, 12],
|
|
837
837
|
}),
|
|
838
838
|
},
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
839
|
+
// recovery in the case of specific blob rows required
|
|
840
|
+
recoverBlobSidecars: {
|
|
841
|
+
blobsReconstructed: register.counter({
|
|
842
|
+
name: "lodestar_blobs_reconstructed_total",
|
|
843
|
+
help: "Total count of reconstructed blobs",
|
|
844
|
+
}),
|
|
845
|
+
reconstructionTime: register.histogram({
|
|
846
|
+
name: "lodestar_blob_reconstruction_seconds",
|
|
847
|
+
help: "Time taken to reconstruct blobs",
|
|
848
|
+
buckets: [0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 2, 5],
|
|
844
849
|
}),
|
|
850
|
+
},
|
|
851
|
+
recoverDataColumnSidecars: {
|
|
845
852
|
custodyBeforeReconstruction: register.gauge({
|
|
846
853
|
name: "lodestar_data_columns_in_custody_before_reconstruction",
|
|
847
854
|
help: "Number of data columns in custody before reconstruction",
|
|
848
855
|
}),
|
|
849
|
-
numberOfColumnsRecovered: register.gauge({
|
|
850
|
-
name: "lodestar_recover_data_column_sidecar_recovered_columns_total",
|
|
851
|
-
help: "Total number of columns that were recovered",
|
|
852
|
-
}),
|
|
853
856
|
reconstructionResult: register.counter<{result: DataColumnReconstructionCode}>({
|
|
854
857
|
name: "lodestar_data_column_sidecars_reconstruction_result",
|
|
855
858
|
help: "Data column sidecars reconstruction result",
|
|
@@ -857,6 +860,10 @@ export function createLodestarMetrics(
|
|
|
857
860
|
}),
|
|
858
861
|
},
|
|
859
862
|
dataColumns: {
|
|
863
|
+
alreadyAdded: register.counter({
|
|
864
|
+
name: "lodestar_data_column_sidecar_already_added",
|
|
865
|
+
help: "Total number of columns that were already added by other sources while waiting",
|
|
866
|
+
}),
|
|
860
867
|
bySource: register.gauge<{source: BlockInputSource}>({
|
|
861
868
|
name: "lodestar_data_columns_by_source",
|
|
862
869
|
help: "Number of received data columns by source",
|
|
@@ -912,11 +919,6 @@ export function createLodestarMetrics(
|
|
|
912
919
|
help: "Total number of imported blobs by source",
|
|
913
920
|
labelNames: ["blobsSource"],
|
|
914
921
|
}),
|
|
915
|
-
columnsBySource: register.gauge<{source: BlockInputSource}>({
|
|
916
|
-
name: "lodestar_import_columns_by_source_total",
|
|
917
|
-
help: "Total number of imported columns (sampled columns) by source",
|
|
918
|
-
labelNames: ["source"],
|
|
919
|
-
}),
|
|
920
922
|
notOverrideFcuReason: register.counter<{reason: NotReorgedReason}>({
|
|
921
923
|
name: "lodestar_import_block_not_override_fcu_reason_total",
|
|
922
924
|
help: "Reason why the fcu call is not suppressed during block import",
|
|
@@ -4,7 +4,7 @@ import {IClock} from "../../util/clock.js";
|
|
|
4
4
|
import {ENRKey} from "../metadata.js";
|
|
5
5
|
|
|
6
6
|
export enum ENRRelevance {
|
|
7
|
-
|
|
7
|
+
no_transport = "no_transport",
|
|
8
8
|
no_eth2 = "no_eth2",
|
|
9
9
|
// biome-ignore lint/style/useNamingConvention: Need to use the this name for network convention
|
|
10
10
|
unknown_forkDigest = "unknown_forkDigest",
|
|
@@ -13,10 +13,11 @@ export enum ENRRelevance {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function enrRelevance(enr: ENR, config: BeaconConfig, clock: IClock): ENRRelevance {
|
|
16
|
-
// We are not interested in peers that don't advertise
|
|
16
|
+
// We are not interested in peers that don't advertise at least one transport (tcp or quic)
|
|
17
17
|
const multiaddrTCP = enr.getLocationMultiaddr(ENRKey.tcp);
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const multiaddrQUIC = enr.getLocationMultiaddr(ENRKey.quic);
|
|
19
|
+
if (!multiaddrTCP && !multiaddrQUIC) {
|
|
20
|
+
return ENRRelevance.no_transport;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
// Check if the ENR.eth2 field matches and is of interest
|
|
@@ -11,7 +11,7 @@ import type {PeerScoreParams, PeerScoreStatsDump} from "@libp2p/gossipsub/score"
|
|
|
11
11
|
import type {AddrInfo, PublishOpts, TopicStr} from "@libp2p/gossipsub/types";
|
|
12
12
|
import type {PeerId} from "@libp2p/interface";
|
|
13
13
|
import {peerIdFromString} from "@libp2p/peer-id";
|
|
14
|
-
import {multiaddr} from "@multiformats/multiaddr";
|
|
14
|
+
import {type Multiaddr, multiaddr} from "@multiformats/multiaddr";
|
|
15
15
|
import {ENR} from "@chainsafe/enr";
|
|
16
16
|
import {routes} from "@lodestar/api";
|
|
17
17
|
import {BeaconConfig, ForkBoundary} from "@lodestar/config";
|
|
@@ -537,19 +537,24 @@ export function parseDirectPeers(directPeerStrs: routes.lodestar.DirectPeer[], l
|
|
|
537
537
|
const enr = ENR.decodeTxt(peerStr);
|
|
538
538
|
const peerId = enr.peerId;
|
|
539
539
|
|
|
540
|
-
// Get
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
540
|
+
// Get all available transport multiaddrs from ENR
|
|
541
|
+
const addrs = [enr.getLocationMultiaddr("quic"), enr.getLocationMultiaddr("tcp")].filter(
|
|
542
|
+
(a): a is Multiaddr => a != null
|
|
543
|
+
);
|
|
544
|
+
if (addrs.length === 0) {
|
|
545
|
+
logger.warn("ENR does not contain any transport multiaddr", {enr: peerStr});
|
|
544
546
|
continue;
|
|
545
547
|
}
|
|
546
548
|
|
|
547
549
|
directPeers.push({
|
|
548
550
|
id: peerId,
|
|
549
|
-
addrs
|
|
551
|
+
addrs,
|
|
550
552
|
});
|
|
551
553
|
|
|
552
|
-
logger.info("Added direct peer from ENR", {
|
|
554
|
+
logger.info("Added direct peer from ENR", {
|
|
555
|
+
peerId: peerId.toString(),
|
|
556
|
+
addrs: addrs.map((a) => a.toString()).join(", "),
|
|
557
|
+
});
|
|
553
558
|
} catch (e) {
|
|
554
559
|
logger.warn("Failed to parse direct peer ENR", {enr: peerStr}, e as Error);
|
|
555
560
|
}
|
|
@@ -5,11 +5,12 @@ import {mdns} from "@libp2p/mdns";
|
|
|
5
5
|
import {mplex} from "@libp2p/mplex";
|
|
6
6
|
import {prometheusMetrics} from "@libp2p/prometheus-metrics";
|
|
7
7
|
import {tcp} from "@libp2p/tcp";
|
|
8
|
-
import {createLibp2p} from "libp2p";
|
|
8
|
+
import {Libp2pInit, createLibp2p} from "libp2p";
|
|
9
9
|
import {Registry} from "prom-client";
|
|
10
10
|
import {ENR} from "@chainsafe/enr";
|
|
11
11
|
import {noise} from "@chainsafe/libp2p-noise";
|
|
12
12
|
import {asCrypto, defaultCrypto} from "@chainsafe/libp2p-noise/crypto";
|
|
13
|
+
import {quic} from "@chainsafe/libp2p-quic";
|
|
13
14
|
import {Libp2p, LodestarComponents} from "../interface.js";
|
|
14
15
|
import {NetworkOptions, defaultNetworkOptions} from "../options.js";
|
|
15
16
|
import {Eth2PeerDataStore} from "../peers/datastore.js";
|
|
@@ -21,11 +22,14 @@ export type NodeJsLibp2pOpts = {
|
|
|
21
22
|
metricsRegistry?: Registry;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
|
-
export async function getDiscv5Multiaddrs(bootEnrs: string[]): Promise<string[]> {
|
|
25
|
+
export async function getDiscv5Multiaddrs(bootEnrs: string[], quicEnabled?: boolean): Promise<string[]> {
|
|
25
26
|
const bootMultiaddrs = [];
|
|
26
27
|
for (const enrStr of bootEnrs) {
|
|
27
28
|
const enr = ENR.decodeTxt(enrStr);
|
|
28
|
-
|
|
29
|
+
// Prefer QUIC over TCP when available
|
|
30
|
+
const quicMultiaddr = quicEnabled ? (await enr.getFullMultiaddr("quic"))?.toString() : undefined;
|
|
31
|
+
const tcpMultiaddr = (await enr.getFullMultiaddr("tcp"))?.toString();
|
|
32
|
+
const multiaddrWithPeerId = quicMultiaddr ?? tcpMultiaddr;
|
|
29
33
|
if (multiaddrWithPeerId) {
|
|
30
34
|
bootMultiaddrs.push(multiaddrWithPeerId);
|
|
31
35
|
}
|
|
@@ -53,7 +57,9 @@ export async function createNodeJsLibp2p(
|
|
|
53
57
|
const bootMultiaddrs = [
|
|
54
58
|
...(networkOpts.bootMultiaddrs ?? defaultNetworkOptions.bootMultiaddrs ?? []),
|
|
55
59
|
// Append discv5.bootEnrs to bootMultiaddrs if requested
|
|
56
|
-
...(networkOpts.connectToDiscv5Bootnodes
|
|
60
|
+
...(networkOpts.connectToDiscv5Bootnodes
|
|
61
|
+
? await getDiscv5Multiaddrs(networkOpts.discv5?.bootEnrs ?? [], networkOpts.quic)
|
|
62
|
+
: []),
|
|
57
63
|
];
|
|
58
64
|
|
|
59
65
|
if ((bootMultiaddrs.length ?? 0) > 0) {
|
|
@@ -64,6 +70,35 @@ export async function createNodeJsLibp2p(
|
|
|
64
70
|
peerDiscovery.push(mdns());
|
|
65
71
|
}
|
|
66
72
|
}
|
|
73
|
+
const transports: Libp2pInit["transports"] = [];
|
|
74
|
+
if (networkOpts.tcp ?? true) {
|
|
75
|
+
transports.unshift(
|
|
76
|
+
tcp({
|
|
77
|
+
// Reject connections when the server's connection count gets high
|
|
78
|
+
maxConnections: networkOpts.maxPeers,
|
|
79
|
+
// socket option: the maximum length of the queue of pending connections
|
|
80
|
+
// https://nodejs.org/dist/latest-v18.x/docs/api/net.html#serverlisten
|
|
81
|
+
// it's not safe if we increase this number
|
|
82
|
+
backlog: 5,
|
|
83
|
+
closeServerOnMaxConnections: {
|
|
84
|
+
closeAbove: networkOpts.maxPeers ?? Infinity,
|
|
85
|
+
listenBelow: networkOpts.maxPeers ?? Infinity,
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (networkOpts.quic) {
|
|
91
|
+
transports.unshift(
|
|
92
|
+
quic({
|
|
93
|
+
handshakeTimeout: 5_000,
|
|
94
|
+
maxIdleTimeout: 10_000,
|
|
95
|
+
keepAliveInterval: 5_000,
|
|
96
|
+
maxConcurrentStreamLimit: 256,
|
|
97
|
+
maxStreamData: 10_000_000,
|
|
98
|
+
maxConnectionData: 15_000_000,
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
}
|
|
67
102
|
|
|
68
103
|
const noiseCrypto = {
|
|
69
104
|
...defaultCrypto,
|
|
@@ -85,20 +120,7 @@ export async function createNodeJsLibp2p(
|
|
|
85
120
|
announce: [],
|
|
86
121
|
},
|
|
87
122
|
connectionEncrypters: [noise({crypto: noiseCrypto})],
|
|
88
|
-
|
|
89
|
-
transports: [
|
|
90
|
-
tcp({
|
|
91
|
-
maxConnections: networkOpts.maxPeers,
|
|
92
|
-
// socket option: the maximum length of the queue of pending connections
|
|
93
|
-
// https://nodejs.org/dist/latest-v18.x/docs/api/net.html#serverlisten
|
|
94
|
-
// it's not safe if we increase this number
|
|
95
|
-
backlog: 5,
|
|
96
|
-
closeServerOnMaxConnections: {
|
|
97
|
-
closeAbove: networkOpts.maxPeers ?? Infinity,
|
|
98
|
-
listenBelow: networkOpts.maxPeers ?? Infinity,
|
|
99
|
-
},
|
|
100
|
-
}),
|
|
101
|
-
],
|
|
123
|
+
transports,
|
|
102
124
|
streamMuxers: [mplex({disconnectThreshold})],
|
|
103
125
|
peerDiscovery,
|
|
104
126
|
metrics: nodeJsLibp2pOpts.metrics
|