-
-
Notifications
You must be signed in to change notification settings - Fork 438
feat: add gloas execution payload envelope import pipeline #8962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: unstable
Are you sure you want to change the base?
Changes from all commits
5473bb5
9c91667
9681ba4
048be5e
4be9bfb
91c6787
7c998d3
a920a05
27dba2a
548cf77
9a949e9
569eb98
aa3ac88
6402206
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ import { | |
| } from "@lodestar/types"; | ||
| import {fromHex, sleep, toHex, toRootHex} from "@lodestar/utils"; | ||
| import {BlockInputSource, isBlockInputBlobs, isBlockInputColumns} from "../../../../chain/blocks/blockInput/index.js"; | ||
| import {PayloadEnvelopeInputSource} from "../../../../chain/blocks/payloadEnvelopeInput/index.ts"; | ||
| import {ImportBlockOpts} from "../../../../chain/blocks/types.js"; | ||
| import {verifyBlocksInEpoch} from "../../../../chain/blocks/verifyBlock.js"; | ||
| import {BeaconChain} from "../../../../chain/chain.js"; | ||
|
|
@@ -48,6 +49,7 @@ import { | |
| ProduceFullGloas, | ||
| } from "../../../../chain/produceBlock/index.js"; | ||
| import {validateGossipBlock} from "../../../../chain/validation/block.js"; | ||
| import {validateApiExecutionPayloadEnvelope} from "../../../../chain/validation/executionPayloadEnvelope.js"; | ||
| import {OpSource} from "../../../../chain/validatorMonitor.js"; | ||
| import { | ||
| computePreFuluKzgCommitmentsInclusionProof, | ||
|
|
@@ -676,6 +678,7 @@ export function getBeaconBlockApi({ | |
| } | ||
|
|
||
| if (cachedResult.cells && cachedResult.blobsBundle.commitments.length > 0) { | ||
| const timer = metrics?.peerDas.dataColumnSidecarComputationTime.startTimer(); | ||
| const cellsAndProofs = cachedResult.cells.map((rowCells, rowIndex) => ({ | ||
| cells: rowCells, | ||
| proofs: cachedResult.blobsBundle.proofs.slice( | ||
|
|
@@ -685,24 +688,55 @@ export function getBeaconBlockApi({ | |
| })); | ||
|
|
||
| dataColumnSidecars = getDataColumnSidecarsForGloas(slot, envelope.beaconBlockRoot, cellsAndProofs); | ||
| timer?.(); | ||
| } | ||
| } else { | ||
| // TODO GLOAS: will this api be used by builders or only for self-building? | ||
| } | ||
|
|
||
| // TODO GLOAS: Verify execution payload envelope signature | ||
| // For self-builds, the proposer signs with their own validator key | ||
| // For external builders, verify using the builder's registered pubkey | ||
| // Use verify_execution_payload_envelope_signature(state, signed_envelope) | ||
| await validateApiExecutionPayloadEnvelope(chain, signedExecutionPayloadEnvelope); | ||
|
|
||
| // TODO GLOAS: Process execution payload via state transition | ||
| // Call process_execution_payload(state, signed_envelope, execution_engine) | ||
| // If called near a slot boundary (e.g. late in slot N-1), hold briefly so gossip aligns with slot N. | ||
| const msToBlockSlot = computeTimeAtSlot(config, slot, chain.genesisTime) * 1000 - Date.now(); | ||
| if (msToBlockSlot <= MAX_API_CLOCK_DISPARITY_MS && msToBlockSlot > 0) { | ||
| await sleep(msToBlockSlot); | ||
| } | ||
|
|
||
| // TODO GLOAS: Update fork choice with the execution payload | ||
| // Call on_execution_payload(store, signed_envelope) to update fork choice state | ||
| const payloadInput = chain.seenPayloadEnvelopeInput.get(blockRootHex); | ||
| if (!payloadInput) { | ||
| throw new ApiError(404, `PayloadEnvelopeInput not found for block root ${blockRootHex}`); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can happen if block and payload are submitted in parallel as documented here #8915 we will need a queuing mechanism on the api, we can just throw for now as we currently only submit sequentially which is fine for the devnets |
||
|
|
||
| // TODO GLOAS: Add envelope and data columns to block input via seenBlockInputCache | ||
| // and trigger block import (Gloas block import requires both beacon block and envelope) | ||
| payloadInput.addPayloadEnvelope({ | ||
| envelope: signedExecutionPayloadEnvelope, | ||
| source: PayloadEnvelopeInputSource.api, | ||
| seenTimestampSec, | ||
| peerIdStr: undefined, | ||
| }); | ||
|
|
||
| if (dataColumnSidecars.length > 0) { | ||
| for (const columnSidecar of dataColumnSidecars) { | ||
| payloadInput.addColumn({ | ||
| columnSidecar, | ||
| source: PayloadEnvelopeInputSource.api, | ||
| seenTimestampSec, | ||
| peerIdStr: undefined, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| // TODO GLOAS: Unlike publishBlock which gossips and imports in parallel, we import before gossip here. | ||
| // The publishExecutionPayloadEnvelope spec says success = "gossip validation + broadcast", so we may | ||
| // want to gossip first. Need spec clarification on whether import failure should prevent broadcast. | ||
| if (payloadInput.shouldImport()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really see a reason why this should work differently than pre-gloas publish block flow, we can gossip and import in parallel
so I think here we can assume all validation checks have passed already |
||
| // Signature already verified in validateApiExecutionPayloadEnvelope | ||
| await chain.importExecutionPayload(payloadInput, {validSignature: true}); | ||
| chain.persistPayloadEnvelope(payloadInput); | ||
| chain.emitter.emit(routes.events.EventType.executionPayloadAvailable, { | ||
| slot, | ||
| blockRoot: blockRootHex, | ||
| }); | ||
| } | ||
|
|
||
| const valLogMeta = { | ||
| slot, | ||
|
|
@@ -712,14 +746,9 @@ export function getBeaconBlockApi({ | |
| dataColumns: dataColumnSidecars.length, | ||
| }; | ||
|
|
||
| // If called near a slot boundary (e.g. late in slot N-1), hold briefly so gossip aligns with slot N. | ||
| const msToBlockSlot = computeTimeAtSlot(config, slot, chain.genesisTime) * 1000 - Date.now(); | ||
| if (msToBlockSlot <= MAX_API_CLOCK_DISPARITY_MS && msToBlockSlot > 0) { | ||
| await sleep(msToBlockSlot); | ||
| } | ||
|
|
||
| const delaySec = seenTimestampSec - computeTimeAtSlot(config, slot, chain.genesisTime); | ||
| metrics?.gossipExecutionPayloadEnvelope.elapsedTimeTillReceived.observe({source: OpSource.api}, delaySec); | ||
| chain.validatorMonitor?.registerExecutionPayloadEnvelope(OpSource.api, delaySec, signedExecutionPayloadEnvelope); | ||
|
|
||
| chain.logger.info("Publishing execution payload envelope", valLogMeta); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably run this validation earlier, based on ethereum/beacon-APIs#580 (comment) we wanna implement
broadcast_validationso we can mirror what we have implemented inpublishBlockV2