-
-
Notifications
You must be signed in to change notification settings - Fork 436
EIP-4844: Update produce block flow #4864
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
Changes from all commits
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 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ import { | |||||||||
| BLSPubkey, | ||||||||||
| BLSSignature, | ||||||||||
| capella, | ||||||||||
| eip4844, | ||||||||||
| } from "@lodestar/types"; | ||||||||||
| import { | ||||||||||
| CachedBeaconStateAllForks, | ||||||||||
|
|
@@ -39,6 +40,7 @@ import { | |||||||||
| import {ZERO_HASH, ZERO_HASH_HEX} from "../../constants/index.js"; | ||||||||||
| import {IEth1ForBlockProduction} from "../../eth1/index.js"; | ||||||||||
| import {numToQuantity} from "../../eth1/provider/utils.js"; | ||||||||||
| import {validateBlobsAndKzgCommitments} from "./validateBlobsAndKzgCommitments.js"; | ||||||||||
|
|
||||||||||
| // Time to provide the EL to generate a payload from new payload id | ||||||||||
| const PAYLOAD_GENERATION_TIME_MS = 500; | ||||||||||
|
|
@@ -65,6 +67,15 @@ export type AssembledBlockType<T extends BlockType> = T extends BlockType.Full | |||||||||
| ? allForks.BeaconBlock | ||||||||||
| : allForks.BlindedBeaconBlock; | ||||||||||
|
|
||||||||||
| export enum BlobsResultType { | ||||||||||
| preEIP4844, | ||||||||||
| produced, | ||||||||||
| } | ||||||||||
|
|
||||||||||
| export type BlobsResult = | ||||||||||
| | {type: BlobsResultType.preEIP4844} | ||||||||||
| | {type: BlobsResultType.produced; blobs: eip4844.Blobs; blockHash: RootHex}; | ||||||||||
|
|
||||||||||
| export async function produceBlockBody<T extends BlockType>( | ||||||||||
| this: BeaconChain, | ||||||||||
| blockType: T, | ||||||||||
|
|
@@ -83,7 +94,10 @@ export async function produceBlockBody<T extends BlockType>( | |||||||||
| proposerIndex: ValidatorIndex; | ||||||||||
| proposerPubKey: BLSPubkey; | ||||||||||
| } | ||||||||||
| ): Promise<AssembledBodyType<T>> { | ||||||||||
| ): Promise<{body: AssembledBodyType<T>; blobs: BlobsResult}> { | ||||||||||
| // We assign this in an EIP-4844 branch below and return it | ||||||||||
| let blobs: {blobs: eip4844.Blobs; blockHash: RootHex} | null = null; | ||||||||||
|
|
||||||||||
| // TODO: | ||||||||||
| // Iterate through the naive aggregation pool and ensure all the attestations from there | ||||||||||
| // are included in the operation pool. | ||||||||||
|
|
@@ -153,7 +167,16 @@ export async function produceBlockBody<T extends BlockType>( | |||||||||
| currentState as CachedBeaconStateBellatrix, | ||||||||||
| proposerPubKey | ||||||||||
| ); | ||||||||||
| } else { | ||||||||||
|
|
||||||||||
| // Capella and later forks have withdrawalRoot on their ExecutionPayloadHeader | ||||||||||
| // TODO Capella: Remove this. It will come from the execution client. | ||||||||||
| if (ForkSeq[fork] >= ForkSeq.capella) { | ||||||||||
| throw Error("Builder blinded blocks not supported after capella"); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // blockType === BlockType.Full | ||||||||||
| else { | ||||||||||
| // try catch payload fetch here, because there is still a recovery path possible if we | ||||||||||
| // are pre-merge. We don't care the same for builder segment as the execution block | ||||||||||
| // will takeover if the builder flow was activated and errors | ||||||||||
|
|
@@ -188,6 +211,28 @@ export async function produceBlockBody<T extends BlockType>( | |||||||||
| if (payload.transactions.length === 0) { | ||||||||||
| this.metrics?.blockPayload.emptyPayloads.inc({prepType}); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (fork === ForkName.eip4844) { | ||||||||||
| // SPEC: https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/validator.md#blob-kzg-commitments | ||||||||||
| // After retrieving the execution payload from the execution engine as specified in Bellatrix, use the | ||||||||||
| // payload_id to retrieve blobs and blob_kzg_commitments via get_blobs_and_kzg_commitments(payload_id) | ||||||||||
| // TODO EIP-4844: getBlobsBundle and getPayload must be either coupled or called in parallel to save time. | ||||||||||
| const blobsBundle = await this.executionEngine.getBlobsBundle(payloadId); | ||||||||||
|
|
||||||||||
| // Sanity check consistency between getPayload() and getBlobsBundle() | ||||||||||
| const blockHash = toHex(payload.blockHash); | ||||||||||
|
Contributor
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. here we return payload block hash but seems later on we get by beacon block hash
Contributor
Author
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. Get by execution payload blockHash lodestar/packages/beacon-node/src/chain/chain.ts Lines 424 to 425 in 95739bd
Set by execution payload blockHash
Which is computed here from the payload
|
||||||||||
| if (blobsBundle.blockHash !== blockHash) { | ||||||||||
| throw Error(`blobsBundle incorrect blockHash ${blobsBundle.blockHash} != ${blockHash}`); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Optionally sanity-check that the KZG commitments match the versioned hashes in the transactions | ||||||||||
| if (this.opts.sanityCheckExecutionEngineBlobs) { | ||||||||||
| validateBlobsAndKzgCommitments(payload, blobsBundle); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| (blockBody as eip4844.BeaconBlockBody).blobKzgCommitments = blobsBundle.kzgs; | ||||||||||
| blobs = {blobs: blobsBundle.blobs, blockHash}; | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } catch (e) { | ||||||||||
| this.metrics?.blockPayload.payloadFetchErrors.inc(); | ||||||||||
|
|
@@ -217,7 +262,20 @@ export async function produceBlockBody<T extends BlockType>( | |||||||||
| (blockBody as capella.BeaconBlockBody).blsToExecutionChanges = []; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| return blockBody as AssembledBodyType<T>; | ||||||||||
| // Type-safe for blobs variable. Translate 'null' value into 'preEIP4844' enum | ||||||||||
| // TODO: Not ideal, but better than just using null. | ||||||||||
| // TODO: Does not guarantee that preEIP4844 enum goes with a preEIP4844 block | ||||||||||
| let blobsResult: BlobsResult; | ||||||||||
| if (currentState.config.getForkSeq(blockSlot) >= ForkSeq.eip4844) { | ||||||||||
| if (!blobs) { | ||||||||||
| throw Error("Blobs are null post eip4844"); | ||||||||||
| } | ||||||||||
| blobsResult = {type: BlobsResultType.produced, ...blobs}; | ||||||||||
| } else { | ||||||||||
| blobsResult = {type: BlobsResultType.preEIP4844}; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| return {body: blockBody as AssembledBodyType<T>, blobs: blobsResult}; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /** | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import {blobToKzgCommitment} from "c-kzg"; | ||
| import {verifyKzgCommitmentsAgainstTransactions} from "@lodestar/state-transition"; | ||
| import {allForks, eip4844} from "@lodestar/types"; | ||
| import {toHex} from "@lodestar/utils"; | ||
| import {BlobsBundle} from "../../execution/index.js"; | ||
| import {byteArrayEquals} from "../../util/bytes.js"; | ||
|
|
||
| /** | ||
| * Optionally sanity-check that the KZG commitments match the versioned hashes in the transactions | ||
| * https://github.com/ethereum/consensus-specs/blob/11a037fd9227e29ee809c9397b09f8cc3383a8c0/specs/eip4844/validator.md#blob-kzg-commitments | ||
| */ | ||
| export function validateBlobsAndKzgCommitments(payload: allForks.ExecutionPayload, blobsBundle: BlobsBundle): void { | ||
| verifyKzgCommitmentsAgainstTransactions(payload.transactions, blobsBundle.kzgs); | ||
|
|
||
| // Optionally sanity-check that the KZG commitments match the blobs (as produced by the execution engine) | ||
| if (blobsBundle.blobs.length !== blobsBundle.kzgs.length) { | ||
| throw Error(`Blobs bundle blobs len ${blobsBundle.blobs.length} != kzgs len ${blobsBundle.kzgs.length}`); | ||
| } | ||
|
|
||
| for (let i = 0; i < blobsBundle.blobs.length; i++) { | ||
| const kzg = blobToKzgCommitment(blobsBundle.blobs[i]) as eip4844.KZGCommitment; | ||
| if (!byteArrayEquals(kzg, blobsBundle.kzgs[i])) { | ||
| throw Error(`Wrong KZG[${i}] ${toHex(blobsBundle.kzgs[i])} expected ${toHex(kzg)}`); | ||
| } | ||
| } | ||
| } |
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.
seems here we get from beacon block hash while we cache by payload block hash
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.
const blockHash = toHex(beaconBlock.body.executionPayload.blockHash);is payload blockHash