@lodestar/beacon-node 1.43.0-dev.2870b59b6a → 1.43.0-dev.2fba242f5d
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 +17 -9
- 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 +45 -2
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -2
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +0 -1
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +67 -5
- 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/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/interface.d.ts +4 -4
- package/lib/chain/archiveStore/interface.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +2 -4
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +45 -49
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +28 -14
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +88 -88
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts +5 -3
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +59 -26
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +4 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +25 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.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 +7 -5
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +16 -21
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +89 -12
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts +5 -3
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +50 -7
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
- package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
- 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 +30 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +8 -6
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +35 -36
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +16 -15
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +5 -4
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +8 -1
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/errors/index.d.ts +1 -0
- package/lib/chain/errors/index.d.ts.map +1 -1
- package/lib/chain/errors/index.js +1 -0
- package/lib/chain/errors/index.js.map +1 -1
- package/lib/chain/errors/proposerPreferences.d.ts +33 -0
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
- package/lib/chain/errors/proposerPreferences.js +13 -0
- package/lib/chain/errors/proposerPreferences.js.map +1 -0
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +11 -15
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +7 -5
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
- package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +26 -4
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +47 -23
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts +3 -9
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +5 -32
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +12 -8
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +67 -25
- 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 +7 -11
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +1 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/regen/queued.d.ts +6 -10
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +4 -14
- 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 +1 -12
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/seenCache/index.d.ts +1 -0
- package/lib/chain/seenCache/index.d.ts.map +1 -1
- package/lib/chain/seenCache/index.js +1 -0
- package/lib/chain/seenCache/index.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +19 -6
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +40 -22
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.d.ts +15 -0
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
- package/lib/chain/seenCache/seenProposerPreferences.js +25 -0
- package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -7
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -9
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +0 -6
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +1 -0
- 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 +13 -1
- 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 +20 -10
- 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 +4 -3
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts +8 -0
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
- package/lib/chain/validation/proposerPreferences.js +69 -0
- package/lib/chain/validation/proposerPreferences.js.map +1 -0
- package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
- package/lib/db/repositories/executionPayloadEnvelopeArchive.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 +6 -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/metrics/metrics/lodestar.d.ts +1 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +4 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/interface.d.ts +7 -1
- package/lib/network/gossip/interface.d.ts.map +1 -1
- package/lib/network/gossip/interface.js +1 -0
- package/lib/network/gossip/interface.js.map +1 -1
- package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
- package/lib/network/gossip/scoringParameters.js +12 -1
- package/lib/network/gossip/scoringParameters.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +11 -2
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +6 -0
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/interface.d.ts +1 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +1 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +6 -1
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +46 -22
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
- package/lib/network/processor/gossipQueues/index.js +5 -0
- package/lib/network/processor/gossipQueues/index.js.map +1 -1
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +6 -5
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
- 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 +7 -4
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +6 -4
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/batch.d.ts +23 -2
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +84 -33
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +6 -2
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +26 -7
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +17 -6
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/types.d.ts +34 -0
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +34 -0
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +22 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +602 -53
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +46 -10
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +164 -24
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +16 -2
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.js +0 -9
- package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +16 -3
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +17 -16
- package/src/api/impl/beacon/blocks/index.ts +22 -9
- package/src/api/impl/beacon/pool/index.ts +83 -1
- package/src/api/impl/beacon/state/utils.ts +2 -2
- package/src/api/impl/debug/index.ts +0 -1
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +83 -6
- package/src/chain/GetBlobsTracker.ts +1 -2
- package/src/chain/archiveStore/archiveStore.ts +5 -5
- package/src/chain/archiveStore/interface.ts +4 -4
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +6 -8
- package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
- package/src/chain/blocks/importBlock.ts +46 -73
- package/src/chain/blocks/importExecutionPayload.ts +109 -101
- package/src/chain/blocks/index.ts +74 -24
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +33 -1
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -0
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +7 -6
- package/src/chain/blocks/types.ts +16 -26
- package/src/chain/blocks/utils/chainSegment.ts +114 -17
- package/src/chain/blocks/verifyBlock.ts +70 -9
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +41 -0
- package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
- package/src/chain/chain.ts +51 -51
- package/src/chain/emitter.ts +15 -14
- package/src/chain/errors/blockError.ts +4 -1
- package/src/chain/errors/executionPayloadBid.ts +6 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
- package/src/chain/errors/index.ts +1 -0
- package/src/chain/errors/proposerPreferences.ts +39 -0
- package/src/chain/forkChoice/index.ts +8 -20
- package/src/chain/interface.ts +11 -3
- package/src/chain/opPools/payloadAttestationPool.ts +29 -8
- package/src/chain/prepareNextSlot.ts +55 -24
- package/src/chain/produceBlock/computeNewStateRoot.ts +6 -43
- package/src/chain/produceBlock/produceBlockBody.ts +89 -27
- package/src/chain/regen/errors.ts +1 -6
- package/src/chain/regen/interface.ts +7 -11
- package/src/chain/regen/queued.ts +8 -21
- package/src/chain/regen/regen.ts +2 -15
- package/src/chain/seenCache/index.ts +1 -0
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +47 -25
- package/src/chain/seenCache/seenProposerPreferences.ts +29 -0
- package/src/chain/stateCache/persistentCheckpointsCache.ts +5 -15
- package/src/chain/stateCache/types.ts +0 -3
- package/src/chain/validation/block.ts +1 -0
- package/src/chain/validation/executionPayloadBid.ts +14 -0
- package/src/chain/validation/executionPayloadEnvelope.ts +21 -11
- package/src/chain/validation/payloadAttestationMessage.ts +5 -3
- package/src/chain/validation/proposerPreferences.ts +91 -0
- package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
- package/src/execution/engine/http.ts +21 -14
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/mock.ts +8 -1
- package/src/execution/engine/types.ts +41 -0
- package/src/metrics/metrics/lodestar.ts +4 -0
- package/src/network/gossip/interface.ts +6 -0
- package/src/network/gossip/scoringParameters.ts +14 -1
- package/src/network/gossip/topic.ts +6 -0
- package/src/network/interface.ts +1 -0
- package/src/network/network.ts +12 -1
- package/src/network/processor/gossipHandlers.ts +61 -27
- package/src/network/processor/gossipQueues/index.ts +5 -0
- package/src/network/processor/index.ts +6 -5
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
- package/src/node/nodejs.ts +6 -4
- package/src/sync/range/batch.ts +142 -38
- package/src/sync/range/chain.ts +37 -9
- package/src/sync/range/range.ts +18 -6
- package/src/sync/types.ts +72 -0
- package/src/sync/unknownBlock.ts +760 -57
- package/src/sync/utils/downloadByRange.ts +274 -39
- package/src/sync/utils/downloadByRoot.ts +24 -2
- package/src/sync/utils/pendingBlocksTree.ts +0 -15
- package/src/util/sszBytes.ts +21 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {SignedBeaconBlock} from "@lodestar/types";
|
|
1
|
+
import {SignedBeaconBlock, Slot} from "@lodestar/types";
|
|
2
2
|
import {isErrorAborted, toRootHex} from "@lodestar/utils";
|
|
3
3
|
import {Metrics} from "../../metrics/metrics.js";
|
|
4
4
|
import {nextEventLoop} from "../../util/eventLoop.js";
|
|
@@ -8,6 +8,8 @@ import {BlockError, BlockErrorCode, isBlockErrorAborted} from "../errors/index.j
|
|
|
8
8
|
import {BlockProcessOpts} from "../options.js";
|
|
9
9
|
import {IBlockInput} from "./blockInput/types.js";
|
|
10
10
|
import {importBlock} from "./importBlock.js";
|
|
11
|
+
import {importExecutionPayload} from "./importExecutionPayload.js";
|
|
12
|
+
import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
11
13
|
import {FullyVerifiedBlock, ImportBlockOpts} from "./types.js";
|
|
12
14
|
import {assertLinearChainSegment} from "./utils/chainSegment.js";
|
|
13
15
|
import {verifyBlocksInEpoch} from "./verifyBlock.js";
|
|
@@ -21,20 +23,24 @@ const QUEUE_MAX_LENGTH = 256;
|
|
|
21
23
|
* BlockProcessor processes block jobs in a queued fashion, one after the other.
|
|
22
24
|
*/
|
|
23
25
|
export class BlockProcessor {
|
|
24
|
-
readonly jobQueue: JobItemQueue<[IBlockInput[], ImportBlockOpts], void>;
|
|
26
|
+
readonly jobQueue: JobItemQueue<[IBlockInput[], Map<Slot, PayloadEnvelopeInput> | null, ImportBlockOpts], void>;
|
|
25
27
|
|
|
26
28
|
constructor(chain: BeaconChain, metrics: Metrics | null, opts: BlockProcessOpts, signal: AbortSignal) {
|
|
27
|
-
this.jobQueue = new JobItemQueue<[IBlockInput[], ImportBlockOpts], void>(
|
|
28
|
-
(job, importOpts) => {
|
|
29
|
-
return processBlocks.call(chain, job, {...opts, ...importOpts});
|
|
29
|
+
this.jobQueue = new JobItemQueue<[IBlockInput[], Map<Slot, PayloadEnvelopeInput> | null, ImportBlockOpts], void>(
|
|
30
|
+
(job, payloadEnvelopes, importOpts) => {
|
|
31
|
+
return processBlocks.call(chain, job, payloadEnvelopes, {...opts, ...importOpts});
|
|
30
32
|
},
|
|
31
33
|
{maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
|
|
32
34
|
metrics?.blockProcessorQueue ?? undefined
|
|
33
35
|
);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
async processBlocksJob(
|
|
37
|
-
|
|
38
|
+
async processBlocksJob(
|
|
39
|
+
job: IBlockInput[],
|
|
40
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
41
|
+
opts: ImportBlockOpts = {}
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
await this.jobQueue.push(job, payloadEnvelopes, opts);
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
|
|
@@ -51,18 +57,15 @@ export class BlockProcessor {
|
|
|
51
57
|
export async function processBlocks(
|
|
52
58
|
this: BeaconChain,
|
|
53
59
|
blocks: IBlockInput[],
|
|
60
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
54
61
|
opts: BlockProcessOpts & ImportBlockOpts
|
|
55
62
|
): Promise<void> {
|
|
56
63
|
if (blocks.length === 0) {
|
|
57
64
|
return; // TODO: or throw?
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
if (blocks.length > 1) {
|
|
61
|
-
assertLinearChainSegment(this.config, blocks);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
67
|
try {
|
|
65
|
-
const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, opts);
|
|
68
|
+
const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, payloadEnvelopes, opts);
|
|
66
69
|
|
|
67
70
|
// No relevant blocks, skip verifyBlocksInEpoch()
|
|
68
71
|
if (relevantBlocks.length === 0 || parentBlock === null) {
|
|
@@ -70,10 +73,31 @@ export async function processBlocks(
|
|
|
70
73
|
return;
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
const {warnings: orphanedPayloads} = assertLinearChainSegment(
|
|
77
|
+
this.config,
|
|
78
|
+
relevantBlocks,
|
|
79
|
+
payloadEnvelopes,
|
|
80
|
+
parentBlock
|
|
81
|
+
);
|
|
82
|
+
if (orphanedPayloads != null) {
|
|
83
|
+
for (const orphaned of orphanedPayloads) {
|
|
84
|
+
this.logger.debug("Orphaned payload envelope in chain segment", {
|
|
85
|
+
slot: orphaned.slot,
|
|
86
|
+
blockRoot: orphaned.payloadEnvelopeInput.blockRootHex,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
73
91
|
// Fully verify a block to be imported immediately after. Does not produce any side-effects besides adding intermediate
|
|
74
92
|
// states in the state cache through regen.
|
|
75
|
-
const {
|
|
76
|
-
|
|
93
|
+
const {
|
|
94
|
+
postStates,
|
|
95
|
+
blockDAStatuses,
|
|
96
|
+
payloadDAStatuses,
|
|
97
|
+
proposerBalanceDeltas,
|
|
98
|
+
segmentExecStatus,
|
|
99
|
+
indexedAttestationsByBlock,
|
|
100
|
+
} = await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, payloadEnvelopes, opts);
|
|
77
101
|
|
|
78
102
|
// If segmentExecStatus has lvhForkchoice then, the entire segment should be invalid
|
|
79
103
|
// and we need to further propagate
|
|
@@ -85,25 +109,51 @@ export async function processBlocks(
|
|
|
85
109
|
}
|
|
86
110
|
|
|
87
111
|
const {executionStatuses} = segmentExecStatus;
|
|
88
|
-
const
|
|
89
|
-
|
|
112
|
+
const verifiedBlocksBySlot = new Map<Slot, FullyVerifiedBlock>();
|
|
113
|
+
for (let i = 0; i < relevantBlocks.length; i++) {
|
|
114
|
+
const block = relevantBlocks[i];
|
|
115
|
+
verifiedBlocksBySlot.set(block.getBlock().message.slot, {
|
|
90
116
|
blockInput: block,
|
|
91
|
-
|
|
92
|
-
postPayloadState: null,
|
|
117
|
+
postState: postStates[i],
|
|
93
118
|
parentBlockSlot: parentSlots[i],
|
|
94
119
|
executionStatus: executionStatuses[i],
|
|
95
120
|
// start supporting optimistic syncing/processing
|
|
96
|
-
dataAvailabilityStatus:
|
|
121
|
+
dataAvailabilityStatus: blockDAStatuses[i],
|
|
97
122
|
proposerBalanceDelta: proposerBalanceDeltas[i],
|
|
98
123
|
indexedAttestations: indexedAttestationsByBlock[i],
|
|
99
124
|
// TODO: Make this param mandatory and capture in gossip
|
|
100
125
|
seenTimestampSec: opts.seenTimestampSec ?? Math.floor(Date.now() / 1000),
|
|
101
|
-
})
|
|
102
|
-
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Iterate slots from the original `blocks` input (which spans the entire batch including
|
|
130
|
+
// slots filtered out of `relevantBlocks`). The first batch of a checkpoint sync may contain
|
|
131
|
+
// a payload at the anchor slot whose block is already in fork-choice (added by
|
|
132
|
+
// initializeForkChoice as PENDING+EMPTY) and therefore not in verifiedBlocksBySlot — the
|
|
133
|
+
// payload still needs to be imported here to populate the anchor's FULL variant so
|
|
134
|
+
// subsequent slots can find their parent payload.
|
|
135
|
+
const slots = Array.from(new Set(blocks.map((b) => b.getBlock().message.slot)));
|
|
136
|
+
for (const slot of slots) {
|
|
137
|
+
const fullyVerifiedBlock = verifiedBlocksBySlot.get(slot);
|
|
138
|
+
if (fullyVerifiedBlock !== undefined) {
|
|
139
|
+
// TODO: Consider batching importBlock too if it takes significant time
|
|
140
|
+
await importBlock.call(this, fullyVerifiedBlock, opts);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const payloadInput = payloadEnvelopes?.get(slot);
|
|
144
|
+
if (payloadInput?.hasPayloadEnvelope()) {
|
|
145
|
+
if (!payloadInput.isComplete()) {
|
|
146
|
+
// we validated DA before reaching this
|
|
147
|
+
throw new Error(`Payload envelope for slot ${slot} not complete after DA verification`);
|
|
148
|
+
}
|
|
149
|
+
// we already awaited DA in verifyBlocksInEpoch for this segment
|
|
150
|
+
const payloadDA = payloadDAStatuses.get(slot);
|
|
151
|
+
if (payloadDA === undefined) {
|
|
152
|
+
throw new Error(`Missing payload DA status for slot ${slot}`);
|
|
153
|
+
}
|
|
154
|
+
await importExecutionPayload.call(this, payloadInput, payloadDA, {validSignature: false});
|
|
155
|
+
}
|
|
103
156
|
|
|
104
|
-
for (const fullyVerifiedBlock of fullyVerifiedBlocks) {
|
|
105
|
-
// TODO: Consider batching importBlock too if it takes significant time
|
|
106
|
-
await importBlock.call(this, fullyVerifiedBlock, opts);
|
|
107
157
|
await nextEventLoop();
|
|
108
158
|
}
|
|
109
159
|
} catch (e) {
|
|
@@ -64,6 +64,7 @@ export class PayloadEnvelopeInput {
|
|
|
64
64
|
readonly proposerIndex: ValidatorIndex;
|
|
65
65
|
readonly bid: gloas.ExecutionPayloadBid;
|
|
66
66
|
readonly versionedHashes: VersionedHashes;
|
|
67
|
+
readonly daOutOfRange: boolean;
|
|
67
68
|
|
|
68
69
|
private columnsCache = new Map<ColumnIndex, ColumnWithSource>();
|
|
69
70
|
|
|
@@ -73,6 +74,7 @@ export class PayloadEnvelopeInput {
|
|
|
73
74
|
private timeCreatedSec: number;
|
|
74
75
|
|
|
75
76
|
private readonly payloadEnvelopeDataPromise: PromiseParts<gloas.SignedExecutionPayloadEnvelope>;
|
|
77
|
+
private readonly allDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
|
|
76
78
|
private readonly columnsDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
|
|
77
79
|
|
|
78
80
|
state: PayloadEnvelopeInputState;
|
|
@@ -86,6 +88,7 @@ export class PayloadEnvelopeInput {
|
|
|
86
88
|
sampledColumns: ColumnIndex[];
|
|
87
89
|
custodyColumns: ColumnIndex[];
|
|
88
90
|
timeCreatedSec: number;
|
|
91
|
+
daOutOfRange: boolean;
|
|
89
92
|
}) {
|
|
90
93
|
this.blockRootHex = props.blockRootHex;
|
|
91
94
|
this.slot = props.slot;
|
|
@@ -96,15 +99,18 @@ export class PayloadEnvelopeInput {
|
|
|
96
99
|
this.sampledColumns = props.sampledColumns;
|
|
97
100
|
this.custodyColumns = props.custodyColumns;
|
|
98
101
|
this.timeCreatedSec = props.timeCreatedSec;
|
|
102
|
+
this.daOutOfRange = props.daOutOfRange;
|
|
99
103
|
this.payloadEnvelopeDataPromise = createPromise();
|
|
104
|
+
this.allDataPromise = createPromise();
|
|
100
105
|
this.columnsDataPromise = createPromise();
|
|
101
106
|
|
|
102
107
|
const noBlobs = props.bid.blobKzgCommitments.length === 0;
|
|
103
108
|
const noSampledColumns = props.sampledColumns.length === 0;
|
|
104
|
-
const hasAllData = noBlobs || noSampledColumns;
|
|
109
|
+
const hasAllData = props.daOutOfRange || noBlobs || noSampledColumns;
|
|
105
110
|
|
|
106
111
|
if (hasAllData) {
|
|
107
112
|
this.state = {hasPayload: false, hasAllData: true, hasComputedAllData: true};
|
|
113
|
+
this.allDataPromise.resolve(this.getSampledColumns());
|
|
108
114
|
this.columnsDataPromise.resolve(this.getSampledColumns());
|
|
109
115
|
} else {
|
|
110
116
|
this.state = {hasPayload: false, hasAllData: false, hasComputedAllData: false};
|
|
@@ -122,6 +128,7 @@ export class PayloadEnvelopeInput {
|
|
|
122
128
|
sampledColumns: props.sampledColumns,
|
|
123
129
|
custodyColumns: props.custodyColumns,
|
|
124
130
|
timeCreatedSec: props.timeCreatedSec,
|
|
131
|
+
daOutOfRange: props.daOutOfRange,
|
|
125
132
|
});
|
|
126
133
|
}
|
|
127
134
|
|
|
@@ -149,6 +156,7 @@ export class PayloadEnvelopeInput {
|
|
|
149
156
|
throw new Error("Payload envelope beacon_block_root mismatch");
|
|
150
157
|
}
|
|
151
158
|
|
|
159
|
+
// TODO GLOAS: track source by metrics, maybe inside the seen cache
|
|
152
160
|
const source: SourceMeta = {
|
|
153
161
|
source: props.source,
|
|
154
162
|
seenTimestampSec: props.seenTimestampSec,
|
|
@@ -203,6 +211,12 @@ export class PayloadEnvelopeInput {
|
|
|
203
211
|
return true;
|
|
204
212
|
}
|
|
205
213
|
|
|
214
|
+
// Resolve allDataPromise on the first transition to hasAllData (either sampled-complete or
|
|
215
|
+
// reconstruction-threshold branch). Guarded so it fires exactly once.
|
|
216
|
+
if (!this.state.hasAllData && hasAllData) {
|
|
217
|
+
this.allDataPromise.resolve(sampledColumns);
|
|
218
|
+
}
|
|
219
|
+
|
|
206
220
|
if (hasComputedAllData) {
|
|
207
221
|
this.columnsDataPromise.resolve(sampledColumns);
|
|
208
222
|
}
|
|
@@ -315,6 +329,24 @@ export class PayloadEnvelopeInput {
|
|
|
315
329
|
return this.state.hasComputedAllData;
|
|
316
330
|
}
|
|
317
331
|
|
|
332
|
+
waitForAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
|
|
333
|
+
if (this.state.hasAllData) {
|
|
334
|
+
return Promise.resolve(this.getSampledColumns());
|
|
335
|
+
}
|
|
336
|
+
return withTimeout(() => this.allDataPromise.promise, timeout, signal);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async waitForEnvelopeAndAllData(timeout: number, signal?: AbortSignal): Promise<this> {
|
|
340
|
+
if (!this.state.hasPayload || !this.state.hasAllData) {
|
|
341
|
+
await withTimeout(
|
|
342
|
+
() => Promise.all([this.payloadEnvelopeDataPromise.promise, this.allDataPromise.promise]),
|
|
343
|
+
timeout,
|
|
344
|
+
signal
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
return this;
|
|
348
|
+
}
|
|
349
|
+
|
|
318
350
|
waitForComputedAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
|
|
319
351
|
if (this.state.hasComputedAllData) {
|
|
320
352
|
return Promise.resolve(this.getSampledColumns());
|
|
@@ -2,7 +2,7 @@ import {Metrics} from "../../metrics/metrics.js";
|
|
|
2
2
|
import {JobItemQueue} from "../../util/queue/index.js";
|
|
3
3
|
import type {BeaconChain} from "../chain.js";
|
|
4
4
|
import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
|
|
5
|
-
import {
|
|
5
|
+
import {processExecutionPayload} from "./importExecutionPayload.js";
|
|
6
6
|
import {ImportPayloadOpts} from "./types.js";
|
|
7
7
|
|
|
8
8
|
// TODO GLOAS: Set to be equal to DEFAULT_MAX_PENDING_UNFINALIZED_PAYLOAD_ENVELOPE_WRITES for now
|
|
@@ -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
|
|
33
|
+
return processExecutionPayload.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
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {BlockExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
|
|
2
|
+
import type {BlockExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
|
|
3
3
|
import {ForkSeq} from "@lodestar/params";
|
|
4
4
|
import {DataAvailabilityStatus, IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
|
|
5
5
|
import type {IndexedAttestation, Slot, fulu} from "@lodestar/types";
|
|
@@ -43,8 +43,9 @@ export enum BlobSidecarValidation {
|
|
|
43
43
|
|
|
44
44
|
export type ImportPayloadOpts = {
|
|
45
45
|
/**
|
|
46
|
-
* Set to true
|
|
47
|
-
*
|
|
46
|
+
* Set to true when the envelope was already validated upstream (e.g., gossip/API validation):
|
|
47
|
+
* signature is trusted and execution_requests_root was already verified against the bid.
|
|
48
|
+
* When false/undefined, both are verified during import.
|
|
48
49
|
*/
|
|
49
50
|
validSignature?: boolean;
|
|
50
51
|
};
|
|
@@ -88,9 +89,17 @@ export type ImportBlockOpts = {
|
|
|
88
89
|
seenTimestampSec?: number;
|
|
89
90
|
};
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
/**
|
|
93
|
+
* A wrapper around a `SignedBeaconBlock` that indicates that this block is fully verified and ready to import.
|
|
94
|
+
*
|
|
95
|
+
* `executionStatus` reflects the outcome of execution payload verification at block-import time:
|
|
96
|
+
* - pre-gloas: Valid | Syncing | PreMerge (from EL notifyNewPayload against the in-block payload)
|
|
97
|
+
* - post-gloas: inherited from parent's chain (Valid/Syncing) by importBlock; payload arrives
|
|
98
|
+
* separately as an envelope and creates the FULL variant later via onExecutionPayload
|
|
99
|
+
*/
|
|
100
|
+
export type FullyVerifiedBlock = {
|
|
92
101
|
blockInput: IBlockInput;
|
|
93
|
-
|
|
102
|
+
postState: IBeaconStateView;
|
|
94
103
|
parentBlockSlot: Slot;
|
|
95
104
|
proposerBalanceDelta: number;
|
|
96
105
|
dataAvailabilityStatus: DataAvailabilityStatus;
|
|
@@ -98,25 +107,6 @@ type FullyVerifiedBlockBase = {
|
|
|
98
107
|
indexedAttestations: IndexedAttestation[];
|
|
99
108
|
/** Seen timestamp seconds */
|
|
100
109
|
seenTimestampSec: number;
|
|
110
|
+
/** If the execution payload couldn't be verified because of EL syncing status, used in optimistic sync */
|
|
111
|
+
executionStatus: BlockExecutionStatus | PayloadExecutionStatus;
|
|
101
112
|
};
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* A wrapper around a `SignedBeaconBlock` that indicates that this block is fully verified and ready to import.
|
|
105
|
-
*
|
|
106
|
-
* Discriminated union on `postPayloadState`:
|
|
107
|
-
* - `null` → block has no pre-verified envelope; `executionStatus` is any `BlockExecutionStatus`
|
|
108
|
-
* - non-null → envelope was pre-verified during state transition; `executionStatus` is narrowed to
|
|
109
|
-
* `Valid | Syncing` (matching what `forkChoice.onExecutionPayload` expects)
|
|
110
|
-
*/
|
|
111
|
-
export type FullyVerifiedBlock = FullyVerifiedBlockBase &
|
|
112
|
-
(
|
|
113
|
-
| {
|
|
114
|
-
postPayloadState: null;
|
|
115
|
-
/** If the execution payload couldn't be verified because of EL syncing status, used in optimistic sync or for merge block */
|
|
116
|
-
executionStatus: BlockExecutionStatus;
|
|
117
|
-
}
|
|
118
|
-
| {
|
|
119
|
-
postPayloadState: IBeaconStateView;
|
|
120
|
-
executionStatus: PayloadExecutionStatus;
|
|
121
|
-
}
|
|
122
|
-
);
|
|
@@ -1,29 +1,126 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
2
|
+
import {ProtoBlock} from "@lodestar/fork-choice";
|
|
3
|
+
import {Slot, isGloasBeaconBlock, ssz} from "@lodestar/types";
|
|
4
|
+
import {toRootHex} from "@lodestar/utils";
|
|
3
5
|
import {BlockError, BlockErrorCode} from "../../errors/index.js";
|
|
4
6
|
import {IBlockInput} from "../blockInput/types.js";
|
|
7
|
+
import {PayloadEnvelopeInput} from "../payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
8
|
+
|
|
9
|
+
export type OrphanedPayloadEnvelope = {
|
|
10
|
+
slot: Slot;
|
|
11
|
+
payloadEnvelopeInput: PayloadEnvelopeInput;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ChainSegmentResult = {warnings: OrphanedPayloadEnvelope[] | null};
|
|
5
15
|
|
|
6
16
|
/**
|
|
7
|
-
* Assert this chain segment of blocks is linear with slot numbers and hashes
|
|
17
|
+
* Assert this chain segment of blocks is linear with slot numbers and hashes,
|
|
18
|
+
* and that the provided envelopes are consistent with their respective blocks.
|
|
19
|
+
*
|
|
20
|
+
* Must be called after verifyBlocksSanityChecks so that parentBlock (from forkchoice)
|
|
21
|
+
* is available to seed the execution hash chain.
|
|
22
|
+
*
|
|
23
|
+
* For each block:
|
|
24
|
+
* - Verifies parent root + slot linearity
|
|
25
|
+
* - For gloas: verifies bid.parentBlockHash matches the tracked execution hash; if not, the
|
|
26
|
+
* previous FULL envelope is treated as orphaned (segment continues as if previous slot was EMPTY)
|
|
27
|
+
* - If an envelope exists for this slot: verifies it references this block's root
|
|
28
|
+
* - Advances the tracked execution hash (FULL if envelope present, EMPTY if not)
|
|
8
29
|
*/
|
|
30
|
+
export function assertLinearChainSegment(
|
|
31
|
+
config: ChainForkConfig,
|
|
32
|
+
blocks: IBlockInput[],
|
|
33
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
34
|
+
parentBlock: ProtoBlock
|
|
35
|
+
): ChainSegmentResult {
|
|
36
|
+
const warnings: OrphanedPayloadEnvelope[] = [];
|
|
9
37
|
|
|
10
|
-
|
|
11
|
-
|
|
38
|
+
// Track the expected execution payload block hash through the segment.
|
|
39
|
+
// Starts from the known forkchoice parent's execution hash.
|
|
40
|
+
// - FULL variant (envelope present for slot): advances to envelope.payload.blockHash
|
|
41
|
+
// - EMPTY variant (no envelope for slot): execution hash is unchanged
|
|
42
|
+
// null only for pre-merge parents, which cannot precede gloas blocks.
|
|
43
|
+
let currentExecHash: string | null = parentBlock.executionPayloadBlockHash;
|
|
44
|
+
// Checkpoint sync first batch: parent is the anchor PENDING whose executionPayloadBlockHash
|
|
45
|
+
// is the inherited parentBlockHash semantic (= grandparent's payload), not its own payload.
|
|
46
|
+
// If parent's own payload envelope arrives in this batch, advance currentExecHash to that
|
|
47
|
+
// payload's blockHash so the segment validation sees the true EL chain head.
|
|
48
|
+
const parentPayloadInput = payloadEnvelopes?.get(parentBlock.slot);
|
|
49
|
+
if (parentPayloadInput?.hasPayloadEnvelope()) {
|
|
50
|
+
currentExecHash = parentPayloadInput.getBlockHashHex();
|
|
51
|
+
}
|
|
52
|
+
// Track the execution hash before the last FULL advancement so we can recover
|
|
53
|
+
// if the next block reveals that envelope was orphaned.
|
|
54
|
+
let prevExecHash: string | null = currentExecHash;
|
|
55
|
+
// The slot whose envelope last advanced currentExecHash (for warning context).
|
|
56
|
+
let lastFullSlot: Slot | null = null;
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
12
59
|
const block = blocks[i].getBlock();
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
60
|
+
const slot = block.message.slot;
|
|
61
|
+
|
|
62
|
+
if (i > 0) {
|
|
63
|
+
const prevBlock = blocks[i - 1].getBlock();
|
|
64
|
+
// Ensure parent root matches the previous block's root
|
|
65
|
+
if (
|
|
66
|
+
!ssz.Root.equals(
|
|
67
|
+
config.getForkTypes(prevBlock.message.slot).BeaconBlock.hashTreeRoot(prevBlock.message),
|
|
68
|
+
block.message.parentRoot
|
|
69
|
+
)
|
|
70
|
+
) {
|
|
71
|
+
throw new BlockError(block, {code: BlockErrorCode.NON_LINEAR_PARENT_ROOTS});
|
|
72
|
+
}
|
|
73
|
+
// Ensure slots are strictly increasing
|
|
74
|
+
if (slot <= prevBlock.message.slot) {
|
|
75
|
+
throw new BlockError(block, {code: BlockErrorCode.NON_LINEAR_SLOTS});
|
|
76
|
+
}
|
|
23
77
|
}
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
|
|
78
|
+
|
|
79
|
+
if (isGloasBeaconBlock(block.message) && currentExecHash !== null) {
|
|
80
|
+
// Verify the bid's parentBlockHash matches the tracked execution hash.
|
|
81
|
+
// This ensures the block was built on the correct FULL or EMPTY variant of its parent.
|
|
82
|
+
const bidParentHash = toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash);
|
|
83
|
+
if (bidParentHash !== currentExecHash) {
|
|
84
|
+
// Maybe the previous slot's FULL envelope was orphaned — try falling back.
|
|
85
|
+
// If even prevExecHash doesn't match, the segment is non-linear.
|
|
86
|
+
if (bidParentHash !== prevExecHash) {
|
|
87
|
+
throw new BlockError(block, {
|
|
88
|
+
code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
|
|
89
|
+
parentRoot: toRootHex(block.message.parentRoot),
|
|
90
|
+
parentBlockHash: bidParentHash,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (lastFullSlot !== null && payloadEnvelopes !== null) {
|
|
94
|
+
const orphanedInput = payloadEnvelopes.get(lastFullSlot);
|
|
95
|
+
if (orphanedInput != null) {
|
|
96
|
+
warnings.push({slot: lastFullSlot, payloadEnvelopeInput: orphanedInput});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
currentExecHash = prevExecHash;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const payloadInput = payloadEnvelopes?.get(slot) ?? null;
|
|
103
|
+
const payloadEnvelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : null;
|
|
104
|
+
if (payloadEnvelope !== null) {
|
|
105
|
+
// Verify the envelope references this block's root
|
|
106
|
+
const blockRoot = toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block.message));
|
|
107
|
+
const envelopeBlockRoot = toRootHex(payloadEnvelope.message.beaconBlockRoot);
|
|
108
|
+
if (blockRoot !== envelopeBlockRoot) {
|
|
109
|
+
throw new BlockError(block, {
|
|
110
|
+
code: BlockErrorCode.ENVELOPE_BLOCK_ROOT_MISMATCH,
|
|
111
|
+
envelopeBlockRoot,
|
|
112
|
+
blockRoot,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// FULL variant: save state before advancing, then advance
|
|
117
|
+
prevExecHash = currentExecHash;
|
|
118
|
+
lastFullSlot = slot;
|
|
119
|
+
currentExecHash = toRootHex(payloadEnvelope.message.payload.blockHash);
|
|
120
|
+
}
|
|
121
|
+
// EMPTY variant: currentExecHash unchanged
|
|
27
122
|
}
|
|
28
123
|
}
|
|
124
|
+
|
|
125
|
+
return {warnings: warnings.length > 0 ? warnings : null};
|
|
29
126
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import {ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice";
|
|
2
|
-
import {ForkName, isForkPostFulu} from "@lodestar/params";
|
|
2
|
+
import {ForkName, ForkSeq, isForkPostFulu} from "@lodestar/params";
|
|
3
3
|
import {DataAvailabilityStatus, IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
|
|
4
|
-
import {IndexedAttestation, deneb} from "@lodestar/types";
|
|
4
|
+
import {IndexedAttestation, Slot, deneb} from "@lodestar/types";
|
|
5
|
+
import {getBlobKzgCommitments} from "../../util/dataColumns.js";
|
|
5
6
|
import type {BeaconChain} from "../chain.js";
|
|
6
7
|
import {BlockError, BlockErrorCode} from "../errors/index.js";
|
|
7
8
|
import {BlockProcessOpts} from "../options.js";
|
|
8
9
|
import {RegenCaller} from "../regen/index.js";
|
|
9
10
|
import {DAType, IBlockInput} from "./blockInput/index.js";
|
|
11
|
+
import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
10
12
|
import {ImportBlockOpts} from "./types.js";
|
|
11
13
|
import {DENEB_BLOWFISH_BANNER} from "./utils/blowfishBanner.js";
|
|
12
14
|
import {ELECTRA_GIRAFFE_BANNER} from "./utils/giraffeBanner.js";
|
|
@@ -16,6 +18,7 @@ import {verifyBlocksDataAvailability} from "./verifyBlocksDataAvailability.js";
|
|
|
16
18
|
import {SegmentExecStatus, verifyBlocksExecutionPayload} from "./verifyBlocksExecutionPayloads.js";
|
|
17
19
|
import {verifyBlocksSignatures} from "./verifyBlocksSignatures.js";
|
|
18
20
|
import {verifyBlocksStateTransitionOnly} from "./verifyBlocksStateTransitionOnly.js";
|
|
21
|
+
import {verifyPayloadsDataAvailability} from "./verifyPayloadsDataAvailability.js";
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Verifies 1 or more blocks are fully valid; from a linear sequence of blocks.
|
|
@@ -32,12 +35,14 @@ export async function verifyBlocksInEpoch(
|
|
|
32
35
|
this: BeaconChain,
|
|
33
36
|
parentBlock: ProtoBlock,
|
|
34
37
|
blockInputs: IBlockInput[],
|
|
38
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
35
39
|
opts: BlockProcessOpts & ImportBlockOpts
|
|
36
40
|
): Promise<{
|
|
37
41
|
postStates: IBeaconStateView[];
|
|
38
42
|
proposerBalanceDeltas: number[];
|
|
39
43
|
segmentExecStatus: SegmentExecStatus;
|
|
40
|
-
|
|
44
|
+
blockDAStatuses: DataAvailabilityStatus[];
|
|
45
|
+
payloadDAStatuses: Map<Slot, DataAvailabilityStatus>;
|
|
41
46
|
indexedAttestationsByBlock: IndexedAttestation[][];
|
|
42
47
|
}> {
|
|
43
48
|
const blocks = blockInputs.map((blockInput) => blockInput.getBlock());
|
|
@@ -110,17 +115,61 @@ export async function verifyBlocksInEpoch(
|
|
|
110
115
|
});
|
|
111
116
|
}
|
|
112
117
|
|
|
118
|
+
// Pick the data-availability source by fork:
|
|
119
|
+
// - Pre-Gloas: blob/Fulu-column data lives in IBlockInput → verifyBlocksDataAvailability.
|
|
120
|
+
// - Post-Gloas: verifyPayloadsDataAvailability (payload-level DA, keyed by slot).
|
|
121
|
+
const daAvailabilityPromise: Promise<{
|
|
122
|
+
blockDAStatuses: DataAvailabilityStatus[];
|
|
123
|
+
payloadDAStatuses: Map<Slot, DataAvailabilityStatus>;
|
|
124
|
+
availableTime: number;
|
|
125
|
+
}> =
|
|
126
|
+
fork >= ForkSeq.gloas
|
|
127
|
+
? (async () => {
|
|
128
|
+
// Validate DA for ALL payloads in the Map, not just those paired with blockInputs.
|
|
129
|
+
// A checkpoint-sync batch may include a payload for a slot whose block was filtered
|
|
130
|
+
// out of relevantBlocks (e.g., the anchor at the finalized slot); that payload still
|
|
131
|
+
// needs DA validation so it can be imported in processBlocks.
|
|
132
|
+
const payloadInputsForDa: PayloadEnvelopeInput[] =
|
|
133
|
+
payloadEnvelopes !== null ? Array.from(payloadEnvelopes.values()) : [];
|
|
134
|
+
const {dataAvailabilityStatuses, availableTime} = await verifyPayloadsDataAvailability(
|
|
135
|
+
payloadInputsForDa,
|
|
136
|
+
abortController.signal
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const payloadDAStatuses = new Map<Slot, DataAvailabilityStatus>();
|
|
140
|
+
for (let i = 0; i < payloadInputsForDa.length; i++) {
|
|
141
|
+
payloadDAStatuses.set(payloadInputsForDa[i].slot, dataAvailabilityStatuses[i]);
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
// post-gloas, DataAvailabilityStatus is NotRequired for forkChoice.onBlock() ProtoBlock
|
|
145
|
+
blockDAStatuses: blockInputs.map(() => DataAvailabilityStatus.NotRequired),
|
|
146
|
+
payloadDAStatuses,
|
|
147
|
+
availableTime,
|
|
148
|
+
};
|
|
149
|
+
})()
|
|
150
|
+
: (async () => {
|
|
151
|
+
const {dataAvailabilityStatuses, availableTime} = await verifyBlocksDataAvailability(
|
|
152
|
+
blockInputs,
|
|
153
|
+
abortController.signal
|
|
154
|
+
);
|
|
155
|
+
return {
|
|
156
|
+
blockDAStatuses: dataAvailabilityStatuses,
|
|
157
|
+
payloadDAStatuses: new Map<Slot, DataAvailabilityStatus>(),
|
|
158
|
+
availableTime,
|
|
159
|
+
};
|
|
160
|
+
})();
|
|
161
|
+
|
|
113
162
|
// batch all I/O operations to reduce overhead
|
|
114
163
|
const [
|
|
115
164
|
segmentExecStatus,
|
|
116
|
-
{
|
|
165
|
+
{blockDAStatuses, payloadDAStatuses, availableTime},
|
|
117
166
|
{postStates, proposerBalanceDeltas, verifyStateTime},
|
|
118
167
|
{verifySignaturesTime},
|
|
119
168
|
] = await Promise.all([
|
|
120
169
|
verifyExecutionPayloadsPromise,
|
|
121
170
|
|
|
122
|
-
// data availability
|
|
123
|
-
|
|
171
|
+
// data availability (fork-specific; see daAvailabilityPromise above)
|
|
172
|
+
daAvailabilityPromise,
|
|
124
173
|
|
|
125
174
|
// Run state transition only
|
|
126
175
|
// TODO: Ensure it yields to allow flushing to workers and engine API
|
|
@@ -149,6 +198,9 @@ export async function verifyBlocksInEpoch(
|
|
|
149
198
|
opts
|
|
150
199
|
)
|
|
151
200
|
: Promise.resolve({verifySignaturesTime: Date.now()}),
|
|
201
|
+
|
|
202
|
+
// TODO GLOAS: can verify payload signatures in batch too
|
|
203
|
+
// maybe chain with the above verifyBlocksSignatures()
|
|
152
204
|
]);
|
|
153
205
|
|
|
154
206
|
if (opts.verifyOnly !== true) {
|
|
@@ -200,7 +252,9 @@ export async function verifyBlocksInEpoch(
|
|
|
200
252
|
blockInputs.length === 1 &&
|
|
201
253
|
// gossip blocks have seenTimestampSec
|
|
202
254
|
opts.seenTimestampSec !== undefined &&
|
|
255
|
+
// PreData (pre-deneb) and NoData (gloas) carry no blob data on the block — skip metric
|
|
203
256
|
blockInputs[0].type !== DAType.PreData &&
|
|
257
|
+
blockInputs[0].type !== DAType.NoData &&
|
|
204
258
|
executionStatuses[0] === ExecutionStatus.Valid
|
|
205
259
|
) {
|
|
206
260
|
// Find the max time when the block was actually verified
|
|
@@ -209,8 +263,8 @@ export async function verifyBlocksInEpoch(
|
|
|
209
263
|
this.metrics?.gossipBlock.receivedToFullyVerifiedTime.observe(recvTofullyVerifedTime);
|
|
210
264
|
|
|
211
265
|
const verifiedToBlobsAvailabiltyTime = Math.max(availableTime - fullyVerifiedTime, 0) / 1000;
|
|
212
|
-
const block = blockInputs[0].getBlock()
|
|
213
|
-
const numBlobs = block.
|
|
266
|
+
const block = blockInputs[0].getBlock();
|
|
267
|
+
const numBlobs = getBlobKzgCommitments(blockInputs[0].forkName, block as deneb.SignedBeaconBlock).length;
|
|
214
268
|
|
|
215
269
|
this.metrics?.gossipBlock.verifiedToBlobsAvailabiltyTime.observe({numBlobs}, verifiedToBlobsAvailabiltyTime);
|
|
216
270
|
this.logger.verbose("Verified blockInput fully with blobs availability", {
|
|
@@ -229,7 +283,14 @@ export async function verifyBlocksInEpoch(
|
|
|
229
283
|
);
|
|
230
284
|
}
|
|
231
285
|
|
|
232
|
-
return {
|
|
286
|
+
return {
|
|
287
|
+
postStates,
|
|
288
|
+
blockDAStatuses,
|
|
289
|
+
payloadDAStatuses,
|
|
290
|
+
proposerBalanceDeltas,
|
|
291
|
+
segmentExecStatus,
|
|
292
|
+
indexedAttestationsByBlock,
|
|
293
|
+
};
|
|
233
294
|
} finally {
|
|
234
295
|
abortController.abort();
|
|
235
296
|
}
|