@lodestar/beacon-node 1.42.0 → 1.43.0-dev.0bc48d3b54
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 +20 -0
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +4 -0
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +13 -10
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/lodestar/attesterSlashing.d.ts +8 -0
- package/lib/api/impl/lodestar/attesterSlashing.d.ts.map +1 -0
- package/lib/api/impl/lodestar/attesterSlashing.js +29 -0
- package/lib/api/impl/lodestar/attesterSlashing.js.map +1 -0
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +39 -0
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +11 -4
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/GetBlobsTracker.d.ts +1 -1
- package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
- package/lib/chain/GetBlobsTracker.js +1 -2
- package/lib/chain/GetBlobsTracker.js.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +2 -4
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +29 -35
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +24 -13
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.js +2 -2
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +6 -4
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +4 -4
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +3 -2
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +4 -2
- package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
- package/lib/chain/chain.d.ts +2 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +30 -36
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +13 -1
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +5 -0
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/attestationError.d.ts +8 -1
- package/lib/chain/errors/attestationError.d.ts.map +1 -1
- package/lib/chain/errors/attestationError.js +4 -0
- package/lib/chain/errors/attestationError.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +11 -1
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +4 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +22 -12
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -1
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts +2 -2
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +7 -0
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +5 -2
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.d.ts +2 -2
- package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.js +2 -2
- package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +22 -10
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts +1 -7
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +1 -28
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +5 -10
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +46 -19
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/errors.d.ts +1 -11
- package/lib/chain/regen/errors.d.ts.map +1 -1
- package/lib/chain/regen/errors.js +0 -2
- package/lib/chain/regen/errors.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +6 -12
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/queued.d.ts +6 -11
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +8 -40
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +0 -5
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +7 -34
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/stateCache/datastore/db.d.ts +5 -4
- package/lib/chain/stateCache/datastore/db.d.ts.map +1 -1
- package/lib/chain/stateCache/datastore/db.js +10 -32
- 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 +1 -7
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +0 -8
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +13 -30
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +120 -216
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +8 -15
- 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 +12 -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 +12 -0
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +27 -5
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +7 -4
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +8 -3
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +8 -4
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/syncCommittee.d.ts.map +1 -1
- package/lib/chain/validation/syncCommittee.js +4 -0
- package/lib/chain/validation/syncCommittee.js.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +3 -3
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +21 -14
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -0
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +3 -0
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/types.d.ts +20 -0
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +18 -0
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -0
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +23 -3
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +2 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.js +2 -0
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts +2 -2
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +7 -3
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +6 -0
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts +2 -2
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +7 -3
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +3 -8
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +6 -1
- package/lib/node/nodejs.js.map +1 -1
- package/lib/node/notifier.d.ts.map +1 -1
- package/lib/node/notifier.js +2 -2
- package/lib/node/notifier.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/beacon/blocks/index.ts +29 -0
- package/src/api/impl/beacon/pool/index.ts +4 -0
- package/src/api/impl/beacon/state/index.ts +15 -15
- package/src/api/impl/lodestar/attesterSlashing.ts +43 -0
- package/src/api/impl/lodestar/index.ts +51 -1
- package/src/api/impl/validator/index.ts +13 -5
- package/src/chain/GetBlobsTracker.ts +1 -2
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +2 -4
- package/src/chain/blocks/importBlock.ts +33 -42
- package/src/chain/blocks/importExecutionPayload.ts +26 -12
- package/src/chain/blocks/index.ts +2 -2
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +6 -5
- package/src/chain/blocks/types.ts +4 -4
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +2 -1
- package/src/chain/blocks/verifyBlocksSignatures.ts +9 -2
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
- package/src/chain/chain.ts +38 -47
- package/src/chain/emitter.ts +12 -0
- package/src/chain/errors/attestationError.ts +6 -1
- package/src/chain/errors/blockError.ts +7 -1
- package/src/chain/forkChoice/index.ts +23 -12
- package/src/chain/interface.ts +5 -0
- package/src/chain/lightClient/index.ts +15 -3
- package/src/chain/opPools/aggregatedAttestationPool.ts +6 -1
- package/src/chain/opPools/executionPayloadBidPool.ts +3 -3
- package/src/chain/prepareNextSlot.ts +26 -9
- package/src/chain/produceBlock/computeNewStateRoot.ts +1 -37
- package/src/chain/produceBlock/produceBlockBody.ts +71 -23
- package/src/chain/regen/errors.ts +1 -6
- package/src/chain/regen/interface.ts +6 -12
- package/src/chain/regen/queued.ts +12 -48
- package/src/chain/regen/regen.ts +8 -36
- package/src/chain/stateCache/datastore/db.ts +10 -33
- package/src/chain/stateCache/datastore/file.ts +5 -6
- package/src/chain/stateCache/datastore/types.ts +2 -3
- package/src/chain/stateCache/fifoBlockStateCache.ts +1 -10
- package/src/chain/stateCache/persistentCheckpointsCache.ts +139 -247
- package/src/chain/stateCache/types.ts +8 -14
- package/src/chain/validation/aggregateAndProof.ts +13 -0
- package/src/chain/validation/attestation.ts +13 -0
- package/src/chain/validation/block.ts +30 -7
- package/src/chain/validation/executionPayloadBid.ts +7 -3
- package/src/chain/validation/executionPayloadEnvelope.ts +12 -3
- package/src/chain/validation/payloadAttestationMessage.ts +9 -3
- package/src/chain/validation/syncCommittee.ts +5 -1
- package/src/chain/validation/syncCommitteeContributionAndProof.ts +5 -1
- package/src/chain/validatorMonitor.ts +3 -2
- package/src/execution/engine/http.ts +21 -14
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/mock.ts +3 -0
- package/src/execution/engine/types.ts +41 -0
- package/src/network/processor/gossipHandlers.ts +28 -7
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +3 -1
- package/src/network/reqresp/handlers/beaconBlocksByRoot.ts +3 -0
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +15 -3
- package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +11 -0
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +19 -3
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +3 -1
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +3 -12
- package/src/node/nodejs.ts +7 -2
- package/src/node/notifier.ts +7 -2
|
@@ -14,7 +14,15 @@ import {
|
|
|
14
14
|
isForkPostBellatrix,
|
|
15
15
|
isForkPostGloas,
|
|
16
16
|
} from "@lodestar/params";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
G2_POINT_AT_INFINITY,
|
|
19
|
+
IBeaconStateView,
|
|
20
|
+
type IBeaconStateViewBellatrix,
|
|
21
|
+
computeTimeAtSlot,
|
|
22
|
+
isStatePostBellatrix,
|
|
23
|
+
isStatePostCapella,
|
|
24
|
+
isStatePostGloas,
|
|
25
|
+
} from "@lodestar/state-transition";
|
|
18
26
|
import {
|
|
19
27
|
BLSPubkey,
|
|
20
28
|
BLSSignature,
|
|
@@ -39,7 +47,7 @@ import {
|
|
|
39
47
|
fulu,
|
|
40
48
|
gloas,
|
|
41
49
|
} from "@lodestar/types";
|
|
42
|
-
import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
50
|
+
import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
43
51
|
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
44
52
|
import {numToQuantity} from "../../execution/engine/utils.js";
|
|
45
53
|
import {
|
|
@@ -102,12 +110,6 @@ export type ProduceFullGloas = {
|
|
|
102
110
|
executionRequests: electra.ExecutionRequests;
|
|
103
111
|
blobsBundle: BlobsBundle<ForkPostGloas>;
|
|
104
112
|
cells: fulu.Cell[][];
|
|
105
|
-
/**
|
|
106
|
-
* Cached envelope state root computed during block production.
|
|
107
|
-
* This is the state root after running `processExecutionPayloadEnvelope` on the
|
|
108
|
-
* post-block state, and later used to construct the `ExecutionPayloadEnvelope`.
|
|
109
|
-
*/
|
|
110
|
-
envelopeStateRoot: Root;
|
|
111
113
|
};
|
|
112
114
|
export type ProduceFullFulu = {
|
|
113
115
|
type: BlockType.Full;
|
|
@@ -191,6 +193,10 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
191
193
|
this.logger.verbose("Producing beacon block body", logMeta);
|
|
192
194
|
|
|
193
195
|
if (isForkPostGloas(fork)) {
|
|
196
|
+
if (!isStatePostGloas(currentState)) {
|
|
197
|
+
throw new Error("Expected Gloas state for Gloas block production");
|
|
198
|
+
}
|
|
199
|
+
|
|
194
200
|
// TODO GLOAS: support non self-building here, the block type differentiation between
|
|
195
201
|
// full and blinded no longer makes sense in gloas, it might be a good idea to move
|
|
196
202
|
// this into a completely separate function and have pre/post gloas more separated
|
|
@@ -207,11 +213,15 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
207
213
|
});
|
|
208
214
|
|
|
209
215
|
// Get execution payload from EL
|
|
216
|
+
const parentBlockHash = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot))
|
|
217
|
+
? currentState.latestExecutionPayloadBid.blockHash
|
|
218
|
+
: currentState.latestExecutionPayloadBid.parentBlockHash;
|
|
210
219
|
const prepareRes = await prepareExecutionPayload(
|
|
211
220
|
this,
|
|
212
221
|
this.logger,
|
|
213
222
|
fork,
|
|
214
223
|
parentBlockRoot,
|
|
224
|
+
parentBlockHash,
|
|
215
225
|
safeBlockHash,
|
|
216
226
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
217
227
|
currentState,
|
|
@@ -248,8 +258,8 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
248
258
|
|
|
249
259
|
// Create self-build execution payload bid
|
|
250
260
|
const bid: gloas.ExecutionPayloadBid = {
|
|
251
|
-
parentBlockHash
|
|
252
|
-
parentBlockRoot
|
|
261
|
+
parentBlockHash,
|
|
262
|
+
parentBlockRoot,
|
|
253
263
|
blockHash: executionPayload.blockHash,
|
|
254
264
|
prevRandao: currentState.getRandaoMix(currentState.epoch),
|
|
255
265
|
feeRecipient: executionPayload.feeRecipient,
|
|
@@ -297,6 +307,10 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
297
307
|
shouldOverrideBuilder,
|
|
298
308
|
});
|
|
299
309
|
} else if (isForkPostBellatrix(fork)) {
|
|
310
|
+
if (!isStatePostBellatrix(currentState)) {
|
|
311
|
+
throw new Error("Expected Bellatrix state for execution block production");
|
|
312
|
+
}
|
|
313
|
+
|
|
300
314
|
const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
|
|
301
315
|
const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
|
|
302
316
|
const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
|
|
@@ -323,6 +337,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
323
337
|
this.logger,
|
|
324
338
|
fork,
|
|
325
339
|
parentBlockRoot,
|
|
340
|
+
currentState.latestExecutionPayloadHeader.blockHash,
|
|
326
341
|
safeBlockHash,
|
|
327
342
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
328
343
|
currentState,
|
|
@@ -431,6 +446,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
431
446
|
this.logger,
|
|
432
447
|
fork,
|
|
433
448
|
parentBlockRoot,
|
|
449
|
+
currentState.latestExecutionPayloadHeader.blockHash,
|
|
434
450
|
safeBlockHash,
|
|
435
451
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
436
452
|
currentState,
|
|
@@ -596,17 +612,17 @@ export async function prepareExecutionPayload(
|
|
|
596
612
|
logger: Logger,
|
|
597
613
|
fork: ForkPostBellatrix,
|
|
598
614
|
parentBlockRoot: Root,
|
|
615
|
+
parentBlockHash: Bytes32,
|
|
599
616
|
safeBlockHash: RootHex,
|
|
600
617
|
finalizedBlockHash: RootHex,
|
|
601
|
-
state:
|
|
618
|
+
state: IBeaconStateViewBellatrix,
|
|
602
619
|
suggestedFeeRecipient: string
|
|
603
620
|
): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
|
|
604
|
-
const parentHash = state.latestBlockHash;
|
|
605
621
|
const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
|
|
606
622
|
const prevRandao = state.getRandaoMix(state.epoch);
|
|
607
623
|
|
|
608
624
|
const payloadIdCached = chain.executionEngine.payloadIdCache.get({
|
|
609
|
-
headBlockHash: toRootHex(
|
|
625
|
+
headBlockHash: toRootHex(parentBlockHash),
|
|
610
626
|
finalizedBlockHash,
|
|
611
627
|
timestamp: numToQuantity(timestamp),
|
|
612
628
|
prevRandao: toHex(prevRandao),
|
|
@@ -635,12 +651,13 @@ export async function prepareExecutionPayload(
|
|
|
635
651
|
prepareState: state,
|
|
636
652
|
prepareSlot: state.slot,
|
|
637
653
|
parentBlockRoot,
|
|
654
|
+
parentBlockHash,
|
|
638
655
|
feeRecipient: suggestedFeeRecipient,
|
|
639
656
|
});
|
|
640
657
|
|
|
641
658
|
payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
|
|
642
659
|
fork,
|
|
643
|
-
toRootHex(
|
|
660
|
+
toRootHex(parentBlockHash),
|
|
644
661
|
safeBlockHash,
|
|
645
662
|
finalizedBlockHash,
|
|
646
663
|
attributes
|
|
@@ -666,7 +683,7 @@ async function prepareExecutionPayloadHeader(
|
|
|
666
683
|
config: ChainForkConfig;
|
|
667
684
|
},
|
|
668
685
|
fork: ForkPostBellatrix,
|
|
669
|
-
state:
|
|
686
|
+
state: IBeaconStateViewBellatrix,
|
|
670
687
|
proposerPubKey: BLSPubkey
|
|
671
688
|
): Promise<{
|
|
672
689
|
header: ExecutionPayloadHeader;
|
|
@@ -692,20 +709,30 @@ export function getPayloadAttributesForSSE(
|
|
|
692
709
|
prepareState,
|
|
693
710
|
prepareSlot,
|
|
694
711
|
parentBlockRoot,
|
|
712
|
+
parentBlockHash,
|
|
695
713
|
feeRecipient,
|
|
696
|
-
}: {
|
|
714
|
+
}: {
|
|
715
|
+
prepareState: IBeaconStateViewBellatrix;
|
|
716
|
+
prepareSlot: Slot;
|
|
717
|
+
parentBlockRoot: Root;
|
|
718
|
+
parentBlockHash: Bytes32;
|
|
719
|
+
feeRecipient: string;
|
|
720
|
+
}
|
|
697
721
|
): SSEPayloadAttributes {
|
|
698
|
-
const parentHash = prepareState.latestBlockHash;
|
|
699
722
|
const payloadAttributes = preparePayloadAttributes(fork, chain, {
|
|
700
723
|
prepareState,
|
|
701
724
|
prepareSlot,
|
|
702
725
|
parentBlockRoot,
|
|
726
|
+
parentBlockHash,
|
|
703
727
|
feeRecipient,
|
|
704
728
|
});
|
|
705
729
|
|
|
706
730
|
let parentBlockNumber: number;
|
|
707
731
|
if (isForkPostGloas(fork)) {
|
|
708
|
-
const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
|
|
732
|
+
const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
|
|
733
|
+
toRootHex(parentBlockRoot),
|
|
734
|
+
toRootHex(parentBlockHash)
|
|
735
|
+
);
|
|
709
736
|
if (parentBlock?.executionPayloadBlockHash == null) {
|
|
710
737
|
throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
|
|
711
738
|
}
|
|
@@ -719,7 +746,7 @@ export function getPayloadAttributesForSSE(
|
|
|
719
746
|
proposalSlot: prepareSlot,
|
|
720
747
|
parentBlockNumber,
|
|
721
748
|
parentBlockRoot,
|
|
722
|
-
parentBlockHash
|
|
749
|
+
parentBlockHash,
|
|
723
750
|
payloadAttributes,
|
|
724
751
|
};
|
|
725
752
|
return ssePayloadAttributes;
|
|
@@ -734,11 +761,13 @@ function preparePayloadAttributes(
|
|
|
734
761
|
prepareState,
|
|
735
762
|
prepareSlot,
|
|
736
763
|
parentBlockRoot,
|
|
764
|
+
parentBlockHash,
|
|
737
765
|
feeRecipient,
|
|
738
766
|
}: {
|
|
739
|
-
prepareState:
|
|
767
|
+
prepareState: IBeaconStateViewBellatrix;
|
|
740
768
|
prepareSlot: Slot;
|
|
741
769
|
parentBlockRoot: Root;
|
|
770
|
+
parentBlockHash: Bytes32;
|
|
742
771
|
feeRecipient: string;
|
|
743
772
|
}
|
|
744
773
|
): SSEPayloadAttributes["payloadAttributes"] {
|
|
@@ -751,15 +780,34 @@ function preparePayloadAttributes(
|
|
|
751
780
|
};
|
|
752
781
|
|
|
753
782
|
if (ForkSeq[fork] >= ForkSeq.capella) {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
783
|
+
if (!isStatePostCapella(prepareState)) {
|
|
784
|
+
throw new Error("Expected Capella state for withdrawals");
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (isStatePostGloas(prepareState)) {
|
|
788
|
+
const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
|
|
789
|
+
// When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
|
|
790
|
+
// already deducted from CL balances but never credited on the EL (the envelope
|
|
791
|
+
// was not delivered). The next payload must carry those same withdrawals to
|
|
792
|
+
// restore CL/EL consistency, otherwise validators permanently lose that balance.
|
|
793
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = isExtendingPayload
|
|
794
|
+
? prepareState.getExpectedWithdrawals().expectedWithdrawals
|
|
795
|
+
: prepareState.payloadExpectedWithdrawals;
|
|
796
|
+
} else {
|
|
797
|
+
// withdrawals logic is now fork aware as it changes on electra fork post capella
|
|
798
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
799
|
+
prepareState.getExpectedWithdrawals().expectedWithdrawals;
|
|
800
|
+
}
|
|
757
801
|
}
|
|
758
802
|
|
|
759
803
|
if (ForkSeq[fork] >= ForkSeq.deneb) {
|
|
760
804
|
(payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
|
|
761
805
|
}
|
|
762
806
|
|
|
807
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
808
|
+
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
|
|
809
|
+
}
|
|
810
|
+
|
|
763
811
|
return payloadAttributes;
|
|
764
812
|
}
|
|
765
813
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
2
1
|
import {Root, RootHex, Slot} from "@lodestar/types";
|
|
3
2
|
|
|
4
3
|
export enum RegenErrorCode {
|
|
@@ -10,8 +9,6 @@ export enum RegenErrorCode {
|
|
|
10
9
|
BLOCK_NOT_IN_DB = "REGEN_ERROR_BLOCK_NOT_IN_DB",
|
|
11
10
|
STATE_TRANSITION_ERROR = "REGEN_ERROR_STATE_TRANSITION_ERROR",
|
|
12
11
|
INVALID_STATE_ROOT = "REGEN_ERROR_INVALID_STATE_ROOT",
|
|
13
|
-
UNEXPECTED_PAYLOAD_STATUS = "REGEN_ERROR_UNEXPECTED_PAYLOAD_STATUS",
|
|
14
|
-
INTERNAL_ERROR = "REGEN_ERROR_INTERNAL_ERROR",
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
export type RegenErrorType =
|
|
@@ -22,9 +19,7 @@ export type RegenErrorType =
|
|
|
22
19
|
| {code: RegenErrorCode.TOO_MANY_BLOCK_PROCESSED; stateRoot: RootHex | Root}
|
|
23
20
|
| {code: RegenErrorCode.BLOCK_NOT_IN_DB; blockRoot: RootHex | Root}
|
|
24
21
|
| {code: RegenErrorCode.STATE_TRANSITION_ERROR; error: Error}
|
|
25
|
-
| {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex}
|
|
26
|
-
| {code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS; blockRoot: RootHex | Root; payloadStatus: PayloadStatus}
|
|
27
|
-
| {code: RegenErrorCode.INTERNAL_ERROR; message: string};
|
|
22
|
+
| {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex};
|
|
28
23
|
|
|
29
24
|
export class RegenError extends Error {
|
|
30
25
|
type: RegenErrorType;
|
|
@@ -2,7 +2,7 @@ import {routes} from "@lodestar/api";
|
|
|
2
2
|
import {ProtoBlock} from "@lodestar/fork-choice";
|
|
3
3
|
import {IBeaconStateView} from "@lodestar/state-transition";
|
|
4
4
|
import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
|
|
5
|
-
import {
|
|
5
|
+
import {CheckpointHex} from "../stateCache/types.js";
|
|
6
6
|
|
|
7
7
|
export enum RegenCaller {
|
|
8
8
|
getDuties = "getDuties",
|
|
@@ -40,21 +40,15 @@ export interface IStateRegenerator extends IStateRegeneratorInternal {
|
|
|
40
40
|
dumpCacheSummary(): routes.lodestar.StateCacheItem[];
|
|
41
41
|
getStateSync(stateRoot: RootHex): IBeaconStateView | null;
|
|
42
42
|
getPreStateSync(block: BeaconBlock): IBeaconStateView | null;
|
|
43
|
-
getCheckpointStateOrBytes(cp:
|
|
44
|
-
getCheckpointStateSync(cp:
|
|
43
|
+
getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null>;
|
|
44
|
+
getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null;
|
|
45
45
|
getClosestHeadState(head: ProtoBlock): IBeaconStateView | null;
|
|
46
46
|
pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void;
|
|
47
47
|
pruneOnFinalized(finalizedEpoch: Epoch): void;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* payloadPresent is true if this is payload state, false if block state.
|
|
52
|
-
* payloadPresent is always true for pre-gloas.
|
|
53
|
-
*/
|
|
54
|
-
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, payloadPresent: boolean): void;
|
|
48
|
+
processState(blockRootHex: RootHex, postState: IBeaconStateView): void;
|
|
49
|
+
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void;
|
|
55
50
|
updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void;
|
|
56
|
-
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch
|
|
57
|
-
upgradeForGloas(epoch: Epoch): void;
|
|
51
|
+
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
54
|
/**
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
|
-
import {IForkChoice,
|
|
2
|
+
import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
3
3
|
import {IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
|
|
4
4
|
import {BeaconBlock, Epoch, RootHex, Slot, isGloasBeaconBlock, phase0} from "@lodestar/types";
|
|
5
|
-
import {Logger,
|
|
5
|
+
import {Logger, toRootHex} from "@lodestar/utils";
|
|
6
6
|
import {Metrics} from "../../metrics/index.js";
|
|
7
7
|
import {JobItemQueue} from "../../util/queue/index.js";
|
|
8
|
-
import {BlockStateCache,
|
|
8
|
+
import {BlockStateCache, CheckpointHex, CheckpointStateCache} from "../stateCache/types.js";
|
|
9
9
|
import {RegenError, RegenErrorCode} from "./errors.js";
|
|
10
10
|
import {
|
|
11
11
|
IStateRegenerator,
|
|
@@ -104,19 +104,9 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
104
104
|
const parentEpoch = computeEpochAtSlot(parentBlock.slot);
|
|
105
105
|
const blockEpoch = computeEpochAtSlot(block.slot);
|
|
106
106
|
|
|
107
|
-
// Convert PayloadStatus to payloadPresent boolean
|
|
108
|
-
if (parentBlock.payloadStatus === PayloadStatus.PENDING) {
|
|
109
|
-
throw new RegenError({
|
|
110
|
-
code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS,
|
|
111
|
-
blockRoot: block.parentRoot,
|
|
112
|
-
payloadStatus: parentBlock.payloadStatus,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const payloadPresent = parentBlock.payloadStatus === PayloadStatus.FULL;
|
|
116
|
-
|
|
117
107
|
// Check the checkpoint cache (if the pre-state is a checkpoint state)
|
|
118
108
|
if (parentEpoch < blockEpoch) {
|
|
119
|
-
const checkpointState = this.checkpointStateCache.getLatest(parentRoot, blockEpoch
|
|
109
|
+
const checkpointState = this.checkpointStateCache.getLatest(parentRoot, blockEpoch);
|
|
120
110
|
if (checkpointState && computeEpochAtSlot(checkpointState.slot) === blockEpoch) {
|
|
121
111
|
return checkpointState;
|
|
122
112
|
}
|
|
@@ -135,14 +125,14 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
135
125
|
return null;
|
|
136
126
|
}
|
|
137
127
|
|
|
138
|
-
async getCheckpointStateOrBytes(cp:
|
|
128
|
+
async getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null> {
|
|
139
129
|
return this.checkpointStateCache.getStateOrBytes(cp);
|
|
140
130
|
}
|
|
141
131
|
|
|
142
132
|
/**
|
|
143
133
|
* Get checkpoint state from cache
|
|
144
134
|
*/
|
|
145
|
-
getCheckpointStateSync(cp:
|
|
135
|
+
getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null {
|
|
146
136
|
return this.checkpointStateCache.get(cp);
|
|
147
137
|
}
|
|
148
138
|
|
|
@@ -150,19 +140,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
150
140
|
* Get state closest to head
|
|
151
141
|
*/
|
|
152
142
|
getClosestHeadState(head: ProtoBlock): IBeaconStateView | null {
|
|
153
|
-
|
|
154
|
-
if (head.payloadStatus === PayloadStatus.PENDING) {
|
|
155
|
-
throw new RegenError({
|
|
156
|
-
code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS,
|
|
157
|
-
blockRoot: fromHex(head.blockRoot),
|
|
158
|
-
payloadStatus: head.payloadStatus,
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
const payloadPresent = head.payloadStatus === PayloadStatus.FULL;
|
|
162
|
-
return (
|
|
163
|
-
this.checkpointStateCache.getLatest(head.blockRoot, Infinity, payloadPresent) ||
|
|
164
|
-
this.blockStateCache.get(head.stateRoot)
|
|
165
|
-
);
|
|
143
|
+
return this.checkpointStateCache.getLatest(head.blockRoot, Infinity) || this.blockStateCache.get(head.stateRoot);
|
|
166
144
|
}
|
|
167
145
|
|
|
168
146
|
pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void {
|
|
@@ -175,24 +153,15 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
175
153
|
this.blockStateCache.deleteAllBeforeEpoch(finalizedEpoch);
|
|
176
154
|
}
|
|
177
155
|
|
|
178
|
-
|
|
156
|
+
processState(blockRootHex: RootHex, postState: IBeaconStateView): void {
|
|
179
157
|
this.blockStateCache.add(postState);
|
|
180
158
|
this.checkpointStateCache.processState(blockRootHex, postState).catch((e) => {
|
|
181
159
|
this.logger.debug("Error processing block state", {blockRootHex, slot: postState.slot}, e);
|
|
182
160
|
});
|
|
183
161
|
}
|
|
184
162
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
*/
|
|
188
|
-
processPayloadState(payloadState: IBeaconStateView): void {
|
|
189
|
-
// Add payload state to block state cache (keyed by payload state root)
|
|
190
|
-
this.blockStateCache.add(payloadState);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// TODO GLOAS: This should also be called when importing execution payload after we implement it
|
|
194
|
-
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, payloadPresent: boolean): void {
|
|
195
|
-
this.checkpointStateCache.add(cp, item, payloadPresent);
|
|
163
|
+
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void {
|
|
164
|
+
this.checkpointStateCache.add(cp, item);
|
|
196
165
|
}
|
|
197
166
|
|
|
198
167
|
updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void {
|
|
@@ -228,13 +197,8 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
228
197
|
}
|
|
229
198
|
}
|
|
230
199
|
|
|
231
|
-
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch
|
|
232
|
-
return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
upgradeForGloas(epoch: Epoch): void {
|
|
236
|
-
this.logger.verbose("Upgrading block state cache for Gloas fork", {epoch});
|
|
237
|
-
this.blockStateCache.upgradeToGloas();
|
|
200
|
+
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null {
|
|
201
|
+
return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch);
|
|
238
202
|
}
|
|
239
203
|
|
|
240
204
|
/**
|
package/src/chain/regen/regen.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {IForkChoice,
|
|
3
|
-
import {
|
|
2
|
+
import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
3
|
+
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
4
4
|
import {
|
|
5
5
|
DataAvailabilityStatus,
|
|
6
6
|
ExecutionPayloadStatus,
|
|
@@ -110,19 +110,9 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
110
110
|
const {checkpointStateCache} = this.modules;
|
|
111
111
|
const epoch = computeEpochAtSlot(slot);
|
|
112
112
|
|
|
113
|
-
// Convert PayloadStatus to payloadPresent boolean
|
|
114
|
-
if (block.payloadStatus === PayloadStatus.PENDING) {
|
|
115
|
-
throw new RegenError({
|
|
116
|
-
code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS,
|
|
117
|
-
blockRoot: fromHex(blockRoot),
|
|
118
|
-
payloadStatus: block.payloadStatus,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
const payloadPresent = block.payloadStatus === PayloadStatus.FULL;
|
|
122
|
-
|
|
123
113
|
const latestCheckpointStateCtx = allowDiskReload
|
|
124
|
-
? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch
|
|
125
|
-
: checkpointStateCache.getLatest(blockRoot, epoch
|
|
114
|
+
? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch)
|
|
115
|
+
: checkpointStateCache.getLatest(blockRoot, epoch);
|
|
126
116
|
|
|
127
117
|
// If a checkpoint state exists with the given checkpoint root, it either is in requested epoch
|
|
128
118
|
// or needs to have empty slots processed until the requested epoch
|
|
@@ -176,18 +166,9 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
176
166
|
if (!lastBlockToReplay) continue;
|
|
177
167
|
const epoch = computeEpochAtSlot(lastBlockToReplay.slot - 1);
|
|
178
168
|
|
|
179
|
-
// Convert PayloadStatus to payloadPresent boolean
|
|
180
|
-
if (b.payloadStatus === PayloadStatus.PENDING) {
|
|
181
|
-
throw new RegenError({
|
|
182
|
-
code: RegenErrorCode.INTERNAL_ERROR,
|
|
183
|
-
message: `Unexpected PENDING payloadStatus for ancestor block ${b.blockRoot} at slot ${b.slot}`,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
const payloadPresent = b.payloadStatus === PayloadStatus.FULL;
|
|
187
|
-
|
|
188
169
|
state = allowDiskReload
|
|
189
|
-
? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch
|
|
190
|
-
: checkpointStateCache.getLatest(b.blockRoot, epoch
|
|
170
|
+
? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch)
|
|
171
|
+
: checkpointStateCache.getLatest(b.blockRoot, epoch);
|
|
191
172
|
if (state) {
|
|
192
173
|
break;
|
|
193
174
|
}
|
|
@@ -351,11 +332,6 @@ async function processSlotsByCheckpoint(
|
|
|
351
332
|
* emitting "checkpoint" events after every epoch processed.
|
|
352
333
|
*
|
|
353
334
|
* Stops processing after no more full epochs can be processed.
|
|
354
|
-
*
|
|
355
|
-
* Output state variant:
|
|
356
|
-
* - Post-Gloas: If slots are processed, returns block state (payloadPresent=false).
|
|
357
|
-
* If no slots processed, returns preState as-is (preserves variant).
|
|
358
|
-
* - Pre-Gloas: Always payloadPresent=true (no block/payload distinction).
|
|
359
335
|
*/
|
|
360
336
|
export async function processSlotsToNearestCheckpoint(
|
|
361
337
|
modules: {
|
|
@@ -375,7 +351,7 @@ export async function processSlotsToNearestCheckpoint(
|
|
|
375
351
|
const postSlot = slot;
|
|
376
352
|
const preEpoch = computeEpochAtSlot(preSlot);
|
|
377
353
|
let postState = preState;
|
|
378
|
-
const {
|
|
354
|
+
const {checkpointStateCache, emitter, metrics, logger} = modules;
|
|
379
355
|
let count = 0;
|
|
380
356
|
|
|
381
357
|
for (
|
|
@@ -399,11 +375,7 @@ export async function processSlotsToNearestCheckpoint(
|
|
|
399
375
|
// This may becomes the "official" checkpoint state if the 1st block of epoch is skipped
|
|
400
376
|
const checkpointState = postState;
|
|
401
377
|
const cp = getCheckpointFromState(checkpointState);
|
|
402
|
-
|
|
403
|
-
// Pre-Gloas: payloadPresent is always true (execution payload embedded in block)
|
|
404
|
-
// Post-Gloas: result is a block state (payloadPresent=false)
|
|
405
|
-
const isPayloadPresent = config.getForkSeq(checkpointState.slot) < ForkSeq.gloas;
|
|
406
|
-
checkpointStateCache.add(cp, checkpointState, isPayloadPresent);
|
|
378
|
+
checkpointStateCache.add(cp, checkpointState);
|
|
407
379
|
// consumers should not mutate state ever
|
|
408
380
|
emitter?.emit(ChainEvent.checkpoint, cp, checkpointState);
|
|
409
381
|
|
|
@@ -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
|
|
3
|
+
import {MapDef} 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
|
|
18
|
-
const serializedCheckpoint = checkpointToDatastoreKey(cpKey
|
|
17
|
+
async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise<DatastoreKey> {
|
|
18
|
+
const serializedCheckpoint = checkpointToDatastoreKey(cpKey);
|
|
19
19
|
await this.db.checkpointState.putBinary(serializedCheckpoint, stateBytes);
|
|
20
20
|
return serializedCheckpoint;
|
|
21
21
|
}
|
|
@@ -40,30 +40,18 @@ 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
|
-
|
|
48
43
|
export function datastoreKeyToCheckpoint(key: DatastoreKey): phase0.Checkpoint {
|
|
49
|
-
return ssz.phase0.Checkpoint.deserialize(
|
|
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;
|
|
44
|
+
return ssz.phase0.Checkpoint.deserialize(key);
|
|
58
45
|
}
|
|
59
46
|
|
|
60
|
-
function
|
|
61
|
-
return
|
|
47
|
+
export function checkpointToDatastoreKey(cp: phase0.Checkpoint): DatastoreKey {
|
|
48
|
+
return ssz.phase0.Checkpoint.serialize(cp);
|
|
62
49
|
}
|
|
63
50
|
|
|
64
51
|
/**
|
|
65
|
-
* Get the latest
|
|
66
|
-
* -
|
|
52
|
+
* Get the latest safe checkpoint state the node can use to boot from
|
|
53
|
+
* - it should be the checkpoint state that's unique in its epoch
|
|
54
|
+
* - its last processed block slot should be at epoch boundary or last slot of previous epoch
|
|
67
55
|
* - state slot should be at epoch boundary
|
|
68
56
|
* - state slot should be equal to epoch * SLOTS_PER_EPOCH
|
|
69
57
|
*
|
|
@@ -82,20 +70,9 @@ export async function getLatestSafeDatastoreKey(
|
|
|
82
70
|
|
|
83
71
|
const dataStoreKeyByEpoch: Map<Epoch, DatastoreKey> = new Map();
|
|
84
72
|
for (const [epoch, keys] of checkpointsByEpoch.entries()) {
|
|
73
|
+
// only consider epochs with a single checkpoint to avoid ambiguity from forks
|
|
85
74
|
if (keys.length === 1) {
|
|
86
|
-
// PRCS (skipped slot) or CRCS and no payloadPresent
|
|
87
|
-
// Pre-gloas always fall into this case
|
|
88
75
|
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
|
-
}
|
|
99
76
|
}
|
|
100
77
|
}
|
|
101
78
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {phase0} from "@lodestar/types";
|
|
2
|
+
import {phase0, ssz} 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 {
|
|
5
|
+
import {getLatestSafeDatastoreKey} from "./db.js";
|
|
6
6
|
import {CPStateDatastore, DatastoreKey} from "./types.js";
|
|
7
7
|
|
|
8
8
|
const CHECKPOINT_STATES_FOLDER = "checkpoint_states";
|
|
9
|
-
|
|
10
|
-
const CHECKPOINT_FILE_NAME_LENGTH = 84;
|
|
9
|
+
const CHECKPOINT_FILE_NAME_LENGTH = 82;
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* Implementation of CPStateDatastore using file system, this is beneficial for debugging.
|
|
@@ -29,8 +28,8 @@ export class FileCPStateDatastore implements CPStateDatastore {
|
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array
|
|
33
|
-
const serializedCheckpoint =
|
|
31
|
+
async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise<DatastoreKey> {
|
|
32
|
+
const serializedCheckpoint = ssz.phase0.Checkpoint.serialize(cpKey);
|
|
34
33
|
const filePath = path.join(this.folderPath, toHex(serializedCheckpoint));
|
|
35
34
|
await writeIfNotExist(filePath, stateBytes);
|
|
36
35
|
return serializedCheckpoint;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import {phase0} from "@lodestar/types";
|
|
2
2
|
|
|
3
|
-
// With db implementation, persistedKey is serialized data of a checkpoint
|
|
4
|
-
// ie a fixed size of `ssz.phase0.Checkpoint.minSize + 1`
|
|
3
|
+
// With db implementation, persistedKey is serialized data of a checkpoint
|
|
5
4
|
export type DatastoreKey = Uint8Array;
|
|
6
5
|
|
|
7
6
|
// Make this generic to support testing
|
|
8
7
|
export interface CPStateDatastore {
|
|
9
|
-
write: (cpKey: phase0.Checkpoint, stateBytes: Uint8Array
|
|
8
|
+
write: (cpKey: phase0.Checkpoint, stateBytes: Uint8Array) => Promise<DatastoreKey>;
|
|
10
9
|
remove: (key: DatastoreKey) => Promise<void>;
|
|
11
10
|
read: (key: DatastoreKey) => Promise<Uint8Array | null>;
|
|
12
11
|
readLatestSafe: () => Promise<Uint8Array | null>;
|
|
@@ -20,11 +20,6 @@ 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;
|
|
28
23
|
|
|
29
24
|
/**
|
|
30
25
|
* New implementation of BlockStateCache that keeps the most recent n states consistently
|
|
@@ -46,7 +41,7 @@ export const DEFAULT_MAX_BLOCK_STATES_GLOAS = 128;
|
|
|
46
41
|
* The maintained key order would be: 11 -> 13 -> 12 -> 10, and state 10 will be pruned first.
|
|
47
42
|
*/
|
|
48
43
|
export class FIFOBlockStateCache implements BlockStateCache {
|
|
49
|
-
|
|
44
|
+
readonly maxStates: number;
|
|
50
45
|
|
|
51
46
|
private readonly cache: MapTracker<string, IBeaconStateView>;
|
|
52
47
|
/**
|
|
@@ -172,10 +167,6 @@ export class FIFOBlockStateCache implements BlockStateCache {
|
|
|
172
167
|
}
|
|
173
168
|
}
|
|
174
169
|
|
|
175
|
-
upgradeToGloas(): void {
|
|
176
|
-
this.maxStates = DEFAULT_MAX_BLOCK_STATES_GLOAS;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
170
|
/**
|
|
180
171
|
* No need for this implementation
|
|
181
172
|
* This is only to conform to the old api
|