@lodestar/beacon-node 1.43.0-dev.9fa9f08ef6 → 1.43.0-dev.a142c56215
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.js +4 -6
- package/lib/api/impl/beacon/blocks/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/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 +0 -4
- 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/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +6 -3
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +26 -14
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +73 -86
- 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 +28 -10
- package/lib/chain/blocks/index.js.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 +14 -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 +81 -12
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts +3 -2
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +30 -5
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +15 -4
- 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/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 +6 -5
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +16 -5
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +3 -3
- package/lib/chain/emitter.d.ts.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/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 +5 -4
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +30 -10
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -2
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +39 -13
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- 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 +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 +19 -9
- 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/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/topic.d.ts +23 -2
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/network.js +1 -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 +5 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +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/notifier.js +7 -1
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/range/batch.d.ts +12 -2
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +56 -30
- 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 +4 -3
- 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 +24 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +649 -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 +147 -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 +6 -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 +6 -6
- package/src/api/impl/beacon/state/utils.ts +2 -2
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +0 -4
- 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/importBlock.ts +4 -2
- package/src/chain/blocks/importExecutionPayload.ts +92 -107
- package/src/chain/blocks/index.ts +44 -13
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
- package/src/chain/blocks/types.ts +14 -25
- package/src/chain/blocks/utils/chainSegment.ts +106 -17
- package/src/chain/blocks/verifyBlock.ts +35 -6
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -7
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
- package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
- package/src/chain/chain.ts +33 -19
- package/src/chain/emitter.ts +3 -3
- 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/forkChoice/index.ts +2 -22
- package/src/chain/interface.ts +9 -3
- package/src/chain/prepareNextSlot.ts +42 -12
- package/src/chain/produceBlock/produceBlockBody.ts +43 -11
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
- package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
- package/src/chain/validation/block.ts +1 -0
- package/src/chain/validation/executionPayloadBid.ts +14 -0
- package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
- package/src/chain/validation/payloadAttestationMessage.ts +5 -3
- 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/network.ts +1 -1
- package/src/network/processor/gossipHandlers.ts +7 -4
- 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/notifier.ts +8 -1
- package/src/sync/range/batch.ts +90 -35
- package/src/sync/range/chain.ts +13 -5
- package/src/sync/range/range.ts +18 -6
- package/src/sync/types.ts +72 -0
- package/src/sync/unknownBlock.ts +810 -57
- package/src/sync/utils/downloadByRange.ts +256 -39
- package/src/sync/utils/downloadByRoot.ts +12 -2
- package/src/sync/utils/pendingBlocksTree.ts +0 -15
- package/src/util/sszBytes.ts +21 -3
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
isStatePostBellatrix,
|
|
11
11
|
isStatePostGloas,
|
|
12
12
|
} from "@lodestar/state-transition";
|
|
13
|
-
import {Bytes32, Slot} from "@lodestar/types";
|
|
13
|
+
import {Bytes32, Slot, electra} from "@lodestar/types";
|
|
14
14
|
import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
|
|
15
15
|
import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js";
|
|
16
16
|
import {BuilderStatus} from "../execution/builder/http.js";
|
|
@@ -83,7 +83,7 @@ export class PrepareNextSlotScheduler {
|
|
|
83
83
|
const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
|
|
84
84
|
const {slot: headSlot, blockRoot: headRoot} = headBlock;
|
|
85
85
|
// may be updated below if we predict a proposer-boost-reorg
|
|
86
|
-
let
|
|
86
|
+
let updatedHead = headBlock;
|
|
87
87
|
|
|
88
88
|
// PS: previously this was comparing slots, but that gave no leway on the skipped
|
|
89
89
|
// slots on epoch bounday. Making it more fluid.
|
|
@@ -148,7 +148,7 @@ export class PrepareNextSlotScheduler {
|
|
|
148
148
|
{dontTransferCache: !isEpochTransition},
|
|
149
149
|
RegenCaller.predictProposerHead
|
|
150
150
|
);
|
|
151
|
-
|
|
151
|
+
updatedHead = proposerHead;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// Update the builder status, if enabled shoot an api call to check status
|
|
@@ -165,14 +165,19 @@ export class PrepareNextSlotScheduler {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
let parentBlockHash: Bytes32;
|
|
168
|
+
let isExtendingPayload = false;
|
|
168
169
|
if (isStatePostGloas(updatedPrepareState)) {
|
|
169
|
-
|
|
170
|
+
isExtendingPayload = this.chain.forkChoice.shouldExtendPayload(updatedHead.blockRoot);
|
|
171
|
+
parentBlockHash = isExtendingPayload
|
|
170
172
|
? updatedPrepareState.latestExecutionPayloadBid.blockHash
|
|
171
173
|
: updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
|
|
172
174
|
} else {
|
|
173
175
|
parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
|
|
174
176
|
}
|
|
175
177
|
|
|
178
|
+
// Reused by the SSE emit below to avoid a second DB lookup on cache miss
|
|
179
|
+
let parentExecutionRequests: electra.ExecutionRequests | undefined;
|
|
180
|
+
|
|
176
181
|
if (feeRecipient) {
|
|
177
182
|
const preparationTime =
|
|
178
183
|
computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
|
|
@@ -182,6 +187,13 @@ export class PrepareNextSlotScheduler {
|
|
|
182
187
|
const finalizedBlockHash =
|
|
183
188
|
this.chain.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
|
|
184
189
|
|
|
190
|
+
if (isExtendingPayload) {
|
|
191
|
+
parentExecutionRequests = await this.chain.getParentExecutionRequests(
|
|
192
|
+
updatedHead.slot,
|
|
193
|
+
updatedHead.blockRoot
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
185
197
|
// awaiting here instead of throwing an async call because there is no other task
|
|
186
198
|
// left for scheduler and this gives nice semantics to catch and log errors in the
|
|
187
199
|
// try/catch wrapper here.
|
|
@@ -189,12 +201,13 @@ export class PrepareNextSlotScheduler {
|
|
|
189
201
|
this.chain,
|
|
190
202
|
this.logger,
|
|
191
203
|
fork as ForkPostBellatrix, // State is of execution type
|
|
192
|
-
fromHex(
|
|
204
|
+
fromHex(updatedHead.blockRoot),
|
|
193
205
|
parentBlockHash,
|
|
194
206
|
safeBlockHash,
|
|
195
207
|
finalizedBlockHash,
|
|
196
208
|
updatedPrepareState,
|
|
197
|
-
feeRecipient
|
|
209
|
+
feeRecipient,
|
|
210
|
+
parentExecutionRequests
|
|
198
211
|
);
|
|
199
212
|
this.logger.verbose("PrepareNextSlotScheduler prepared new payload", {
|
|
200
213
|
prepareSlot,
|
|
@@ -203,21 +216,38 @@ export class PrepareNextSlotScheduler {
|
|
|
203
216
|
});
|
|
204
217
|
}
|
|
205
218
|
|
|
219
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
220
|
+
// Cutoff = slot of the parent of the block we'll actually build on (post-reorg).
|
|
221
|
+
// Steady state: cache holds just 2 entries — head (parent for next-slot production)
|
|
222
|
+
// and head.parent (proposer-boost-reorg fallback). Anything older is evicted.
|
|
223
|
+
const updatedHeadParent = this.chain.forkChoice.getBlockHexDefaultStatus(updatedHead.parentRoot);
|
|
224
|
+
if (updatedHeadParent) {
|
|
225
|
+
this.chain.seenPayloadEnvelopeInputCache.pruneBelow(updatedHeadParent.slot);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
206
229
|
this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
|
|
207
230
|
|
|
208
|
-
// If emitPayloadAttributes is true emit a SSE payloadAttributes event
|
|
231
|
+
// If emitPayloadAttributes is true emit a SSE payloadAttributes event for
|
|
232
|
+
// every slot. Without the flag, only emit the event if we are proposing in the next slot.
|
|
209
233
|
if (
|
|
210
|
-
this.chain.opts.emitPayloadAttributes === true &&
|
|
234
|
+
(feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
|
|
211
235
|
this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
|
|
212
236
|
) {
|
|
237
|
+
// if we didn't fetch above (not proposing), SSE still needs it here
|
|
238
|
+
if (!parentExecutionRequests && isExtendingPayload) {
|
|
239
|
+
parentExecutionRequests = await this.chain.getParentExecutionRequests(
|
|
240
|
+
updatedHead.slot,
|
|
241
|
+
updatedHead.blockRoot
|
|
242
|
+
);
|
|
243
|
+
}
|
|
213
244
|
const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
|
|
214
245
|
prepareState: updatedPrepareState,
|
|
215
246
|
prepareSlot,
|
|
216
|
-
parentBlockRoot: fromHex(
|
|
247
|
+
parentBlockRoot: fromHex(updatedHead.blockRoot),
|
|
217
248
|
parentBlockHash,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
feeRecipient: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
249
|
+
feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
|
|
250
|
+
parentExecutionRequests,
|
|
221
251
|
});
|
|
222
252
|
this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
|
|
223
253
|
}
|
|
@@ -46,9 +46,10 @@ 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
|
-
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
52
|
+
import {ZERO_HASH, ZERO_HASH_HEX} from "../../constants/index.js";
|
|
52
53
|
import {numToQuantity} from "../../execution/engine/utils.js";
|
|
53
54
|
import {
|
|
54
55
|
IExecutionBuilder,
|
|
@@ -213,9 +214,19 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
213
214
|
});
|
|
214
215
|
|
|
215
216
|
// Get execution payload from EL
|
|
216
|
-
const
|
|
217
|
+
const isExtendingPayload = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot));
|
|
218
|
+
let parentBlockHash = isExtendingPayload
|
|
217
219
|
? currentState.latestExecutionPayloadBid.blockHash
|
|
218
220
|
: currentState.latestExecutionPayloadBid.parentBlockHash;
|
|
221
|
+
// At gloas genesis the committed bid has no prior EL block to reference
|
|
222
|
+
// (`bid.parentBlockHash` is zero). Fall back to `bid.blockHash` (= eth1 genesis hash) so the
|
|
223
|
+
// FCU to the EL carries a valid head. Post-genesis bids always reference a non-zero parent.
|
|
224
|
+
if (isStatePostGloas(currentState) && byteArrayEquals(parentBlockHash, ZERO_HASH)) {
|
|
225
|
+
parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
|
|
226
|
+
}
|
|
227
|
+
const parentExecutionRequests = isExtendingPayload
|
|
228
|
+
? await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot)
|
|
229
|
+
: ssz.electra.ExecutionRequests.defaultValue();
|
|
219
230
|
const prepareRes = await prepareExecutionPayload(
|
|
220
231
|
this,
|
|
221
232
|
this.logger,
|
|
@@ -225,7 +236,8 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
225
236
|
safeBlockHash,
|
|
226
237
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
227
238
|
currentState,
|
|
228
|
-
feeRecipient
|
|
239
|
+
feeRecipient,
|
|
240
|
+
parentExecutionRequests
|
|
229
241
|
);
|
|
230
242
|
|
|
231
243
|
const {prepType, payloadId} = prepareRes;
|
|
@@ -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,
|
|
@@ -280,6 +293,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
280
293
|
gloasBody.signedExecutionPayloadBid = signedBid;
|
|
281
294
|
// TODO GLOAS: Get payload attestations from pool for previous slot
|
|
282
295
|
gloasBody.payloadAttestations = [];
|
|
296
|
+
gloasBody.parentExecutionRequests = parentExecutionRequests;
|
|
283
297
|
blockBody = gloasBody as AssembledBodyType<T>;
|
|
284
298
|
|
|
285
299
|
// Store execution payload data required to construct execution payload envelope later
|
|
@@ -616,7 +630,8 @@ export async function prepareExecutionPayload(
|
|
|
616
630
|
safeBlockHash: RootHex,
|
|
617
631
|
finalizedBlockHash: RootHex,
|
|
618
632
|
state: IBeaconStateViewBellatrix,
|
|
619
|
-
suggestedFeeRecipient: string
|
|
633
|
+
suggestedFeeRecipient: string,
|
|
634
|
+
parentExecutionRequests?: electra.ExecutionRequests
|
|
620
635
|
): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
|
|
621
636
|
const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
|
|
622
637
|
const prevRandao = state.getRandaoMix(state.epoch);
|
|
@@ -653,6 +668,7 @@ export async function prepareExecutionPayload(
|
|
|
653
668
|
parentBlockRoot,
|
|
654
669
|
parentBlockHash,
|
|
655
670
|
feeRecipient: suggestedFeeRecipient,
|
|
671
|
+
parentExecutionRequests,
|
|
656
672
|
});
|
|
657
673
|
|
|
658
674
|
payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
|
|
@@ -711,12 +727,14 @@ export function getPayloadAttributesForSSE(
|
|
|
711
727
|
parentBlockRoot,
|
|
712
728
|
parentBlockHash,
|
|
713
729
|
feeRecipient,
|
|
730
|
+
parentExecutionRequests,
|
|
714
731
|
}: {
|
|
715
732
|
prepareState: IBeaconStateViewBellatrix;
|
|
716
733
|
prepareSlot: Slot;
|
|
717
734
|
parentBlockRoot: Root;
|
|
718
735
|
parentBlockHash: Bytes32;
|
|
719
736
|
feeRecipient: string;
|
|
737
|
+
parentExecutionRequests?: electra.ExecutionRequests;
|
|
720
738
|
}
|
|
721
739
|
): SSEPayloadAttributes {
|
|
722
740
|
const payloadAttributes = preparePayloadAttributes(fork, chain, {
|
|
@@ -725,6 +743,7 @@ export function getPayloadAttributesForSSE(
|
|
|
725
743
|
parentBlockRoot,
|
|
726
744
|
parentBlockHash,
|
|
727
745
|
feeRecipient,
|
|
746
|
+
parentExecutionRequests,
|
|
728
747
|
});
|
|
729
748
|
|
|
730
749
|
let parentBlockNumber: number;
|
|
@@ -763,12 +782,14 @@ function preparePayloadAttributes(
|
|
|
763
782
|
parentBlockRoot,
|
|
764
783
|
parentBlockHash,
|
|
765
784
|
feeRecipient,
|
|
785
|
+
parentExecutionRequests,
|
|
766
786
|
}: {
|
|
767
787
|
prepareState: IBeaconStateViewBellatrix;
|
|
768
788
|
prepareSlot: Slot;
|
|
769
789
|
parentBlockRoot: Root;
|
|
770
790
|
parentBlockHash: Bytes32;
|
|
771
791
|
feeRecipient: string;
|
|
792
|
+
parentExecutionRequests?: electra.ExecutionRequests;
|
|
772
793
|
}
|
|
773
794
|
): SSEPayloadAttributes["payloadAttributes"] {
|
|
774
795
|
const timestamp = computeTimeAtSlot(chain.config, prepareSlot, prepareState.genesisTime);
|
|
@@ -786,13 +807,20 @@ function preparePayloadAttributes(
|
|
|
786
807
|
|
|
787
808
|
if (isStatePostGloas(prepareState)) {
|
|
788
809
|
const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
810
|
+
if (isExtendingPayload) {
|
|
811
|
+
if (parentExecutionRequests === undefined) {
|
|
812
|
+
throw new Error("parentExecutionRequests required when extending full parent");
|
|
813
|
+
}
|
|
814
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
815
|
+
prepareState.getExpectedWithdrawalsForFullParent(parentExecutionRequests);
|
|
816
|
+
} else {
|
|
817
|
+
// When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
|
|
818
|
+
// already deducted from CL balances but never credited on the EL (the envelope
|
|
819
|
+
// was not delivered). The next payload must carry those same withdrawals to
|
|
820
|
+
// restore CL/EL consistency, otherwise validators permanently lose that balance.
|
|
821
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
822
|
+
prepareState.payloadExpectedWithdrawals;
|
|
823
|
+
}
|
|
796
824
|
} else {
|
|
797
825
|
// withdrawals logic is now fork aware as it changes on electra fork post capella
|
|
798
826
|
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
@@ -804,6 +832,10 @@ function preparePayloadAttributes(
|
|
|
804
832
|
(payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
|
|
805
833
|
}
|
|
806
834
|
|
|
835
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
836
|
+
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
|
|
837
|
+
}
|
|
838
|
+
|
|
807
839
|
return payloadAttributes;
|
|
808
840
|
}
|
|
809
841
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
2
2
|
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
3
|
-
import {RootHex} from "@lodestar/types";
|
|
3
|
+
import {RootHex, Slot} from "@lodestar/types";
|
|
4
4
|
import {Logger} from "@lodestar/utils";
|
|
5
5
|
import {Metrics} from "../../metrics/metrics.js";
|
|
6
6
|
import {SerializedCache} from "../../util/serializedCache.js";
|
|
@@ -21,8 +21,15 @@ export type SeenPayloadEnvelopeInputModules = {
|
|
|
21
21
|
/**
|
|
22
22
|
* Cache for tracking PayloadEnvelopeInput instances, keyed by beacon block root.
|
|
23
23
|
*
|
|
24
|
-
* Created during block import when a block is processed.
|
|
25
|
-
*
|
|
24
|
+
* Created during block import when a block is processed. Two pruning paths:
|
|
25
|
+
* - `prepareNextSlot` calls `pruneBelow(headParentSlot)` every slot once the head we'll build
|
|
26
|
+
* on is known.
|
|
27
|
+
* - `onFinalized` calls `pruneBelow(finalizedSlot)` on every finalization for bulk cleanup.
|
|
28
|
+
*
|
|
29
|
+
* Steady state (linear chain, healthy progression): the cache holds ~2 entries — the head
|
|
30
|
+
* (parent for next-slot production) and its parent (proposer-boost-reorg fallback). It can
|
|
31
|
+
* transiently hold more during forks, range-sync bursts, or when `prepareNextSlot` skips
|
|
32
|
+
* ticks; subsequent ticks settle it back.
|
|
26
33
|
*/
|
|
27
34
|
export class SeenPayloadEnvelopeInput {
|
|
28
35
|
private readonly chainEvents: ChainEventEmitter;
|
|
@@ -58,16 +65,7 @@ export class SeenPayloadEnvelopeInput {
|
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
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});
|
|
68
|
+
this.pruneBelow(computeStartSlotAtEpoch(checkpoint.epoch));
|
|
71
69
|
};
|
|
72
70
|
|
|
73
71
|
add(props: CreateFromBlockProps): PayloadEnvelopeInput {
|
|
@@ -88,17 +86,21 @@ export class SeenPayloadEnvelopeInput {
|
|
|
88
86
|
return this.payloadInputs.get(blockRootHex)?.hasPayloadEnvelope() ?? false;
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
prune(blockRootHex: RootHex): void {
|
|
92
|
-
const payloadInput = this.payloadInputs.get(blockRootHex);
|
|
93
|
-
if (payloadInput) {
|
|
94
|
-
this.evictPayloadInput(payloadInput);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
89
|
size(): number {
|
|
99
90
|
return this.payloadInputs.size;
|
|
100
91
|
}
|
|
101
92
|
|
|
93
|
+
pruneBelow(slot: Slot): void {
|
|
94
|
+
let deletedCount = 0;
|
|
95
|
+
for (const [, input] of this.payloadInputs) {
|
|
96
|
+
if (input.slot < slot) {
|
|
97
|
+
this.evictPayloadInput(input);
|
|
98
|
+
deletedCount++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
this.logger?.debug("SeenPayloadEnvelopeInput.pruneBelow deleted entries", {slot, deletedCount});
|
|
102
|
+
}
|
|
103
|
+
|
|
102
104
|
private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
|
|
103
105
|
this.serializedCache.delete(payloadInput.getSerializedCacheKeys());
|
|
104
106
|
this.payloadInputs.delete(payloadInput.blockRootHex);
|
|
@@ -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,
|
|
@@ -76,6 +77,19 @@ async function validateExecutionPayloadBid(
|
|
|
76
77
|
// `SignedProposerPreferences` associated with `bid.slot`.
|
|
77
78
|
// TODO GLOAS: Implement this along with proposer preference
|
|
78
79
|
|
|
80
|
+
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
81
|
+
// consensus layer -- i.e. validate that
|
|
82
|
+
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
83
|
+
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
84
|
+
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
85
|
+
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
86
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
87
|
+
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
88
|
+
blobKzgCommitmentsLen,
|
|
89
|
+
commitmentLimit: maxBlobsPerBlock,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
// [IGNORE] this is the first signed bid seen with a valid signature from the given builder for this slot.
|
|
80
94
|
if (chain.seenExecutionPayloadBids.isKnown(bid.slot, bid.builderIndex)) {
|
|
81
95
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
@@ -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)) {
|
|
@@ -18,7 +18,8 @@ export async function validateApiPayloadAttestationMessage(
|
|
|
18
18
|
chain: IBeaconChain,
|
|
19
19
|
payloadAttestationMessage: gloas.PayloadAttestationMessage
|
|
20
20
|
): Promise<PayloadAttestationValidationResult> {
|
|
21
|
-
|
|
21
|
+
const prioritizeBls = true;
|
|
22
|
+
return validatePayloadAttestationMessage(chain, payloadAttestationMessage, prioritizeBls);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export async function validateGossipPayloadAttestationMessage(
|
|
@@ -30,7 +31,8 @@ export async function validateGossipPayloadAttestationMessage(
|
|
|
30
31
|
|
|
31
32
|
async function validatePayloadAttestationMessage(
|
|
32
33
|
chain: IBeaconChain,
|
|
33
|
-
payloadAttestationMessage: gloas.PayloadAttestationMessage
|
|
34
|
+
payloadAttestationMessage: gloas.PayloadAttestationMessage,
|
|
35
|
+
prioritizeBls = false
|
|
34
36
|
): Promise<PayloadAttestationValidationResult> {
|
|
35
37
|
const {data, validatorIndex} = payloadAttestationMessage;
|
|
36
38
|
const epoch = computeEpochAtSlot(data.slot);
|
|
@@ -102,7 +104,7 @@ async function validatePayloadAttestationMessage(
|
|
|
102
104
|
payloadAttestationMessage.signature
|
|
103
105
|
);
|
|
104
106
|
|
|
105
|
-
if (!(await chain.bls.verifySignatureSets([signatureSet]))) {
|
|
107
|
+
if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}))) {
|
|
106
108
|
throw new PayloadAttestationError(GossipAction.REJECT, {
|
|
107
109
|
code: PayloadAttestationErrorCode.INVALID_SIGNATURE,
|
|
108
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 {
|
|
@@ -216,13 +216,15 @@ export class ExecutionEngineHttp implements IExecutionEngine {
|
|
|
216
216
|
executionRequests?: ExecutionRequests
|
|
217
217
|
): Promise<ExecutePayloadResponse> {
|
|
218
218
|
const method =
|
|
219
|
-
ForkSeq[fork] >= ForkSeq.
|
|
220
|
-
? "
|
|
221
|
-
: ForkSeq[fork] >= ForkSeq.
|
|
222
|
-
? "
|
|
223
|
-
: ForkSeq[fork] >= ForkSeq.
|
|
224
|
-
? "
|
|
225
|
-
:
|
|
219
|
+
ForkSeq[fork] >= ForkSeq.gloas
|
|
220
|
+
? "engine_newPayloadV5"
|
|
221
|
+
: ForkSeq[fork] >= ForkSeq.electra
|
|
222
|
+
? "engine_newPayloadV4"
|
|
223
|
+
: ForkSeq[fork] >= ForkSeq.deneb
|
|
224
|
+
? "engine_newPayloadV3"
|
|
225
|
+
: ForkSeq[fork] >= ForkSeq.capella
|
|
226
|
+
? "engine_newPayloadV2"
|
|
227
|
+
: "engine_newPayloadV1";
|
|
226
228
|
|
|
227
229
|
const serializedExecutionPayload = serializeExecutionPayload(fork, executionPayload);
|
|
228
230
|
|
|
@@ -244,7 +246,7 @@ export class ExecutionEngineHttp implements IExecutionEngine {
|
|
|
244
246
|
}
|
|
245
247
|
const serializedExecutionRequests = serializeExecutionRequests(executionRequests);
|
|
246
248
|
engineRequest = {
|
|
247
|
-
method: "engine_newPayloadV4",
|
|
249
|
+
method: ForkSeq[fork] >= ForkSeq.gloas ? "engine_newPayloadV5" : "engine_newPayloadV4",
|
|
248
250
|
params: [
|
|
249
251
|
serializedExecutionPayload,
|
|
250
252
|
serializedVersionedHashes,
|
|
@@ -348,11 +350,13 @@ export class ExecutionEngineHttp implements IExecutionEngine {
|
|
|
348
350
|
// Once on capella, should this need to be permanently switched to v2 when payload attrs
|
|
349
351
|
// not provided
|
|
350
352
|
const method =
|
|
351
|
-
ForkSeq[fork] >= ForkSeq.
|
|
352
|
-
? "
|
|
353
|
-
: ForkSeq[fork] >= ForkSeq.
|
|
354
|
-
? "
|
|
355
|
-
:
|
|
353
|
+
ForkSeq[fork] >= ForkSeq.gloas
|
|
354
|
+
? "engine_forkchoiceUpdatedV4"
|
|
355
|
+
: ForkSeq[fork] >= ForkSeq.deneb
|
|
356
|
+
? "engine_forkchoiceUpdatedV3"
|
|
357
|
+
: ForkSeq[fork] >= ForkSeq.capella
|
|
358
|
+
? "engine_forkchoiceUpdatedV2"
|
|
359
|
+
: "engine_forkchoiceUpdatedV1";
|
|
356
360
|
const payloadAttributesRpc = payloadAttributes ? serializePayloadAttributes(payloadAttributes) : undefined;
|
|
357
361
|
// If we are just fcUing and not asking execution for payload, retry is not required
|
|
358
362
|
// and we can move on, as the next fcU will be issued soon on the new slot
|
|
@@ -438,9 +442,12 @@ export class ExecutionEngineHttp implements IExecutionEngine {
|
|
|
438
442
|
case ForkName.electra:
|
|
439
443
|
method = "engine_getPayloadV4";
|
|
440
444
|
break;
|
|
441
|
-
|
|
445
|
+
case ForkName.fulu:
|
|
442
446
|
method = "engine_getPayloadV5";
|
|
443
447
|
break;
|
|
448
|
+
default:
|
|
449
|
+
method = "engine_getPayloadV6";
|
|
450
|
+
break;
|
|
444
451
|
}
|
|
445
452
|
const payloadResponse = await this.rpc.fetchWithRetries<
|
|
446
453
|
EngineApiRpcReturnTypes[typeof method],
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
SLOTS_PER_EPOCH,
|
|
12
12
|
} from "@lodestar/params";
|
|
13
13
|
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
14
|
-
import {ExecutionPayload, RootHex, bellatrix, deneb, ssz} from "@lodestar/types";
|
|
14
|
+
import {ExecutionPayload, RootHex, bellatrix, deneb, gloas, ssz} from "@lodestar/types";
|
|
15
15
|
import {fromHex, toRootHex} from "@lodestar/utils";
|
|
16
16
|
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
17
17
|
import {INTEROP_BLOCK_HASH} from "../../node/utils/interop/state.js";
|
|
@@ -132,14 +132,17 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
132
132
|
engine_newPayloadV2: this.notifyNewPayload.bind(this),
|
|
133
133
|
engine_newPayloadV3: this.notifyNewPayload.bind(this),
|
|
134
134
|
engine_newPayloadV4: this.notifyNewPayload.bind(this),
|
|
135
|
+
engine_newPayloadV5: this.notifyNewPayload.bind(this),
|
|
135
136
|
engine_forkchoiceUpdatedV1: this.notifyForkchoiceUpdate.bind(this),
|
|
136
137
|
engine_forkchoiceUpdatedV2: this.notifyForkchoiceUpdate.bind(this),
|
|
137
138
|
engine_forkchoiceUpdatedV3: this.notifyForkchoiceUpdate.bind(this),
|
|
139
|
+
engine_forkchoiceUpdatedV4: this.notifyForkchoiceUpdate.bind(this),
|
|
138
140
|
engine_getPayloadV1: this.getPayloadV1.bind(this),
|
|
139
141
|
engine_getPayloadV2: this.getPayloadV5.bind(this),
|
|
140
142
|
engine_getPayloadV3: this.getPayloadV5.bind(this),
|
|
141
143
|
engine_getPayloadV4: this.getPayloadV5.bind(this),
|
|
142
144
|
engine_getPayloadV5: this.getPayloadV5.bind(this),
|
|
145
|
+
engine_getPayloadV6: this.getPayloadV5.bind(this),
|
|
143
146
|
engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this),
|
|
144
147
|
engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this),
|
|
145
148
|
engine_getClientVersionV1: this.getClientVersionV1.bind(this),
|
|
@@ -379,6 +382,10 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
379
382
|
(executionPayload as ExecutionPayload<ForkPostCapella>).withdrawals = ssz.capella.Withdrawals.defaultValue();
|
|
380
383
|
}
|
|
381
384
|
|
|
385
|
+
if (ForkSeq[fork] >= ForkSeq.gloas && payloadAttributes.slotNumber != null) {
|
|
386
|
+
(executionPayload as gloas.ExecutionPayload).slotNumber = payloadAttributes.slotNumber;
|
|
387
|
+
}
|
|
388
|
+
|
|
382
389
|
this.preparingPayloads.set(payloadId, {
|
|
383
390
|
executionPayload: serializeExecutionPayload(fork, executionPayload),
|
|
384
391
|
blobsBundle: serializeBlobsBundle({
|