@lodestar/beacon-node 1.43.0-dev.9c8becae00 → 1.43.0-dev.9f5db5b9c7
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 +68 -6
- package/lib/api/impl/validator/index.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.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/blockInput/blockInput.d.ts +3 -0
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +4 -1
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +24 -20
- 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 -90
- 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 +9 -2
- 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.js +2 -2
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +15 -20
- 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 +79 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
- 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 +21 -6
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +3 -14
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +0 -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 +40 -0
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
- package/lib/chain/errors/proposerPreferences.js +14 -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 +5 -17
- 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 +31 -13
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +52 -14
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +1 -0
- 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.map +1 -1
- package/lib/chain/regen/queued.js +1 -4
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +1 -4
- 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 +16 -0
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
- package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
- package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.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 +24 -9
- 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 +19 -9
- package/lib/chain/validation/executionPayloadEnvelope.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 +91 -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 +13 -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 +27 -19
- 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.js +2 -2
- 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 +132 -44
- 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 +162 -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 +20 -5
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +16 -15
- 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 +82 -5
- package/src/chain/archiveStore/archiveStore.ts +5 -5
- package/src/chain/archiveStore/interface.ts +4 -4
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
- package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
- package/src/chain/blocks/blockInput/blockInput.ts +4 -1
- package/src/chain/blocks/importBlock.ts +24 -38
- package/src/chain/blocks/importExecutionPayload.ts +109 -105
- package/src/chain/blocks/index.ts +73 -23
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +10 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -0
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
- package/src/chain/blocks/types.ts +15 -25
- 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 +134 -0
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
- package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
- package/src/chain/chain.ts +38 -19
- package/src/chain/emitter.ts +3 -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 +47 -0
- package/src/chain/forkChoice/index.ts +2 -22
- package/src/chain/interface.ts +11 -3
- package/src/chain/opPools/payloadAttestationPool.ts +29 -8
- package/src/chain/prepareNextSlot.ts +36 -14
- package/src/chain/produceBlock/produceBlockBody.ts +63 -13
- package/src/chain/regen/interface.ts +1 -0
- package/src/chain/regen/queued.ts +2 -7
- package/src/chain/regen/regen.ts +2 -7
- package/src/chain/seenCache/index.ts +1 -0
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +47 -25
- package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
- package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
- package/src/chain/validation/block.ts +1 -0
- package/src/chain/validation/executionPayloadBid.ts +25 -8
- package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
- package/src/chain/validation/proposerPreferences.ts +110 -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 +38 -20
- 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 +2 -2
- package/src/sync/range/batch.ts +188 -49
- 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 +272 -39
- package/src/sync/utils/downloadByRoot.ts +24 -2
- package/src/sync/utils/pendingBlocksTree.ts +0 -15
- package/src/util/sszBytes.ts +25 -5
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
electra,
|
|
47
47
|
fulu,
|
|
48
48
|
gloas,
|
|
49
|
+
ssz,
|
|
49
50
|
} from "@lodestar/types";
|
|
50
51
|
import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
51
52
|
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
@@ -110,6 +111,7 @@ export type ProduceFullGloas = {
|
|
|
110
111
|
executionRequests: electra.ExecutionRequests;
|
|
111
112
|
blobsBundle: BlobsBundle<ForkPostGloas>;
|
|
112
113
|
cells: fulu.Cell[][];
|
|
114
|
+
parentBlockRoot: Root;
|
|
113
115
|
};
|
|
114
116
|
export type ProduceFullFulu = {
|
|
115
117
|
type: BlockType.Full;
|
|
@@ -213,9 +215,19 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
213
215
|
});
|
|
214
216
|
|
|
215
217
|
// Get execution payload from EL
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
let parentBlockHash: Bytes32;
|
|
219
|
+
let parentExecutionRequests: electra.ExecutionRequests;
|
|
220
|
+
// Apply parent payload once here as it's reused by EL prep and voluntary exit filtering below
|
|
221
|
+
let stateAfterParentPayload: IBeaconStateViewBellatrix = currentState;
|
|
222
|
+
const isExtendingPayload = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot));
|
|
223
|
+
if (isExtendingPayload) {
|
|
224
|
+
parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
|
|
225
|
+
parentExecutionRequests = await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot);
|
|
226
|
+
stateAfterParentPayload = currentState.withParentPayloadApplied(parentExecutionRequests);
|
|
227
|
+
} else {
|
|
228
|
+
parentBlockHash = currentState.latestExecutionPayloadBid.parentBlockHash;
|
|
229
|
+
parentExecutionRequests = ssz.electra.ExecutionRequests.defaultValue();
|
|
230
|
+
}
|
|
219
231
|
const prepareRes = await prepareExecutionPayload(
|
|
220
232
|
this,
|
|
221
233
|
this.logger,
|
|
@@ -224,7 +236,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
224
236
|
parentBlockHash,
|
|
225
237
|
safeBlockHash,
|
|
226
238
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
227
|
-
|
|
239
|
+
stateAfterParentPayload,
|
|
228
240
|
feeRecipient
|
|
229
241
|
);
|
|
230
242
|
|
|
@@ -269,6 +281,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
269
281
|
value: 0,
|
|
270
282
|
executionPayment: 0,
|
|
271
283
|
blobKzgCommitments: blobsBundle.commitments,
|
|
284
|
+
executionRequestsRoot: ssz.electra.ExecutionRequests.hashTreeRoot(executionRequests),
|
|
272
285
|
};
|
|
273
286
|
const signedBid: gloas.SignedExecutionPayloadBid = {
|
|
274
287
|
message: bid,
|
|
@@ -278,8 +291,19 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
278
291
|
const commonBlockBody = await commonBlockBodyPromise;
|
|
279
292
|
const gloasBody = Object.assign({}, commonBlockBody) as gloas.BeaconBlockBody;
|
|
280
293
|
gloasBody.signedExecutionPayloadBid = signedBid;
|
|
281
|
-
|
|
282
|
-
|
|
294
|
+
gloasBody.payloadAttestations = this.payloadAttestationPool.getPayloadAttestationsForBlock(
|
|
295
|
+
parentBlock.blockRoot,
|
|
296
|
+
blockSlot - 1
|
|
297
|
+
);
|
|
298
|
+
gloasBody.parentExecutionRequests = parentExecutionRequests;
|
|
299
|
+
// Drop voluntary exits that parent_execution_requests have invalidated (e.g. a withdrawal
|
|
300
|
+
// request initiating an exit on the same validator). Op pool selected against the unapplied
|
|
301
|
+
// state, so re-validate against the post-apply state to avoid producing an invalid block.
|
|
302
|
+
if (isExtendingPayload && commonBlockBody.voluntaryExits.length > 0) {
|
|
303
|
+
gloasBody.voluntaryExits = commonBlockBody.voluntaryExits.filter((signedVoluntaryExit) =>
|
|
304
|
+
stateAfterParentPayload.isValidVoluntaryExit(signedVoluntaryExit, false)
|
|
305
|
+
);
|
|
306
|
+
}
|
|
283
307
|
blockBody = gloasBody as AssembledBodyType<T>;
|
|
284
308
|
|
|
285
309
|
// Store execution payload data required to construct execution payload envelope later
|
|
@@ -288,6 +312,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
288
312
|
gloasResult.executionRequests = executionRequests;
|
|
289
313
|
gloasResult.blobsBundle = blobsBundle;
|
|
290
314
|
gloasResult.cells = cells;
|
|
315
|
+
gloasResult.parentBlockRoot = fromHex(parentBlock.blockRoot);
|
|
291
316
|
|
|
292
317
|
const fetchedTime = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.genesisTime);
|
|
293
318
|
this.metrics?.blockPayload.payloadFetchedTime.observe({prepType}, fetchedTime);
|
|
@@ -615,6 +640,10 @@ export async function prepareExecutionPayload(
|
|
|
615
640
|
parentBlockHash: Bytes32,
|
|
616
641
|
safeBlockHash: RootHex,
|
|
617
642
|
finalizedBlockHash: RootHex,
|
|
643
|
+
/**
|
|
644
|
+
* Post-gloas, when extending a full parent, callers must apply
|
|
645
|
+
* parent execution payload first (see `withParentPayloadApplied`).
|
|
646
|
+
*/
|
|
618
647
|
state: IBeaconStateViewBellatrix,
|
|
619
648
|
suggestedFeeRecipient: string
|
|
620
649
|
): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
|
|
@@ -712,6 +741,10 @@ export function getPayloadAttributesForSSE(
|
|
|
712
741
|
parentBlockHash,
|
|
713
742
|
feeRecipient,
|
|
714
743
|
}: {
|
|
744
|
+
/**
|
|
745
|
+
* Post-gloas, when extending a full parent, callers must apply
|
|
746
|
+
* parent execution payload first (see `withParentPayloadApplied`).
|
|
747
|
+
*/
|
|
715
748
|
prepareState: IBeaconStateViewBellatrix;
|
|
716
749
|
prepareSlot: Slot;
|
|
717
750
|
parentBlockRoot: Root;
|
|
@@ -764,6 +797,10 @@ function preparePayloadAttributes(
|
|
|
764
797
|
parentBlockHash,
|
|
765
798
|
feeRecipient,
|
|
766
799
|
}: {
|
|
800
|
+
/**
|
|
801
|
+
* Post-gloas, when extending a full parent, callers must apply
|
|
802
|
+
* parent execution payload first (see `withParentPayloadApplied`).
|
|
803
|
+
*/
|
|
767
804
|
prepareState: IBeaconStateViewBellatrix;
|
|
768
805
|
prepareSlot: Slot;
|
|
769
806
|
parentBlockRoot: Root;
|
|
@@ -786,13 +823,22 @@ function preparePayloadAttributes(
|
|
|
786
823
|
|
|
787
824
|
if (isStatePostGloas(prepareState)) {
|
|
788
825
|
const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
826
|
+
if (isExtendingPayload) {
|
|
827
|
+
// applyParentExecutionPayload sets latestBlockHash = parentBid.blockHash, so a mismatch
|
|
828
|
+
// here means the caller did not apply parent payload to prepareState
|
|
829
|
+
if (!byteArrayEquals(prepareState.latestBlockHash, prepareState.latestExecutionPayloadBid.blockHash)) {
|
|
830
|
+
throw new Error("Expected state with parent execution payload applied for withdrawals");
|
|
831
|
+
}
|
|
832
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
833
|
+
prepareState.getExpectedWithdrawals().expectedWithdrawals;
|
|
834
|
+
} else {
|
|
835
|
+
// When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
|
|
836
|
+
// already deducted from CL balances but never credited on the EL (the envelope
|
|
837
|
+
// was not delivered). The next payload must carry those same withdrawals to
|
|
838
|
+
// restore CL/EL consistency, otherwise validators permanently lose that balance.
|
|
839
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
840
|
+
prepareState.payloadExpectedWithdrawals;
|
|
841
|
+
}
|
|
796
842
|
} else {
|
|
797
843
|
// withdrawals logic is now fork aware as it changes on electra fork post capella
|
|
798
844
|
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
@@ -804,6 +850,10 @@ function preparePayloadAttributes(
|
|
|
804
850
|
(payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
|
|
805
851
|
}
|
|
806
852
|
|
|
853
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
854
|
+
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
|
|
855
|
+
}
|
|
856
|
+
|
|
807
857
|
return payloadAttributes;
|
|
808
858
|
}
|
|
809
859
|
|
|
@@ -21,6 +21,7 @@ export enum RegenCaller {
|
|
|
21
21
|
validateGossipAttestation = "validateGossipAttestation",
|
|
22
22
|
validateGossipVoluntaryExit = "validateGossipVoluntaryExit",
|
|
23
23
|
validateGossipExecutionPayloadBid = "validateGossipExecutionPayloadBid",
|
|
24
|
+
validateGossipProposerPreferences = "validateGossipProposerPreferences",
|
|
24
25
|
onForkChoiceFinalized = "onForkChoiceFinalized",
|
|
25
26
|
restApi = "restApi",
|
|
26
27
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
3
3
|
import {IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
|
|
4
|
-
import {BeaconBlock, Epoch, RootHex, Slot,
|
|
4
|
+
import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
|
|
5
5
|
import {Logger, toRootHex} from "@lodestar/utils";
|
|
6
6
|
import {Metrics} from "../../metrics/index.js";
|
|
7
7
|
import {JobItemQueue} from "../../util/queue/index.js";
|
|
@@ -88,12 +88,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
88
88
|
*/
|
|
89
89
|
getPreStateSync(block: BeaconBlock): IBeaconStateView | null {
|
|
90
90
|
const parentRoot = toRootHex(block.parentRoot);
|
|
91
|
-
const parentBlock =
|
|
92
|
-
? this.forkChoice.getBlockHexAndBlockHash(
|
|
93
|
-
parentRoot,
|
|
94
|
-
toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
|
|
95
|
-
)
|
|
96
|
-
: this.forkChoice.getBlockHexDefaultStatus(parentRoot);
|
|
91
|
+
const parentBlock = this.forkChoice.getBlockHexDefaultStatus(parentRoot);
|
|
97
92
|
if (!parentBlock) {
|
|
98
93
|
throw new RegenError({
|
|
99
94
|
code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
|
package/src/chain/regen/regen.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
computeEpochAtSlot,
|
|
10
10
|
computeStartSlotAtEpoch,
|
|
11
11
|
} from "@lodestar/state-transition";
|
|
12
|
-
import {BeaconBlock, RootHex, SignedBeaconBlock, Slot
|
|
12
|
+
import {BeaconBlock, RootHex, SignedBeaconBlock, Slot} from "@lodestar/types";
|
|
13
13
|
import {Logger, fromHex, toRootHex} from "@lodestar/utils";
|
|
14
14
|
import {IBeaconDb} from "../../db/index.js";
|
|
15
15
|
import {Metrics} from "../../metrics/index.js";
|
|
@@ -57,12 +57,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
57
57
|
regenCaller: RegenCaller
|
|
58
58
|
): Promise<IBeaconStateView> {
|
|
59
59
|
const parentRoot = toRootHex(block.parentRoot);
|
|
60
|
-
const parentBlock =
|
|
61
|
-
? this.modules.forkChoice.getBlockHexAndBlockHash(
|
|
62
|
-
parentRoot,
|
|
63
|
-
toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
|
|
64
|
-
)
|
|
65
|
-
: this.modules.forkChoice.getBlockHexDefaultStatus(parentRoot);
|
|
60
|
+
const parentBlock = this.modules.forkChoice.getBlockHexDefaultStatus(parentRoot);
|
|
66
61
|
if (!parentBlock) {
|
|
67
62
|
throw new RegenError({
|
|
68
63
|
code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
|
|
@@ -5,3 +5,4 @@ export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
|
|
|
5
5
|
export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
|
|
6
6
|
export {SeenBlockInput} from "./seenGossipBlockInput.js";
|
|
7
7
|
export {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenPayloadEnvelopeInput.js";
|
|
8
|
+
export {SeenProposerPreferences} from "./seenProposerPreferences.js";
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
1
2
|
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
2
3
|
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
3
|
-
import {RootHex} from "@lodestar/types";
|
|
4
|
+
import {RootHex, Slot} from "@lodestar/types";
|
|
4
5
|
import {Logger} from "@lodestar/utils";
|
|
5
6
|
import {Metrics} from "../../metrics/metrics.js";
|
|
7
|
+
import {IClock} from "../../util/clock.js";
|
|
6
8
|
import {SerializedCache} from "../../util/serializedCache.js";
|
|
9
|
+
import {isDaOutOfRange} from "../blocks/blockInput/index.js";
|
|
7
10
|
import {CreateFromBlockProps, PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
|
|
8
11
|
import {ChainEvent, ChainEventEmitter} from "../emitter.js";
|
|
9
12
|
|
|
@@ -11,6 +14,8 @@ export type {PayloadEnvelopeInputState} from "../blocks/payloadEnvelopeInput/ind
|
|
|
11
14
|
export {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
|
|
12
15
|
|
|
13
16
|
export type SeenPayloadEnvelopeInputModules = {
|
|
17
|
+
config: ChainForkConfig;
|
|
18
|
+
clock: IClock;
|
|
14
19
|
chainEvents: ChainEventEmitter;
|
|
15
20
|
signal: AbortSignal;
|
|
16
21
|
serializedCache: SerializedCache;
|
|
@@ -21,10 +26,19 @@ export type SeenPayloadEnvelopeInputModules = {
|
|
|
21
26
|
/**
|
|
22
27
|
* Cache for tracking PayloadEnvelopeInput instances, keyed by beacon block root.
|
|
23
28
|
*
|
|
24
|
-
* Created during block import when a block is processed.
|
|
25
|
-
*
|
|
29
|
+
* Created during block import when a block is processed. Two pruning paths:
|
|
30
|
+
* - `prepareNextSlot` calls `pruneBelow(headParentSlot)` every slot once the head we'll build
|
|
31
|
+
* on is known.
|
|
32
|
+
* - `onFinalized` calls `pruneBelow(finalizedSlot)` on every finalization for bulk cleanup.
|
|
33
|
+
*
|
|
34
|
+
* Steady state (linear chain, healthy progression): the cache holds ~2 entries — the head
|
|
35
|
+
* (parent for next-slot production) and its parent (proposer-boost-reorg fallback). It can
|
|
36
|
+
* transiently hold more during forks, range-sync bursts, or when `prepareNextSlot` skips
|
|
37
|
+
* ticks; subsequent ticks settle it back.
|
|
26
38
|
*/
|
|
27
39
|
export class SeenPayloadEnvelopeInput {
|
|
40
|
+
private readonly config: ChainForkConfig;
|
|
41
|
+
private readonly clock: IClock;
|
|
28
42
|
private readonly chainEvents: ChainEventEmitter;
|
|
29
43
|
private readonly signal: AbortSignal;
|
|
30
44
|
private readonly serializedCache: SerializedCache;
|
|
@@ -32,7 +46,9 @@ export class SeenPayloadEnvelopeInput {
|
|
|
32
46
|
private readonly logger?: Logger;
|
|
33
47
|
private payloadInputs = new Map<RootHex, PayloadEnvelopeInput>();
|
|
34
48
|
|
|
35
|
-
constructor({chainEvents, signal, serializedCache, metrics, logger}: SeenPayloadEnvelopeInputModules) {
|
|
49
|
+
constructor({config, clock, chainEvents, signal, serializedCache, metrics, logger}: SeenPayloadEnvelopeInputModules) {
|
|
50
|
+
this.config = config;
|
|
51
|
+
this.clock = clock;
|
|
36
52
|
this.chainEvents = chainEvents;
|
|
37
53
|
this.signal = signal;
|
|
38
54
|
this.serializedCache = serializedCache;
|
|
@@ -58,25 +74,27 @@ export class SeenPayloadEnvelopeInput {
|
|
|
58
74
|
}
|
|
59
75
|
|
|
60
76
|
private onFinalized = (checkpoint: CheckpointWithHex): void => {
|
|
61
|
-
|
|
62
|
-
const finalizedSlot = computeStartSlotAtEpoch(checkpoint.epoch);
|
|
63
|
-
let deletedCount = 0;
|
|
64
|
-
for (const [, input] of this.payloadInputs) {
|
|
65
|
-
if (input.slot < finalizedSlot) {
|
|
66
|
-
this.evictPayloadInput(input);
|
|
67
|
-
deletedCount++;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
this.logger?.debug("SeenPayloadEnvelopeInput.onFinalized deleted cached entries", {deletedCount});
|
|
77
|
+
this.pruneBelow(computeStartSlotAtEpoch(checkpoint.epoch));
|
|
71
78
|
};
|
|
72
79
|
|
|
73
|
-
add(props: CreateFromBlockProps): PayloadEnvelopeInput {
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
add(props: Omit<CreateFromBlockProps, "daOutOfRange">): PayloadEnvelopeInput {
|
|
81
|
+
const existing = this.payloadInputs.get(props.blockRootHex);
|
|
82
|
+
if (existing !== undefined) {
|
|
83
|
+
this.logger?.verbose("SeenPayloadEnvelopeInput.add reused existing entry", {
|
|
84
|
+
slot: existing.slot,
|
|
85
|
+
root: props.blockRootHex,
|
|
86
|
+
});
|
|
87
|
+
return existing;
|
|
76
88
|
}
|
|
77
|
-
const
|
|
89
|
+
const daOutOfRange = isDaOutOfRange(this.config, props.forkName, props.block.message.slot, this.clock.currentEpoch);
|
|
90
|
+
const input = PayloadEnvelopeInput.createFromBlock({...props, daOutOfRange});
|
|
78
91
|
this.payloadInputs.set(props.blockRootHex, input);
|
|
79
92
|
this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
|
|
93
|
+
this.logger?.verbose("SeenPayloadEnvelopeInput.add created new entry", {
|
|
94
|
+
slot: input.slot,
|
|
95
|
+
root: props.blockRootHex,
|
|
96
|
+
daOutOfRange,
|
|
97
|
+
});
|
|
80
98
|
return input;
|
|
81
99
|
}
|
|
82
100
|
|
|
@@ -88,17 +106,21 @@ export class SeenPayloadEnvelopeInput {
|
|
|
88
106
|
return this.payloadInputs.get(blockRootHex)?.hasPayloadEnvelope() ?? false;
|
|
89
107
|
}
|
|
90
108
|
|
|
91
|
-
prune(blockRootHex: RootHex): void {
|
|
92
|
-
const payloadInput = this.payloadInputs.get(blockRootHex);
|
|
93
|
-
if (payloadInput) {
|
|
94
|
-
this.evictPayloadInput(payloadInput);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
109
|
size(): number {
|
|
99
110
|
return this.payloadInputs.size;
|
|
100
111
|
}
|
|
101
112
|
|
|
113
|
+
pruneBelow(slot: Slot): void {
|
|
114
|
+
let deletedCount = 0;
|
|
115
|
+
for (const [, input] of this.payloadInputs) {
|
|
116
|
+
if (input.slot < slot) {
|
|
117
|
+
this.evictPayloadInput(input);
|
|
118
|
+
deletedCount++;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
this.logger?.debug("SeenPayloadEnvelopeInput.pruneBelow deleted entries", {slot, deletedCount});
|
|
122
|
+
}
|
|
123
|
+
|
|
102
124
|
private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
|
|
103
125
|
this.serializedCache.delete(payloadInput.getSerializedCacheKeys());
|
|
104
126
|
this.payloadInputs.delete(payloadInput.blockRootHex);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {RootHex, Slot, ValidatorIndex} from "@lodestar/types";
|
|
2
|
+
import {MapDef} from "@lodestar/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tracks signed proposer preferences we've already seen per (dependent_root, proposal_slot, validator_index).
|
|
6
|
+
*/
|
|
7
|
+
export class SeenProposerPreferences {
|
|
8
|
+
private readonly validatorByDependentRootBySlot = new MapDef<Slot, Map<RootHex, ValidatorIndex>>(
|
|
9
|
+
() => new Map<RootHex, ValidatorIndex>()
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
isKnown(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): boolean {
|
|
13
|
+
return this.validatorByDependentRootBySlot.get(proposalSlot)?.get(dependentRoot) === validatorIndex;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
add(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): void {
|
|
17
|
+
this.validatorByDependentRootBySlot.getOrDefault(proposalSlot).set(dependentRoot, validatorIndex);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Entries are only load-bearing while `proposal_slot > current_slot`. Once the slot has
|
|
22
|
+
* passed the `[IGNORE] proposal_slot > current_slot` gossip rule takes over, so drop them
|
|
23
|
+
* on each slot tick.
|
|
24
|
+
*/
|
|
25
|
+
prune(currentSlot: Slot): void {
|
|
26
|
+
for (const slot of this.validatorByDependentRootBySlot.keys()) {
|
|
27
|
+
if (slot < currentSlot) {
|
|
28
|
+
this.validatorByDependentRootBySlot.delete(slot);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -226,7 +226,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
226
226
|
}
|
|
227
227
|
sszTimer?.();
|
|
228
228
|
const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer();
|
|
229
|
-
|
|
229
|
+
// preload validators and balances for faster state transition
|
|
230
|
+
const newCachedState = seedState.loadOtherState(stateBytes, validatorsBytes, {
|
|
231
|
+
preloadValidatorsAndBalances: true,
|
|
232
|
+
});
|
|
230
233
|
// hashTreeRoot() calls the commit() inside
|
|
231
234
|
// there is no modification inside the state, it's just that we want to compute and cache all roots
|
|
232
235
|
const stateRoot = toRootHex(newCachedState.hashTreeRoot());
|
|
@@ -103,6 +103,7 @@ export async function validateGossipBlock(
|
|
|
103
103
|
if (chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHashHex) === null) {
|
|
104
104
|
throw new BlockGossipError(GossipAction.IGNORE, {
|
|
105
105
|
code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
|
|
106
|
+
parentRoot,
|
|
106
107
|
parentBlockHash: parentBlockHashHex,
|
|
107
108
|
});
|
|
108
109
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {PublicKey} from "@chainsafe/blst";
|
|
2
2
|
import {
|
|
3
|
+
computeEpochAtSlot,
|
|
3
4
|
createSingleSignatureSetFromComponents,
|
|
4
5
|
getExecutionPayloadBidSigningRoot,
|
|
5
6
|
isActiveBuilder,
|
|
@@ -47,9 +48,12 @@ async function validateExecutionPayloadBid(
|
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
// [IGNORE]
|
|
51
|
-
//
|
|
52
|
-
//
|
|
51
|
+
// [IGNORE] A `SignedProposerPreferences` matching `bid.slot` and the bid's branch has been
|
|
52
|
+
// seen — i.e. `proposal_slot == bid.slot` AND `dependent_root ==
|
|
53
|
+
// get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`,
|
|
54
|
+
// where `parent_state` is the post-state of `bid.parent_block_root`.
|
|
55
|
+
// This is the message referenced as `proposer_preferences` in the following REJECT rules.
|
|
56
|
+
// TODO GLOAS: Implement once a ProposerPreferencesPool exists.
|
|
53
57
|
|
|
54
58
|
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
55
59
|
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
@@ -70,11 +74,24 @@ async function validateExecutionPayloadBid(
|
|
|
70
74
|
});
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
// [REJECT] `bid.fee_recipient
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
// TODO GLOAS: Implement
|
|
77
|
+
// [REJECT] `bid.fee_recipient == proposer_preferences.fee_recipient`.
|
|
78
|
+
// [REJECT] `bid.gas_limit == proposer_preferences.gas_limit`.
|
|
79
|
+
// Both compared against the matching `proposer_preferences` defined above (same branch
|
|
80
|
+
// via dependent_root, same proposal_slot).
|
|
81
|
+
// TODO GLOAS: Implement once a ProposerPreferencesPool exists.
|
|
82
|
+
|
|
83
|
+
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
84
|
+
// consensus layer -- i.e. validate that
|
|
85
|
+
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
86
|
+
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
87
|
+
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
88
|
+
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
89
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
90
|
+
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
91
|
+
blobKzgCommitmentsLen,
|
|
92
|
+
commitmentLimit: maxBlobsPerBlock,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
78
95
|
|
|
79
96
|
// [IGNORE] this is the first signed bid seen with a valid signature from the given builder for this slot.
|
|
80
97
|
if (chain.seenExecutionPayloadBids.isKnown(bid.slot, bid.builderIndex)) {
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
getExecutionPayloadEnvelopeSignatureSet,
|
|
5
5
|
isStatePostGloas,
|
|
6
6
|
} from "@lodestar/state-transition";
|
|
7
|
-
import {gloas} from "@lodestar/types";
|
|
8
|
-
import {toRootHex} from "@lodestar/utils";
|
|
7
|
+
import {gloas, ssz} from "@lodestar/types";
|
|
8
|
+
import {byteArrayEquals, toRootHex} from "@lodestar/utils";
|
|
9
9
|
import {ExecutionPayloadEnvelopeError, ExecutionPayloadEnvelopeErrorCode, GossipAction} from "../errors/index.js";
|
|
10
10
|
import {IBeaconChain} from "../index.js";
|
|
11
11
|
import {RegenCaller} from "../regen/index.js";
|
|
@@ -53,7 +53,7 @@ async function validateExecutionPayloadEnvelope(
|
|
|
53
53
|
throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
|
|
54
54
|
code: ExecutionPayloadEnvelopeErrorCode.ENVELOPE_ALREADY_KNOWN,
|
|
55
55
|
blockRoot: blockRootHex,
|
|
56
|
-
slot:
|
|
56
|
+
slot: payload.slotNumber,
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -65,13 +65,13 @@ async function validateExecutionPayloadEnvelope(
|
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
// [IGNORE] The envelope is from a slot greater than or equal to the latest finalized slot -- i.e. validate that `
|
|
68
|
+
// [IGNORE] The envelope is from a slot greater than or equal to the latest finalized slot -- i.e. validate that `payload.slotNumber >= compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)`
|
|
69
69
|
const finalizedCheckpoint = chain.forkChoice.getFinalizedCheckpoint();
|
|
70
70
|
const finalizedSlot = computeStartSlotAtEpoch(finalizedCheckpoint.epoch);
|
|
71
|
-
if (
|
|
71
|
+
if (payload.slotNumber < finalizedSlot) {
|
|
72
72
|
throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
|
|
73
73
|
code: ExecutionPayloadEnvelopeErrorCode.BELONG_TO_FINALIZED_BLOCK,
|
|
74
|
-
envelopeSlot:
|
|
74
|
+
envelopeSlot: payload.slotNumber,
|
|
75
75
|
finalizedSlot,
|
|
76
76
|
});
|
|
77
77
|
}
|
|
@@ -80,11 +80,11 @@ async function validateExecutionPayloadEnvelope(
|
|
|
80
80
|
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
|
|
81
81
|
// it is possible that the block didn't pass the validation
|
|
82
82
|
|
|
83
|
-
// [REJECT] `block.slot` equals `
|
|
84
|
-
if (block.slot !==
|
|
83
|
+
// [REJECT] `block.slot` equals `payload.slotNumber`.
|
|
84
|
+
if (block.slot !== payload.slotNumber) {
|
|
85
85
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
86
86
|
code: ExecutionPayloadEnvelopeErrorCode.SLOT_MISMATCH,
|
|
87
|
-
envelopeSlot:
|
|
87
|
+
envelopeSlot: payload.slotNumber,
|
|
88
88
|
blockSlot: block.slot,
|
|
89
89
|
});
|
|
90
90
|
}
|
|
@@ -107,6 +107,16 @@ async function validateExecutionPayloadEnvelope(
|
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
// [REJECT] `hash_tree_root(envelope.execution_requests) == bid.execution_requests_root`
|
|
111
|
+
const requestsRoot = ssz.electra.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
|
|
112
|
+
if (!byteArrayEquals(requestsRoot, payloadInput.getBid().executionRequestsRoot)) {
|
|
113
|
+
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
114
|
+
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH,
|
|
115
|
+
envelopeRequestsRoot: toRootHex(requestsRoot),
|
|
116
|
+
bidRequestsRoot: toRootHex(payloadInput.getBid().executionRequestsRoot),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
110
120
|
// Get the block state to verify the builder's signature.
|
|
111
121
|
const blockState = await chain.regen
|
|
112
122
|
.getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)
|
|
@@ -114,7 +124,7 @@ async function validateExecutionPayloadEnvelope(
|
|
|
114
124
|
throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
|
|
115
125
|
code: ExecutionPayloadEnvelopeErrorCode.UNKNOWN_BLOCK_STATE,
|
|
116
126
|
blockRoot: blockRootHex,
|
|
117
|
-
slot:
|
|
127
|
+
slot: payload.slotNumber,
|
|
118
128
|
});
|
|
119
129
|
});
|
|
120
130
|
if (!isStatePostGloas(blockState)) {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {
|
|
3
|
+
computeEpochAtSlot,
|
|
4
|
+
createSingleSignatureSetFromComponents,
|
|
5
|
+
getProposerPreferencesSigningRoot,
|
|
6
|
+
} from "@lodestar/state-transition";
|
|
7
|
+
import {ValidatorIndex, gloas} from "@lodestar/types";
|
|
8
|
+
import {toRootHex} from "@lodestar/utils";
|
|
9
|
+
import {GossipAction, ProposerPreferencesError, ProposerPreferencesErrorCode} from "../errors/index.js";
|
|
10
|
+
import {IBeaconChain} from "../index.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validates a gossiped `SignedProposerPreferences` per
|
|
14
|
+
* https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/p2p-interface.md#proposer_preferences
|
|
15
|
+
*/
|
|
16
|
+
export async function validateGossipProposerPreferences(
|
|
17
|
+
chain: IBeaconChain,
|
|
18
|
+
signedProposerPreferences: gloas.SignedProposerPreferences
|
|
19
|
+
): Promise<void> {
|
|
20
|
+
const preferences = signedProposerPreferences.message;
|
|
21
|
+
const {proposalSlot, validatorIndex, dependentRoot} = preferences;
|
|
22
|
+
const dependentRootHex = toRootHex(dependentRoot);
|
|
23
|
+
const proposalEpoch = computeEpochAtSlot(proposalSlot);
|
|
24
|
+
|
|
25
|
+
// [IGNORE] `preferences.proposal_slot` is in the current or next epoch.
|
|
26
|
+
const currentEpoch = chain.clock.currentEpoch;
|
|
27
|
+
if (proposalEpoch < currentEpoch || proposalEpoch > currentEpoch + 1) {
|
|
28
|
+
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
29
|
+
code: ProposerPreferencesErrorCode.INVALID_EPOCH,
|
|
30
|
+
proposalSlot,
|
|
31
|
+
currentEpoch,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// [IGNORE] `preferences.proposal_slot` has not already passed.
|
|
36
|
+
const currentSlot = chain.clock.currentSlot;
|
|
37
|
+
if (proposalSlot <= currentSlot) {
|
|
38
|
+
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
39
|
+
code: ProposerPreferencesErrorCode.PROPOSAL_SLOT_PASSED,
|
|
40
|
+
proposalSlot,
|
|
41
|
+
currentSlot,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// [IGNORE] The block with root `dependent_root` has been seen by the node.
|
|
46
|
+
// Resolve the proposer lookahead for the message's branch via head state (fast path) or
|
|
47
|
+
// the previous-root checkpoint state (populated by `processSlotsToNearestCheckpoint` for
|
|
48
|
+
// any imported branch crossing into `proposalEpoch - 1`). The head-state path also handles
|
|
49
|
+
// narrow timing windows where the checkpoint state isn't yet populated.
|
|
50
|
+
const headState = chain.getHeadState();
|
|
51
|
+
let proposers: ValidatorIndex[] | null = null;
|
|
52
|
+
if (headState.epoch === proposalEpoch && headState.currentDecisionRoot === dependentRootHex) {
|
|
53
|
+
proposers = headState.currentProposers;
|
|
54
|
+
} else if (headState.epoch === proposalEpoch - 1 && headState.nextDecisionRoot === dependentRootHex) {
|
|
55
|
+
proposers = headState.nextProposers;
|
|
56
|
+
} else {
|
|
57
|
+
// Sync lookup only to not trigger disk reload from gossip input.
|
|
58
|
+
const checkpointState = chain.regen.getCheckpointStateSync({epoch: proposalEpoch - 1, rootHex: dependentRootHex});
|
|
59
|
+
if (checkpointState !== null) {
|
|
60
|
+
// State is at `proposalEpoch - 1`, so proposers for `proposalSlot` (next epoch from
|
|
61
|
+
// the state's perspective) live in `nextProposers`.
|
|
62
|
+
proposers = checkpointState.nextProposers;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (proposers === null) {
|
|
66
|
+
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
67
|
+
code: ProposerPreferencesErrorCode.UNKNOWN_DEPENDENT_ROOT,
|
|
68
|
+
proposalSlot,
|
|
69
|
+
dependentRoot: dependentRootHex,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// [REJECT] `is_valid_proposal_slot(state, preferences)` returns True.
|
|
74
|
+
if (proposers[proposalSlot % SLOTS_PER_EPOCH] !== validatorIndex) {
|
|
75
|
+
throw new ProposerPreferencesError(GossipAction.REJECT, {
|
|
76
|
+
code: ProposerPreferencesErrorCode.INVALID_PROPOSER,
|
|
77
|
+
proposalSlot,
|
|
78
|
+
validatorIndex,
|
|
79
|
+
dependentRoot: dependentRootHex,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// [IGNORE] First valid message for (dependent_root, proposal_slot, validator_index).
|
|
84
|
+
if (chain.seenProposerPreferences.isKnown(dependentRootHex, proposalSlot, validatorIndex)) {
|
|
85
|
+
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
86
|
+
code: ProposerPreferencesErrorCode.ALREADY_KNOWN,
|
|
87
|
+
proposalSlot,
|
|
88
|
+
validatorIndex,
|
|
89
|
+
dependentRoot: dependentRootHex,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// [REJECT] `signed_proposer_preferences.signature` is valid with respect to the validator's public key.
|
|
94
|
+
const signatureSet = createSingleSignatureSetFromComponents(
|
|
95
|
+
chain.pubkeyCache.getOrThrow(validatorIndex),
|
|
96
|
+
getProposerPreferencesSigningRoot(chain.config, preferences),
|
|
97
|
+
signedProposerPreferences.signature
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true}))) {
|
|
101
|
+
throw new ProposerPreferencesError(GossipAction.REJECT, {
|
|
102
|
+
code: ProposerPreferencesErrorCode.INVALID_SIGNATURE,
|
|
103
|
+
proposalSlot,
|
|
104
|
+
validatorIndex,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Valid
|
|
109
|
+
chain.seenProposerPreferences.add(dependentRootHex, proposalSlot, validatorIndex);
|
|
110
|
+
}
|
|
@@ -19,7 +19,7 @@ export class ExecutionPayloadEnvelopeArchiveRepository extends Repository<Slot,
|
|
|
19
19
|
* Id is the slot from the envelope
|
|
20
20
|
*/
|
|
21
21
|
getId(value: gloas.SignedExecutionPayloadEnvelope): Slot {
|
|
22
|
-
return value.message.
|
|
22
|
+
return value.message.payload.slotNumber;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
encodeKey(id: Slot): Uint8Array {
|