@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
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
computeStartSlotAtEpoch,
|
|
26
26
|
computeTimeAtSlot,
|
|
27
27
|
getCurrentSlot,
|
|
28
|
+
isStatePostAltair,
|
|
28
29
|
proposerShufflingDecisionRoot,
|
|
29
30
|
} from "@lodestar/state-transition";
|
|
30
31
|
import {
|
|
@@ -69,7 +70,7 @@ import {ChainEvent, CommonBlockBody} from "../../../chain/index.js";
|
|
|
69
70
|
import {PREPARE_NEXT_SLOT_BPS} from "../../../chain/prepareNextSlot.js";
|
|
70
71
|
import {BlockType, ProduceFullDeneb, ProduceFullGloas} from "../../../chain/produceBlock/index.js";
|
|
71
72
|
import {RegenCaller} from "../../../chain/regen/index.js";
|
|
72
|
-
import {
|
|
73
|
+
import {CheckpointHex} from "../../../chain/stateCache/types.js";
|
|
73
74
|
import {validateApiAggregateAndProof} from "../../../chain/validation/index.js";
|
|
74
75
|
import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/validation/syncCommitteeContributionAndProof.js";
|
|
75
76
|
import {ZERO_HASH} from "../../../constants/index.js";
|
|
@@ -300,7 +301,7 @@ export function getValidatorApi(
|
|
|
300
301
|
* |
|
|
301
302
|
* prepareNextSlot (4s before next slot)
|
|
302
303
|
*/
|
|
303
|
-
async function waitForCheckpointState(cpHex:
|
|
304
|
+
async function waitForCheckpointState(cpHex: CheckpointHex): Promise<IBeaconStateView | null> {
|
|
304
305
|
const cpState = chain.regen.getCheckpointStateSync(cpHex);
|
|
305
306
|
if (cpState) {
|
|
306
307
|
return cpState;
|
|
@@ -1112,7 +1113,6 @@ export function getValidatorApi(
|
|
|
1112
1113
|
const cpState = await waitForCheckpointState({
|
|
1113
1114
|
rootHex: head.blockRoot,
|
|
1114
1115
|
epoch,
|
|
1115
|
-
payloadPresent: head.payloadStatus === PayloadStatus.FULL,
|
|
1116
1116
|
});
|
|
1117
1117
|
if (cpState) {
|
|
1118
1118
|
state = cpState;
|
|
@@ -1282,6 +1282,9 @@ export function getValidatorApi(
|
|
|
1282
1282
|
if (indices.length === 0) {
|
|
1283
1283
|
throw new ApiError(400, "No validator to get attester duties");
|
|
1284
1284
|
}
|
|
1285
|
+
if (epoch < config.ALTAIR_FORK_EPOCH) {
|
|
1286
|
+
throw new ApiError(400, "Sync committee duties are not supported before Altair");
|
|
1287
|
+
}
|
|
1285
1288
|
|
|
1286
1289
|
// May request for an epoch that's in the future
|
|
1287
1290
|
await waitForNextClosestEpoch();
|
|
@@ -1291,6 +1294,9 @@ export function getValidatorApi(
|
|
|
1291
1294
|
// Note: does not support requesting past duties
|
|
1292
1295
|
const head = chain.forkChoice.getHead();
|
|
1293
1296
|
const state = chain.getHeadState();
|
|
1297
|
+
if (!isStatePostAltair(state)) {
|
|
1298
|
+
throw new ApiError(400, "Sync committee duties are not available before Altair");
|
|
1299
|
+
}
|
|
1294
1300
|
|
|
1295
1301
|
// Check that all validatorIndex belong to the state before calling getCommitteeAssignments()
|
|
1296
1302
|
const pubkeys = getPubkeysForIndices(state, indices);
|
|
@@ -1635,7 +1641,7 @@ export function getValidatorApi(
|
|
|
1635
1641
|
throw Error("Cached block production result is not full block");
|
|
1636
1642
|
}
|
|
1637
1643
|
|
|
1638
|
-
const {executionPayload, executionRequests
|
|
1644
|
+
const {executionPayload, executionRequests} = produceResult as ProduceFullGloas;
|
|
1639
1645
|
|
|
1640
1646
|
const envelope: gloas.ExecutionPayloadEnvelope = {
|
|
1641
1647
|
payload: executionPayload,
|
|
@@ -1643,7 +1649,9 @@ export function getValidatorApi(
|
|
|
1643
1649
|
builderIndex: BUILDER_INDEX_SELF_BUILD,
|
|
1644
1650
|
beaconBlockRoot,
|
|
1645
1651
|
slot,
|
|
1646
|
-
|
|
1652
|
+
// TODO GLOAS: stateRoot is no longer computed during block production.
|
|
1653
|
+
// This field will be removed when we implement defer payload processing
|
|
1654
|
+
stateRoot: ZERO_HASH,
|
|
1647
1655
|
};
|
|
1648
1656
|
|
|
1649
1657
|
logger.info("Produced execution payload envelope", {
|
|
@@ -44,7 +44,7 @@ export class GetBlobsTracker {
|
|
|
44
44
|
this.config = init.config;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
triggerGetBlobs(input: IBlockInput | PayloadEnvelopeInput
|
|
47
|
+
triggerGetBlobs(input: IBlockInput | PayloadEnvelopeInput): void {
|
|
48
48
|
if (this.activeReconstructions.has(input.blockRootHex)) {
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
@@ -101,7 +101,6 @@ export class GetBlobsTracker {
|
|
|
101
101
|
.then((result) => {
|
|
102
102
|
this.logger.debug("getBlobsV2 result for block", {...logCtx, result});
|
|
103
103
|
this.metrics?.dataColumns.dataColumnEngineResult.inc({result});
|
|
104
|
-
onComplete?.();
|
|
105
104
|
})
|
|
106
105
|
.catch((error) => {
|
|
107
106
|
this.logger.debug("Error during getBlobsV2 for block", logCtx, error as Error);
|
|
@@ -9,7 +9,6 @@ import {AllocSource, BufferPool} from "../../../util/bufferPool.js";
|
|
|
9
9
|
import {getStateSlotFromBytes} from "../../../util/multifork.js";
|
|
10
10
|
import {IStateRegenerator} from "../../regen/interface.js";
|
|
11
11
|
import {serializeState} from "../../serializeState.js";
|
|
12
|
-
import {fcCheckpointToHexPayload} from "../../stateCache/persistentCheckpointsCache.js";
|
|
13
12
|
import {StateArchiveStrategy, StatesArchiveOpts} from "../interface.js";
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -108,9 +107,8 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
|
|
|
108
107
|
async archiveState(finalized: CheckpointWithPayloadStatus, metrics?: Metrics | null): Promise<void> {
|
|
109
108
|
// starting from Mar 2024, the finalized state could be from disk or in memory
|
|
110
109
|
let timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalizedHexPayload);
|
|
110
|
+
const finalizedHex = {epoch: finalized.epoch, rootHex: finalized.rootHex};
|
|
111
|
+
const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalizedHex);
|
|
114
112
|
timer?.({step: FrequencyStateArchiveStep.GetFinalizedState});
|
|
115
113
|
|
|
116
114
|
const {rootHex} = finalized;
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
ForkChoiceErrorCode,
|
|
9
9
|
NotReorgedReason,
|
|
10
10
|
getSafeExecutionBlockHash,
|
|
11
|
-
isGloasBlock,
|
|
12
11
|
} from "@lodestar/fork-choice";
|
|
13
12
|
import {
|
|
14
13
|
ForkPostAltair,
|
|
@@ -25,6 +24,8 @@ import {
|
|
|
25
24
|
computeStartSlotAtEpoch,
|
|
26
25
|
computeTimeAtSlot,
|
|
27
26
|
isStartSlotOfEpoch,
|
|
27
|
+
isStatePostAltair,
|
|
28
|
+
isStatePostBellatrix,
|
|
28
29
|
} from "@lodestar/state-transition";
|
|
29
30
|
import {
|
|
30
31
|
Attestation,
|
|
@@ -46,7 +47,7 @@ import type {BeaconChain} from "../chain.js";
|
|
|
46
47
|
import {ChainEvent, ReorgEventData} from "../emitter.js";
|
|
47
48
|
import {ForkchoiceCaller} from "../forkChoice/index.js";
|
|
48
49
|
import {REPROCESS_MIN_TIME_TO_NEXT_SLOT_SEC} from "../reprocess.js";
|
|
49
|
-
import {
|
|
50
|
+
import {toCheckpointHex} from "../stateCache/persistentCheckpointsCache.js";
|
|
50
51
|
import {isBlockInputBlobs, isBlockInputColumns} from "./blockInput/blockInput.js";
|
|
51
52
|
import {AttestationImportOpt, FullyVerifiedBlock, ImportBlockOpts} from "./types.js";
|
|
52
53
|
import {getCheckpointFromState} from "./utils/checkpoint.js";
|
|
@@ -85,7 +86,7 @@ export async function importBlock(
|
|
|
85
86
|
fullyVerifiedBlock: FullyVerifiedBlock,
|
|
86
87
|
opts: ImportBlockOpts
|
|
87
88
|
): Promise<void> {
|
|
88
|
-
const {blockInput,
|
|
89
|
+
const {blockInput, postState, parentBlockSlot, executionStatus, dataAvailabilityStatus, indexedAttestations} =
|
|
89
90
|
fullyVerifiedBlock;
|
|
90
91
|
const block = blockInput.getBlock();
|
|
91
92
|
const source = blockInput.getBlockSource();
|
|
@@ -97,7 +98,7 @@ export async function importBlock(
|
|
|
97
98
|
const blockEpoch = computeEpochAtSlot(blockSlot);
|
|
98
99
|
const prevFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
|
|
99
100
|
const blockDelaySec =
|
|
100
|
-
fullyVerifiedBlock.seenTimestampSec - computeTimeAtSlot(this.config, blockSlot,
|
|
101
|
+
fullyVerifiedBlock.seenTimestampSec - computeTimeAtSlot(this.config, blockSlot, postState.genesisTime);
|
|
101
102
|
const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000);
|
|
102
103
|
const fork = this.config.getForkSeq(blockSlot);
|
|
103
104
|
|
|
@@ -120,10 +121,10 @@ export async function importBlock(
|
|
|
120
121
|
// 2. Import block to fork choice
|
|
121
122
|
|
|
122
123
|
// Should compute checkpoint balances before forkchoice.onBlock
|
|
123
|
-
this.checkpointBalancesCache.processState(blockRootHex,
|
|
124
|
+
this.checkpointBalancesCache.processState(blockRootHex, postState);
|
|
124
125
|
const blockSummary = this.forkChoice.onBlock(
|
|
125
126
|
block.message,
|
|
126
|
-
|
|
127
|
+
postState,
|
|
127
128
|
blockDelaySec,
|
|
128
129
|
currentSlot,
|
|
129
130
|
fork >= ForkSeq.gloas ? ExecutionStatus.PayloadSeparated : executionStatus,
|
|
@@ -132,11 +133,7 @@ export async function importBlock(
|
|
|
132
133
|
|
|
133
134
|
// This adds the state necessary to process the next block
|
|
134
135
|
// Some block event handlers require state being in state cache so need to do this before emitting EventType.block
|
|
135
|
-
|
|
136
|
-
// Post-Gloas: blockSummary.payloadStatus is always PENDING, so payloadPresent = false (block state only, no payload processing yet)
|
|
137
|
-
const payloadPresent = !isGloasBlock(blockSummary);
|
|
138
|
-
// processState manages both block state and payload state variants together for memory/disk management
|
|
139
|
-
this.regen.processBlockState(blockRootHex, postBlockState);
|
|
136
|
+
this.regen.processState(blockRootHex, postState);
|
|
140
137
|
|
|
141
138
|
// For Gloas blocks, create PayloadEnvelopeInput so it's available for later payload import
|
|
142
139
|
if (fork >= ForkSeq.gloas) {
|
|
@@ -159,17 +156,9 @@ export async function importBlock(
|
|
|
159
156
|
// which is all the information we need so there is no reason to delay until execution payload arrives
|
|
160
157
|
// TODO GLOAS: If we want EL retries after this initial attempt, add an explicit retry policy here
|
|
161
158
|
// (for example later in the slot). Do not couple retries to incoming gossip columns.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this.processExecutionPayload(payloadInput, {validSignature: true}).catch((e) => {
|
|
166
|
-
this.logger.debug(
|
|
167
|
-
"Error processing execution payload after getBlobs",
|
|
168
|
-
{slot: blockSlot, root: blockRootHex},
|
|
169
|
-
e as Error
|
|
170
|
-
);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
159
|
+
// Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
|
|
160
|
+
// in-flight importExecutionPayload. No processExecutionPayload trigger needed from this path.
|
|
161
|
+
this.getBlobsTracker.triggerGetBlobs(payloadInput);
|
|
173
162
|
}
|
|
174
163
|
|
|
175
164
|
this.metrics?.importBlock.bySource.inc({source: source.source});
|
|
@@ -189,7 +178,7 @@ export async function importBlock(
|
|
|
189
178
|
(opts.importAttestations !== AttestationImportOpt.Skip && blockEpoch >= currentEpoch - FORK_CHOICE_ATT_EPOCH_LIMIT)
|
|
190
179
|
) {
|
|
191
180
|
const attestations = block.message.body.attestations;
|
|
192
|
-
const rootCache = new RootCache(
|
|
181
|
+
const rootCache = new RootCache(postState);
|
|
193
182
|
const invalidAttestationErrorsByCode = new Map<string, {error: Error; count: number}>();
|
|
194
183
|
|
|
195
184
|
const addAttestation = fork >= ForkSeq.electra ? addAttestationPostElectra : addAttestationPreElectra;
|
|
@@ -203,7 +192,7 @@ export async function importBlock(
|
|
|
203
192
|
const attDataRoot = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(indexedAttestation.data));
|
|
204
193
|
addAttestation.call(
|
|
205
194
|
this,
|
|
206
|
-
|
|
195
|
+
postState,
|
|
207
196
|
target,
|
|
208
197
|
attDataRoot,
|
|
209
198
|
attestation as Attestation<ForkPostElectra>,
|
|
@@ -318,7 +307,7 @@ export async function importBlock(
|
|
|
318
307
|
|
|
319
308
|
if (newHead.blockRoot !== oldHead.blockRoot) {
|
|
320
309
|
// Set head state as strong reference
|
|
321
|
-
this.regen.updateHeadState(newHead,
|
|
310
|
+
this.regen.updateHeadState(newHead, postState);
|
|
322
311
|
|
|
323
312
|
try {
|
|
324
313
|
this.emitter.emit(routes.events.EventType.head, {
|
|
@@ -388,11 +377,13 @@ export async function importBlock(
|
|
|
388
377
|
// we want to import block asap so do this in the next event loop
|
|
389
378
|
callInNextEventLoop(() => {
|
|
390
379
|
try {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
380
|
+
if (isStatePostAltair(postState)) {
|
|
381
|
+
this.lightClientServer?.onImportBlockHead(
|
|
382
|
+
block.message as BeaconBlock<ForkPostAltair>,
|
|
383
|
+
postState,
|
|
384
|
+
parentBlockSlot
|
|
385
|
+
);
|
|
386
|
+
}
|
|
396
387
|
} catch (e) {
|
|
397
388
|
this.logger.verbose("Error lightClientServer.onImportBlock", {slot: blockSlot}, e as Error);
|
|
398
389
|
}
|
|
@@ -411,11 +402,11 @@ export async function importBlock(
|
|
|
411
402
|
// and the block is weak and can potentially be reorged out.
|
|
412
403
|
let shouldOverrideFcu = false;
|
|
413
404
|
|
|
414
|
-
if (blockSlot >= currentSlot &&
|
|
405
|
+
if (blockSlot >= currentSlot && isStatePostBellatrix(postState) && postState.isExecutionStateType) {
|
|
415
406
|
let notOverrideFcuReason = NotReorgedReason.Unknown;
|
|
416
407
|
const proposalSlot = blockSlot + 1;
|
|
417
408
|
try {
|
|
418
|
-
const proposerIndex =
|
|
409
|
+
const proposerIndex = postState.getBeaconProposer(proposalSlot);
|
|
419
410
|
const feeRecipient = this.beaconProposerCache.get(proposerIndex);
|
|
420
411
|
|
|
421
412
|
if (feeRecipient) {
|
|
@@ -495,27 +486,27 @@ export async function importBlock(
|
|
|
495
486
|
}
|
|
496
487
|
}
|
|
497
488
|
|
|
498
|
-
if (!
|
|
499
|
-
this.logger.verbose("After importBlock caching postState without SSZ cache", {slot:
|
|
489
|
+
if (!postState.isStateValidatorsNodesPopulated()) {
|
|
490
|
+
this.logger.verbose("After importBlock caching postState without SSZ cache", {slot: postState.slot});
|
|
500
491
|
}
|
|
501
492
|
|
|
502
493
|
// Cache shufflings when crossing an epoch boundary
|
|
503
494
|
const parentEpoch = computeEpochAtSlot(parentBlockSlot);
|
|
504
495
|
if (parentEpoch < blockEpoch) {
|
|
505
|
-
this.shufflingCache.processState(
|
|
496
|
+
this.shufflingCache.processState(postState);
|
|
506
497
|
this.logger.verbose("Processed shuffling for next epoch", {parentEpoch, blockEpoch, slot: blockSlot});
|
|
507
498
|
}
|
|
508
499
|
|
|
509
500
|
if (blockSlot % SLOTS_PER_EPOCH === 0) {
|
|
510
501
|
// Cache state to preserve epoch transition work
|
|
511
|
-
const checkpointState =
|
|
502
|
+
const checkpointState = postState;
|
|
512
503
|
const cp = getCheckpointFromState(checkpointState);
|
|
513
|
-
this.regen.addCheckpointState(cp, checkpointState
|
|
504
|
+
this.regen.addCheckpointState(cp, checkpointState);
|
|
514
505
|
// consumers should not mutate state ever
|
|
515
506
|
this.emitter.emit(ChainEvent.checkpoint, cp, checkpointState);
|
|
516
507
|
|
|
517
508
|
// Note: in-lined code from previos handler of ChainEvent.checkpoint
|
|
518
|
-
this.logger.verbose("Checkpoint processed",
|
|
509
|
+
this.logger.verbose("Checkpoint processed", toCheckpointHex(cp));
|
|
519
510
|
|
|
520
511
|
const activeValidatorsCount = checkpointState.activeValidatorCount;
|
|
521
512
|
this.metrics?.currentActiveValidators.set(activeValidatorsCount);
|
|
@@ -533,7 +524,7 @@ export async function importBlock(
|
|
|
533
524
|
const justifiedEpoch = justifiedCheckpoint.epoch;
|
|
534
525
|
const preJustifiedEpoch = parentBlockSummary.justifiedEpoch;
|
|
535
526
|
if (justifiedEpoch > preJustifiedEpoch) {
|
|
536
|
-
this.logger.verbose("Checkpoint justified",
|
|
527
|
+
this.logger.verbose("Checkpoint justified", toCheckpointHex(justifiedCheckpoint));
|
|
537
528
|
this.metrics?.previousJustifiedEpoch.set(checkpointState.previousJustifiedCheckpoint.epoch);
|
|
538
529
|
this.metrics?.currentJustifiedEpoch.set(justifiedCheckpoint.epoch);
|
|
539
530
|
}
|
|
@@ -547,7 +538,7 @@ export async function importBlock(
|
|
|
547
538
|
state: toRootHex(checkpointState.hashTreeRoot()),
|
|
548
539
|
executionOptimistic: false,
|
|
549
540
|
});
|
|
550
|
-
this.logger.verbose("Checkpoint finalized",
|
|
541
|
+
this.logger.verbose("Checkpoint finalized", toCheckpointHex(finalizedCheckpoint));
|
|
551
542
|
this.metrics?.finalizedEpoch.set(finalizedCheckpoint.epoch);
|
|
552
543
|
}
|
|
553
544
|
}
|
|
@@ -598,11 +589,11 @@ export async function importBlock(
|
|
|
598
589
|
this.metrics?.parentBlockDistance.observe(blockSlot - parentBlockSlot);
|
|
599
590
|
this.metrics?.proposerBalanceDeltaAny.observe(fullyVerifiedBlock.proposerBalanceDelta);
|
|
600
591
|
this.validatorMonitor?.registerImportedBlock(block.message, fullyVerifiedBlock);
|
|
601
|
-
if (
|
|
592
|
+
if (isStatePostAltair(fullyVerifiedBlock.postState)) {
|
|
602
593
|
this.validatorMonitor?.registerSyncAggregateInBlock(
|
|
603
594
|
blockEpoch,
|
|
604
595
|
(block as altair.SignedBeaconBlock).message.body.syncAggregate,
|
|
605
|
-
fullyVerifiedBlock.
|
|
596
|
+
fullyVerifiedBlock.postState.currentSyncCommitteeIndexed.validatorIndices
|
|
606
597
|
);
|
|
607
598
|
}
|
|
608
599
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
|
|
3
3
|
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
4
|
-
import {getExecutionPayloadEnvelopeSignatureSet} from "@lodestar/state-transition";
|
|
4
|
+
import {getExecutionPayloadEnvelopeSignatureSet, isStatePostGloas} from "@lodestar/state-transition";
|
|
5
5
|
import {byteArrayEquals, fromHex, toRootHex} from "@lodestar/utils";
|
|
6
6
|
import {ExecutionPayloadStatus} from "../../execution/index.js";
|
|
7
7
|
import {isQueueErrorAborted} from "../../util/queue/index.js";
|
|
@@ -9,6 +9,7 @@ import {BeaconChain} from "../chain.js";
|
|
|
9
9
|
import {RegenCaller} from "../regen/interface.js";
|
|
10
10
|
import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
|
|
11
11
|
import {ImportPayloadOpts} from "./types.js";
|
|
12
|
+
import {verifyPayloadsDataAvailability} from "./verifyPayloadsDataAvailability.js";
|
|
12
13
|
|
|
13
14
|
const EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS = 64;
|
|
14
15
|
|
|
@@ -84,6 +85,7 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
|
|
|
84
85
|
export async function importExecutionPayload(
|
|
85
86
|
this: BeaconChain,
|
|
86
87
|
payloadInput: PayloadEnvelopeInput,
|
|
88
|
+
signal: AbortSignal,
|
|
87
89
|
opts: ImportPayloadOpts = {}
|
|
88
90
|
): Promise<void> {
|
|
89
91
|
const signedEnvelope = payloadInput.getPayloadEnvelope();
|
|
@@ -96,7 +98,7 @@ export async function importExecutionPayload(
|
|
|
96
98
|
// is already complete, so the payload and required data are available for payload attestation.
|
|
97
99
|
// This event is only about availability, not validity of the execution payload, hence we can emit
|
|
98
100
|
// it before getting a response from the execution client on whether the payload is valid or not.
|
|
99
|
-
if (this.clock.currentSlot
|
|
101
|
+
if (this.clock.currentSlot - envelope.slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
|
|
100
102
|
this.emitter.emit(routes.events.EventType.executionPayloadAvailable, {
|
|
101
103
|
slot: envelope.slot,
|
|
102
104
|
blockRoot: blockRootHex,
|
|
@@ -112,11 +114,15 @@ export async function importExecutionPayload(
|
|
|
112
114
|
});
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
// 3.
|
|
117
|
+
// 3. Wait for data columns to be available before claiming a write-queue slot.
|
|
118
|
+
// The helper is shared with future gloas sync services; take the single-item batch form here.
|
|
119
|
+
await verifyPayloadsDataAvailability([payloadInput], signal);
|
|
120
|
+
|
|
121
|
+
// 4. Apply backpressure from the write queue, before doing verification work.
|
|
116
122
|
// The actual DB write is deferred until after verification succeeds.
|
|
117
123
|
await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
|
|
118
124
|
|
|
119
|
-
//
|
|
125
|
+
// 5. Get pre-state for processExecutionPayloadEnvelope
|
|
120
126
|
// We need the block state (post-block, pre-payload) to process the envelope
|
|
121
127
|
const blockState = await this.regen.getBlockSlotState(
|
|
122
128
|
protoBlock,
|
|
@@ -124,10 +130,14 @@ export async function importExecutionPayload(
|
|
|
124
130
|
{dontTransferCache: true},
|
|
125
131
|
RegenCaller.processBlock
|
|
126
132
|
);
|
|
133
|
+
if (!isStatePostGloas(blockState)) {
|
|
134
|
+
throw new PayloadError({
|
|
135
|
+
code: PayloadErrorCode.STATE_TRANSITION_ERROR,
|
|
136
|
+
message: `Expected gloas+ block state for payload import, got fork=${blockState.forkName}`,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
127
139
|
|
|
128
|
-
//
|
|
129
|
-
// Note: No data availability check needed here - importExecutionPayload is only
|
|
130
|
-
// called when payloadInput.isComplete() is true, so all data is already available.
|
|
140
|
+
// 6. Run verification steps in parallel
|
|
131
141
|
const [execResult, signatureValid, postPayloadResult] = await Promise.all([
|
|
132
142
|
this.executionEngine.notifyNewPayload(
|
|
133
143
|
fork,
|
|
@@ -218,7 +228,7 @@ export async function importExecutionPayload(
|
|
|
218
228
|
if (!isQueueErrorAborted(e)) {
|
|
219
229
|
this.logger.error(
|
|
220
230
|
"Error pushing payload envelope to unfinalized write queue",
|
|
221
|
-
{slot: envelope.slot,
|
|
231
|
+
{slot: envelope.slot, blockRoot: blockRootHex},
|
|
222
232
|
e as Error
|
|
223
233
|
);
|
|
224
234
|
}
|
|
@@ -234,10 +244,10 @@ export async function importExecutionPayload(
|
|
|
234
244
|
);
|
|
235
245
|
|
|
236
246
|
// 8. Cache payload state
|
|
237
|
-
this.regen.
|
|
247
|
+
this.regen.processState(blockRootHex, postPayloadState);
|
|
238
248
|
if (postPayloadState.slot % SLOTS_PER_EPOCH === 0) {
|
|
239
249
|
const {checkpoint} = postPayloadState.computeAnchorCheckpoint();
|
|
240
|
-
this.regen.addCheckpointState(checkpoint, postPayloadState
|
|
250
|
+
this.regen.addCheckpointState(checkpoint, postPayloadState);
|
|
241
251
|
}
|
|
242
252
|
|
|
243
253
|
// 9. Record metrics for payload envelope and column sources
|
|
@@ -246,6 +256,8 @@ export async function importExecutionPayload(
|
|
|
246
256
|
this.metrics?.importPayload.columnsBySource.inc({source});
|
|
247
257
|
}
|
|
248
258
|
|
|
259
|
+
const stateRootHex = toRootHex(envelope.stateRoot);
|
|
260
|
+
|
|
249
261
|
// 10. Emit event after payload is fully verified and imported to fork choice, only for recent enough payloads
|
|
250
262
|
if (this.clock.currentSlot - envelope.slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
|
|
251
263
|
this.emitter.emit(routes.events.EventType.executionPayload, {
|
|
@@ -253,7 +265,7 @@ export async function importExecutionPayload(
|
|
|
253
265
|
builderIndex: envelope.builderIndex,
|
|
254
266
|
blockHash: blockHashHex,
|
|
255
267
|
blockRoot: blockRootHex,
|
|
256
|
-
stateRoot:
|
|
268
|
+
stateRoot: stateRootHex,
|
|
257
269
|
// TODO GLOAS: revisit once we support optimistic import
|
|
258
270
|
executionOptimistic: false,
|
|
259
271
|
});
|
|
@@ -261,7 +273,9 @@ export async function importExecutionPayload(
|
|
|
261
273
|
|
|
262
274
|
this.logger.verbose("Execution payload imported", {
|
|
263
275
|
slot: envelope.slot,
|
|
264
|
-
|
|
276
|
+
builderIndex: envelope.builderIndex,
|
|
277
|
+
blockRoot: blockRootHex,
|
|
265
278
|
blockHash: blockHashHex,
|
|
279
|
+
stateRoot: stateRootHex,
|
|
266
280
|
});
|
|
267
281
|
}
|
|
@@ -88,8 +88,8 @@ export async function processBlocks(
|
|
|
88
88
|
const fullyVerifiedBlocks = relevantBlocks.map(
|
|
89
89
|
(block, i): FullyVerifiedBlock => ({
|
|
90
90
|
blockInput: block,
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
postState: postStates[i],
|
|
92
|
+
postPayloadState: null,
|
|
93
93
|
parentBlockSlot: parentSlots[i],
|
|
94
94
|
executionStatus: executionStatuses[i],
|
|
95
95
|
// start supporting optimistic syncing/processing
|
|
@@ -73,6 +73,7 @@ export class PayloadEnvelopeInput {
|
|
|
73
73
|
private timeCreatedSec: number;
|
|
74
74
|
|
|
75
75
|
private readonly payloadEnvelopeDataPromise: PromiseParts<gloas.SignedExecutionPayloadEnvelope>;
|
|
76
|
+
private readonly allDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
|
|
76
77
|
private readonly columnsDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
|
|
77
78
|
|
|
78
79
|
state: PayloadEnvelopeInputState;
|
|
@@ -97,6 +98,7 @@ export class PayloadEnvelopeInput {
|
|
|
97
98
|
this.custodyColumns = props.custodyColumns;
|
|
98
99
|
this.timeCreatedSec = props.timeCreatedSec;
|
|
99
100
|
this.payloadEnvelopeDataPromise = createPromise();
|
|
101
|
+
this.allDataPromise = createPromise();
|
|
100
102
|
this.columnsDataPromise = createPromise();
|
|
101
103
|
|
|
102
104
|
const noBlobs = props.bid.blobKzgCommitments.length === 0;
|
|
@@ -105,6 +107,7 @@ export class PayloadEnvelopeInput {
|
|
|
105
107
|
|
|
106
108
|
if (hasAllData) {
|
|
107
109
|
this.state = {hasPayload: false, hasAllData: true, hasComputedAllData: true};
|
|
110
|
+
this.allDataPromise.resolve(this.getSampledColumns());
|
|
108
111
|
this.columnsDataPromise.resolve(this.getSampledColumns());
|
|
109
112
|
} else {
|
|
110
113
|
this.state = {hasPayload: false, hasAllData: false, hasComputedAllData: false};
|
|
@@ -203,6 +206,12 @@ export class PayloadEnvelopeInput {
|
|
|
203
206
|
return true;
|
|
204
207
|
}
|
|
205
208
|
|
|
209
|
+
// Resolve allDataPromise on the first transition to hasAllData (either sampled-complete or
|
|
210
|
+
// reconstruction-threshold branch). Guarded so it fires exactly once.
|
|
211
|
+
if (!this.state.hasAllData && hasAllData) {
|
|
212
|
+
this.allDataPromise.resolve(sampledColumns);
|
|
213
|
+
}
|
|
214
|
+
|
|
206
215
|
if (hasComputedAllData) {
|
|
207
216
|
this.columnsDataPromise.resolve(sampledColumns);
|
|
208
217
|
}
|
|
@@ -315,6 +324,24 @@ export class PayloadEnvelopeInput {
|
|
|
315
324
|
return this.state.hasComputedAllData;
|
|
316
325
|
}
|
|
317
326
|
|
|
327
|
+
waitForAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
|
|
328
|
+
if (this.state.hasAllData) {
|
|
329
|
+
return Promise.resolve(this.getSampledColumns());
|
|
330
|
+
}
|
|
331
|
+
return withTimeout(() => this.allDataPromise.promise, timeout, signal);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async waitForEnvelopeAndAllData(timeout: number, signal?: AbortSignal): Promise<this> {
|
|
335
|
+
if (!this.state.hasPayload || !this.state.hasAllData) {
|
|
336
|
+
await withTimeout(
|
|
337
|
+
() => Promise.all([this.payloadEnvelopeDataPromise.promise, this.allDataPromise.promise]),
|
|
338
|
+
timeout,
|
|
339
|
+
signal
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
344
|
+
|
|
318
345
|
waitForComputedAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
|
|
319
346
|
if (this.state.hasComputedAllData) {
|
|
320
347
|
return Promise.resolve(this.getSampledColumns());
|
|
@@ -16,6 +16,11 @@ enum PayloadEnvelopeImportStatus {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* PayloadEnvelopeProcessor processes payload envelope jobs in a queued fashion, one after the other.
|
|
19
|
+
*
|
|
20
|
+
* Jobs are enqueued only on envelope arrival (gossip or API). The envelope may reach us before
|
|
21
|
+
* the sampled data columns; importExecutionPayload awaits `verifyPayloadsDataAvailability`
|
|
22
|
+
* internally, so a queued job can pend for up to `PAYLOAD_DATA_AVAILABILITY_TIMEOUT` while
|
|
23
|
+
* waiting for columns. Duplicate triggers for the same payloadInput are deduped via `importStatus`.
|
|
19
24
|
*/
|
|
20
25
|
export class PayloadEnvelopeProcessor {
|
|
21
26
|
readonly jobQueue: JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>;
|
|
@@ -25,7 +30,7 @@ export class PayloadEnvelopeProcessor {
|
|
|
25
30
|
this.jobQueue = new JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>(
|
|
26
31
|
(payloadInput, opts) => {
|
|
27
32
|
this.importStatus.set(payloadInput, PayloadEnvelopeImportStatus.importing);
|
|
28
|
-
return importExecutionPayload.call(chain, payloadInput, opts);
|
|
33
|
+
return importExecutionPayload.call(chain, payloadInput, signal, opts);
|
|
29
34
|
},
|
|
30
35
|
{maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
|
|
31
36
|
metrics?.payloadEnvelopeProcessorQueue ?? undefined
|
|
@@ -33,10 +38,6 @@ export class PayloadEnvelopeProcessor {
|
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
async processPayloadEnvelopeJob(payloadInput: PayloadEnvelopeInput, opts: ImportPayloadOpts = {}): Promise<void> {
|
|
36
|
-
if (!payloadInput.isComplete()) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
41
|
if (this.importStatus.get(payloadInput) !== undefined) {
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
@@ -90,7 +90,7 @@ export type ImportBlockOpts = {
|
|
|
90
90
|
|
|
91
91
|
type FullyVerifiedBlockBase = {
|
|
92
92
|
blockInput: IBlockInput;
|
|
93
|
-
|
|
93
|
+
postState: IBeaconStateView;
|
|
94
94
|
parentBlockSlot: Slot;
|
|
95
95
|
proposerBalanceDelta: number;
|
|
96
96
|
dataAvailabilityStatus: DataAvailabilityStatus;
|
|
@@ -103,7 +103,7 @@ type FullyVerifiedBlockBase = {
|
|
|
103
103
|
/**
|
|
104
104
|
* A wrapper around a `SignedBeaconBlock` that indicates that this block is fully verified and ready to import.
|
|
105
105
|
*
|
|
106
|
-
* Discriminated union on `
|
|
106
|
+
* Discriminated union on `postPayloadState`:
|
|
107
107
|
* - `null` → block has no pre-verified envelope; `executionStatus` is any `BlockExecutionStatus`
|
|
108
108
|
* - non-null → envelope was pre-verified during state transition; `executionStatus` is narrowed to
|
|
109
109
|
* `Valid | Syncing` (matching what `forkChoice.onExecutionPayload` expects)
|
|
@@ -111,12 +111,12 @@ type FullyVerifiedBlockBase = {
|
|
|
111
111
|
export type FullyVerifiedBlock = FullyVerifiedBlockBase &
|
|
112
112
|
(
|
|
113
113
|
| {
|
|
114
|
-
|
|
114
|
+
postPayloadState: null;
|
|
115
115
|
/** If the execution payload couldn't be verified because of EL syncing status, used in optimistic sync or for merge block */
|
|
116
116
|
executionStatus: BlockExecutionStatus;
|
|
117
117
|
}
|
|
118
118
|
| {
|
|
119
|
-
|
|
119
|
+
postPayloadState: IBeaconStateView;
|
|
120
120
|
executionStatus: PayloadExecutionStatus;
|
|
121
121
|
}
|
|
122
122
|
);
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ProtoBlock,
|
|
9
9
|
} from "@lodestar/fork-choice";
|
|
10
10
|
import {ForkSeq} from "@lodestar/params";
|
|
11
|
-
import {IBeaconStateView, isExecutionBlockBodyType} from "@lodestar/state-transition";
|
|
11
|
+
import {IBeaconStateView, isExecutionBlockBodyType, isStatePostBellatrix} from "@lodestar/state-transition";
|
|
12
12
|
import {bellatrix, electra} from "@lodestar/types";
|
|
13
13
|
import {ErrorAborted, Logger, toRootHex} from "@lodestar/utils";
|
|
14
14
|
import {ExecutionPayloadStatus, IExecutionEngine} from "../../execution/engine/interface.js";
|
|
@@ -152,6 +152,7 @@ export async function verifyBlockExecutionPayload(
|
|
|
152
152
|
|
|
153
153
|
/** Not null if execution is enabled */
|
|
154
154
|
const executionPayloadEnabled =
|
|
155
|
+
isStatePostBellatrix(preState0) &&
|
|
155
156
|
preState0.isExecutionStateType &&
|
|
156
157
|
isExecutionBlockBodyType(block.message.body) &&
|
|
157
158
|
preState0.isExecutionEnabled(block.message)
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
IBeaconStateView,
|
|
4
|
+
SyncCommitteeCacheEmpty,
|
|
5
|
+
getBlockSignatureSets,
|
|
6
|
+
isStatePostAltair,
|
|
7
|
+
} from "@lodestar/state-transition";
|
|
3
8
|
import {IndexedAttestation, SignedBeaconBlock} from "@lodestar/types";
|
|
4
9
|
import {Logger} from "@lodestar/utils";
|
|
5
10
|
import {Metrics} from "../../metrics/metrics.js";
|
|
@@ -27,7 +32,9 @@ export async function verifyBlocksSignatures(
|
|
|
27
32
|
): Promise<{verifySignaturesTime: number}> {
|
|
28
33
|
const isValidPromises: Promise<boolean>[] = [];
|
|
29
34
|
const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000);
|
|
30
|
-
const currentSyncCommitteeIndexed = preState0
|
|
35
|
+
const currentSyncCommitteeIndexed = isStatePostAltair(preState0)
|
|
36
|
+
? preState0.currentSyncCommitteeIndexed
|
|
37
|
+
: new SyncCommitteeCacheEmpty();
|
|
31
38
|
|
|
32
39
|
// Verifies signatures after running state transition, so all SyncCommittee signed roots are known at this point.
|
|
33
40
|
// We must ensure block.slot <= state.slot before running getAllBlockSignatureSets().
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {DataAvailabilityStatus} from "@lodestar/state-transition";
|
|
2
|
+
import {gloas} from "@lodestar/types";
|
|
3
|
+
import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
|
|
4
|
+
|
|
5
|
+
// we can now wait for full 12 seconds because sync and reconstruction will try pulling
|
|
6
|
+
// the data columns from the network anyway while the envelope is being processed
|
|
7
|
+
export const PAYLOAD_DATA_AVAILABILITY_TIMEOUT = 12_000;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Verifies that all payload envelope inputs have their data columns available.
|
|
11
|
+
* - Waits a max of PAYLOAD_DATA_AVAILABILITY_TIMEOUT for all data to be available
|
|
12
|
+
* - Returns the time at which all data was available
|
|
13
|
+
* - Returns the data availability status for each payload input
|
|
14
|
+
*/
|
|
15
|
+
export async function verifyPayloadsDataAvailability(
|
|
16
|
+
payloadInputs: PayloadEnvelopeInput[],
|
|
17
|
+
signal: AbortSignal
|
|
18
|
+
): Promise<{
|
|
19
|
+
dataAvailabilityStatuses: DataAvailabilityStatus[];
|
|
20
|
+
availableTime: number;
|
|
21
|
+
}> {
|
|
22
|
+
const promises: Promise<gloas.DataColumnSidecar[]>[] = [];
|
|
23
|
+
for (const payloadInput of payloadInputs) {
|
|
24
|
+
if (!payloadInput.hasAllData()) {
|
|
25
|
+
promises.push(payloadInput.waitForAllData(PAYLOAD_DATA_AVAILABILITY_TIMEOUT, signal));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
await Promise.all(promises);
|
|
29
|
+
|
|
30
|
+
const availableTime = Math.max(0, Math.max(...payloadInputs.map((payloadInput) => payloadInput.getTimeComplete())));
|
|
31
|
+
const dataAvailabilityStatuses: DataAvailabilityStatus[] = payloadInputs.map((payloadInput) =>
|
|
32
|
+
payloadInput.getBlobKzgCommitments().length === 0
|
|
33
|
+
? DataAvailabilityStatus.NotRequired
|
|
34
|
+
: DataAvailabilityStatus.Available
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return {dataAvailabilityStatuses, availableTime};
|
|
38
|
+
}
|