From acd897db868dc9e7b6a1c638849559288283f6a0 Mon Sep 17 00:00:00 2001 From: gajinder Date: Mon, 23 Oct 2023 19:35:04 +0530 Subject: [PATCH] apply feedback --- .../src/api/impl/beacon/blocks/index.ts | 154 +++++++++++------- packages/utils/src/logger.ts | 2 +- 2 files changed, 95 insertions(+), 61 deletions(-) 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 88e59a7a67e2..81eac4ed6e47 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -2,7 +2,7 @@ import {fromHexString, toHexString} from "@chainsafe/ssz"; import {routes, ServerApi, ResponseFormat} from "@lodestar/api"; import {computeTimeAtSlot, signedBlindedBlockToFull, signedBlindedBlobSidecarsToFull} from "@lodestar/state-transition"; import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; -import {sleep, toHex} from "@lodestar/utils"; +import {sleep, toHex, LogDataBasic} from "@lodestar/utils"; import {allForks, deneb, isSignedBlockContents, isSignedBlindedBlockContents} from "@lodestar/types"; import {BlockSource, getBlockInput, ImportBlockOpts, BlockInput} from "../../../../chain/blocks/types.js"; import {promiseAllMaybeAsync} from "../../../../util/promises.js"; @@ -15,6 +15,11 @@ import {resolveBlockId, toBeaconHeaderResponse} from "./utils.js"; type PublishBlockOpts = ImportBlockOpts & {broadcastValidation?: routes.beacon.BroadcastValidation}; +type ParsedSignedBlindedBlockOrContents = { + signedBlindedBlock: allForks.SignedBlindedBeaconBlock; + signedBlindedBlobSidecars: deneb.SignedBlindedBlobSidecars | null; +}; + /** * Validator clock may be advanced from beacon's clock. If the validator requests a resource in a * future slot, wait some time instead of rejecting the request because it's in the future @@ -138,78 +143,36 @@ export function getBeaconBlockApi({ signedBlindedBlockOrContents, opts: PublishBlockOpts = {} ) => { - let signedBlindedBlock: allForks.SignedBlindedBeaconBlock; - let signedBlindedBlobSidecars: deneb.SignedBlindedBlobSidecars | null; + const {signedBlindedBlock, signedBlindedBlobSidecars} = + parseSignedBlindedBlockOrContents(signedBlindedBlockOrContents); - if (isSignedBlindedBlockContents(signedBlindedBlockOrContents)) { - signedBlindedBlock = signedBlindedBlockOrContents.signedBlindedBlock; - signedBlindedBlobSidecars = signedBlindedBlockOrContents.signedBlindedBlobSidecars; - } else { - signedBlindedBlock = signedBlindedBlockOrContents; - signedBlindedBlobSidecars = null; - } const slot = signedBlindedBlock.message.slot; const blockRoot = toHex( chain.config .getBlindedForkTypes(signedBlindedBlock.message.slot) .BeaconBlock.hashTreeRoot(signedBlindedBlock.message) ); - const executionPayload = chain.producedBlockRoot.get(blockRoot); - let signedBlockOrContents: allForks.SignedBeaconBlockOrContents; - const logCtx = {blockRoot, slot}; - if (executionPayload !== null && executionPayload !== undefined) { - Object.assign(logCtx, {transactions: executionPayload.transactions.length}); - } // Either the payload/blobs are cached from i) engine locally or ii) they are from the builder // // executionPayload can be null or a real payload in locally produced, its only undefined when // the block came from the builder - - if (executionPayload !== undefined) { - const signedBlock = signedBlindedBlockToFull(signedBlindedBlock, executionPayload); - - if (signedBlindedBlobSidecars !== null) { - if (executionPayload === null) { - throw Error("Missing locally produced executionPayload for deneb+ publishBlindedBlock"); - } - - const blockHash = toHex(executionPayload.blockHash); - const blobSidecars = chain.producedBlobSidecarsCache.get(blockHash); - if (blobSidecars === undefined) { - throw Error("Missing blobSidecars from the local execution cache"); - } - if (blobSidecars.length !== signedBlindedBlobSidecars.length) { - throw Error( - `Length mismatch signedBlindedBlobSidecars=${signedBlindedBlobSidecars.length} blobSidecars=${blobSidecars.length}` - ); - } - const signedBlobSidecars = signedBlindedBlobSidecarsToFull( - signedBlindedBlobSidecars, - blobSidecars.map((blobSidecar) => blobSidecar.blob) - ); - - signedBlockOrContents = {signedBlock, signedBlobSidecars} as allForks.SignedBeaconBlockOrContents; - Object.assign(logCtx, {blobs: signedBlindedBlobSidecars.length}); - } else { - signedBlockOrContents = signedBlock as allForks.SignedBeaconBlockOrContents; - } - - chain.logger.verbose("Publishing block assembled from locally cached payload", logCtx); - } else { - // Mechanism for blobs & blocks on builder is implemenented separately in a followup deneb-builder PR - if (isSignedBlindedBlockContents(signedBlindedBlockOrContents)) { - throw Error("exeutionBuilder not yet implemented for deneb+ forks"); - } - const executionBuilder = chain.executionBuilder; - if (!executionBuilder) throw Error("exeutionBuilder required to publish SignedBlindedBeaconBlock"); - signedBlockOrContents = await executionBuilder.submitBlindedBlock(signedBlindedBlockOrContents); - chain.logger.verbose("Publishing block assembled from the builder", logCtx); - } - - // the full block is published by relay and it's possible that the block is already known to us by gossip - // see https://github.com/ChainSafe/lodestar/issues/5404 + const executionPayload = chain.producedBlockRoot.get(blockRoot); + const signedBlockOrContents = + executionPayload !== undefined + ? reconstructLocalBlockOrContents( + chain, + {signedBlindedBlock, signedBlindedBlobSidecars}, + executionPayload, + logCtx + ) + : await reconstructBuilderBlockOrContents(chain, signedBlindedBlockOrContents, logCtx); + + // the full block is published by relay and it's possible that the block is already known to us + // by gossip + // + // see: https://github.com/ChainSafe/lodestar/issues/5404 return publishBlock(signedBlockOrContents, {...opts, ignoreIfKnown: true}); }; @@ -401,3 +364,74 @@ export function getBeaconBlockApi({ }, }; } + +function parseSignedBlindedBlockOrContents( + signedBlindedBlockOrContents: allForks.SignedBlindedBeaconBlockOrContents +): ParsedSignedBlindedBlockOrContents { + if (isSignedBlindedBlockContents(signedBlindedBlockOrContents)) { + const signedBlindedBlock = signedBlindedBlockOrContents.signedBlindedBlock; + const signedBlindedBlobSidecars = signedBlindedBlockOrContents.signedBlindedBlobSidecars; + return {signedBlindedBlock, signedBlindedBlobSidecars}; + } else { + return {signedBlindedBlock: signedBlindedBlockOrContents, signedBlindedBlobSidecars: null}; + } +} + +function reconstructLocalBlockOrContents( + chain: ApiModules["chain"], + {signedBlindedBlock, signedBlindedBlobSidecars}: ParsedSignedBlindedBlockOrContents, + executionPayload: allForks.ExecutionPayload | null, + logCtx: Record +): allForks.SignedBeaconBlockOrContents { + const signedBlock = signedBlindedBlockToFull(signedBlindedBlock, executionPayload); + if (executionPayload !== null) { + Object.assign(logCtx, {transactions: executionPayload.transactions.length}); + } + + if (signedBlindedBlobSidecars !== null) { + if (executionPayload === null) { + throw Error("Missing locally produced executionPayload for deneb+ publishBlindedBlock"); + } + + const blockHash = toHex(executionPayload.blockHash); + const blobSidecars = chain.producedBlobSidecarsCache.get(blockHash); + if (blobSidecars === undefined) { + throw Error("Missing blobSidecars from the local execution cache"); + } + if (blobSidecars.length !== signedBlindedBlobSidecars.length) { + throw Error( + `Length mismatch signedBlindedBlobSidecars=${signedBlindedBlobSidecars.length} blobSidecars=${blobSidecars.length}` + ); + } + const signedBlobSidecars = signedBlindedBlobSidecarsToFull( + signedBlindedBlobSidecars, + blobSidecars.map((blobSidecar) => blobSidecar.blob) + ); + + Object.assign(logCtx, {blobs: signedBlindedBlobSidecars.length}); + chain.logger.verbose("Block & blobs assembled from locally cached payload", logCtx); + return {signedBlock, signedBlobSidecars} as allForks.SignedBeaconBlockOrContents; + } else { + chain.logger.verbose("Block assembled from locally cached payload", logCtx); + return signedBlock as allForks.SignedBeaconBlockOrContents; + } +} + +async function reconstructBuilderBlockOrContents( + chain: ApiModules["chain"], + signedBlindedBlockOrContents: allForks.SignedBlindedBeaconBlockOrContents, + logCtx: Record +): Promise { + // Mechanism for blobs & blocks on builder is implemenented separately in a followup deneb-builder PR + if (isSignedBlindedBlockContents(signedBlindedBlockOrContents)) { + throw Error("exeutionBuilder not yet implemented for deneb+ forks"); + } + const executionBuilder = chain.executionBuilder; + if (!executionBuilder) { + throw Error("exeutionBuilder required to publish SignedBlindedBeaconBlock"); + } + + const signedBlockOrContents = await executionBuilder.submitBlindedBlock(signedBlindedBlockOrContents); + chain.logger.verbose("Publishing block assembled from the builder", logCtx); + return signedBlockOrContents; +} diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 622ec823cb5f..925a357f4b98 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -17,5 +17,5 @@ export const LogLevels = Object.values(LogLevel); export type LogHandler = (message: string, context?: LogData, error?: Error) => void; -type LogDataBasic = string | number | bigint | boolean | null | undefined; +export type LogDataBasic = string | number | bigint | boolean | null | undefined; export type LogData = LogDataBasic | Record | LogDataBasic[] | Record[];