@lodestar/beacon-node 1.41.0 → 1.42.0-dev.1d50253953
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 +35 -16
- 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/blockInput/types.d.ts +3 -3
- package/lib/chain/blocks/blockInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +29 -9
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +48 -0
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -0
- package/lib/chain/blocks/importExecutionPayload.js +159 -0
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeInput/index.d.ts +3 -0
- package/lib/chain/blocks/payloadEnvelopeInput/index.d.ts.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeInput/index.js +3 -0
- package/lib/chain/blocks/payloadEnvelopeInput/index.js.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +80 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +248 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +29 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.js +11 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +15 -0
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -0
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +46 -0
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -0
- package/lib/chain/blocks/types.d.ts +7 -0
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +12 -0
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -0
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +40 -0
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -0
- package/lib/chain/chain.d.ts +10 -5
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +44 -10
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +12 -2
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +3 -1
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +0 -10
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +8 -5
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +1 -1
- package/lib/chain/opPools/utils.js.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/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +6 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +1 -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 +14 -6
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +2 -0
- package/lib/chain/regen/interface.js.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/seenCache/index.d.ts +1 -1
- package/lib/chain/seenCache/index.d.ts.map +1 -1
- package/lib/chain/seenCache/index.js +1 -1
- package/lib/chain/seenCache/index.js.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js +2 -2
- package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +38 -0
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -0
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +76 -0
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -0
- 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/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +30 -19
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/lightClientFinalityUpdate.js +1 -1
- package/lib/chain/validation/lightClientFinalityUpdate.js.map +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.js +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.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/chain/validatorMonitor.d.ts +2 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +4 -1
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +2 -2
- package/lib/metrics/metrics/lodestar.d.ts +28 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +74 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/network.js +2 -2
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/extractSlotRootFns.d.ts.map +1 -1
- package/lib/network/processor/extractSlotRootFns.js +14 -4
- package/lib/network/processor/extractSlotRootFns.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +31 -3
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.d.ts +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
- package/lib/sync/backfill/backfill.d.ts +1 -1
- package/lib/sync/backfill/backfill.js +1 -1
- package/lib/sync/constants.d.ts +1 -1
- package/lib/sync/constants.js +1 -1
- package/lib/util/sszBytes.d.ts +4 -1
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +69 -12
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +36 -17
- 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/blockInput/types.ts +3 -3
- package/src/chain/blocks/importBlock.ts +47 -8
- package/src/chain/blocks/importExecutionPayload.ts +241 -0
- package/src/chain/blocks/payloadEnvelopeInput/index.ts +2 -0
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +336 -0
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +33 -0
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +61 -0
- package/src/chain/blocks/types.ts +8 -0
- package/src/chain/blocks/verifyBlocksSignatures.ts +1 -1
- package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +55 -0
- package/src/chain/chain.ts +60 -15
- package/src/chain/errors/executionPayloadEnvelope.ts +6 -2
- package/src/chain/forkChoice/index.ts +0 -10
- package/src/chain/interface.ts +8 -5
- package/src/chain/opPools/utils.ts +1 -1
- package/src/chain/prepareNextSlot.ts +6 -2
- package/src/chain/produceBlock/computeNewStateRoot.ts +6 -1
- package/src/chain/produceBlock/produceBlockBody.ts +1 -1
- package/src/chain/regen/errors.ts +6 -1
- package/src/chain/regen/interface.ts +14 -6
- package/src/chain/regen/queued.ts +48 -12
- package/src/chain/regen/regen.ts +37 -7
- package/src/chain/seenCache/index.ts +1 -1
- package/src/chain/seenCache/seenGossipBlockInput.ts +2 -2
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +106 -0
- 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/executionPayloadEnvelope.ts +38 -25
- package/src/chain/validation/lightClientFinalityUpdate.ts +1 -1
- package/src/chain/validation/lightClientOptimisticUpdate.ts +1 -1
- package/src/chain/validation/voluntaryExit.ts +2 -1
- package/src/chain/validatorMonitor.ts +11 -1
- package/src/execution/engine/interface.ts +2 -2
- package/src/metrics/metrics/lodestar.ts +77 -0
- package/src/network/network.ts +2 -2
- package/src/network/processor/extractSlotRootFns.ts +18 -5
- package/src/network/processor/gossipHandlers.ts +37 -1
- package/src/network/reqresp/ReqRespBeaconNode.ts +1 -1
- package/src/sync/backfill/backfill.ts +1 -1
- package/src/sync/constants.ts +1 -1
- package/src/util/sszBytes.ts +90 -10
- 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/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts +0 -15
- package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts.map +0 -1
- package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js +0 -28
- package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js.map +0 -1
- package/src/chain/archiveStore/utils/archivePayloads.ts +0 -15
- package/src/chain/seenCache/seenExecutionPayloadEnvelope.ts +0 -34
package/src/chain/regen/regen.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
3
|
-
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {IForkChoice, PayloadStatus, ProtoBlock} from "@lodestar/fork-choice";
|
|
3
|
+
import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
4
4
|
import {
|
|
5
5
|
CachedBeaconStateAllForks,
|
|
6
6
|
DataAvailabilityStatus,
|
|
@@ -111,9 +111,20 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
111
111
|
const {blockRoot} = block;
|
|
112
112
|
const {checkpointStateCache} = this.modules;
|
|
113
113
|
const epoch = computeEpochAtSlot(slot);
|
|
114
|
+
|
|
115
|
+
// Convert PayloadStatus to payloadPresent boolean
|
|
116
|
+
if (block.payloadStatus === PayloadStatus.PENDING) {
|
|
117
|
+
throw new RegenError({
|
|
118
|
+
code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS,
|
|
119
|
+
blockRoot: fromHex(blockRoot),
|
|
120
|
+
payloadStatus: block.payloadStatus,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const payloadPresent = block.payloadStatus === PayloadStatus.FULL;
|
|
124
|
+
|
|
114
125
|
const latestCheckpointStateCtx = allowDiskReload
|
|
115
|
-
? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch)
|
|
116
|
-
: checkpointStateCache.getLatest(blockRoot, epoch);
|
|
126
|
+
? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch, payloadPresent)
|
|
127
|
+
: checkpointStateCache.getLatest(blockRoot, epoch, payloadPresent);
|
|
117
128
|
|
|
118
129
|
// If a checkpoint state exists with the given checkpoint root, it either is in requested epoch
|
|
119
130
|
// or needs to have empty slots processed until the requested epoch
|
|
@@ -166,9 +177,19 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
166
177
|
const lastBlockToReplay = blocksToReplay.at(-1);
|
|
167
178
|
if (!lastBlockToReplay) continue;
|
|
168
179
|
const epoch = computeEpochAtSlot(lastBlockToReplay.slot - 1);
|
|
180
|
+
|
|
181
|
+
// Convert PayloadStatus to payloadPresent boolean
|
|
182
|
+
if (b.payloadStatus === PayloadStatus.PENDING) {
|
|
183
|
+
throw new RegenError({
|
|
184
|
+
code: RegenErrorCode.INTERNAL_ERROR,
|
|
185
|
+
message: `Unexpected PENDING payloadStatus for ancestor block ${b.blockRoot} at slot ${b.slot}`,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
const payloadPresent = b.payloadStatus === PayloadStatus.FULL;
|
|
189
|
+
|
|
169
190
|
state = allowDiskReload
|
|
170
|
-
? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch)
|
|
171
|
-
: checkpointStateCache.getLatest(b.blockRoot, epoch);
|
|
191
|
+
? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch, payloadPresent)
|
|
192
|
+
: checkpointStateCache.getLatest(b.blockRoot, epoch, payloadPresent);
|
|
172
193
|
if (state) {
|
|
173
194
|
break;
|
|
174
195
|
}
|
|
@@ -332,6 +353,11 @@ async function processSlotsByCheckpoint(
|
|
|
332
353
|
* emitting "checkpoint" events after every epoch processed.
|
|
333
354
|
*
|
|
334
355
|
* Stops processing after no more full epochs can be processed.
|
|
356
|
+
*
|
|
357
|
+
* Output state variant:
|
|
358
|
+
* - Post-Gloas: If slots are processed, returns block state (payloadPresent=false).
|
|
359
|
+
* If no slots processed, returns preState as-is (preserves variant).
|
|
360
|
+
* - Pre-Gloas: Always payloadPresent=true (no block/payload distinction).
|
|
335
361
|
*/
|
|
336
362
|
export async function processSlotsToNearestCheckpoint(
|
|
337
363
|
modules: {
|
|
@@ -374,7 +400,11 @@ export async function processSlotsToNearestCheckpoint(
|
|
|
374
400
|
// This may becomes the "official" checkpoint state if the 1st block of epoch is skipped
|
|
375
401
|
const checkpointState = postState;
|
|
376
402
|
const cp = getCheckpointFromState(checkpointState);
|
|
377
|
-
|
|
403
|
+
// processSlots() only does epoch transitions, never processes payloads
|
|
404
|
+
// Pre-Gloas: payloadPresent is always true (execution payload embedded in block)
|
|
405
|
+
// Post-Gloas: result is a block state (payloadPresent=false)
|
|
406
|
+
const isPayloadPresent = checkpointState.config.getForkSeq(checkpointState.slot) < ForkSeq.gloas;
|
|
407
|
+
checkpointStateCache.add(cp, checkpointState, isPayloadPresent);
|
|
378
408
|
// consumers should not mutate state ever
|
|
379
409
|
emitter?.emit(ChainEvent.checkpoint, cp, checkpointState);
|
|
380
410
|
|
|
@@ -3,5 +3,5 @@ export {SeenBlockProposers} from "./seenBlockProposers.js";
|
|
|
3
3
|
export {SeenSyncCommitteeMessages} from "./seenCommittee.js";
|
|
4
4
|
export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
|
|
5
5
|
export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
|
|
6
|
-
export {SeenExecutionPayloadEnvelopes} from "./seenExecutionPayloadEnvelope.js";
|
|
7
6
|
export {SeenBlockInput} from "./seenGossipBlockInput.js";
|
|
7
|
+
export {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenPayloadEnvelopeInput.js";
|
|
@@ -180,7 +180,7 @@ export class SeenBlockInput {
|
|
|
180
180
|
blockInput = this.blockInputs.get(parentRootHex ?? "");
|
|
181
181
|
parentRootHex = blockInput?.parentRootHex;
|
|
182
182
|
}
|
|
183
|
-
this.logger?.debug(
|
|
183
|
+
this.logger?.debug("BlockInputCache.prune deleted cached BlockInputs", {deletedCount});
|
|
184
184
|
this.pruneToMaxSize();
|
|
185
185
|
}
|
|
186
186
|
|
|
@@ -193,7 +193,7 @@ export class SeenBlockInput {
|
|
|
193
193
|
this.evictBlockInput(blockInput);
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
this.logger?.debug(
|
|
196
|
+
this.logger?.debug("BlockInputCache.onFinalized deleted cached BlockInputs", {deletedCount});
|
|
197
197
|
this.pruneToMaxSize();
|
|
198
198
|
};
|
|
199
199
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
2
|
+
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
3
|
+
import {RootHex} from "@lodestar/types";
|
|
4
|
+
import {Logger} from "@lodestar/utils";
|
|
5
|
+
import {Metrics} from "../../metrics/metrics.js";
|
|
6
|
+
import {SerializedCache} from "../../util/serializedCache.js";
|
|
7
|
+
import {CreateFromBlockProps, PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
|
|
8
|
+
import {ChainEvent, ChainEventEmitter} from "../emitter.js";
|
|
9
|
+
|
|
10
|
+
export type {PayloadEnvelopeInputState} from "../blocks/payloadEnvelopeInput/index.js";
|
|
11
|
+
export {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
|
|
12
|
+
|
|
13
|
+
export type SeenPayloadEnvelopeInputModules = {
|
|
14
|
+
chainEvents: ChainEventEmitter;
|
|
15
|
+
signal: AbortSignal;
|
|
16
|
+
serializedCache: SerializedCache;
|
|
17
|
+
metrics: Metrics | null;
|
|
18
|
+
logger?: Logger;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Cache for tracking PayloadEnvelopeInput instances, keyed by beacon block root.
|
|
23
|
+
*
|
|
24
|
+
* Created during block import when a block is processed.
|
|
25
|
+
* Pruned on finalization and after payload is written to DB.
|
|
26
|
+
*/
|
|
27
|
+
export class SeenPayloadEnvelopeInput {
|
|
28
|
+
private readonly chainEvents: ChainEventEmitter;
|
|
29
|
+
private readonly signal: AbortSignal;
|
|
30
|
+
private readonly serializedCache: SerializedCache;
|
|
31
|
+
private readonly metrics: Metrics | null;
|
|
32
|
+
private readonly logger?: Logger;
|
|
33
|
+
private payloadInputs = new Map<RootHex, PayloadEnvelopeInput>();
|
|
34
|
+
|
|
35
|
+
constructor({chainEvents, signal, serializedCache, metrics, logger}: SeenPayloadEnvelopeInputModules) {
|
|
36
|
+
this.chainEvents = chainEvents;
|
|
37
|
+
this.signal = signal;
|
|
38
|
+
this.serializedCache = serializedCache;
|
|
39
|
+
this.metrics = metrics;
|
|
40
|
+
this.logger = logger;
|
|
41
|
+
|
|
42
|
+
if (metrics) {
|
|
43
|
+
metrics.seenCache.payloadEnvelopeInput.count.addCollect(() => {
|
|
44
|
+
metrics.seenCache.payloadEnvelopeInput.count.set(this.payloadInputs.size);
|
|
45
|
+
metrics.seenCache.payloadEnvelopeInput.serializedObjectRefs.set(
|
|
46
|
+
Array.from(this.payloadInputs.values()).reduce(
|
|
47
|
+
(count, payloadInput) => count + payloadInput.getSerializedCacheKeys().length,
|
|
48
|
+
0
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.chainEvents.on(ChainEvent.forkChoiceFinalized, this.onFinalized);
|
|
55
|
+
this.signal.addEventListener("abort", () => {
|
|
56
|
+
this.chainEvents.off(ChainEvent.forkChoiceFinalized, this.onFinalized);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private onFinalized = (checkpoint: CheckpointWithHex): void => {
|
|
61
|
+
// Prune all entries with slot < finalized slot
|
|
62
|
+
const finalizedSlot = computeStartSlotAtEpoch(checkpoint.epoch);
|
|
63
|
+
let deletedCount = 0;
|
|
64
|
+
for (const [, input] of this.payloadInputs) {
|
|
65
|
+
if (input.slot < finalizedSlot) {
|
|
66
|
+
this.evictPayloadInput(input);
|
|
67
|
+
deletedCount++;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
this.logger?.debug("SeenPayloadEnvelopeInput.onFinalized deleted cached entries", {deletedCount});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
add(props: CreateFromBlockProps): PayloadEnvelopeInput {
|
|
74
|
+
if (this.payloadInputs.has(props.blockRootHex)) {
|
|
75
|
+
throw new Error(`PayloadEnvelopeInput already exists for block ${props.blockRootHex}`);
|
|
76
|
+
}
|
|
77
|
+
const input = PayloadEnvelopeInput.createFromBlock(props);
|
|
78
|
+
this.payloadInputs.set(props.blockRootHex, input);
|
|
79
|
+
this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
|
|
80
|
+
return input;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get(blockRootHex: RootHex): PayloadEnvelopeInput | undefined {
|
|
84
|
+
return this.payloadInputs.get(blockRootHex);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
has(blockRootHex: RootHex): boolean {
|
|
88
|
+
return this.payloadInputs.has(blockRootHex);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
prune(blockRootHex: RootHex): void {
|
|
92
|
+
const payloadInput = this.payloadInputs.get(blockRootHex);
|
|
93
|
+
if (payloadInput) {
|
|
94
|
+
this.evictPayloadInput(payloadInput);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
size(): number {
|
|
99
|
+
return this.payloadInputs.size;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
|
|
103
|
+
this.serializedCache.delete(payloadInput.getSerializedCacheKeys());
|
|
104
|
+
this.payloadInputs.delete(payloadInput.blockRootHex);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
2
|
import {Epoch, phase0, ssz} from "@lodestar/types";
|
|
3
|
-
import {MapDef} from "@lodestar/utils";
|
|
3
|
+
import {MapDef, byteArrayEquals} from "@lodestar/utils";
|
|
4
4
|
import {IBeaconDb} from "../../../db/interface.js";
|
|
5
5
|
import {
|
|
6
6
|
getLastProcessedSlotFromBeaconStateSerialized,
|
|
@@ -14,8 +14,8 @@ import {CPStateDatastore, DatastoreKey} from "./types.js";
|
|
|
14
14
|
export class DbCPStateDatastore implements CPStateDatastore {
|
|
15
15
|
constructor(private readonly db: IBeaconDb) {}
|
|
16
16
|
|
|
17
|
-
async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise<DatastoreKey> {
|
|
18
|
-
const serializedCheckpoint = checkpointToDatastoreKey(cpKey);
|
|
17
|
+
async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array, payloadPresent: boolean): Promise<DatastoreKey> {
|
|
18
|
+
const serializedCheckpoint = checkpointToDatastoreKey(cpKey, payloadPresent);
|
|
19
19
|
await this.db.checkpointState.putBinary(serializedCheckpoint, stateBytes);
|
|
20
20
|
return serializedCheckpoint;
|
|
21
21
|
}
|
|
@@ -40,18 +40,30 @@ export class DbCPStateDatastore implements CPStateDatastore {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function extractCheckpointBytes(key: DatastoreKey): Uint8Array {
|
|
44
|
+
const fixedSize = ssz.phase0.Checkpoint.minSize;
|
|
45
|
+
return key.subarray(0, fixedSize);
|
|
46
|
+
}
|
|
47
|
+
|
|
43
48
|
export function datastoreKeyToCheckpoint(key: DatastoreKey): phase0.Checkpoint {
|
|
44
|
-
return ssz.phase0.Checkpoint.deserialize(key);
|
|
49
|
+
return ssz.phase0.Checkpoint.deserialize(extractCheckpointBytes(key));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function checkpointToDatastoreKey(cp: phase0.Checkpoint, payloadPresent: boolean): DatastoreKey {
|
|
53
|
+
const cpBytes = ssz.phase0.Checkpoint.serialize(cp);
|
|
54
|
+
const key = new Uint8Array(cpBytes.length + 1);
|
|
55
|
+
key.set(cpBytes);
|
|
56
|
+
key[cpBytes.length] = payloadPresent ? 1 : 0;
|
|
57
|
+
return key;
|
|
45
58
|
}
|
|
46
59
|
|
|
47
|
-
|
|
48
|
-
return
|
|
60
|
+
function isPayloadCheckpointState(key: DatastoreKey): boolean {
|
|
61
|
+
return key.at(-1) === 1;
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
/**
|
|
52
|
-
* Get the latest safe checkpoint state the node can use to boot from
|
|
53
|
-
* -
|
|
54
|
-
* - its last processed block slot should be at epoch boundary or last slot of previous epoch
|
|
65
|
+
* Get the latest "safe" checkpoint state the node can use to boot from
|
|
66
|
+
* - its last processed block slot should be at epoch boundary (CRCS) or last slot of previous epoch (PRCS)
|
|
55
67
|
* - state slot should be at epoch boundary
|
|
56
68
|
* - state slot should be equal to epoch * SLOTS_PER_EPOCH
|
|
57
69
|
*
|
|
@@ -70,9 +82,20 @@ export async function getLatestSafeDatastoreKey(
|
|
|
70
82
|
|
|
71
83
|
const dataStoreKeyByEpoch: Map<Epoch, DatastoreKey> = new Map();
|
|
72
84
|
for (const [epoch, keys] of checkpointsByEpoch.entries()) {
|
|
73
|
-
// only consider epochs with a single checkpoint to avoid ambiguity from forks
|
|
74
85
|
if (keys.length === 1) {
|
|
86
|
+
// PRCS (skipped slot) or CRCS and no payloadPresent
|
|
87
|
+
// Pre-gloas always fall into this case
|
|
75
88
|
dataStoreKeyByEpoch.set(epoch, keys[0]);
|
|
89
|
+
} else if (keys.length === 2) {
|
|
90
|
+
// CRCS without payload and CRCS with payload
|
|
91
|
+
// ie Two keys for the same checkpoint with different payloadPresent suffix (FULL/EMPTY)
|
|
92
|
+
// TODO GLOAS: Here we pick FULL key, there is a chance that payload is orphaned hence we not be able to sync
|
|
93
|
+
const cp0 = extractCheckpointBytes(keys[0]);
|
|
94
|
+
const cp1 = extractCheckpointBytes(keys[1]);
|
|
95
|
+
if (byteArrayEquals(cp0, cp1)) {
|
|
96
|
+
const fullKey = isPayloadCheckpointState(keys[0]) ? keys[0] : keys[1];
|
|
97
|
+
dataStoreKeyByEpoch.set(epoch, fullKey);
|
|
98
|
+
}
|
|
76
99
|
}
|
|
77
100
|
}
|
|
78
101
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {phase0
|
|
2
|
+
import {phase0} from "@lodestar/types";
|
|
3
3
|
import {fromHex, toHex} from "@lodestar/utils";
|
|
4
4
|
import {ensureDir, readFile, readFileNames, removeFile, writeIfNotExist} from "../../../util/file.js";
|
|
5
|
-
import {getLatestSafeDatastoreKey} from "./db.js";
|
|
5
|
+
import {checkpointToDatastoreKey, getLatestSafeDatastoreKey} from "./db.js";
|
|
6
6
|
import {CPStateDatastore, DatastoreKey} from "./types.js";
|
|
7
7
|
|
|
8
8
|
const CHECKPOINT_STATES_FOLDER = "checkpoint_states";
|
|
9
|
-
|
|
9
|
+
/** 41 bytes (40 checkpoint + 1 payloadPresent) = 82 hex chars + "0x" prefix = 84 */
|
|
10
|
+
const CHECKPOINT_FILE_NAME_LENGTH = 84;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Implementation of CPStateDatastore using file system, this is beneficial for debugging.
|
|
@@ -28,8 +29,8 @@ export class FileCPStateDatastore implements CPStateDatastore {
|
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise<DatastoreKey> {
|
|
32
|
-
const serializedCheckpoint =
|
|
32
|
+
async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array, payloadPresent: boolean): Promise<DatastoreKey> {
|
|
33
|
+
const serializedCheckpoint = checkpointToDatastoreKey(cpKey, payloadPresent);
|
|
33
34
|
const filePath = path.join(this.folderPath, toHex(serializedCheckpoint));
|
|
34
35
|
await writeIfNotExist(filePath, stateBytes);
|
|
35
36
|
return serializedCheckpoint;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {phase0} from "@lodestar/types";
|
|
2
2
|
|
|
3
|
-
// With db implementation, persistedKey is serialized data of a checkpoint
|
|
3
|
+
// With db implementation, persistedKey is serialized data of a checkpoint + 1
|
|
4
|
+
// ie a fixed size of `ssz.phase0.Checkpoint.minSize + 1`
|
|
4
5
|
export type DatastoreKey = Uint8Array;
|
|
5
6
|
|
|
6
7
|
// Make this generic to support testing
|
|
7
8
|
export interface CPStateDatastore {
|
|
8
|
-
write: (cpKey: phase0.Checkpoint, stateBytes: Uint8Array) => Promise<DatastoreKey>;
|
|
9
|
+
write: (cpKey: phase0.Checkpoint, stateBytes: Uint8Array, payloadPresent: boolean) => Promise<DatastoreKey>;
|
|
9
10
|
remove: (key: DatastoreKey) => Promise<void>;
|
|
10
11
|
read: (key: DatastoreKey) => Promise<Uint8Array | null>;
|
|
11
12
|
readLatestSafe: () => Promise<Uint8Array | null>;
|
|
@@ -20,6 +20,11 @@ export type FIFOBlockStateCacheOpts = {
|
|
|
20
20
|
* clock slot
|
|
21
21
|
*/
|
|
22
22
|
export const DEFAULT_MAX_BLOCK_STATES = 64;
|
|
23
|
+
/**
|
|
24
|
+
* For Gloas (ePBS), each block can have two states: block state and payload state.
|
|
25
|
+
* Double the cache size to maintain the same effective block depth.
|
|
26
|
+
*/
|
|
27
|
+
export const DEFAULT_MAX_BLOCK_STATES_GLOAS = 128;
|
|
23
28
|
|
|
24
29
|
/**
|
|
25
30
|
* New implementation of BlockStateCache that keeps the most recent n states consistently
|
|
@@ -41,10 +46,7 @@ export const DEFAULT_MAX_BLOCK_STATES = 64;
|
|
|
41
46
|
* The maintained key order would be: 11 -> 13 -> 12 -> 10, and state 10 will be pruned first.
|
|
42
47
|
*/
|
|
43
48
|
export class FIFOBlockStateCache implements BlockStateCache {
|
|
44
|
-
|
|
45
|
-
* Max number of states allowed in the cache
|
|
46
|
-
*/
|
|
47
|
-
readonly maxStates: number;
|
|
49
|
+
private maxStates: number;
|
|
48
50
|
|
|
49
51
|
private readonly cache: MapTracker<string, CachedBeaconStateAllForks>;
|
|
50
52
|
/**
|
|
@@ -170,6 +172,10 @@ export class FIFOBlockStateCache implements BlockStateCache {
|
|
|
170
172
|
}
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
upgradeToGloas(): void {
|
|
176
|
+
this.maxStates = DEFAULT_MAX_BLOCK_STATES_GLOAS;
|
|
177
|
+
}
|
|
178
|
+
|
|
173
179
|
/**
|
|
174
180
|
* No need for this implementation
|
|
175
181
|
* This is only to conform to the old api
|