@lodestar/beacon-node 1.39.0-dev.2fe8de2346 → 1.39.0-dev.375b1b3da7
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/README.md +1 -1
- 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/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/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 +9 -2
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +4 -2
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +3 -2
- package/lib/chain/blocks/verifyBlocksSignatures.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 +11 -11
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +36 -40
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +3 -3
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +6 -9
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.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 +8 -12
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +13 -142
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/opPool.d.ts +3 -0
- package/lib/chain/opPools/opPool.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.js +14 -16
- 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 +4 -4
- 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 +9 -7
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +21 -19
- 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/aggregateAndProof.js +9 -0
- package/lib/chain/validation/aggregateAndProof.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 +2 -2
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
- package/lib/chain/validation/blobSidecar.js +2 -3
- package/lib/chain/validation/blobSidecar.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +5 -3
- 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 +10 -3
- package/lib/chain/validation/blsToExecutionChange.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +2 -3
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +3 -2
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.js +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
- package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -1
- package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/contributionAndProof.js +2 -2
- package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -1
- package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommittee.js +2 -2
- package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts +2 -1
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.js +2 -2
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -1
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +1 -2
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
- package/lib/chain/validation/syncCommittee.js +1 -1
- package/lib/chain/validation/syncCommittee.js.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js +3 -3
- package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +1 -1
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/db/beacon.d.ts +2 -0
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +32 -0
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/buckets.d.ts +12 -0
- package/lib/db/buckets.d.ts.map +1 -1
- package/lib/db/buckets.js +12 -6
- package/lib/db/buckets.js.map +1 -1
- package/lib/db/interface.d.ts +1 -0
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
- package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
- package/lib/db/repositories/stateArchive.d.ts +1 -1
- package/lib/db/repositories/stateArchive.d.ts.map +1 -1
- package/lib/db/repositories/stateArchive.js +2 -2
- 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/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/peers/discover.d.ts.map +1 -1
- package/lib/network/peers/discover.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 +6 -3
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +30 -3
- package/lib/node/nodejs.js.map +1 -1
- package/lib/node/notifier.d.ts.map +1 -1
- package/lib/node/notifier.js +9 -6
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/backfill/backfill.d.ts.map +1 -1
- package/lib/sync/backfill/backfill.js +2 -4
- package/lib/sync/backfill/backfill.js.map +1 -1
- package/lib/sync/backfill/verify.d.ts +2 -2
- package/lib/sync/backfill/verify.d.ts.map +1 -1
- package/lib/sync/backfill/verify.js +3 -3
- package/lib/sync/backfill/verify.js.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +28 -20
- package/src/api/impl/beacon/state/utils.ts +2 -22
- 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/blocks/importBlock.ts +13 -3
- package/src/chain/blocks/verifyBlock.ts +10 -3
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +9 -2
- package/src/chain/blocks/verifyBlocksSignatures.ts +13 -3
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +1 -0
- package/src/chain/chain.ts +50 -48
- package/src/chain/forkChoice/index.ts +3 -2
- package/src/chain/interface.ts +6 -8
- package/src/chain/lightClient/proofs.ts +0 -2
- package/src/chain/opPools/aggregatedAttestationPool.ts +23 -195
- package/src/chain/opPools/opPool.ts +13 -15
- package/src/chain/prepareNextSlot.ts +2 -6
- package/src/chain/produceBlock/produceBlockBody.ts +9 -4
- 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 +32 -27
- package/src/chain/stateCache/types.ts +5 -10
- package/src/chain/validation/aggregateAndProof.ts +12 -0
- package/src/chain/validation/attestation.ts +3 -3
- package/src/chain/validation/attesterSlashing.ts +14 -2
- package/src/chain/validation/blobSidecar.ts +3 -3
- package/src/chain/validation/block.ts +6 -2
- package/src/chain/validation/blsToExecutionChange.ts +10 -8
- package/src/chain/validation/dataColumnSidecar.ts +3 -3
- package/src/chain/validation/proposerSlashing.ts +8 -2
- package/src/chain/validation/signatureSets/aggregateAndProof.ts +1 -1
- package/src/chain/validation/signatureSets/contributionAndProof.ts +3 -1
- package/src/chain/validation/signatureSets/syncCommittee.ts +3 -1
- package/src/chain/validation/signatureSets/syncCommitteeContribution.ts +3 -1
- package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +2 -1
- package/src/chain/validation/syncCommittee.ts +1 -1
- package/src/chain/validation/syncCommitteeContributionAndProof.ts +8 -3
- package/src/chain/validation/voluntaryExit.ts +1 -1
- package/src/db/beacon.ts +38 -1
- package/src/db/buckets.ts +12 -6
- package/src/db/interface.ts +2 -0
- package/src/db/repositories/stateArchive.ts +2 -2
- package/src/execution/engine/mock.ts +40 -13
- package/src/metrics/metrics/lodestar.ts +3 -17
- package/src/network/peers/discover.ts +3 -3
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +1 -1
- package/src/node/nodejs.ts +37 -4
- package/src/node/notifier.ts +13 -7
- package/src/sync/backfill/backfill.ts +2 -9
- package/src/sync/backfill/verify.ts +3 -8
- package/src/util/sszBytes.ts +1 -1
- package/lib/chain/rewards/attestationsRewards.d.ts +0 -7
- package/lib/chain/rewards/attestationsRewards.d.ts.map +0 -1
- package/lib/chain/rewards/attestationsRewards.js +0 -112
- package/lib/chain/rewards/attestationsRewards.js.map +0 -1
- package/lib/chain/rewards/blockRewards.d.ts +0 -14
- package/lib/chain/rewards/blockRewards.d.ts.map +0 -1
- package/lib/chain/rewards/blockRewards.js +0 -94
- package/lib/chain/rewards/blockRewards.js.map +0 -1
- package/lib/chain/rewards/syncCommitteeRewards.d.ts +0 -6
- package/lib/chain/rewards/syncCommitteeRewards.d.ts.map +0 -1
- package/lib/chain/rewards/syncCommitteeRewards.js +0 -36
- package/lib/chain/rewards/syncCommitteeRewards.js.map +0 -1
- package/src/chain/rewards/attestationsRewards.ts +0 -197
- package/src/chain/rewards/blockRewards.ts +0 -150
- package/src/chain/rewards/syncCommitteeRewards.ts +0 -58
package/src/chain/regen/regen.ts
CHANGED
|
@@ -78,7 +78,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// Otherwise, get the state normally.
|
|
81
|
-
return this.getState(parentBlock.stateRoot, regenCaller,
|
|
81
|
+
return this.getState(parentBlock.stateRoot, regenCaller, allowDiskReload);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
@@ -124,8 +124,8 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
124
124
|
const {checkpointStateCache} = this.modules;
|
|
125
125
|
const epoch = computeEpochAtSlot(slot);
|
|
126
126
|
const latestCheckpointStateCtx = allowDiskReload
|
|
127
|
-
? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch
|
|
128
|
-
: checkpointStateCache.getLatest(blockRoot, epoch
|
|
127
|
+
? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch)
|
|
128
|
+
: checkpointStateCache.getLatest(blockRoot, epoch);
|
|
129
129
|
|
|
130
130
|
// If a checkpoint state exists with the given checkpoint root, it either is in requested epoch
|
|
131
131
|
// or needs to have empty slots processed until the requested epoch
|
|
@@ -136,7 +136,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
136
136
|
// Otherwise, use the fork choice to get the stateRoot from block at the checkpoint root
|
|
137
137
|
// regenerate that state,
|
|
138
138
|
// then process empty slots until the requested epoch
|
|
139
|
-
const blockStateCtx = await this.getState(block.stateRoot, regenCaller,
|
|
139
|
+
const blockStateCtx = await this.getState(block.stateRoot, regenCaller, allowDiskReload);
|
|
140
140
|
return processSlotsByCheckpoint(this.modules, blockStateCtx, slot, regenCaller, opts);
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -148,23 +148,15 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
148
148
|
async getState(
|
|
149
149
|
stateRoot: RootHex,
|
|
150
150
|
caller: RegenCaller,
|
|
151
|
-
opts?: StateRegenerationOpts,
|
|
152
151
|
// internal option, don't want to expose to external caller
|
|
153
152
|
allowDiskReload = false
|
|
154
153
|
): Promise<CachedBeaconStateAllForks> {
|
|
155
154
|
// Trivial case, state at stateRoot is already cached
|
|
156
|
-
const cachedStateCtx = this.modules.blockStateCache.get(stateRoot
|
|
155
|
+
const cachedStateCtx = this.modules.blockStateCache.get(stateRoot);
|
|
157
156
|
if (cachedStateCtx) {
|
|
158
157
|
return cachedStateCtx;
|
|
159
158
|
}
|
|
160
159
|
|
|
161
|
-
// in block gossip validation (getPreState() call), dontTransferCache is specified as true because we only want to transfer cache in verifyBlocksStateTransitionOnly()
|
|
162
|
-
// but here we want to process blocks as fast as possible so force to transfer cache in this case
|
|
163
|
-
if (opts && allowDiskReload) {
|
|
164
|
-
// if there is no `opts` specified, it already means "false"
|
|
165
|
-
opts.dontTransferCache = false;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
160
|
// Otherwise we have to use the fork choice to traverse backwards, block by block,
|
|
169
161
|
// searching the state caches
|
|
170
162
|
// then replay blocks forward to the desired stateRoot
|
|
@@ -179,7 +171,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
179
171
|
const getSeedStateTimer = this.modules.metrics?.regenGetState.getSeedState.startTimer({caller});
|
|
180
172
|
// iterateAncestorBlocks only returns ancestor blocks, not the block itself
|
|
181
173
|
for (const b of this.modules.forkChoice.iterateAncestorBlocks(block.blockRoot)) {
|
|
182
|
-
state = this.modules.blockStateCache.get(b.stateRoot
|
|
174
|
+
state = this.modules.blockStateCache.get(b.stateRoot);
|
|
183
175
|
if (state) {
|
|
184
176
|
break;
|
|
185
177
|
}
|
|
@@ -187,8 +179,8 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
187
179
|
if (!lastBlockToReplay) continue;
|
|
188
180
|
const epoch = computeEpochAtSlot(lastBlockToReplay.slot - 1);
|
|
189
181
|
state = allowDiskReload
|
|
190
|
-
? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch
|
|
191
|
-
: checkpointStateCache.getLatest(b.blockRoot, epoch
|
|
182
|
+
? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch)
|
|
183
|
+
: checkpointStateCache.getLatest(b.blockRoot, epoch);
|
|
192
184
|
if (state) {
|
|
193
185
|
break;
|
|
194
186
|
}
|
|
@@ -255,6 +247,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
255
247
|
try {
|
|
256
248
|
// Only advances state trusting block's signture and hashes.
|
|
257
249
|
// We are only running the state transition to get a specific state's data.
|
|
250
|
+
// stateTransition() does the clone() inside, transfer cache to make the regen faster
|
|
258
251
|
state = stateTransition(
|
|
259
252
|
state,
|
|
260
253
|
block,
|
|
@@ -265,6 +258,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
265
258
|
verifyStateRoot: false,
|
|
266
259
|
verifyProposer: false,
|
|
267
260
|
verifySignatures: false,
|
|
261
|
+
dontTransferCache: false,
|
|
268
262
|
},
|
|
269
263
|
this.modules
|
|
270
264
|
);
|
|
@@ -390,8 +384,8 @@ export async function processSlotsToNearestCheckpoint(
|
|
|
390
384
|
const checkpointState = postState;
|
|
391
385
|
const cp = getCheckpointFromState(checkpointState);
|
|
392
386
|
checkpointStateCache.add(cp, checkpointState);
|
|
393
|
-
// consumers should not mutate
|
|
394
|
-
emitter?.emit(ChainEvent.checkpoint, cp, checkpointState
|
|
387
|
+
// consumers should not mutate state ever
|
|
388
|
+
emitter?.emit(ChainEvent.checkpoint, cp, checkpointState);
|
|
395
389
|
|
|
396
390
|
if (count >= 1) {
|
|
397
391
|
// in normal condition, we only process 1 epoch so never reach this
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import {ForkSeq} from "@lodestar/params";
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
+
CachedBeaconStateAllForks,
|
|
3
4
|
EpochShuffling,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
computeEpochShufflingAsync,
|
|
5
|
+
getAttestingIndices,
|
|
6
|
+
getBeaconCommittees,
|
|
7
|
+
getIndexedAttestation,
|
|
8
8
|
} from "@lodestar/state-transition";
|
|
9
|
-
import {Epoch, RootHex} from "@lodestar/types";
|
|
9
|
+
import {Attestation, CommitteeIndex, Epoch, IndexedAttestation, RootHex, Slot} from "@lodestar/types";
|
|
10
10
|
import {LodestarError, Logger, MapDef, pruneSetToMax} from "@lodestar/utils";
|
|
11
11
|
import {Metrics} from "../metrics/metrics.js";
|
|
12
12
|
|
|
@@ -53,7 +53,7 @@ export type ShufflingCacheOpts = {
|
|
|
53
53
|
* - if a shuffling is not available (which does not happen with default chain option of maxSkipSlots = 32), track a promise to make sure we don't compute the same shuffling twice
|
|
54
54
|
* - skip computing shuffling when loading state bytes from disk
|
|
55
55
|
*/
|
|
56
|
-
export class ShufflingCache
|
|
56
|
+
export class ShufflingCache {
|
|
57
57
|
/** LRU cache implemented as a map, pruned every time we add an item */
|
|
58
58
|
private readonly itemsByDecisionRootByEpoch: MapDef<Epoch, Map<RootHex, CacheItem>> = new MapDef(
|
|
59
59
|
() => new Map<RootHex, CacheItem>()
|
|
@@ -136,60 +136,76 @@ export class ShufflingCache implements IShufflingCache {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* NOTE: If a shuffling is already queued and not calculated it will build and resolve
|
|
143
|
-
* the promise but the already queued build will happen at some later time
|
|
139
|
+
* Get a shuffling synchronously, return null if not present.
|
|
140
|
+
* The only time we have a promise cache item is when we regen shuffling for attestation, which never happens
|
|
141
|
+
* with default chain option.
|
|
144
142
|
*/
|
|
145
|
-
getSync
|
|
146
|
-
epoch: Epoch,
|
|
147
|
-
decisionRoot: RootHex,
|
|
148
|
-
buildProps?: T
|
|
149
|
-
): T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null {
|
|
143
|
+
getSync(epoch: Epoch, decisionRoot: RootHex): EpochShuffling | null {
|
|
150
144
|
const cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(epoch).get(decisionRoot);
|
|
151
|
-
if (
|
|
145
|
+
if (cacheItem === undefined) {
|
|
152
146
|
this.metrics?.shufflingCache.miss.inc();
|
|
153
|
-
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (isShufflingCacheItem(cacheItem)) {
|
|
154
151
|
this.metrics?.shufflingCache.hit.inc();
|
|
155
152
|
return cacheItem.shuffling;
|
|
156
|
-
} else if (buildProps) {
|
|
157
|
-
// TODO: (@matthewkeil) This should possible log a warning??
|
|
158
|
-
this.metrics?.shufflingCache.shufflingPromiseNotResolvedAndThrownAway.inc();
|
|
159
|
-
} else {
|
|
160
|
-
this.metrics?.shufflingCache.shufflingPromiseNotResolved.inc();
|
|
161
153
|
}
|
|
162
154
|
|
|
163
|
-
|
|
164
|
-
if (buildProps) {
|
|
165
|
-
const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "getSync"});
|
|
166
|
-
shuffling = computeEpochShuffling(buildProps.state, buildProps.activeIndices, epoch);
|
|
167
|
-
timer?.();
|
|
168
|
-
this.set(shuffling, decisionRoot);
|
|
169
|
-
}
|
|
170
|
-
return shuffling as T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null;
|
|
155
|
+
return null;
|
|
171
156
|
}
|
|
172
157
|
|
|
173
158
|
/**
|
|
174
|
-
*
|
|
159
|
+
* Process a state to extract and cache all shufflings (previous, current, next).
|
|
160
|
+
* Uses the stored decision roots from epochCtx.
|
|
175
161
|
*/
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
162
|
+
processState(state: CachedBeaconStateAllForks): void {
|
|
163
|
+
const {epochCtx} = state;
|
|
164
|
+
|
|
165
|
+
// Cache previous shuffling
|
|
166
|
+
this.set(epochCtx.previousShuffling, epochCtx.previousDecisionRoot);
|
|
167
|
+
|
|
168
|
+
// Cache current shuffling
|
|
169
|
+
this.set(epochCtx.currentShuffling, epochCtx.currentDecisionRoot);
|
|
170
|
+
|
|
171
|
+
// Cache next shuffling
|
|
172
|
+
this.set(epochCtx.nextShuffling, epochCtx.nextDecisionRoot);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
getIndexedAttestation(
|
|
176
|
+
epoch: number,
|
|
177
|
+
decisionRoot: string,
|
|
178
|
+
fork: ForkSeq,
|
|
179
|
+
attestation: Attestation
|
|
180
|
+
): IndexedAttestation {
|
|
181
|
+
const shuffling = this.getShufflingOrThrow(epoch, decisionRoot);
|
|
182
|
+
return getIndexedAttestation(shuffling, fork, attestation);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
getAttestingIndices(epoch: number, decisionRoot: string, fork: ForkSeq, attestation: Attestation): number[] {
|
|
186
|
+
const shuffling = this.getShufflingOrThrow(epoch, decisionRoot);
|
|
187
|
+
return getAttestingIndices(shuffling, fork, attestation);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
getBeaconCommittee(epoch: number, decisionRoot: string, slot: Slot, index: CommitteeIndex): Uint32Array {
|
|
191
|
+
return this.getBeaconCommittees(epoch, decisionRoot, slot, [index])[0];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
getBeaconCommittees(epoch: number, decisionRoot: string, slot: Slot, indices: CommitteeIndex[]): Uint32Array[] {
|
|
195
|
+
const shuffling = this.getShufflingOrThrow(epoch, decisionRoot);
|
|
196
|
+
return getBeaconCommittees(shuffling, slot, indices);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private getShufflingOrThrow(epoch: number, decisionRoot: string): EpochShuffling {
|
|
200
|
+
const shuffling = this.getSync(epoch, decisionRoot);
|
|
201
|
+
if (shuffling === null) {
|
|
202
|
+
throw new ShufflingCacheError({
|
|
203
|
+
code: ShufflingCacheErrorCode.NO_SHUFFLING_FOUND,
|
|
204
|
+
epoch,
|
|
205
|
+
decisionRoot,
|
|
192
206
|
});
|
|
207
|
+
}
|
|
208
|
+
return shuffling;
|
|
193
209
|
}
|
|
194
210
|
|
|
195
211
|
/**
|
|
@@ -207,7 +223,8 @@ export class ShufflingCache implements IShufflingCache {
|
|
|
207
223
|
(Date.now() - cacheItem.timeInsertedMs) / 1000
|
|
208
224
|
);
|
|
209
225
|
} else {
|
|
210
|
-
this.metrics?.shufflingCache.
|
|
226
|
+
this.metrics?.shufflingCache.shufflingSetMultipleTimes.inc();
|
|
227
|
+
return;
|
|
211
228
|
}
|
|
212
229
|
}
|
|
213
230
|
// set the shuffling
|
|
@@ -3,7 +3,6 @@ import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
|
|
|
3
3
|
import {Epoch, RootHex} from "@lodestar/types";
|
|
4
4
|
import {toRootHex} from "@lodestar/utils";
|
|
5
5
|
import {Metrics} from "../../metrics/index.js";
|
|
6
|
-
import {StateRegenerationOpts} from "../regen/interface.js";
|
|
7
6
|
import {MapTracker} from "./mapMetrics.js";
|
|
8
7
|
import {BlockStateCache} from "./types.js";
|
|
9
8
|
|
|
@@ -39,7 +38,7 @@ export class BlockStateCacheImpl implements BlockStateCache {
|
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
get(rootHex: RootHex
|
|
41
|
+
get(rootHex: RootHex): CachedBeaconStateAllForks | null {
|
|
43
42
|
this.metrics?.lookups.inc();
|
|
44
43
|
const item = this.head?.stateRoot === rootHex ? this.head.state : this.cache.get(rootHex);
|
|
45
44
|
if (!item) {
|
|
@@ -49,7 +48,7 @@ export class BlockStateCacheImpl implements BlockStateCache {
|
|
|
49
48
|
this.metrics?.hits.inc();
|
|
50
49
|
this.metrics?.stateClonedCount.observe(item.clonedCount);
|
|
51
50
|
|
|
52
|
-
return item
|
|
51
|
+
return item;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
add(item: CachedBeaconStateAllForks): void {
|
|
@@ -4,7 +4,6 @@ import {RootHex} from "@lodestar/types";
|
|
|
4
4
|
import {toRootHex} from "@lodestar/utils";
|
|
5
5
|
import {Metrics} from "../../metrics/index.js";
|
|
6
6
|
import {LinkedList} from "../../util/array.js";
|
|
7
|
-
import {StateRegenerationOpts} from "../regen/interface.js";
|
|
8
7
|
import {MapTracker} from "./mapMetrics.js";
|
|
9
8
|
import {BlockStateCache} from "./types.js";
|
|
10
9
|
|
|
@@ -86,14 +85,14 @@ export class FIFOBlockStateCache implements BlockStateCache {
|
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
const firstState = firstValue.value;
|
|
89
|
-
//
|
|
90
|
-
return firstState
|
|
88
|
+
// consumers should not mutate the returned state
|
|
89
|
+
return firstState;
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
/**
|
|
94
93
|
* Get a state from this cache given a state root hex.
|
|
95
94
|
*/
|
|
96
|
-
get(rootHex: RootHex
|
|
95
|
+
get(rootHex: RootHex): CachedBeaconStateAllForks | null {
|
|
97
96
|
this.metrics?.lookups.inc();
|
|
98
97
|
const item = this.cache.get(rootHex);
|
|
99
98
|
if (!item) {
|
|
@@ -103,7 +102,7 @@ export class FIFOBlockStateCache implements BlockStateCache {
|
|
|
103
102
|
this.metrics?.hits.inc();
|
|
104
103
|
this.metrics?.stateClonedCount.observe(item.clonedCount);
|
|
105
104
|
|
|
106
|
-
return item
|
|
105
|
+
return item;
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
/**
|
|
@@ -3,7 +3,6 @@ import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
|
|
|
3
3
|
import {Epoch, RootHex, phase0} from "@lodestar/types";
|
|
4
4
|
import {MapDef, toRootHex} from "@lodestar/utils";
|
|
5
5
|
import {Metrics} from "../../metrics/index.js";
|
|
6
|
-
import {StateRegenerationOpts} from "../regen/interface.js";
|
|
7
6
|
import {MapTracker} from "./mapMetrics.js";
|
|
8
7
|
import {CacheItemType, CheckpointStateCache} from "./types.js";
|
|
9
8
|
|
|
@@ -42,21 +41,16 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
|
|
|
42
41
|
this.maxEpochs = maxEpochs;
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
async getOrReload(cp: CheckpointHex
|
|
46
|
-
return this.get(cp
|
|
44
|
+
async getOrReload(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | null> {
|
|
45
|
+
return this.get(cp);
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
async getStateOrBytes(cp: CheckpointHex): Promise<Uint8Array | CachedBeaconStateAllForks | null> {
|
|
50
|
-
|
|
51
|
-
return this.get(cp, {dontTransferCache: true});
|
|
49
|
+
return this.get(cp);
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
async getOrReloadLatest(
|
|
55
|
-
rootHex
|
|
56
|
-
maxEpoch: number,
|
|
57
|
-
opts?: StateRegenerationOpts
|
|
58
|
-
): Promise<CachedBeaconStateAllForks | null> {
|
|
59
|
-
return this.getLatest(rootHex, maxEpoch, opts);
|
|
52
|
+
async getOrReloadLatest(rootHex: string, maxEpoch: number): Promise<CachedBeaconStateAllForks | null> {
|
|
53
|
+
return this.getLatest(rootHex, maxEpoch);
|
|
60
54
|
}
|
|
61
55
|
|
|
62
56
|
async processState(): Promise<number> {
|
|
@@ -64,7 +58,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
|
|
|
64
58
|
return 0;
|
|
65
59
|
}
|
|
66
60
|
|
|
67
|
-
get(cp: CheckpointHex
|
|
61
|
+
get(cp: CheckpointHex): CachedBeaconStateAllForks | null {
|
|
68
62
|
this.metrics?.lookups.inc();
|
|
69
63
|
const cpKey = toCheckpointKey(cp);
|
|
70
64
|
const item = this.cache.get(cpKey);
|
|
@@ -81,7 +75,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
|
|
|
81
75
|
|
|
82
76
|
this.metrics?.stateClonedCount.observe(item.clonedCount);
|
|
83
77
|
|
|
84
|
-
return item
|
|
78
|
+
return item;
|
|
85
79
|
}
|
|
86
80
|
|
|
87
81
|
add(cp: phase0.Checkpoint, item: CachedBeaconStateAllForks): void {
|
|
@@ -98,14 +92,14 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
|
|
|
98
92
|
/**
|
|
99
93
|
* Searches for the latest cached state with a `root`, starting with `epoch` and descending
|
|
100
94
|
*/
|
|
101
|
-
getLatest(rootHex: RootHex, maxEpoch: Epoch
|
|
95
|
+
getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null {
|
|
102
96
|
// sort epochs in descending order, only consider epochs lte `epoch`
|
|
103
97
|
const epochs = Array.from(this.epochIndex.keys())
|
|
104
98
|
.sort((a, b) => b - a)
|
|
105
99
|
.filter((e) => e <= maxEpoch);
|
|
106
100
|
for (const epoch of epochs) {
|
|
107
101
|
if (this.epochIndex.get(epoch)?.has(rootHex)) {
|
|
108
|
-
return this.get({rootHex, epoch}
|
|
102
|
+
return this.get({rootHex, epoch});
|
|
109
103
|
}
|
|
110
104
|
}
|
|
111
105
|
return null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
|
+
import {BeaconConfig} from "@lodestar/config";
|
|
2
3
|
import {
|
|
3
4
|
CachedBeaconStateAllForks,
|
|
4
5
|
computeStartSlotAtEpoch,
|
|
@@ -10,7 +11,6 @@ import {Logger, MapDef, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils"
|
|
|
10
11
|
import {Metrics} from "../../metrics/index.js";
|
|
11
12
|
import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js";
|
|
12
13
|
import {IClock} from "../../util/clock.js";
|
|
13
|
-
import {StateRegenerationOpts} from "../regen/interface.js";
|
|
14
14
|
import {serializeState} from "../serializeState.js";
|
|
15
15
|
import {CPStateDatastore, DatastoreKey} from "./datastore/index.js";
|
|
16
16
|
import {MapTracker} from "./mapMetrics.js";
|
|
@@ -24,6 +24,7 @@ export type PersistentCheckpointStateCacheOpts = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
type PersistentCheckpointStateCacheModules = {
|
|
27
|
+
config: BeaconConfig;
|
|
27
28
|
metrics?: Metrics | null;
|
|
28
29
|
logger: Logger;
|
|
29
30
|
clock?: IClock | null;
|
|
@@ -107,6 +108,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
107
108
|
private readonly cache: MapTracker<CacheKey, CacheItem>;
|
|
108
109
|
/** Epoch -> Set<blockRoot> */
|
|
109
110
|
private readonly epochIndex = new MapDef<Epoch, Set<RootHex>>(() => new Set<string>());
|
|
111
|
+
private readonly config: BeaconConfig;
|
|
110
112
|
private readonly metrics: Metrics | null | undefined;
|
|
111
113
|
private readonly logger: Logger;
|
|
112
114
|
private readonly clock: IClock | null | undefined;
|
|
@@ -120,10 +122,20 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
120
122
|
private readonly bufferPool?: BufferPool | null;
|
|
121
123
|
|
|
122
124
|
constructor(
|
|
123
|
-
{
|
|
125
|
+
{
|
|
126
|
+
config,
|
|
127
|
+
metrics,
|
|
128
|
+
logger,
|
|
129
|
+
clock,
|
|
130
|
+
signal,
|
|
131
|
+
datastore,
|
|
132
|
+
blockStateCache,
|
|
133
|
+
bufferPool,
|
|
134
|
+
}: PersistentCheckpointStateCacheModules,
|
|
124
135
|
opts: PersistentCheckpointStateCacheOpts
|
|
125
136
|
) {
|
|
126
137
|
this.cache = new MapTracker(metrics?.cpStateCache);
|
|
138
|
+
this.config = config;
|
|
127
139
|
if (metrics) {
|
|
128
140
|
this.metrics = metrics;
|
|
129
141
|
metrics.cpStateCache.size.addCollect(() => {
|
|
@@ -191,10 +203,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
191
203
|
* - Get block for processing
|
|
192
204
|
* - Regen head state
|
|
193
205
|
*/
|
|
194
|
-
async getOrReload(cp: CheckpointHex
|
|
195
|
-
const stateOrStateBytesData = await this.getStateOrLoadDb(cp
|
|
206
|
+
async getOrReload(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | null> {
|
|
207
|
+
const stateOrStateBytesData = await this.getStateOrLoadDb(cp);
|
|
196
208
|
if (stateOrStateBytesData === null || isCachedBeaconState(stateOrStateBytesData)) {
|
|
197
|
-
return stateOrStateBytesData
|
|
209
|
+
return stateOrStateBytesData ?? null;
|
|
198
210
|
}
|
|
199
211
|
const {persistedKey, stateBytes} = stateOrStateBytesData;
|
|
200
212
|
const logMeta = {persistedKey: toHex(persistedKey)};
|
|
@@ -220,7 +232,8 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
220
232
|
sszTimer?.();
|
|
221
233
|
const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer();
|
|
222
234
|
const newCachedState = loadCachedBeaconState(seedState, stateBytes, {}, validatorsBytes);
|
|
223
|
-
|
|
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
|
|
224
237
|
const stateRoot = toRootHex(newCachedState.hashTreeRoot());
|
|
225
238
|
timer?.();
|
|
226
239
|
|
|
@@ -239,7 +252,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
239
252
|
this.cache.set(cpKey, {type: CacheItemType.inMemory, state: newCachedState, persistedKey});
|
|
240
253
|
this.epochIndex.getOrDefault(cp.epoch).add(cp.rootHex);
|
|
241
254
|
// don't prune from memory here, call it at the last 1/3 of slot 0 of an epoch
|
|
242
|
-
return newCachedState
|
|
255
|
+
return newCachedState;
|
|
243
256
|
} catch (e) {
|
|
244
257
|
this.logger.debug("Reload: error loading cached state", logMeta, e as Error);
|
|
245
258
|
return null;
|
|
@@ -250,8 +263,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
250
263
|
* Return either state or state bytes loaded from db.
|
|
251
264
|
*/
|
|
252
265
|
async getStateOrBytes(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | Uint8Array | null> {
|
|
253
|
-
|
|
254
|
-
const stateOrLoadedState = await this.getStateOrLoadDb(cp, {dontTransferCache: true});
|
|
266
|
+
const stateOrLoadedState = await this.getStateOrLoadDb(cp);
|
|
255
267
|
if (stateOrLoadedState === null || isCachedBeaconState(stateOrLoadedState)) {
|
|
256
268
|
return stateOrLoadedState;
|
|
257
269
|
}
|
|
@@ -261,12 +273,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
261
273
|
/**
|
|
262
274
|
* Return either state or state bytes with persisted key loaded from db.
|
|
263
275
|
*/
|
|
264
|
-
async getStateOrLoadDb(
|
|
265
|
-
cp: CheckpointHex,
|
|
266
|
-
opts?: StateRegenerationOpts
|
|
267
|
-
): Promise<CachedBeaconStateAllForks | LoadedStateBytesData | null> {
|
|
276
|
+
async getStateOrLoadDb(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | LoadedStateBytesData | null> {
|
|
268
277
|
const cpKey = toCacheKey(cp);
|
|
269
|
-
const inMemoryState = this.get(cpKey
|
|
278
|
+
const inMemoryState = this.get(cpKey);
|
|
270
279
|
if (inMemoryState) {
|
|
271
280
|
return inMemoryState;
|
|
272
281
|
}
|
|
@@ -295,7 +304,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
295
304
|
/**
|
|
296
305
|
* Similar to get() api without reloading from disk
|
|
297
306
|
*/
|
|
298
|
-
get(cpOrKey: CheckpointHex | string
|
|
307
|
+
get(cpOrKey: CheckpointHex | string): CachedBeaconStateAllForks | null {
|
|
299
308
|
this.metrics?.cpStateCache.lookups.inc();
|
|
300
309
|
const cpKey = typeof cpOrKey === "string" ? cpOrKey : toCacheKey(cpOrKey);
|
|
301
310
|
const cacheItem = this.cache.get(cpKey);
|
|
@@ -313,7 +322,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
313
322
|
if (isInMemoryCacheItem(cacheItem)) {
|
|
314
323
|
const {state} = cacheItem;
|
|
315
324
|
this.metrics?.cpStateCache.stateClonedCount.observe(state.clonedCount);
|
|
316
|
-
return state
|
|
325
|
+
return state;
|
|
317
326
|
}
|
|
318
327
|
|
|
319
328
|
return null;
|
|
@@ -347,14 +356,14 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
347
356
|
/**
|
|
348
357
|
* Searches in-memory state for the latest cached state with a `root` without reload, starting with `epoch` and descending
|
|
349
358
|
*/
|
|
350
|
-
getLatest(rootHex: RootHex, maxEpoch: Epoch
|
|
359
|
+
getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null {
|
|
351
360
|
// sort epochs in descending order, only consider epochs lte `epoch`
|
|
352
361
|
const epochs = Array.from(this.epochIndex.keys())
|
|
353
362
|
.sort((a, b) => b - a)
|
|
354
363
|
.filter((e) => e <= maxEpoch);
|
|
355
364
|
for (const epoch of epochs) {
|
|
356
365
|
if (this.epochIndex.get(epoch)?.has(rootHex)) {
|
|
357
|
-
const inMemoryClonedState = this.get({rootHex, epoch}
|
|
366
|
+
const inMemoryClonedState = this.get({rootHex, epoch});
|
|
358
367
|
if (inMemoryClonedState) {
|
|
359
368
|
return inMemoryClonedState;
|
|
360
369
|
}
|
|
@@ -370,11 +379,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
370
379
|
* - Get block for processing
|
|
371
380
|
* - Regen head state
|
|
372
381
|
*/
|
|
373
|
-
async getOrReloadLatest(
|
|
374
|
-
rootHex: RootHex,
|
|
375
|
-
maxEpoch: Epoch,
|
|
376
|
-
opts?: StateRegenerationOpts
|
|
377
|
-
): Promise<CachedBeaconStateAllForks | null> {
|
|
382
|
+
async getOrReloadLatest(rootHex: RootHex, maxEpoch: Epoch): Promise<CachedBeaconStateAllForks | null> {
|
|
378
383
|
// sort epochs in descending order, only consider epochs lte `epoch`
|
|
379
384
|
const epochs = Array.from(this.epochIndex.keys())
|
|
380
385
|
.sort((a, b) => b - a)
|
|
@@ -382,9 +387,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
382
387
|
for (const epoch of epochs) {
|
|
383
388
|
if (this.epochIndex.get(epoch)?.has(rootHex)) {
|
|
384
389
|
try {
|
|
385
|
-
const
|
|
386
|
-
if (
|
|
387
|
-
return
|
|
390
|
+
const state = await this.getOrReload({rootHex, epoch});
|
|
391
|
+
if (state) {
|
|
392
|
+
return state;
|
|
388
393
|
}
|
|
389
394
|
} catch (e) {
|
|
390
395
|
this.logger.debug("Error get or reload state", {epoch, rootHex}, e as Error);
|
|
@@ -484,7 +489,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
484
489
|
}
|
|
485
490
|
|
|
486
491
|
const blockSlot = state.slot;
|
|
487
|
-
const processCPStatesTimeMs =
|
|
492
|
+
const processCPStatesTimeMs = this.config.getSlotComponentDurationMs(PROCESS_CHECKPOINT_STATES_BPS);
|
|
488
493
|
// we always have clock in production, fallback value is only for test
|
|
489
494
|
const msFromSlot = this.clock?.msFromSlot(blockSlot) ?? processCPStatesTimeMs;
|
|
490
495
|
const msToProcessCPStates = processCPStatesTimeMs - msFromSlot;
|
|
@@ -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;
|
|
@@ -245,6 +245,18 @@ async function validateAggregateAndProof(
|
|
|
245
245
|
});
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
// Same race-condition check as above for seen aggregators
|
|
249
|
+
if (
|
|
250
|
+
!skipValidationKnownAttesters &&
|
|
251
|
+
chain.seenAggregatedAttestations.isKnown(targetEpoch, attIndex, attDataRootHex, aggregationBits)
|
|
252
|
+
) {
|
|
253
|
+
throw new AttestationError(GossipAction.IGNORE, {
|
|
254
|
+
code: AttestationErrorCode.ATTESTERS_ALREADY_KNOWN,
|
|
255
|
+
targetEpoch,
|
|
256
|
+
aggregateRoot: attDataRootHex,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
248
260
|
chain.seenAggregators.add(targetEpoch, aggregatorIndex);
|
|
249
261
|
chain.seenAggregatedAttestations.add(
|
|
250
262
|
targetEpoch,
|
|
@@ -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
|
});
|