@lodestar/beacon-node 1.41.0 → 1.42.0-dev.5f2fffc2ce
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 -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 +11 -7
- 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 +16 -7
- 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/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/voluntaryExit.d.ts.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +2 -2
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/package.json +15 -15
- 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 +11 -6
- package/src/chain/blocks/verifyBlocksSignatures.ts +1 -1
- package/src/chain/chain.ts +23 -12
- package/src/chain/interface.ts +2 -2
- package/src/chain/prepareNextSlot.ts +6 -2
- 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/voluntaryExit.ts +2 -1
- 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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
|
+
import {CheckpointWithPayloadStatus} from "@lodestar/fork-choice";
|
|
3
4
|
import {
|
|
4
5
|
CachedBeaconStateAllForks,
|
|
5
6
|
computeStartSlotAtEpoch,
|
|
@@ -14,7 +15,7 @@ import {IClock} from "../../util/clock.js";
|
|
|
14
15
|
import {serializeState} from "../serializeState.js";
|
|
15
16
|
import {CPStateDatastore, DatastoreKey} from "./datastore/index.js";
|
|
16
17
|
import {MapTracker} from "./mapMetrics.js";
|
|
17
|
-
import {BlockStateCache, CacheItemType,
|
|
18
|
+
import {BlockStateCache, CacheItemType, CheckpointHexPayload, CheckpointStateCache} from "./types.js";
|
|
18
19
|
|
|
19
20
|
export type PersistentCheckpointStateCacheOpts = {
|
|
20
21
|
/** Keep max n state epochs in memory, persist the rest to disk */
|
|
@@ -54,6 +55,22 @@ type CacheItem = InMemoryCacheItem | PersistedCacheItem;
|
|
|
54
55
|
|
|
55
56
|
type LoadedStateBytesData = {persistedKey: DatastoreKey; stateBytes: Uint8Array};
|
|
56
57
|
|
|
58
|
+
/** Bitmask for tracking which payload variants exist per root in the epochIndex */
|
|
59
|
+
enum PayloadAvailability {
|
|
60
|
+
NOT_PRESENT = 1,
|
|
61
|
+
PRESENT = 2,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const PAYLOAD_AVAILABILITY_ALL = [PayloadAvailability.NOT_PRESENT, PayloadAvailability.PRESENT] as const;
|
|
65
|
+
|
|
66
|
+
function toPayloadAvailability(payloadPresent: boolean): PayloadAvailability {
|
|
67
|
+
return payloadPresent ? PayloadAvailability.PRESENT : PayloadAvailability.NOT_PRESENT;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function fromPayloadAvailability(flag: PayloadAvailability): boolean {
|
|
71
|
+
return flag === PayloadAvailability.PRESENT;
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
/**
|
|
58
75
|
* Before n-historical states, lodestar keeps all checkpoint states since finalized
|
|
59
76
|
* Since Sep 2024, lodestar stores 3 most recent checkpoint states in memory and the rest on disk. The finalized state
|
|
@@ -106,8 +123,8 @@ const PROCESS_CHECKPOINT_STATES_BPS = 6667;
|
|
|
106
123
|
*/
|
|
107
124
|
export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
108
125
|
private readonly cache: MapTracker<CacheKey, CacheItem>;
|
|
109
|
-
/** Epoch ->
|
|
110
|
-
private readonly epochIndex = new MapDef<Epoch,
|
|
126
|
+
/** Epoch -> Map<blockRoot, PayloadAvailability bitmask> */
|
|
127
|
+
private readonly epochIndex = new MapDef<Epoch, Map<RootHex, number>>(() => new Map());
|
|
111
128
|
private readonly config: BeaconConfig;
|
|
112
129
|
private readonly metrics: Metrics | null | undefined;
|
|
113
130
|
private readonly logger: Logger;
|
|
@@ -203,13 +220,18 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
203
220
|
* - Get block for processing
|
|
204
221
|
* - Regen head state
|
|
205
222
|
*/
|
|
206
|
-
async getOrReload(cp:
|
|
223
|
+
async getOrReload(cp: CheckpointHexPayload): Promise<CachedBeaconStateAllForks | null> {
|
|
207
224
|
const stateOrStateBytesData = await this.getStateOrLoadDb(cp);
|
|
208
225
|
if (stateOrStateBytesData === null || isCachedBeaconState(stateOrStateBytesData)) {
|
|
209
226
|
return stateOrStateBytesData ?? null;
|
|
210
227
|
}
|
|
211
228
|
const {persistedKey, stateBytes} = stateOrStateBytesData;
|
|
212
|
-
const logMeta = {
|
|
229
|
+
const logMeta = {
|
|
230
|
+
epoch: cp.epoch,
|
|
231
|
+
rootHex: cp.rootHex,
|
|
232
|
+
payloadPresent: cp.payloadPresent,
|
|
233
|
+
persistedKey: toHex(persistedKey),
|
|
234
|
+
};
|
|
213
235
|
this.logger.debug("Reload: read state successful", logMeta);
|
|
214
236
|
this.metrics?.cpStateCache.stateReloadSecFromSlot.observe(
|
|
215
237
|
this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0
|
|
@@ -250,7 +272,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
250
272
|
// only remove persisted state once we reload successfully
|
|
251
273
|
const cpKey = toCacheKey(cp);
|
|
252
274
|
this.cache.set(cpKey, {type: CacheItemType.inMemory, state: newCachedState, persistedKey});
|
|
253
|
-
this.
|
|
275
|
+
this.addToEpochIndex(cp.epoch, cp.rootHex, cp.payloadPresent);
|
|
254
276
|
// don't prune from memory here, call it at the last 1/3 of slot 0 of an epoch
|
|
255
277
|
return newCachedState;
|
|
256
278
|
} catch (e) {
|
|
@@ -262,7 +284,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
262
284
|
/**
|
|
263
285
|
* Return either state or state bytes loaded from db.
|
|
264
286
|
*/
|
|
265
|
-
async getStateOrBytes(cp:
|
|
287
|
+
async getStateOrBytes(cp: CheckpointHexPayload): Promise<CachedBeaconStateAllForks | Uint8Array | null> {
|
|
266
288
|
const stateOrLoadedState = await this.getStateOrLoadDb(cp);
|
|
267
289
|
if (stateOrLoadedState === null || isCachedBeaconState(stateOrLoadedState)) {
|
|
268
290
|
return stateOrLoadedState;
|
|
@@ -273,7 +295,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
273
295
|
/**
|
|
274
296
|
* Return either state or state bytes with persisted key loaded from db.
|
|
275
297
|
*/
|
|
276
|
-
async getStateOrLoadDb(cp:
|
|
298
|
+
async getStateOrLoadDb(cp: CheckpointHexPayload): Promise<CachedBeaconStateAllForks | LoadedStateBytesData | null> {
|
|
277
299
|
const cpKey = toCacheKey(cp);
|
|
278
300
|
const inMemoryState = this.get(cpKey);
|
|
279
301
|
if (inMemoryState) {
|
|
@@ -304,7 +326,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
304
326
|
/**
|
|
305
327
|
* Similar to get() api without reloading from disk
|
|
306
328
|
*/
|
|
307
|
-
get(cpOrKey:
|
|
329
|
+
get(cpOrKey: CheckpointHexPayload | CacheKey): CachedBeaconStateAllForks | null {
|
|
308
330
|
this.metrics?.cpStateCache.lookups.inc();
|
|
309
331
|
const cpKey = typeof cpOrKey === "string" ? cpOrKey : toCacheKey(cpOrKey);
|
|
310
332
|
const cacheItem = this.cache.get(cpKey);
|
|
@@ -330,9 +352,11 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
330
352
|
|
|
331
353
|
/**
|
|
332
354
|
* Add a state of a checkpoint to this cache, prune from memory if necessary.
|
|
355
|
+
* @param payloadPresent - For Gloas: true if this is payload state, false if block state.
|
|
356
|
+
* Always true for pre-Gloas.
|
|
333
357
|
*/
|
|
334
|
-
add(cp: phase0.Checkpoint, state: CachedBeaconStateAllForks): void {
|
|
335
|
-
const cpHex =
|
|
358
|
+
add(cp: phase0.Checkpoint, state: CachedBeaconStateAllForks, payloadPresent: boolean): void {
|
|
359
|
+
const cpHex = toCheckpointHexPayload(cp, payloadPresent);
|
|
336
360
|
const key = toCacheKey(cpHex);
|
|
337
361
|
const cacheItem = this.cache.get(key);
|
|
338
362
|
this.metrics?.cpStateCache.adds.inc();
|
|
@@ -343,27 +367,32 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
343
367
|
this.logger.verbose("Added checkpoint state to memory but a persisted key existed", {
|
|
344
368
|
epoch: cp.epoch,
|
|
345
369
|
rootHex: cpHex.rootHex,
|
|
370
|
+
payloadPresent,
|
|
346
371
|
persistedKey: toHex(persistedKey),
|
|
347
372
|
});
|
|
348
373
|
} else {
|
|
349
374
|
this.cache.set(key, {type: CacheItemType.inMemory, state});
|
|
350
|
-
this.logger.verbose("Added checkpoint state to memory", {
|
|
375
|
+
this.logger.verbose("Added checkpoint state to memory", {
|
|
376
|
+
epoch: cp.epoch,
|
|
377
|
+
rootHex: cpHex.rootHex,
|
|
378
|
+
payloadPresent,
|
|
379
|
+
});
|
|
351
380
|
}
|
|
352
|
-
this.
|
|
381
|
+
this.addToEpochIndex(cp.epoch, cpHex.rootHex, cpHex.payloadPresent);
|
|
353
382
|
this.prunePersistedStates();
|
|
354
383
|
}
|
|
355
384
|
|
|
356
385
|
/**
|
|
357
386
|
* Searches in-memory state for the latest cached state with a `root` without reload, starting with `epoch` and descending
|
|
358
387
|
*/
|
|
359
|
-
getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null {
|
|
388
|
+
getLatest(rootHex: RootHex, maxEpoch: Epoch, payloadPresent: boolean): CachedBeaconStateAllForks | null {
|
|
360
389
|
// sort epochs in descending order, only consider epochs lte `epoch`
|
|
361
390
|
const epochs = Array.from(this.epochIndex.keys())
|
|
362
391
|
.sort((a, b) => b - a)
|
|
363
392
|
.filter((e) => e <= maxEpoch);
|
|
364
393
|
for (const epoch of epochs) {
|
|
365
|
-
if (this.
|
|
366
|
-
const inMemoryClonedState = this.get({rootHex, epoch});
|
|
394
|
+
if (this.hasPayloadVariant(epoch, rootHex, payloadPresent)) {
|
|
395
|
+
const inMemoryClonedState = this.get({rootHex, epoch, payloadPresent});
|
|
367
396
|
if (inMemoryClonedState) {
|
|
368
397
|
return inMemoryClonedState;
|
|
369
398
|
}
|
|
@@ -379,20 +408,24 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
379
408
|
* - Get block for processing
|
|
380
409
|
* - Regen head state
|
|
381
410
|
*/
|
|
382
|
-
async getOrReloadLatest(
|
|
411
|
+
async getOrReloadLatest(
|
|
412
|
+
rootHex: RootHex,
|
|
413
|
+
maxEpoch: Epoch,
|
|
414
|
+
payloadPresent: boolean
|
|
415
|
+
): Promise<CachedBeaconStateAllForks | null> {
|
|
383
416
|
// sort epochs in descending order, only consider epochs lte `epoch`
|
|
384
417
|
const epochs = Array.from(this.epochIndex.keys())
|
|
385
418
|
.sort((a, b) => b - a)
|
|
386
419
|
.filter((e) => e <= maxEpoch);
|
|
387
420
|
for (const epoch of epochs) {
|
|
388
|
-
if (this.
|
|
421
|
+
if (this.hasPayloadVariant(epoch, rootHex, payloadPresent)) {
|
|
389
422
|
try {
|
|
390
|
-
const state = await this.getOrReload({rootHex, epoch});
|
|
423
|
+
const state = await this.getOrReload({rootHex, epoch, payloadPresent});
|
|
391
424
|
if (state) {
|
|
392
425
|
return state;
|
|
393
426
|
}
|
|
394
427
|
} catch (e) {
|
|
395
|
-
this.logger.debug("Error get or reload state", {epoch, rootHex}, e as Error);
|
|
428
|
+
this.logger.debug("Error get or reload state", {epoch, rootHex, payloadPresent}, e as Error);
|
|
396
429
|
}
|
|
397
430
|
}
|
|
398
431
|
}
|
|
@@ -400,12 +433,14 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
400
433
|
}
|
|
401
434
|
|
|
402
435
|
/**
|
|
403
|
-
* Update the precomputed checkpoint and return the number of
|
|
436
|
+
* Update the precomputed checkpoint and return the number of hits for the
|
|
404
437
|
* previous one (if any).
|
|
438
|
+
* @param payloadPresent - For Gloas: true if head block has FULL payload, false if EMPTY.
|
|
439
|
+
* Always true for pre-Gloas.
|
|
405
440
|
*/
|
|
406
|
-
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null {
|
|
441
|
+
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch, payloadPresent: boolean): number | null {
|
|
407
442
|
const previousHits = this.preComputedCheckpointHits;
|
|
408
|
-
this.preComputedCheckpoint = toCacheKey({rootHex, epoch});
|
|
443
|
+
this.preComputedCheckpoint = toCacheKey({rootHex, epoch, payloadPresent});
|
|
409
444
|
this.preComputedCheckpointHits = 0;
|
|
410
445
|
return previousHits;
|
|
411
446
|
}
|
|
@@ -479,6 +514,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
479
514
|
* - 2 then we'll persist {root: b2, epoch n-2} checkpoint state to disk, there are also 2 checkpoint states in memory at epoch n, same to the above (maxEpochsInMemory=1)
|
|
480
515
|
*
|
|
481
516
|
* As of Mar 2024, it takes <=350ms to persist a holesky state on fast server
|
|
517
|
+
*
|
|
518
|
+
* For Gloas: Processes both block state and payload state variants together. The decision of which roots to persist/prune
|
|
519
|
+
* is based on root canonicality (from state's view), not payload presence. Both variants are managed as a unit.
|
|
482
520
|
*/
|
|
483
521
|
async processState(blockRootHex: RootHex, state: CachedBeaconStateAllForks): Promise<number> {
|
|
484
522
|
let persistCount = 0;
|
|
@@ -549,7 +587,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
549
587
|
*
|
|
550
588
|
* Use seed state from the block cache if cannot find any seed states within this cache.
|
|
551
589
|
*/
|
|
552
|
-
findSeedStateToReload(reloadedCp:
|
|
590
|
+
findSeedStateToReload(reloadedCp: CheckpointHexPayload): CachedBeaconStateAllForks {
|
|
553
591
|
const maxEpoch = Math.max(...Array.from(this.epochIndex.keys()));
|
|
554
592
|
const reloadedCpSlot = computeStartSlotAtEpoch(reloadedCp.epoch);
|
|
555
593
|
let firstState: CachedBeaconStateAllForks | null = null;
|
|
@@ -562,32 +600,35 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
562
600
|
return firstState;
|
|
563
601
|
}
|
|
564
602
|
|
|
565
|
-
for (const rootHex of this.epochIndex.get(epoch) || []) {
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const {state} = cacheItem;
|
|
574
|
-
if (firstState === null) {
|
|
575
|
-
firstState = state;
|
|
603
|
+
for (const [rootHex, bitmask] of this.epochIndex.get(epoch) || []) {
|
|
604
|
+
for (const flag of PAYLOAD_AVAILABILITY_ALL) {
|
|
605
|
+
if (!(bitmask & flag)) continue;
|
|
606
|
+
const payloadPresent = fromPayloadAvailability(flag);
|
|
607
|
+
const cpKey = toCacheKey({rootHex, epoch, payloadPresent});
|
|
608
|
+
const cacheItem = this.cache.get(cpKey);
|
|
609
|
+
if (cacheItem === undefined) {
|
|
610
|
+
continue;
|
|
576
611
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
612
|
+
if (isInMemoryCacheItem(cacheItem)) {
|
|
613
|
+
const {state} = cacheItem;
|
|
614
|
+
if (firstState === null) {
|
|
615
|
+
firstState = state;
|
|
616
|
+
}
|
|
617
|
+
const cpLog = {cpEpoch: epoch, cpRoot: rootHex, payloadPresent};
|
|
618
|
+
|
|
619
|
+
try {
|
|
620
|
+
// amongst states of the same epoch, choose the one with the same view of reloadedCp
|
|
621
|
+
if (
|
|
622
|
+
reloadedCpSlot < state.slot &&
|
|
623
|
+
toRootHex(getBlockRootAtSlot(state, reloadedCpSlot)) === reloadedCp.rootHex
|
|
624
|
+
) {
|
|
625
|
+
this.logger.verbose("Reload: use checkpoint state as seed state", {...cpLog, ...logCtx});
|
|
626
|
+
return state;
|
|
627
|
+
}
|
|
628
|
+
} catch (e) {
|
|
629
|
+
// getBlockRootAtSlot may throw error
|
|
630
|
+
this.logger.debug("Error finding checkpoint state to reload", {...cpLog, ...logCtx}, e as Error);
|
|
587
631
|
}
|
|
588
|
-
} catch (e) {
|
|
589
|
-
// getBlockRootAtSlot may throw error
|
|
590
|
-
this.logger.debug("Error finding checkpoint state to reload", {...cpLog, ...logCtx}, e as Error);
|
|
591
632
|
}
|
|
592
633
|
}
|
|
593
634
|
}
|
|
@@ -604,6 +645,31 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
604
645
|
this.epochIndex.clear();
|
|
605
646
|
}
|
|
606
647
|
|
|
648
|
+
private addToEpochIndex(epoch: Epoch, rootHex: RootHex, payloadPresent: boolean): void {
|
|
649
|
+
const rootMap = this.epochIndex.getOrDefault(epoch);
|
|
650
|
+
rootMap.set(rootHex, (rootMap.get(rootHex) ?? 0) | toPayloadAvailability(payloadPresent));
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
private removeFromEpochIndex(epoch: Epoch, rootHex: RootHex, payloadPresent: boolean): void {
|
|
654
|
+
const rootMap = this.epochIndex.get(epoch);
|
|
655
|
+
if (rootMap === undefined) return;
|
|
656
|
+
const existing = rootMap.get(rootHex);
|
|
657
|
+
if (existing === undefined) return;
|
|
658
|
+
const updated = existing & ~toPayloadAvailability(payloadPresent);
|
|
659
|
+
if (updated === 0) {
|
|
660
|
+
rootMap.delete(rootHex);
|
|
661
|
+
if (rootMap.size === 0) {
|
|
662
|
+
this.epochIndex.delete(epoch);
|
|
663
|
+
}
|
|
664
|
+
} else {
|
|
665
|
+
rootMap.set(rootHex, updated);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
private hasPayloadVariant(epoch: Epoch, rootHex: RootHex, payloadPresent: boolean): boolean {
|
|
670
|
+
return Boolean((this.epochIndex.get(epoch)?.get(rootHex) ?? 0) & toPayloadAvailability(payloadPresent));
|
|
671
|
+
}
|
|
672
|
+
|
|
607
673
|
/** ONLY FOR DEBUGGING PURPOSES. For lodestar debug API */
|
|
608
674
|
dumpSummary(): routes.lodestar.StateCacheItem[] {
|
|
609
675
|
return Array.from(this.cache.keys()).map((key) => {
|
|
@@ -682,7 +748,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
682
748
|
const prevEpochRoot = toRootHex(getBlockRootAtSlot(state, epochBoundarySlot - 1));
|
|
683
749
|
|
|
684
750
|
// for each epoch, usually there are 2 rootHexes respective to the 2 checkpoint states: Previous Root Checkpoint State and Current Root Checkpoint State
|
|
685
|
-
const
|
|
751
|
+
const cpRootHexMap = this.epochIndex.get(epoch) ?? new Map<RootHex, number>();
|
|
686
752
|
const persistedRootHexes = new Set<RootHex>();
|
|
687
753
|
|
|
688
754
|
// 1) if there is no CRCS, persist PRCS (block 0 of epoch is skipped). In this case prevEpochRoot === epochBoundaryHex
|
|
@@ -691,76 +757,81 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
691
757
|
persistedRootHexes.add(epochBoundaryHex);
|
|
692
758
|
|
|
693
759
|
// 3) persist any states with unknown roots to this state
|
|
694
|
-
for (const rootHex of
|
|
760
|
+
for (const rootHex of cpRootHexMap.keys()) {
|
|
695
761
|
if (rootHex !== epochBoundaryHex && rootHex !== prevEpochRoot) {
|
|
696
762
|
persistedRootHexes.add(rootHex);
|
|
697
763
|
}
|
|
698
764
|
}
|
|
699
765
|
|
|
700
|
-
for (const rootHex of
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
const {state} = cacheItem;
|
|
707
|
-
const logMeta = {
|
|
708
|
-
stateSlot: state.slot,
|
|
709
|
-
rootHex,
|
|
710
|
-
epochBoundaryHex,
|
|
711
|
-
persistedKey: persistedKey ? toHex(persistedKey) : "",
|
|
712
|
-
};
|
|
713
|
-
|
|
714
|
-
if (persistedRootHexes.has(rootHex)) {
|
|
715
|
-
if (persistedKey) {
|
|
716
|
-
// we don't care if the checkpoint state is already persisted
|
|
717
|
-
this.logger.verbose("Pruned checkpoint state from memory but no need to persist", logMeta);
|
|
718
|
-
} else {
|
|
719
|
-
// persist and do not update epochIndex
|
|
720
|
-
this.metrics?.cpStateCache.statePersistSecFromSlot.observe(
|
|
721
|
-
this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0
|
|
722
|
-
);
|
|
723
|
-
const cpPersist = {epoch: epoch, root: fromHex(rootHex)};
|
|
724
|
-
// It's not sustainable to allocate ~240MB for each state every epoch, so we use buffer pool to reuse the memory.
|
|
725
|
-
// As monitored on holesky as of Jan 2024:
|
|
726
|
-
// - This does not increase heap allocation while gc time is the same
|
|
727
|
-
// - It helps stabilize persist time and save ~300ms in average (1.5s vs 1.2s)
|
|
728
|
-
// - It also helps the state reload to save ~500ms in average (4.3s vs 3.8s)
|
|
729
|
-
// - Also `serializeState.test.ts` perf test shows a lot of differences allocating ~240MB once vs per state serialization
|
|
730
|
-
const timer = this.metrics?.stateSerializeDuration.startTimer({
|
|
731
|
-
source: AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE,
|
|
732
|
-
});
|
|
733
|
-
persistedKey = await serializeState(
|
|
734
|
-
state,
|
|
735
|
-
AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE,
|
|
736
|
-
(stateBytes) => {
|
|
737
|
-
timer?.();
|
|
738
|
-
return this.datastore.write(cpPersist, stateBytes);
|
|
739
|
-
},
|
|
740
|
-
this.bufferPool
|
|
741
|
-
);
|
|
766
|
+
for (const [rootHex, bitmask] of cpRootHexMap) {
|
|
767
|
+
for (const flag of PAYLOAD_AVAILABILITY_ALL) {
|
|
768
|
+
if (!(bitmask & flag)) continue;
|
|
769
|
+
const payloadPresent = fromPayloadAvailability(flag);
|
|
770
|
+
const cpKey = toCacheKey({epoch: epoch, rootHex, payloadPresent});
|
|
771
|
+
const cacheItem = this.cache.get(cpKey);
|
|
742
772
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
773
|
+
if (cacheItem !== undefined && isInMemoryCacheItem(cacheItem)) {
|
|
774
|
+
let {persistedKey} = cacheItem;
|
|
775
|
+
const {state} = cacheItem;
|
|
776
|
+
const logMeta = {
|
|
777
|
+
stateSlot: state.slot,
|
|
778
|
+
rootHex,
|
|
779
|
+
payloadPresent,
|
|
780
|
+
epochBoundaryHex,
|
|
781
|
+
persistedKey: persistedKey ? toHex(persistedKey) : "",
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
if (persistedRootHexes.has(rootHex)) {
|
|
785
|
+
if (persistedKey) {
|
|
786
|
+
// we don't care if the checkpoint state is already persisted
|
|
787
|
+
this.logger.verbose("Pruned checkpoint state from memory but no need to persist", logMeta);
|
|
788
|
+
} else {
|
|
789
|
+
// persist and do not update epochIndex
|
|
790
|
+
this.metrics?.cpStateCache.statePersistSecFromSlot.observe(
|
|
791
|
+
this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0
|
|
792
|
+
);
|
|
793
|
+
const cpPersist = {epoch: epoch, root: fromHex(rootHex)};
|
|
794
|
+
// It's not sustainable to allocate ~240MB for each state every epoch, so we use buffer pool to reuse the memory.
|
|
795
|
+
// As monitored on holesky as of Jan 2024:
|
|
796
|
+
// - This does not increase heap allocation while gc time is the same
|
|
797
|
+
// - It helps stabilize persist time and save ~300ms in average (1.5s vs 1.2s)
|
|
798
|
+
// - It also helps the state reload to save ~500ms in average (4.3s vs 3.8s)
|
|
799
|
+
// - Also `serializeState.test.ts` perf test shows a lot of differences allocating ~240MB once vs per state serialization
|
|
800
|
+
const timer = this.metrics?.stateSerializeDuration.startTimer({
|
|
801
|
+
source: AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE,
|
|
802
|
+
});
|
|
803
|
+
persistedKey = await serializeState(
|
|
804
|
+
state,
|
|
805
|
+
AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE,
|
|
806
|
+
(stateBytes) => {
|
|
807
|
+
timer?.();
|
|
808
|
+
return this.datastore.write(cpPersist, stateBytes, payloadPresent);
|
|
809
|
+
},
|
|
810
|
+
this.bufferPool
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
persistCount++;
|
|
814
|
+
this.logger.verbose("Pruned checkpoint state from memory and persisted to disk", {
|
|
815
|
+
...logMeta,
|
|
816
|
+
persistedKey: toHex(persistedKey),
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
// overwrite cpKey, this means the state is deleted from memory
|
|
755
820
|
this.cache.set(cpKey, {type: CacheItemType.persisted, value: persistedKey});
|
|
756
|
-
// do not update epochIndex
|
|
757
821
|
} else {
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
822
|
+
if (persistedKey) {
|
|
823
|
+
// persisted file will be eventually deleted by the archive task
|
|
824
|
+
// this also means the state is deleted from memory
|
|
825
|
+
this.cache.set(cpKey, {type: CacheItemType.persisted, value: persistedKey});
|
|
826
|
+
// do not update epochIndex
|
|
827
|
+
} else {
|
|
828
|
+
// delete the state from memory
|
|
829
|
+
this.cache.delete(cpKey);
|
|
830
|
+
this.removeFromEpochIndex(epoch, rootHex, payloadPresent);
|
|
831
|
+
}
|
|
832
|
+
this.metrics?.cpStateCache.statePruneFromMemoryCount.inc();
|
|
833
|
+
this.logger.verbose("Pruned checkpoint state from memory", logMeta);
|
|
761
834
|
}
|
|
762
|
-
this.metrics?.cpStateCache.statePruneFromMemoryCount.inc();
|
|
763
|
-
this.logger.verbose("Pruned checkpoint state from memory", logMeta);
|
|
764
835
|
}
|
|
765
836
|
}
|
|
766
837
|
}
|
|
@@ -773,26 +844,40 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
773
844
|
*/
|
|
774
845
|
private async deleteAllEpochItems(epoch: Epoch): Promise<void> {
|
|
775
846
|
let persistCount = 0;
|
|
776
|
-
const
|
|
777
|
-
for (const rootHex of
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
847
|
+
const rootHexMap = this.epochIndex.get(epoch) || new Map<RootHex, number>();
|
|
848
|
+
for (const [rootHex, bitmask] of rootHexMap) {
|
|
849
|
+
for (const flag of PAYLOAD_AVAILABILITY_ALL) {
|
|
850
|
+
if (!(bitmask & flag)) continue;
|
|
851
|
+
const payloadPresent = fromPayloadAvailability(flag);
|
|
852
|
+
const key = toCacheKey({rootHex, epoch, payloadPresent});
|
|
853
|
+
const cacheItem = this.cache.get(key);
|
|
854
|
+
|
|
855
|
+
if (cacheItem) {
|
|
856
|
+
const persistedKey = isPersistedCacheItem(cacheItem) ? cacheItem.value : cacheItem.persistedKey;
|
|
857
|
+
if (persistedKey) {
|
|
858
|
+
await this.datastore.remove(persistedKey);
|
|
859
|
+
persistCount++;
|
|
860
|
+
this.metrics?.cpStateCache.persistedStateRemoveCount.inc();
|
|
861
|
+
}
|
|
787
862
|
}
|
|
863
|
+
this.cache.delete(key);
|
|
864
|
+
this.logger.verbose("Pruned checkpoint state", {
|
|
865
|
+
epoch,
|
|
866
|
+
rootHex,
|
|
867
|
+
payloadPresent,
|
|
868
|
+
type: cacheItem ? (isPersistedCacheItem(cacheItem) ? "persisted" : "in-memory") : "missing",
|
|
869
|
+
});
|
|
788
870
|
}
|
|
789
|
-
this.cache.delete(key);
|
|
790
871
|
}
|
|
791
872
|
this.epochIndex.delete(epoch);
|
|
792
|
-
this.logger.verbose("Pruned checkpoint states for epoch", {
|
|
873
|
+
this.logger.verbose("Pruned all checkpoint states for epoch", {
|
|
793
874
|
epoch,
|
|
794
875
|
persistCount,
|
|
795
|
-
|
|
876
|
+
items: Array.from(rootHexMap.entries())
|
|
877
|
+
.flatMap(([rootHex, bitmask]) =>
|
|
878
|
+
PAYLOAD_AVAILABILITY_ALL.filter((f) => bitmask & f).map((f) => `${rootHex}:${fromPayloadAvailability(f)}`)
|
|
879
|
+
)
|
|
880
|
+
.join(","),
|
|
796
881
|
});
|
|
797
882
|
}
|
|
798
883
|
|
|
@@ -844,29 +929,57 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
844
929
|
}
|
|
845
930
|
}
|
|
846
931
|
|
|
847
|
-
export function
|
|
932
|
+
export function toCheckpointHexPayload(checkpoint: phase0.Checkpoint, payloadPresent: boolean): CheckpointHexPayload {
|
|
848
933
|
return {
|
|
849
934
|
epoch: checkpoint.epoch,
|
|
850
935
|
rootHex: toRootHex(checkpoint.root),
|
|
936
|
+
payloadPresent,
|
|
851
937
|
};
|
|
852
938
|
}
|
|
853
939
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
940
|
+
/**
|
|
941
|
+
* Convert fork-choice CheckpointWithPayloadStatus to beacon-node CheckpointHexPayload.
|
|
942
|
+
* Maps PayloadStatus enum to boolean payloadPresent.
|
|
943
|
+
* @throws Error if checkpoint has PENDING payload status (ambiguous which variant to use)
|
|
944
|
+
*/
|
|
945
|
+
export function fcCheckpointToHexPayload(checkpoint: CheckpointWithPayloadStatus): CheckpointHexPayload {
|
|
946
|
+
const PayloadStatus = {PENDING: 0, EMPTY: 1, FULL: 2} as const;
|
|
857
947
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
948
|
+
if (checkpoint.payloadStatus === PayloadStatus.PENDING) {
|
|
949
|
+
throw Error(
|
|
950
|
+
`Cannot convert checkpoint with PENDING payload status at epoch ${checkpoint.epoch} root ${checkpoint.rootHex}`
|
|
951
|
+
);
|
|
861
952
|
}
|
|
862
|
-
|
|
953
|
+
|
|
954
|
+
return {
|
|
955
|
+
epoch: checkpoint.epoch,
|
|
956
|
+
rootHex: checkpoint.rootHex,
|
|
957
|
+
payloadPresent: checkpoint.payloadStatus === PayloadStatus.FULL,
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
export function toCheckpointKey(cp: CheckpointHexPayload): string {
|
|
962
|
+
return `${cp.rootHex}:${cp.epoch}:${cp.payloadPresent}`;
|
|
863
963
|
}
|
|
864
964
|
|
|
865
|
-
|
|
866
|
-
|
|
965
|
+
/**
|
|
966
|
+
* Convert checkpoint to cache key string.
|
|
967
|
+
* Format: `{rootHex}_{epoch}_{payloadPresent}`
|
|
968
|
+
*/
|
|
969
|
+
function toCacheKey(cp: CheckpointHexPayload): CacheKey {
|
|
970
|
+
return `${cp.rootHex}_${cp.epoch}_${cp.payloadPresent}`;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
function fromCacheKey(key: CacheKey): CheckpointHexPayload {
|
|
974
|
+
const parts = key.split("_");
|
|
975
|
+
const rootHex = parts[0];
|
|
976
|
+
const epoch = Number(parts[1]);
|
|
977
|
+
// For backward compatibility with old format (rootHex_epoch), default to true
|
|
978
|
+
const payloadPresent = parts.length > 2 ? parts[2] === "true" : true;
|
|
867
979
|
return {
|
|
868
980
|
rootHex,
|
|
869
|
-
epoch
|
|
981
|
+
epoch,
|
|
982
|
+
payloadPresent,
|
|
870
983
|
};
|
|
871
984
|
}
|
|
872
985
|
|
|
@@ -883,7 +996,3 @@ function isInMemoryCacheItem(cacheItem: CacheItem): cacheItem is InMemoryCacheIt
|
|
|
883
996
|
function isPersistedCacheItem(cacheItem: CacheItem): cacheItem is PersistedCacheItem {
|
|
884
997
|
return cacheItem.type === CacheItemType.persisted;
|
|
885
998
|
}
|
|
886
|
-
|
|
887
|
-
function isCheckpointHex(cp: CheckpointHex | phase0.Checkpoint): cp is CheckpointHex {
|
|
888
|
-
return (cp as CheckpointHex).rootHex !== undefined;
|
|
889
|
-
}
|
|
@@ -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>;
|
|
@@ -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,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { CheckpointWithHex } from "@lodestar/fork-choice";
|
|
2
|
-
import { IBeaconChain } from "../../interface.js";
|
|
3
|
-
/**
|
|
4
|
-
* Archives execution payload envelopes from hot DB to archive DB after finalization.
|
|
5
|
-
*/
|
|
6
|
-
export declare function archiveExecutionPayloadEnvelopes(chain: IBeaconChain, _finalized: CheckpointWithHex): Promise<void>;
|
|
7
|
-
//# sourceMappingURL=archivePayloads.d.ts.map
|