@lodestar/beacon-node 1.39.0 → 1.40.0-dev.3715a82f3f
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/state/utils.d.ts +2 -7
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +0 -12
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/config/constants.d.ts +3 -0
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +5 -1
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/proof/index.d.ts.map +1 -1
- package/lib/api/impl/proof/index.js +1 -2
- package/lib/api/impl/proof/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +1 -3
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -3
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +19 -14
- 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 -3
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +8 -1
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +1 -0
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
- package/lib/chain/chain.d.ts +3 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +16 -6
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/initState.d.ts +1 -1
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +5 -3
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +0 -2
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts +5 -9
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +12 -141
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/opPool.js +5 -8
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +4 -7
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +1 -5
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/queued.d.ts +4 -7
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +15 -25
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +1 -1
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +13 -17
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/shufflingCache.d.ts +16 -11
- package/lib/chain/shufflingCache.d.ts.map +1 -1
- package/lib/chain/shufflingCache.js +47 -41
- package/lib/chain/shufflingCache.js.map +1 -1
- package/lib/chain/stateCache/blockStateCacheImpl.d.ts +1 -2
- package/lib/chain/stateCache/blockStateCacheImpl.d.ts.map +1 -1
- package/lib/chain/stateCache/blockStateCacheImpl.js +2 -2
- package/lib/chain/stateCache/blockStateCacheImpl.js.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +1 -2
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +4 -4
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts +4 -5
- package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/inMemoryCheckpointsCache.js +9 -10
- package/lib/chain/stateCache/inMemoryCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +5 -6
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +17 -17
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +5 -6
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +2 -2
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -1
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +2 -0
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/blsToExecutionChange.d.ts.map +1 -1
- package/lib/chain/validation/blsToExecutionChange.js +9 -2
- package/lib/chain/validation/blsToExecutionChange.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +2 -1
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/db/repositories/checkpointState.d.ts +2 -6
- package/lib/db/repositories/checkpointState.d.ts.map +1 -1
- package/lib/db/repositories/checkpointState.js +3 -15
- package/lib/db/repositories/checkpointState.js.map +1 -1
- package/lib/db/repositories/stateArchive.d.ts +9 -9
- package/lib/db/repositories/stateArchive.d.ts.map +1 -1
- package/lib/db/repositories/stateArchive.js +6 -21
- package/lib/db/repositories/stateArchive.js.map +1 -1
- package/lib/execution/engine/mock.d.ts +9 -6
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +34 -7
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +1 -6
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +3 -17
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +17 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/state/utils.ts +2 -22
- package/src/api/impl/config/constants.ts +8 -0
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/proof/index.ts +1 -2
- package/src/api/impl/validator/index.ts +1 -3
- package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -3
- package/src/chain/archiveStore/utils/archiveBlocks.ts +21 -14
- package/src/chain/blocks/importBlock.ts +13 -3
- package/src/chain/blocks/verifyBlock.ts +9 -3
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +1 -0
- package/src/chain/chain.ts +20 -9
- package/src/chain/initState.ts +5 -3
- package/src/chain/interface.ts +2 -2
- package/src/chain/lightClient/proofs.ts +0 -2
- package/src/chain/opPools/aggregatedAttestationPool.ts +19 -191
- package/src/chain/opPools/opPool.ts +5 -7
- package/src/chain/prepareNextSlot.ts +2 -6
- package/src/chain/produceBlock/produceBlockBody.ts +6 -1
- package/src/chain/regen/interface.ts +1 -5
- package/src/chain/regen/queued.ts +15 -34
- package/src/chain/regen/regen.ts +12 -18
- package/src/chain/shufflingCache.ts +67 -50
- package/src/chain/stateCache/blockStateCacheImpl.ts +2 -3
- package/src/chain/stateCache/fifoBlockStateCache.ts +4 -5
- package/src/chain/stateCache/inMemoryCheckpointsCache.ts +9 -15
- package/src/chain/stateCache/persistentCheckpointsCache.ts +17 -25
- package/src/chain/stateCache/types.ts +5 -10
- package/src/chain/validation/attestation.ts +3 -3
- package/src/chain/validation/attesterSlashing.ts +8 -1
- package/src/chain/validation/block.ts +3 -0
- package/src/chain/validation/blsToExecutionChange.ts +9 -7
- package/src/chain/validation/proposerSlashing.ts +2 -1
- package/src/db/repositories/checkpointState.ts +3 -19
- package/src/db/repositories/stateArchive.ts +13 -27
- package/src/execution/engine/mock.ts +40 -13
- package/src/index.ts +1 -1
- package/src/metrics/metrics/lodestar.ts +3 -17
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +1 -1
- package/src/node/nodejs.ts +18 -3
- package/src/util/sszBytes.ts +1 -1
|
@@ -11,7 +11,6 @@ import {Logger, MapDef, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils"
|
|
|
11
11
|
import {Metrics} from "../../metrics/index.js";
|
|
12
12
|
import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js";
|
|
13
13
|
import {IClock} from "../../util/clock.js";
|
|
14
|
-
import {StateRegenerationOpts} from "../regen/interface.js";
|
|
15
14
|
import {serializeState} from "../serializeState.js";
|
|
16
15
|
import {CPStateDatastore, DatastoreKey} from "./datastore/index.js";
|
|
17
16
|
import {MapTracker} from "./mapMetrics.js";
|
|
@@ -204,10 +203,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
204
203
|
* - Get block for processing
|
|
205
204
|
* - Regen head state
|
|
206
205
|
*/
|
|
207
|
-
async getOrReload(cp: CheckpointHex
|
|
208
|
-
const stateOrStateBytesData = await this.getStateOrLoadDb(cp
|
|
206
|
+
async getOrReload(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | null> {
|
|
207
|
+
const stateOrStateBytesData = await this.getStateOrLoadDb(cp);
|
|
209
208
|
if (stateOrStateBytesData === null || isCachedBeaconState(stateOrStateBytesData)) {
|
|
210
|
-
return stateOrStateBytesData
|
|
209
|
+
return stateOrStateBytesData ?? null;
|
|
211
210
|
}
|
|
212
211
|
const {persistedKey, stateBytes} = stateOrStateBytesData;
|
|
213
212
|
const logMeta = {persistedKey: toHex(persistedKey)};
|
|
@@ -233,7 +232,8 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
233
232
|
sszTimer?.();
|
|
234
233
|
const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer();
|
|
235
234
|
const newCachedState = loadCachedBeaconState(seedState, stateBytes, {}, validatorsBytes);
|
|
236
|
-
|
|
235
|
+
// hashTreeRoot() calls the commit() inside
|
|
236
|
+
// there is no modification inside the state, it's just that we want to compute and cache all roots
|
|
237
237
|
const stateRoot = toRootHex(newCachedState.hashTreeRoot());
|
|
238
238
|
timer?.();
|
|
239
239
|
|
|
@@ -252,7 +252,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
252
252
|
this.cache.set(cpKey, {type: CacheItemType.inMemory, state: newCachedState, persistedKey});
|
|
253
253
|
this.epochIndex.getOrDefault(cp.epoch).add(cp.rootHex);
|
|
254
254
|
// don't prune from memory here, call it at the last 1/3 of slot 0 of an epoch
|
|
255
|
-
return newCachedState
|
|
255
|
+
return newCachedState;
|
|
256
256
|
} catch (e) {
|
|
257
257
|
this.logger.debug("Reload: error loading cached state", logMeta, e as Error);
|
|
258
258
|
return null;
|
|
@@ -263,8 +263,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
263
263
|
* Return either state or state bytes loaded from db.
|
|
264
264
|
*/
|
|
265
265
|
async getStateOrBytes(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | Uint8Array | null> {
|
|
266
|
-
|
|
267
|
-
const stateOrLoadedState = await this.getStateOrLoadDb(cp, {dontTransferCache: true});
|
|
266
|
+
const stateOrLoadedState = await this.getStateOrLoadDb(cp);
|
|
268
267
|
if (stateOrLoadedState === null || isCachedBeaconState(stateOrLoadedState)) {
|
|
269
268
|
return stateOrLoadedState;
|
|
270
269
|
}
|
|
@@ -274,12 +273,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
274
273
|
/**
|
|
275
274
|
* Return either state or state bytes with persisted key loaded from db.
|
|
276
275
|
*/
|
|
277
|
-
async getStateOrLoadDb(
|
|
278
|
-
cp: CheckpointHex,
|
|
279
|
-
opts?: StateRegenerationOpts
|
|
280
|
-
): Promise<CachedBeaconStateAllForks | LoadedStateBytesData | null> {
|
|
276
|
+
async getStateOrLoadDb(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | LoadedStateBytesData | null> {
|
|
281
277
|
const cpKey = toCacheKey(cp);
|
|
282
|
-
const inMemoryState = this.get(cpKey
|
|
278
|
+
const inMemoryState = this.get(cpKey);
|
|
283
279
|
if (inMemoryState) {
|
|
284
280
|
return inMemoryState;
|
|
285
281
|
}
|
|
@@ -308,7 +304,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
308
304
|
/**
|
|
309
305
|
* Similar to get() api without reloading from disk
|
|
310
306
|
*/
|
|
311
|
-
get(cpOrKey: CheckpointHex | string
|
|
307
|
+
get(cpOrKey: CheckpointHex | string): CachedBeaconStateAllForks | null {
|
|
312
308
|
this.metrics?.cpStateCache.lookups.inc();
|
|
313
309
|
const cpKey = typeof cpOrKey === "string" ? cpOrKey : toCacheKey(cpOrKey);
|
|
314
310
|
const cacheItem = this.cache.get(cpKey);
|
|
@@ -326,7 +322,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
326
322
|
if (isInMemoryCacheItem(cacheItem)) {
|
|
327
323
|
const {state} = cacheItem;
|
|
328
324
|
this.metrics?.cpStateCache.stateClonedCount.observe(state.clonedCount);
|
|
329
|
-
return state
|
|
325
|
+
return state;
|
|
330
326
|
}
|
|
331
327
|
|
|
332
328
|
return null;
|
|
@@ -360,14 +356,14 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
360
356
|
/**
|
|
361
357
|
* Searches in-memory state for the latest cached state with a `root` without reload, starting with `epoch` and descending
|
|
362
358
|
*/
|
|
363
|
-
getLatest(rootHex: RootHex, maxEpoch: Epoch
|
|
359
|
+
getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null {
|
|
364
360
|
// sort epochs in descending order, only consider epochs lte `epoch`
|
|
365
361
|
const epochs = Array.from(this.epochIndex.keys())
|
|
366
362
|
.sort((a, b) => b - a)
|
|
367
363
|
.filter((e) => e <= maxEpoch);
|
|
368
364
|
for (const epoch of epochs) {
|
|
369
365
|
if (this.epochIndex.get(epoch)?.has(rootHex)) {
|
|
370
|
-
const inMemoryClonedState = this.get({rootHex, epoch}
|
|
366
|
+
const inMemoryClonedState = this.get({rootHex, epoch});
|
|
371
367
|
if (inMemoryClonedState) {
|
|
372
368
|
return inMemoryClonedState;
|
|
373
369
|
}
|
|
@@ -383,11 +379,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
383
379
|
* - Get block for processing
|
|
384
380
|
* - Regen head state
|
|
385
381
|
*/
|
|
386
|
-
async getOrReloadLatest(
|
|
387
|
-
rootHex: RootHex,
|
|
388
|
-
maxEpoch: Epoch,
|
|
389
|
-
opts?: StateRegenerationOpts
|
|
390
|
-
): Promise<CachedBeaconStateAllForks | null> {
|
|
382
|
+
async getOrReloadLatest(rootHex: RootHex, maxEpoch: Epoch): Promise<CachedBeaconStateAllForks | null> {
|
|
391
383
|
// sort epochs in descending order, only consider epochs lte `epoch`
|
|
392
384
|
const epochs = Array.from(this.epochIndex.keys())
|
|
393
385
|
.sort((a, b) => b - a)
|
|
@@ -395,9 +387,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
395
387
|
for (const epoch of epochs) {
|
|
396
388
|
if (this.epochIndex.get(epoch)?.has(rootHex)) {
|
|
397
389
|
try {
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
400
|
-
return
|
|
390
|
+
const state = await this.getOrReload({rootHex, epoch});
|
|
391
|
+
if (state) {
|
|
392
|
+
return state;
|
|
401
393
|
}
|
|
402
394
|
} catch (e) {
|
|
403
395
|
this.logger.debug("Error get or reload state", {epoch, rootHex}, e as Error);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
|
|
3
3
|
import {Epoch, RootHex, phase0} from "@lodestar/types";
|
|
4
|
-
import {StateRegenerationOpts} from "../regen/interface.js";
|
|
5
4
|
|
|
6
5
|
export type CheckpointHex = {epoch: Epoch; rootHex: RootHex};
|
|
7
6
|
|
|
@@ -21,7 +20,7 @@ export type CheckpointHex = {epoch: Epoch; rootHex: RootHex};
|
|
|
21
20
|
* The cache key is state root
|
|
22
21
|
*/
|
|
23
22
|
export interface BlockStateCache {
|
|
24
|
-
get(rootHex: RootHex
|
|
23
|
+
get(rootHex: RootHex): CachedBeaconStateAllForks | null;
|
|
25
24
|
add(item: CachedBeaconStateAllForks): void;
|
|
26
25
|
setHeadState(item: CachedBeaconStateAllForks | null): void;
|
|
27
26
|
/**
|
|
@@ -60,16 +59,12 @@ export interface BlockStateCache {
|
|
|
60
59
|
*/
|
|
61
60
|
export interface CheckpointStateCache {
|
|
62
61
|
init?: () => Promise<void>;
|
|
63
|
-
getOrReload(cp: CheckpointHex
|
|
62
|
+
getOrReload(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | null>;
|
|
64
63
|
getStateOrBytes(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | Uint8Array | null>;
|
|
65
|
-
get(cpOrKey: CheckpointHex | string
|
|
64
|
+
get(cpOrKey: CheckpointHex | string): CachedBeaconStateAllForks | null;
|
|
66
65
|
add(cp: phase0.Checkpoint, state: CachedBeaconStateAllForks): void;
|
|
67
|
-
getLatest(rootHex: RootHex, maxEpoch: Epoch
|
|
68
|
-
getOrReloadLatest(
|
|
69
|
-
rootHex: RootHex,
|
|
70
|
-
maxEpoch: Epoch,
|
|
71
|
-
opts?: StateRegenerationOpts
|
|
72
|
-
): Promise<CachedBeaconStateAllForks | null>;
|
|
66
|
+
getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null;
|
|
67
|
+
getOrReloadLatest(rootHex: RootHex, maxEpoch: Epoch): Promise<CachedBeaconStateAllForks | null>;
|
|
73
68
|
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null;
|
|
74
69
|
prune(finalizedEpoch: Epoch, justifiedEpoch: Epoch): void;
|
|
75
70
|
pruneFinalized(finalizedEpoch: Epoch): void;
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
isForkPostElectra,
|
|
13
13
|
} from "@lodestar/params";
|
|
14
14
|
import {
|
|
15
|
-
EpochCacheError,
|
|
16
|
-
EpochCacheErrorCode,
|
|
17
15
|
EpochShuffling,
|
|
16
|
+
ShufflingError,
|
|
17
|
+
ShufflingErrorCode,
|
|
18
18
|
SingleSignatureSet,
|
|
19
19
|
computeEpochAtSlot,
|
|
20
20
|
computeSigningRoot,
|
|
@@ -224,7 +224,7 @@ export async function validateApiAttestation(
|
|
|
224
224
|
code: AttestationErrorCode.INVALID_SIGNATURE,
|
|
225
225
|
});
|
|
226
226
|
} catch (err) {
|
|
227
|
-
if (err instanceof
|
|
227
|
+
if (err instanceof ShufflingError && err.type.code === ShufflingErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE) {
|
|
228
228
|
throw new AttestationError(GossipAction.IGNORE, {
|
|
229
229
|
code: AttestationErrorCode.BAD_TARGET_EPOCH,
|
|
230
230
|
});
|
|
@@ -43,7 +43,14 @@ export async function validateAttesterSlashing(
|
|
|
43
43
|
// [REJECT] All of the conditions within process_attester_slashing pass validation.
|
|
44
44
|
try {
|
|
45
45
|
// verifySignature = false, verified in batch below
|
|
46
|
-
assertValidAttesterSlashing(
|
|
46
|
+
assertValidAttesterSlashing(
|
|
47
|
+
chain.config,
|
|
48
|
+
chain.index2pubkey,
|
|
49
|
+
state.slot,
|
|
50
|
+
state.validators.length,
|
|
51
|
+
attesterSlashing,
|
|
52
|
+
false
|
|
53
|
+
);
|
|
47
54
|
} catch (e) {
|
|
48
55
|
throw new AttesterSlashingError(GossipAction.REJECT, {
|
|
49
56
|
code: AttesterSlashingErrorCode.INVALID,
|
|
@@ -134,6 +134,9 @@ export async function validateGossipBlock(
|
|
|
134
134
|
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot});
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
+
// in forky condition, make sure to populate ShufflingCache with regened state
|
|
138
|
+
chain.shufflingCache.processState(blockState);
|
|
139
|
+
|
|
137
140
|
// Extra conditions for merge fork blocks
|
|
138
141
|
// [REJECT] The block's execution payload timestamp is correct with respect to the slot
|
|
139
142
|
// -- i.e. execution_payload.timestamp == compute_timestamp_at_slot(state, block.slot).
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CachedBeaconStateCapella,
|
|
3
|
-
getBlsToExecutionChangeSignatureSet,
|
|
4
|
-
isValidBlsToExecutionChange,
|
|
5
|
-
} from "@lodestar/state-transition";
|
|
1
|
+
import {getBlsToExecutionChangeSignatureSet, isValidBlsToExecutionChange} from "@lodestar/state-transition";
|
|
6
2
|
import {capella} from "@lodestar/types";
|
|
7
3
|
import {BlsToExecutionChangeError, BlsToExecutionChangeErrorCode, GossipAction} from "../errors/index.js";
|
|
8
4
|
import {IBeaconChain} from "../index.js";
|
|
@@ -42,10 +38,16 @@ async function validateBlsToExecutionChange(
|
|
|
42
38
|
// and chanes relevant to `isValidBlsToExecutionChange()` happen only on processBlock(), not processEpoch()
|
|
43
39
|
const state = chain.getHeadState();
|
|
44
40
|
const {config} = chain;
|
|
45
|
-
|
|
41
|
+
const addressChange = blsToExecutionChange.message;
|
|
42
|
+
if (addressChange.validatorIndex >= state.validators.length) {
|
|
43
|
+
throw new BlsToExecutionChangeError(GossipAction.REJECT, {
|
|
44
|
+
code: BlsToExecutionChangeErrorCode.INVALID,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const validator = state.validators.getReadonly(addressChange.validatorIndex);
|
|
46
48
|
// [REJECT] All of the conditions within process_bls_to_execution_change pass validation.
|
|
47
49
|
// verifySignature = false, verified in batch below
|
|
48
|
-
const {valid} = isValidBlsToExecutionChange(
|
|
50
|
+
const {valid} = isValidBlsToExecutionChange(config, validator, blsToExecutionChange, false);
|
|
49
51
|
if (!valid) {
|
|
50
52
|
throw new BlsToExecutionChangeError(GossipAction.REJECT, {
|
|
51
53
|
code: BlsToExecutionChangeErrorCode.INVALID,
|
|
@@ -35,8 +35,9 @@ async function validateProposerSlashing(
|
|
|
35
35
|
|
|
36
36
|
// [REJECT] All of the conditions within process_proposer_slashing pass validation.
|
|
37
37
|
try {
|
|
38
|
+
const proposer = state.validators.getReadonly(proposerSlashing.signedHeader1.message.proposerIndex);
|
|
38
39
|
// verifySignature = false, verified in batch below
|
|
39
|
-
assertValidProposerSlashing(state, proposerSlashing, false);
|
|
40
|
+
assertValidProposerSlashing(chain.config, chain.index2pubkey, state.slot, proposerSlashing, proposer, false);
|
|
40
41
|
} catch (e) {
|
|
41
42
|
throw new ProposerSlashingError(GossipAction.REJECT, {
|
|
42
43
|
code: ProposerSlashingErrorCode.INVALID,
|
|
@@ -1,31 +1,15 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
3
|
-
import {BeaconStateAllForks} from "@lodestar/state-transition";
|
|
4
|
-
import {ssz} from "@lodestar/types";
|
|
2
|
+
import {BinaryRepository, Db} from "@lodestar/db";
|
|
5
3
|
import {Bucket, getBucketNameByValue} from "../buckets.js";
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* Store temporary checkpoint states.
|
|
9
7
|
* We should only put/get binary data from this repository, consumer will load it into an existing state ViewDU object.
|
|
10
8
|
*/
|
|
11
|
-
export class CheckpointStateRepository extends
|
|
9
|
+
export class CheckpointStateRepository extends BinaryRepository<Uint8Array> {
|
|
12
10
|
constructor(config: ChainForkConfig, db: Db) {
|
|
13
|
-
// Pick some type but won't be used. Casted to any because no type can match `BeaconStateAllForks`
|
|
14
|
-
const type = ssz.phase0.BeaconState;
|
|
15
11
|
const bucket = Bucket.allForks_checkpointState;
|
|
16
12
|
// biome-ignore lint/suspicious/noExplicitAny: The type is complex to specify a proper override
|
|
17
|
-
super(config, db, bucket,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
getId(): Uint8Array {
|
|
21
|
-
throw Error("CheckpointStateRepository does not work with value");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
encodeValue(): Uint8Array {
|
|
25
|
-
throw Error("CheckpointStateRepository does not work with value");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
decodeValue(): BeaconStateAllForks {
|
|
29
|
-
throw Error("CheckpointStateRepository does not work with value");
|
|
13
|
+
super(config, db, bucket, getBucketNameByValue(bucket));
|
|
30
14
|
}
|
|
31
15
|
}
|
|
@@ -1,39 +1,25 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {Epoch, Root, RootHex, Slot, ssz} from "@lodestar/types";
|
|
2
|
+
import {BinaryRepository, Db} from "@lodestar/db";
|
|
3
|
+
import {Root, RootHex, Slot} from "@lodestar/types";
|
|
5
4
|
import {bytesToInt, toHex} from "@lodestar/utils";
|
|
6
|
-
import {getStateTypeFromBytes} from "../../util/multifork.js";
|
|
7
5
|
import {Bucket, getBucketNameByValue} from "../buckets.js";
|
|
8
6
|
import {getRootIndex, getRootIndexKey, storeRootIndex} from "./stateArchiveIndex.js";
|
|
9
7
|
|
|
10
|
-
export
|
|
8
|
+
export type BeaconStateArchive = {
|
|
9
|
+
serialize(): Uint8Array;
|
|
10
|
+
hashTreeRoot(): Root;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class StateArchiveRepository extends BinaryRepository<Slot> {
|
|
11
14
|
constructor(config: ChainForkConfig, db: Db) {
|
|
12
|
-
// Pick some type but won't be used. Casted to any because no type can match `BeaconStateAllForks`
|
|
13
|
-
// biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
|
|
14
|
-
const type = ssz.phase0.BeaconState as any;
|
|
15
15
|
const bucket = Bucket.allForks_stateArchive;
|
|
16
|
-
super(config, db, bucket,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Overrides for multi-fork
|
|
20
|
-
|
|
21
|
-
encodeValue(value: BeaconStateAllForks): Uint8Array {
|
|
22
|
-
return value.serialize();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
decodeValue(data: Uint8Array): BeaconStateAllForks {
|
|
26
|
-
return getStateTypeFromBytes(this.config, data).deserializeToViewDU(data);
|
|
16
|
+
super(config, db, bucket, getBucketNameByValue(bucket));
|
|
27
17
|
}
|
|
28
18
|
|
|
29
19
|
// Handle key as slot
|
|
30
20
|
|
|
31
|
-
async put(key: Slot, value:
|
|
32
|
-
await Promise.all([super.
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
getId(state: BeaconStateAllForks): Epoch {
|
|
36
|
-
return state.slot;
|
|
21
|
+
async put(key: Slot, value: BeaconStateArchive): Promise<void> {
|
|
22
|
+
await Promise.all([super.putBinary(key, value.serialize()), storeRootIndex(this.db, key, value.hashTreeRoot())]);
|
|
37
23
|
}
|
|
38
24
|
|
|
39
25
|
decodeKey(data: Uint8Array): number {
|
|
@@ -42,10 +28,10 @@ export class StateArchiveRepository extends Repository<Slot, BeaconStateAllForks
|
|
|
42
28
|
|
|
43
29
|
// Index Root -> Slot
|
|
44
30
|
|
|
45
|
-
async
|
|
31
|
+
async getBinaryByRoot(stateRoot: Root): Promise<Uint8Array | null> {
|
|
46
32
|
const slot = await this.getSlotByRoot(stateRoot);
|
|
47
33
|
if (slot !== null && Number.isInteger(slot)) {
|
|
48
|
-
return this.
|
|
34
|
+
return this.getBinary(slot);
|
|
49
35
|
}
|
|
50
36
|
return null;
|
|
51
37
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
import {ChainConfig} from "@lodestar/config";
|
|
2
3
|
import {
|
|
3
4
|
BLOB_TX_TYPE,
|
|
4
5
|
BYTES_PER_FIELD_ELEMENT,
|
|
@@ -7,7 +8,9 @@ import {
|
|
|
7
8
|
ForkPostBellatrix,
|
|
8
9
|
ForkPostCapella,
|
|
9
10
|
ForkSeq,
|
|
11
|
+
SLOTS_PER_EPOCH,
|
|
10
12
|
} from "@lodestar/params";
|
|
13
|
+
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
11
14
|
import {ExecutionPayload, RootHex, bellatrix, deneb, ssz} from "@lodestar/types";
|
|
12
15
|
import {fromHex, toRootHex} from "@lodestar/utils";
|
|
13
16
|
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
@@ -34,14 +37,11 @@ const INTEROP_GAS_LIMIT = 30e6;
|
|
|
34
37
|
const PRUNE_PAYLOAD_ID_AFTER_MS = 5000;
|
|
35
38
|
|
|
36
39
|
export type ExecutionEngineMockOpts = {
|
|
37
|
-
genesisBlockHash
|
|
40
|
+
genesisBlockHash?: string;
|
|
38
41
|
eth1BlockHash?: string;
|
|
39
42
|
onlyPredefinedResponses?: boolean;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
electraForkTimestamp?: number;
|
|
43
|
-
fuluForkTimestamp?: number;
|
|
44
|
-
gloasForkTimestamp?: number;
|
|
43
|
+
genesisTime?: number;
|
|
44
|
+
config?: ChainConfig;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
type ExecutionBlock = {
|
|
@@ -74,17 +74,21 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
74
74
|
/** Preparing payloads to be retrieved via engine_getPayloadV1 */
|
|
75
75
|
private readonly preparingPayloads = new Map<number, PreparedPayload>();
|
|
76
76
|
private readonly payloadsForDeletion = new Map<number, number>();
|
|
77
|
-
|
|
78
77
|
private readonly predefinedPayloadStatuses = new Map<RootHex, PayloadStatus>();
|
|
79
78
|
|
|
80
79
|
private payloadId = 0;
|
|
80
|
+
private capellaForkTimestamp: number;
|
|
81
|
+
private denebForkTimestamp: number;
|
|
82
|
+
private electraForkTimestamp: number;
|
|
83
|
+
private fuluForkTimestamp: number;
|
|
84
|
+
private gloasForkTimestamp: number;
|
|
81
85
|
|
|
82
86
|
readonly handlers: {
|
|
83
87
|
[K in keyof EngineApiRpcParamTypes]: (...args: EngineApiRpcParamTypes[K]) => EngineApiRpcReturnTypes[K];
|
|
84
88
|
};
|
|
85
89
|
|
|
86
90
|
constructor(private readonly opts: ExecutionEngineMockOpts) {
|
|
87
|
-
this.validBlocks.set(opts.genesisBlockHash, {
|
|
91
|
+
this.validBlocks.set(opts.genesisBlockHash ?? ZERO_HASH_HEX, {
|
|
88
92
|
parentHash: ZERO_HASH_HEX,
|
|
89
93
|
blockHash: ZERO_HASH_HEX,
|
|
90
94
|
timestamp: 0,
|
|
@@ -100,6 +104,29 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
100
104
|
blockNumber: 1,
|
|
101
105
|
});
|
|
102
106
|
|
|
107
|
+
const {config} = opts;
|
|
108
|
+
|
|
109
|
+
this.capellaForkTimestamp =
|
|
110
|
+
opts.genesisTime && config
|
|
111
|
+
? computeTimeAtSlot(config, config.CAPELLA_FORK_EPOCH * SLOTS_PER_EPOCH, opts.genesisTime)
|
|
112
|
+
: Infinity;
|
|
113
|
+
this.denebForkTimestamp =
|
|
114
|
+
opts.genesisTime && config
|
|
115
|
+
? computeTimeAtSlot(config, config.DENEB_FORK_EPOCH * SLOTS_PER_EPOCH, opts.genesisTime)
|
|
116
|
+
: Infinity;
|
|
117
|
+
this.electraForkTimestamp =
|
|
118
|
+
opts.genesisTime && config
|
|
119
|
+
? computeTimeAtSlot(config, config.ELECTRA_FORK_EPOCH * SLOTS_PER_EPOCH, opts.genesisTime)
|
|
120
|
+
: Infinity;
|
|
121
|
+
this.fuluForkTimestamp =
|
|
122
|
+
opts.genesisTime && config
|
|
123
|
+
? computeTimeAtSlot(config, config.FULU_FORK_EPOCH * SLOTS_PER_EPOCH, opts.genesisTime)
|
|
124
|
+
: Infinity;
|
|
125
|
+
this.gloasForkTimestamp =
|
|
126
|
+
opts.genesisTime && config
|
|
127
|
+
? computeTimeAtSlot(config, config.GLOAS_FORK_EPOCH * SLOTS_PER_EPOCH, opts.genesisTime)
|
|
128
|
+
: Infinity;
|
|
129
|
+
|
|
103
130
|
this.handlers = {
|
|
104
131
|
engine_newPayloadV1: this.notifyNewPayload.bind(this),
|
|
105
132
|
engine_newPayloadV2: this.notifyNewPayload.bind(this),
|
|
@@ -448,11 +475,11 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
448
475
|
}
|
|
449
476
|
|
|
450
477
|
private timestampToFork(timestamp: number): ForkPostBellatrix {
|
|
451
|
-
if (timestamp >=
|
|
452
|
-
if (timestamp >=
|
|
453
|
-
if (timestamp >=
|
|
454
|
-
if (timestamp >=
|
|
455
|
-
if (timestamp >=
|
|
478
|
+
if (timestamp >= this.gloasForkTimestamp) return ForkName.gloas;
|
|
479
|
+
if (timestamp >= this.fuluForkTimestamp) return ForkName.fulu;
|
|
480
|
+
if (timestamp >= this.electraForkTimestamp) return ForkName.electra;
|
|
481
|
+
if (timestamp >= this.denebForkTimestamp) return ForkName.deneb;
|
|
482
|
+
if (timestamp >= this.capellaForkTimestamp) return ForkName.capella;
|
|
456
483
|
return ForkName.bellatrix;
|
|
457
484
|
}
|
|
458
485
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
export type {RestApiServerMetrics, RestApiServerModules, RestApiServerOpts} from "./api/rest/base.js";
|
|
4
4
|
export {RestApiServer} from "./api/rest/base.js";
|
|
5
|
-
export {checkAndPersistAnchorState
|
|
5
|
+
export {checkAndPersistAnchorState} from "./chain/index.js";
|
|
6
6
|
export {DbCPStateDatastore} from "./chain/stateCache/datastore/db.js";
|
|
7
7
|
export {FileCPStateDatastore} from "./chain/stateCache/datastore/file.js";
|
|
8
8
|
export {BeaconDb, type IBeaconDb} from "./db/index.js";
|
|
@@ -1308,33 +1308,19 @@ export function createLodestarMetrics(
|
|
|
1308
1308
|
name: "lodestar_shuffling_cache_miss_count",
|
|
1309
1309
|
help: "Count of shuffling cache miss",
|
|
1310
1310
|
}),
|
|
1311
|
-
|
|
1312
|
-
name: "
|
|
1313
|
-
help: "Count of shuffling that were
|
|
1314
|
-
}),
|
|
1315
|
-
shufflingPromiseNotResolvedAndThrownAway: register.gauge({
|
|
1316
|
-
name: "lodestar_shuffling_cache_promise_not_resolved_and_thrown_away_count",
|
|
1317
|
-
help: "Count of shuffling cache promises that were discarded and the shuffling was built synchronously",
|
|
1311
|
+
shufflingSetMultipleTimes: register.gauge({
|
|
1312
|
+
name: "lodestar_shuffling_cache_set_multiple_times_count",
|
|
1313
|
+
help: "Count of shuffling that were set multiple times",
|
|
1318
1314
|
}),
|
|
1319
1315
|
shufflingPromiseNotResolved: register.gauge({
|
|
1320
1316
|
name: "lodestar_shuffling_cache_promise_not_resolved_count",
|
|
1321
1317
|
help: "Count of shuffling cache promises that were requested before the promise was resolved",
|
|
1322
1318
|
}),
|
|
1323
|
-
nextShufflingNotOnEpochCache: register.gauge({
|
|
1324
|
-
name: "lodestar_shuffling_cache_next_shuffling_not_on_epoch_cache",
|
|
1325
|
-
help: "The next shuffling was not on the epoch cache before the epoch transition",
|
|
1326
|
-
}),
|
|
1327
1319
|
shufflingPromiseResolutionTime: register.histogram({
|
|
1328
1320
|
name: "lodestar_shuffling_cache_promise_resolution_time_seconds",
|
|
1329
1321
|
help: "Time from promise insertion until promise resolution when shuffling was ready in seconds",
|
|
1330
1322
|
buckets: [0.5, 1, 1.5, 2],
|
|
1331
1323
|
}),
|
|
1332
|
-
shufflingCalculationTime: register.histogram<{source: "build" | "getSync"}>({
|
|
1333
|
-
name: "lodestar_shuffling_cache_shuffling_calculation_time_seconds",
|
|
1334
|
-
help: "Run time of shuffling calculation",
|
|
1335
|
-
buckets: [0.5, 0.75, 1, 1.25, 1.5],
|
|
1336
|
-
labelNames: ["source"],
|
|
1337
|
-
}),
|
|
1338
1324
|
},
|
|
1339
1325
|
|
|
1340
1326
|
seenCache: {
|
|
@@ -55,7 +55,7 @@ export async function handleColumnSidecarUnavailability({
|
|
|
55
55
|
const blobsCount = getBlobKzgCommitmentsCountFromSignedBeaconBlockSerialized(chain.config, blockBytes);
|
|
56
56
|
|
|
57
57
|
// There are zero blobs for that column index, so we can safely return without any error
|
|
58
|
-
if (blobsCount
|
|
58
|
+
if (blobsCount === 0) return;
|
|
59
59
|
|
|
60
60
|
// There are blobs for that column index so we should have synced for it
|
|
61
61
|
// We need to inform to peers that we don't have that expected data
|
package/src/node/nodejs.ts
CHANGED
|
@@ -6,9 +6,10 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map";
|
|
|
6
6
|
import {BeaconApiMethods} from "@lodestar/api/beacon/server";
|
|
7
7
|
import {BeaconConfig} from "@lodestar/config";
|
|
8
8
|
import type {LoggerNode} from "@lodestar/logger/node";
|
|
9
|
-
import {
|
|
9
|
+
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
10
|
+
import {CachedBeaconStateAllForks, Index2PubkeyCache, isExecutionCachedStateType} from "@lodestar/state-transition";
|
|
10
11
|
import {phase0} from "@lodestar/types";
|
|
11
|
-
import {sleep} from "@lodestar/utils";
|
|
12
|
+
import {sleep, toRootHex} from "@lodestar/utils";
|
|
12
13
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
13
14
|
import {BeaconRestApiServer, getApi} from "../api/index.js";
|
|
14
15
|
import {BeaconChain, IBeaconChain, initBeaconMetrics} from "../chain/index.js";
|
|
@@ -221,6 +222,20 @@ export class BeaconNode {
|
|
|
221
222
|
)
|
|
222
223
|
: null;
|
|
223
224
|
|
|
225
|
+
let executionEngineOpts = opts.executionEngine;
|
|
226
|
+
if (opts.executionEngine.mode === "mock") {
|
|
227
|
+
const eth1BlockHash = isExecutionCachedStateType(anchorState)
|
|
228
|
+
? toRootHex(anchorState.latestExecutionPayloadHeader.blockHash)
|
|
229
|
+
: undefined;
|
|
230
|
+
executionEngineOpts = {
|
|
231
|
+
...opts.executionEngine,
|
|
232
|
+
genesisBlockHash: ZERO_HASH_HEX,
|
|
233
|
+
eth1BlockHash,
|
|
234
|
+
genesisTime: anchorState.genesisTime,
|
|
235
|
+
config,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
224
239
|
const chain = new BeaconChain(opts.chain, {
|
|
225
240
|
privateKey,
|
|
226
241
|
config,
|
|
@@ -236,7 +251,7 @@ export class BeaconNode {
|
|
|
236
251
|
validatorMonitor,
|
|
237
252
|
anchorState,
|
|
238
253
|
isAnchorStateFinalized,
|
|
239
|
-
executionEngine: initializeExecutionEngine(
|
|
254
|
+
executionEngine: initializeExecutionEngine(executionEngineOpts, {
|
|
240
255
|
metrics,
|
|
241
256
|
signal,
|
|
242
257
|
logger: logger.child({module: LoggerModule.execution}),
|
package/src/util/sszBytes.ts
CHANGED
|
@@ -479,7 +479,7 @@ export function getBlobKzgCommitmentsCountFromSignedBeaconBlockSerialized(
|
|
|
479
479
|
blockBytes: Uint8Array
|
|
480
480
|
): number {
|
|
481
481
|
const slot = getSlotFromSignedBeaconBlockSerialized(blockBytes);
|
|
482
|
-
if (
|
|
482
|
+
if (slot === null) throw new Error("Can not parse the slot from block bytes");
|
|
483
483
|
|
|
484
484
|
if (config.getForkSeq(slot) < ForkSeq.deneb) return 0;
|
|
485
485
|
|