From 9e065676c92f767f84c26e2c4f665b7ada09655b Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 19 Oct 2024 16:23:39 +0100 Subject: [PATCH 1/3] feat: forward blinded block ssz bytes to submitBlindedBlock api --- packages/api/src/builder/routes.ts | 6 +++--- packages/beacon-node/src/api/impl/beacon/blocks/index.ts | 7 ++++--- packages/beacon-node/src/execution/builder/http.ts | 7 +++++-- packages/beacon-node/src/execution/builder/interface.ts | 5 ++++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index a203a93b8afe..097edad652e4 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -71,7 +71,7 @@ export type Endpoints = { submitBlindedBlock: Endpoint< "POST", - {signedBlindedBlock: SignedBlindedBeaconBlock}, + {signedBlindedBlock: SignedBlindedBeaconBlock; blockBytes?: Uint8Array | null}, {body: unknown; headers: {[MetaHeader.Version]: string}}, ExecutionPayload | ExecutionPayloadAndBlobsBundle, VersionMeta @@ -138,10 +138,10 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { + writeReqSsz: ({signedBlindedBlock, blockBytes}) => { const fork = config.getForkName(signedBlindedBlock.message.slot); return { - body: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock), + body: blockBytes ?? getExecutionForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock), headers: { [MetaHeader.Version]: fork, }, diff --git a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts index b54e8752a437..4171c9158757 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -269,7 +269,7 @@ export function getBeaconBlockApi({ const source = ProducedBlockSource.builder; chain.logger.debug("Reconstructing signedBlockOrContents", {slot, blockRoot, source}); - const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, signedBlindedBlock); + const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, signedBlindedBlock, context?.sszBytes); // the full block is published by relay and it's possible that the block is already known to us // by gossip @@ -507,13 +507,14 @@ export function getBeaconBlockApi({ async function reconstructBuilderBlockOrContents( chain: ApiModules["chain"], - signedBlindedBlock: SignedBlindedBeaconBlock + signedBlindedBlock: SignedBlindedBeaconBlock, + blockBytes?: Uint8Array | null ): Promise { const executionBuilder = chain.executionBuilder; if (!executionBuilder) { throw Error("executionBuilder required to publish SignedBlindedBeaconBlock"); } - const signedBlockOrContents = await executionBuilder.submitBlindedBlock(signedBlindedBlock); + const signedBlockOrContents = await executionBuilder.submitBlindedBlock(signedBlindedBlock, blockBytes); return signedBlockOrContents; } diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 13f797d1c697..623e234ac3f4 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -149,9 +149,12 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { return {header, executionPayloadValue, blobKzgCommitments, executionRequests}; } - async submitBlindedBlock(signedBlindedBlock: SignedBlindedBeaconBlock): Promise { + async submitBlindedBlock( + signedBlindedBlock: SignedBlindedBeaconBlock, + blockBytes?: Uint8Array | null + ): Promise { const res = await this.api.submitBlindedBlock( - {signedBlindedBlock}, + {signedBlindedBlock, blockBytes}, {retries: 2, requestWireFormat: this.sszSupported ? WireFormat.ssz : WireFormat.json} ); diff --git a/packages/beacon-node/src/execution/builder/interface.ts b/packages/beacon-node/src/execution/builder/interface.ts index 5a6a4eb82f63..d674f2881cf5 100644 --- a/packages/beacon-node/src/execution/builder/interface.ts +++ b/packages/beacon-node/src/execution/builder/interface.ts @@ -39,5 +39,8 @@ export interface IExecutionBuilder { blobKzgCommitments?: deneb.BlobKzgCommitments; executionRequests?: electra.ExecutionRequests; }>; - submitBlindedBlock(signedBlock: SignedBlindedBeaconBlock): Promise; + submitBlindedBlock( + signedBlindedBlock: SignedBlindedBeaconBlock, + blockBytes?: Uint8Array | null + ): Promise; } From 1804002571725a0534da1cc58591ae685692709e Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 21 Oct 2024 23:50:32 +0100 Subject: [PATCH 2/3] Add comment --- packages/api/src/builder/routes.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index 097edad652e4..c23fad1a4408 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -71,7 +71,11 @@ export type Endpoints = { submitBlindedBlock: Endpoint< "POST", - {signedBlindedBlock: SignedBlindedBeaconBlock; blockBytes?: Uint8Array | null}, + { + signedBlindedBlock: SignedBlindedBeaconBlock; + /** SSZ serialized `signedBlindedBlock` bytes */ + blockBytes?: Uint8Array | null; + }, {body: unknown; headers: {[MetaHeader.Version]: string}}, ExecutionPayload | ExecutionPayloadAndBlobsBundle, VersionMeta From 288fe51e1446456793cb733d2f0f227aa2ad6d72 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 22 Oct 2024 11:03:38 +0100 Subject: [PATCH 3/3] Add WithOptionalBytes --- packages/api/src/builder/routes.ts | 23 +++++++++---------- packages/api/test/unit/builder/testData.ts | 2 +- .../src/api/impl/beacon/blocks/index.ts | 11 +++++---- .../beacon-node/src/execution/builder/http.ts | 8 +++---- .../src/execution/builder/interface.ts | 4 ++-- packages/types/src/types.ts | 6 +++++ 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index c23fad1a4408..3911a515e1c6 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -8,6 +8,7 @@ import { ExecutionPayloadAndBlobsBundle, SignedBlindedBeaconBlock, SignedBuilderBid, + WithOptionalBytes, } from "@lodestar/types"; import {ForkName, isForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; @@ -71,11 +72,7 @@ export type Endpoints = { submitBlindedBlock: Endpoint< "POST", - { - signedBlindedBlock: SignedBlindedBeaconBlock; - /** SSZ serialized `signedBlindedBlock` bytes */ - blockBytes?: Uint8Array | null; - }, + {signedBlindedBlock: WithOptionalBytes}, {body: unknown; headers: {[MetaHeader.Version]: string}}, ExecutionPayload | ExecutionPayloadAndBlobsBundle, VersionMeta @@ -128,9 +125,9 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = config.getForkName(signedBlindedBlock.message.slot); + const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { - body: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.toJson(signedBlindedBlock), + body: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.toJson(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, @@ -139,13 +136,15 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedBlindedBlock: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.fromJson(body), + signedBlindedBlock: {data: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.fromJson(body)}, }; }, - writeReqSsz: ({signedBlindedBlock, blockBytes}) => { - const fork = config.getForkName(signedBlindedBlock.message.slot); + writeReqSsz: ({signedBlindedBlock}) => { + const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { - body: blockBytes ?? getExecutionForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock), + body: + signedBlindedBlock.bytes ?? + getExecutionForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, @@ -154,7 +153,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedBlindedBlock: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.deserialize(body), + signedBlindedBlock: {data: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.deserialize(body)}, }; }, schema: { diff --git a/packages/api/test/unit/builder/testData.ts b/packages/api/test/unit/builder/testData.ts index a23823702b6d..a807620258df 100644 --- a/packages/api/test/unit/builder/testData.ts +++ b/packages/api/test/unit/builder/testData.ts @@ -23,7 +23,7 @@ export const testData: GenericServerTestCases = { res: {data: ssz.bellatrix.SignedBuilderBid.defaultValue(), meta: {version: ForkName.bellatrix}}, }, submitBlindedBlock: { - args: {signedBlindedBlock: ssz.deneb.SignedBlindedBeaconBlock.defaultValue()}, + args: {signedBlindedBlock: {data: ssz.deneb.SignedBlindedBeaconBlock.defaultValue()}}, res: {data: ssz.bellatrix.ExecutionPayload.defaultValue(), meta: {version: ForkName.bellatrix}}, }, }; diff --git a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts index 4171c9158757..2d36505d822a 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -15,6 +15,7 @@ import { SignedBeaconBlock, SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, + WithOptionalBytes, } from "@lodestar/types"; import { BlockSource, @@ -269,7 +270,10 @@ export function getBeaconBlockApi({ const source = ProducedBlockSource.builder; chain.logger.debug("Reconstructing signedBlockOrContents", {slot, blockRoot, source}); - const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, signedBlindedBlock, context?.sszBytes); + const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, { + data: signedBlindedBlock, + bytes: context?.sszBytes, + }); // the full block is published by relay and it's possible that the block is already known to us // by gossip @@ -507,14 +511,13 @@ export function getBeaconBlockApi({ async function reconstructBuilderBlockOrContents( chain: ApiModules["chain"], - signedBlindedBlock: SignedBlindedBeaconBlock, - blockBytes?: Uint8Array | null + signedBlindedBlock: WithOptionalBytes ): Promise { const executionBuilder = chain.executionBuilder; if (!executionBuilder) { throw Error("executionBuilder required to publish SignedBlindedBeaconBlock"); } - const signedBlockOrContents = await executionBuilder.submitBlindedBlock(signedBlindedBlock, blockBytes); + const signedBlockOrContents = await executionBuilder.submitBlindedBlock(signedBlindedBlock); return signedBlockOrContents; } diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 623e234ac3f4..ecb22990bfff 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -9,6 +9,7 @@ import { SignedBlindedBeaconBlock, ExecutionPayloadHeader, electra, + WithOptionalBytes, } from "@lodestar/types"; import {parseExecutionPayloadAndBlobsBundle, reconstructFullBlockOrContents} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; @@ -150,11 +151,10 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { } async submitBlindedBlock( - signedBlindedBlock: SignedBlindedBeaconBlock, - blockBytes?: Uint8Array | null + signedBlindedBlock: WithOptionalBytes ): Promise { const res = await this.api.submitBlindedBlock( - {signedBlindedBlock, blockBytes}, + {signedBlindedBlock}, {retries: 2, requestWireFormat: this.sszSupported ? WireFormat.ssz : WireFormat.json} ); @@ -166,6 +166,6 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { // probably need diagonis if this block turns out to be invalid because of some bug // const contents = blobsBundle ? {blobs: blobsBundle.blobs, kzgProofs: blobsBundle.proofs} : null; - return reconstructFullBlockOrContents(signedBlindedBlock, {executionPayload, contents}); + return reconstructFullBlockOrContents(signedBlindedBlock.data, {executionPayload, contents}); } } diff --git a/packages/beacon-node/src/execution/builder/interface.ts b/packages/beacon-node/src/execution/builder/interface.ts index d674f2881cf5..19a935a9bf7e 100644 --- a/packages/beacon-node/src/execution/builder/interface.ts +++ b/packages/beacon-node/src/execution/builder/interface.ts @@ -9,6 +9,7 @@ import { ExecutionPayloadHeader, SignedBlindedBeaconBlock, electra, + WithOptionalBytes, } from "@lodestar/types"; import {ForkExecution} from "@lodestar/params"; @@ -40,7 +41,6 @@ export interface IExecutionBuilder { executionRequests?: electra.ExecutionRequests; }>; submitBlindedBlock( - signedBlindedBlock: SignedBlindedBeaconBlock, - blockBytes?: Uint8Array | null + signedBlindedBlock: WithOptionalBytes ): Promise; } diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 08fc06ac6cb9..51fa2b12a28e 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -32,6 +32,12 @@ export enum ProducedBlockSource { engine = "engine", } +export type WithOptionalBytes = { + data: T; + /** SSZ serialized `data` bytes */ + bytes?: Uint8Array | null; +}; + export type SlotRootHex = {slot: Slot; root: RootHex}; export type SlotOptionalRoot = {slot: Slot; root?: RootHex};