diff --git a/packages/beacon-node/src/chain/blocks/types.ts b/packages/beacon-node/src/chain/blocks/types.ts index fdf751acb45d..9dfc496765fc 100644 --- a/packages/beacon-node/src/chain/blocks/types.ts +++ b/packages/beacon-node/src/chain/blocks/types.ts @@ -47,7 +47,6 @@ type BlockInputCacheType = { }; const MAX_GOSSIPINPUT_CACHE = 5; -// TODO deneb: export from types package // ssz.deneb.BlobSidecars.elementType.fixedSize; const BLOBSIDECAR_FIXED_SIZE = 131256; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts index 45576107b5af..8e1d853869f3 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts @@ -123,7 +123,6 @@ function maybeValidateBlobs( blockInput: BlockInput, opts: ImportBlockOpts ): DataAvailableStatus { - // TODO Deneb: Make switch verify it's exhaustive switch (blockInput.type) { case BlockInputType.postDeneb: { if (opts.validBlobSidecars) { @@ -134,7 +133,6 @@ function maybeValidateBlobs( const blockSlot = block.message.slot; const {blobKzgCommitments} = (block as deneb.SignedBeaconBlock).message.body; const beaconBlockRoot = config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block.message); - // TODO Deneb: This function throws un-typed errors validateBlobSidecars(blockSlot, beaconBlockRoot, blobKzgCommitments, blobs); return DataAvailableStatus.available; diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 7050d7462f4e..341ad943ee4b 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -130,7 +130,6 @@ export class BeaconChain implements IBeaconChain { readonly beaconProposerCache: BeaconProposerCache; readonly checkpointBalancesCache: CheckpointBalancesCache; - // TODO DENEB: Prune data structure every time period, for both old entries /** Map keyed by executionPayload.blockHash of the block for those blobs */ readonly producedBlobSidecarsCache = new Map(); readonly producedBlindedBlobSidecarsCache = new Map< diff --git a/packages/beacon-node/src/chain/errors/blobSidecarError.ts b/packages/beacon-node/src/chain/errors/blobSidecarError.ts index f0ad69167c19..e242cbcb11ba 100644 --- a/packages/beacon-node/src/chain/errors/blobSidecarError.ts +++ b/packages/beacon-node/src/chain/errors/blobSidecarError.ts @@ -1,18 +1,27 @@ -import {Slot} from "@lodestar/types"; +import {Slot, RootHex, ValidatorIndex} from "@lodestar/types"; import {GossipActionError} from "./gossipValidation.js"; export enum BlobSidecarErrorCode { - INVALID_INDEX = "BLOBS_SIDECAR_ERROR_INVALID_INDEX", + INVALID_INDEX = "BLOB_SIDECAR_ERROR_INVALID_INDEX", /** !bls.KeyValidate(block.body.blob_kzg_commitments[i]) */ - INVALID_KZG = "BLOBS_SIDECAR_ERROR_INVALID_KZG", + INVALID_KZG = "BLOB_SIDECAR_ERROR_INVALID_KZG", /** !verify_kzg_commitments_against_transactions(block.body.execution_payload.transactions, block.body.blob_kzg_commitments) */ - INVALID_KZG_TXS = "BLOBS_SIDECAR_ERROR_INVALID_KZG_TXS", + INVALID_KZG_TXS = "BLOB_SIDECAR_ERROR_INVALID_KZG_TXS", /** sidecar.beacon_block_slot != block.slot */ - INCORRECT_SLOT = "BLOBS_SIDECAR_ERROR_INCORRECT_SLOT", + INCORRECT_SLOT = "BLOB_SIDECAR_ERROR_INCORRECT_SLOT", /** BLSFieldElement in valid range (x < BLS_MODULUS) */ - INVALID_BLOB = "BLOBS_SIDECAR_ERROR_INVALID_BLOB", + INVALID_BLOB = "BLOB_SIDECAR_ERROR_INVALID_BLOB", /** !bls.KeyValidate(blobs_sidecar.kzg_aggregated_proof) */ INVALID_KZG_PROOF = "BLOBS_SIDECAR_ERROR_INVALID_KZG_PROOF", + + // following errors are adapted from the block errors + FUTURE_SLOT = "BLOB_SIDECAR_ERROR_FUTURE_SLOT", + WOULD_REVERT_FINALIZED_SLOT = "BLOB_SIDECAR_ERROR_WOULD_REVERT_FINALIZED_SLOT", + ALREADY_KNOWN = "BLOB_SIDECAR_ERROR_ALREADY_KNOWN", + PARENT_UNKNOWN = "BLOB_SIDECAR_ERROR_PARENT_UNKNOWN", + NOT_LATER_THAN_PARENT = "BLOB_SIDECAR_ERROR_NOT_LATER_THAN_PARENT", + PROPOSAL_SIGNATURE_INVALID = "BLOB_SIDECAR_ERROR_PROPOSAL_SIGNATURE_INVALID", + INCORRECT_PROPOSER = "BLOB_SIDECAR_ERROR_INCORRECT_PROPOSER", } export type BlobSidecarErrorType = @@ -21,6 +30,13 @@ export type BlobSidecarErrorType = | {code: BlobSidecarErrorCode.INVALID_KZG_TXS} | {code: BlobSidecarErrorCode.INCORRECT_SLOT; blockSlot: Slot; blobSlot: Slot; blobIdx: number} | {code: BlobSidecarErrorCode.INVALID_BLOB; blobIdx: number} - | {code: BlobSidecarErrorCode.INVALID_KZG_PROOF; blobIdx: number}; + | {code: BlobSidecarErrorCode.INVALID_KZG_PROOF; blobIdx: number} + | {code: BlobSidecarErrorCode.FUTURE_SLOT; blockSlot: Slot; currentSlot: Slot} + | {code: BlobSidecarErrorCode.WOULD_REVERT_FINALIZED_SLOT; blockSlot: Slot; finalizedSlot: Slot} + | {code: BlobSidecarErrorCode.ALREADY_KNOWN; root: RootHex} + | {code: BlobSidecarErrorCode.PARENT_UNKNOWN; parentRoot: RootHex} + | {code: BlobSidecarErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot} + | {code: BlobSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID} + | {code: BlobSidecarErrorCode.INCORRECT_PROPOSER; proposerIndex: ValidatorIndex}; -export class BlobSidecarError extends GossipActionError {} +export class BlobSidecarGossipError extends GossipActionError {} diff --git a/packages/beacon-node/src/chain/validation/blobSidecar.ts b/packages/beacon-node/src/chain/validation/blobSidecar.ts index 9f51b29b817e..d876a1098611 100644 --- a/packages/beacon-node/src/chain/validation/blobSidecar.ts +++ b/packages/beacon-node/src/chain/validation/blobSidecar.ts @@ -3,16 +3,13 @@ import {deneb, Root, Slot} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; import {getBlobProposerSignatureSet, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {BlobSidecarError, BlobSidecarErrorCode} from "../errors/blobSidecarError.js"; +import {BlobSidecarGossipError, BlobSidecarErrorCode} from "../errors/blobSidecarError.js"; import {GossipAction} from "../errors/gossipValidation.js"; import {ckzg} from "../../util/kzg.js"; import {byteArrayEquals} from "../../util/bytes.js"; import {IBeaconChain} from "../interface.js"; import {RegenCaller} from "../regen/index.js"; -// TODO: freetheblobs define blobs own gossip error -import {BlockGossipError, BlockErrorCode} from "../errors/index.js"; - export async function validateGossipBlobSidecar( config: ChainForkConfig, chain: IBeaconChain, @@ -24,7 +21,7 @@ export async function validateGossipBlobSidecar( // [REJECT] The sidecar is for the correct topic -- i.e. sidecar.index matches the topic {index}. if (blobSidecar.index !== gossipIndex) { - throw new BlobSidecarError(GossipAction.REJECT, { + throw new BlobSidecarGossipError(GossipAction.REJECT, { code: BlobSidecarErrorCode.INVALID_INDEX, blobIdx: blobSidecar.index, gossipIndex, @@ -36,8 +33,8 @@ export async function validateGossipBlobSidecar( // the appropriate slot). const currentSlotWithGossipDisparity = chain.clock.currentSlotWithGossipDisparity; if (currentSlotWithGossipDisparity < blobSlot) { - throw new BlockGossipError(GossipAction.IGNORE, { - code: BlockErrorCode.FUTURE_SLOT, + throw new BlobSidecarGossipError(GossipAction.IGNORE, { + code: BlobSidecarErrorCode.FUTURE_SLOT, currentSlot: currentSlotWithGossipDisparity, blockSlot: blobSlot, }); @@ -48,8 +45,8 @@ export async function validateGossipBlobSidecar( const finalizedCheckpoint = chain.forkChoice.getFinalizedCheckpoint(); const finalizedSlot = computeStartSlotAtEpoch(finalizedCheckpoint.epoch); if (blobSlot <= finalizedSlot) { - throw new BlockGossipError(GossipAction.IGNORE, { - code: BlockErrorCode.WOULD_REVERT_FINALIZED_SLOT, + throw new BlobSidecarGossipError(GossipAction.IGNORE, { + code: BlobSidecarErrorCode.WOULD_REVERT_FINALIZED_SLOT, blockSlot: blobSlot, finalizedSlot, }); @@ -63,7 +60,7 @@ export async function validateGossipBlobSidecar( // already know this block. const blockRoot = toHex(blobSidecar.blockRoot); if (chain.forkChoice.getBlockHex(blockRoot) !== null) { - throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.ALREADY_KNOWN, root: blockRoot}); + throw new BlobSidecarGossipError(GossipAction.IGNORE, {code: BlobSidecarErrorCode.ALREADY_KNOWN, root: blockRoot}); } // TODO: freetheblobs - check for badblock @@ -85,13 +82,13 @@ export async function validateGossipBlobSidecar( // descend from the finalized root. // (Non-Lighthouse): Since we prune all blocks non-descendant from finalized checking the `db.block` database won't be useful to guard // against known bad fork blocks, so we throw PARENT_UNKNOWN for cases (1) and (2) - throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot}); + throw new BlobSidecarGossipError(GossipAction.IGNORE, {code: BlobSidecarErrorCode.PARENT_UNKNOWN, parentRoot}); } // [REJECT] The blob is from a higher slot than its parent. if (parentBlock.slot >= blobSlot) { - throw new BlockGossipError(GossipAction.IGNORE, { - code: BlockErrorCode.NOT_LATER_THAN_PARENT, + throw new BlobSidecarGossipError(GossipAction.IGNORE, { + code: BlobSidecarErrorCode.NOT_LATER_THAN_PARENT, parentSlot: parentBlock.slot, slot: blobSlot, }); @@ -106,7 +103,7 @@ export async function validateGossipBlobSidecar( const blockState = await chain.regen .getBlockSlotState(parentRoot, blobSlot, {dontTransferCache: true}, RegenCaller.validateGossipBlob) .catch(() => { - throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot}); + throw new BlobSidecarGossipError(GossipAction.IGNORE, {code: BlobSidecarErrorCode.PARENT_UNKNOWN, parentRoot}); }); // _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the @@ -114,8 +111,8 @@ export async function validateGossipBlobSidecar( const signatureSet = getBlobProposerSignatureSet(blockState, signedBlob); // Don't batch so verification is not delayed if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) { - throw new BlockGossipError(GossipAction.REJECT, { - code: BlockErrorCode.PROPOSAL_SIGNATURE_INVALID, + throw new BlobSidecarGossipError(GossipAction.REJECT, { + code: BlobSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID, }); } @@ -132,11 +129,21 @@ export async function validateGossipBlobSidecar( // a case _do not_ `REJECT`, instead `IGNORE` this message. const proposerIndex = blobSidecar.proposerIndex; if (blockState.epochCtx.getBeaconProposer(blobSlot) !== proposerIndex) { - throw new BlockGossipError(GossipAction.REJECT, {code: BlockErrorCode.INCORRECT_PROPOSER, proposerIndex}); + throw new BlobSidecarGossipError(GossipAction.REJECT, { + code: BlobSidecarErrorCode.INCORRECT_PROPOSER, + proposerIndex, + }); } // blob, proof and commitment as a valid BLS G1 point gets verified in batch validation - validateBlobsAndProofs([blobSidecar.kzgCommitment], [blobSidecar.blob], [blobSidecar.kzgProof]); + try { + validateBlobsAndProofs([blobSidecar.kzgCommitment], [blobSidecar.blob], [blobSidecar.kzgProof]); + } catch (_e) { + throw new BlobSidecarGossipError(GossipAction.REJECT, { + code: BlobSidecarErrorCode.INVALID_KZG_PROOF, + blobIdx: blobSidecar.index, + }); + } } // https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#validate_blobs_sidecar diff --git a/packages/beacon-node/src/db/repositories/blobSidecars.ts b/packages/beacon-node/src/db/repositories/blobSidecars.ts index 82750a338d43..576a03df9e61 100644 --- a/packages/beacon-node/src/db/repositories/blobSidecars.ts +++ b/packages/beacon-node/src/db/repositories/blobSidecars.ts @@ -16,7 +16,6 @@ export const blobSidecarsWrapperSsz = new ContainerType( export type BlobSidecarsWrapper = ValueOf; export const BLOB_SIDECARS_IN_WRAPPER_INDEX = 44; -// TODO deneb: export from types package // ssz.deneb.BlobSidecars.elementType.fixedSize; export const BLOBSIDECAR_FIXED_SIZE = 131256; diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index c64528552ea4..83a5ea3a7ed6 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -136,7 +136,7 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { */ private notifyNewPayload( executionPayloadRpc: EngineApiRpcParamTypes["engine_newPayloadV1"][0], - // TODO deneb: add versionedHashes validation + // add versionedHashes validation later if required _versionedHashes?: EngineApiRpcParamTypes["engine_newPayloadV3"][1] ): EngineApiRpcReturnTypes["engine_newPayloadV1"] { const blockHash = executionPayloadRpc.blockHash; diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 5ffae34a9eeb..b6f0d78f3b06 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -650,6 +650,13 @@ export function createLodestarMetrics( labelNames: ["error"], }), }, + gossipBlob: { + receivedToGossipValidate: register.histogram({ + name: "lodestar_gossip_blob_received_to_gossip_validate", + help: "Time elapsed between blob received and blob validated", + buckets: [0.05, 0.1, 0.2, 0.5, 1, 1.5, 2, 4], + }), + }, importBlock: { persistBlockNoSerializedDataCount: register.gauge({ name: "lodestar_import_block_persist_block_no_serialized_data_count", diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index c216e2dd495e..10d738e61e49 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -12,6 +12,8 @@ import { BlockError, BlockErrorCode, BlockGossipError, + BlobSidecarErrorCode, + BlobSidecarGossipError, GossipAction, GossipActionError, SyncCommitteeError, @@ -143,19 +145,18 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler try { await validateGossipBlock(config, chain, signedBlock, fork); - // TODO: freetheblobs add some serialized data return blockInput; } catch (e) { if (e instanceof BlockGossipError) { // Don't trigger this yet if full block and blobs haven't arrived yet - if (e instanceof BlockGossipError && e.type.code === BlockErrorCode.PARENT_UNKNOWN && blockInput !== null) { + if (e.type.code === BlockErrorCode.PARENT_UNKNOWN && blockInput !== null) { logger.debug("Gossip block has error", {slot, root: blockHex, code: e.type.code}); events.emit(NetworkEvent.unknownBlockParent, {blockInput, peer: peerIdStr}); } - } - if (e instanceof BlockGossipError && e.action === GossipAction.REJECT) { - chain.persistInvalidSszValue(forkTypes.SignedBeaconBlock, signedBlock, `gossip_reject_slot_${slot}`); + if (e.action === GossipAction.REJECT) { + chain.persistInvalidSszValue(forkTypes.SignedBeaconBlock, signedBlock, `gossip_reject_slot_${slot}`); + } } throw e; @@ -180,8 +181,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler blobBytes, }); - // TODO: freetheblobs - // metrics?.gossipBlock.receivedToGossipValidate.observe(recvToVal); + metrics?.gossipBlob.receivedToGossipValidate.observe(recvToVal); logger.verbose("Received gossip blob", { slot: slot, root: blockHex, @@ -197,16 +197,16 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler await validateGossipBlobSidecar(config, chain, signedBlob, gossipIndex); return blockInput; } catch (e) { - if (e instanceof BlockGossipError) { + if (e instanceof BlobSidecarGossipError) { // Don't trigger this yet if full block and blobs haven't arrived yet - if (e instanceof BlockGossipError && e.type.code === BlockErrorCode.PARENT_UNKNOWN && blockInput !== null) { + if (e.type.code === BlobSidecarErrorCode.PARENT_UNKNOWN && blockInput !== null) { logger.debug("Gossip blob has error", {slot, root: blockHex, code: e.type.code}); events.emit(NetworkEvent.unknownBlockParent, {blockInput, peer: peerIdStr}); } - } - if (e instanceof BlockGossipError && e.action === GossipAction.REJECT) { - chain.persistInvalidSszValue(ssz.deneb.SignedBlobSidecar, signedBlob, `gossip_reject_slot_${slot}`); + if (e.action === GossipAction.REJECT) { + chain.persistInvalidSszValue(ssz.deneb.SignedBlobSidecar, signedBlob, `gossip_reject_slot_${slot}`); + } } throw e; diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts index 4811d8bae9e7..c85464a05b61 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts @@ -1,5 +1,6 @@ import {ChainForkConfig} from "@lodestar/config"; -import {Epoch, phase0, deneb, Slot} from "@lodestar/types"; +import {phase0, deneb} from "@lodestar/types"; +import {ForkSeq} from "@lodestar/params"; import {BlockInput, BlockSource} from "../../chain/blocks/types.js"; import {PeerIdStr} from "../../util/peerId.js"; import {INetwork} from "../interface.js"; @@ -9,19 +10,21 @@ export async function beaconBlocksMaybeBlobsByRoot( config: ChainForkConfig, network: INetwork, peerId: PeerIdStr, - request: phase0.BeaconBlocksByRootRequest, - // TODO DENEB: Some validations can be done to see if this is deneb block, ignoring below two for now - _currentSlot: Epoch, - _finalizedSlot: Slot + request: phase0.BeaconBlocksByRootRequest ): Promise { const allBlocks = await network.sendBeaconBlocksByRoot(peerId, request); const blobIdentifiers: deneb.BlobIdentifier[] = []; for (const block of allBlocks) { - const blockRoot = config.getForkTypes(block.data.message.slot).BeaconBlock.hashTreeRoot(block.data.message); - const blobKzgCommitmentsLen = (block.data.message.body as deneb.BeaconBlockBody).blobKzgCommitments?.length ?? 0; - for (let index = 0; index < blobKzgCommitmentsLen; index++) { - blobIdentifiers.push({blockRoot, index}); + const slot = block.data.message.slot; + const blockRoot = config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block.data.message); + const fork = config.getForkName(slot); + + if (ForkSeq[fork] >= ForkSeq.deneb) { + const blobKzgCommitmentsLen = (block.data.message.body as deneb.BeaconBlockBody).blobKzgCommitments.length; + for (let index = 0; index < blobKzgCommitmentsLen; index++) { + blobIdentifiers.push({blockRoot, index}); + } } } diff --git a/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts b/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts index 32802e2c1660..d1046db9651d 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts @@ -7,50 +7,30 @@ import {IBeaconDb} from "../../../db/index.js"; // TODO: Unit test -export function onBeaconBlocksByRange( +export async function* onBeaconBlocksByRange( request: phase0.BeaconBlocksByRangeRequest, chain: IBeaconChain, db: IBeaconDb -): AsyncIterable { - return onBlocksOrBlobSidecarsByRange(request, chain, { - finalized: db.blockArchive, - unfinalized: db.block, - }); -} - -export async function* onBlocksOrBlobSidecarsByRange( - request: phase0.BeaconBlocksByRangeRequest, - chain: IBeaconChain, - db: { - finalized: Pick; - unfinalized: Pick; - } ): AsyncIterable { const {startSlot, count} = validateBeaconBlocksByRangeRequest(request); const endSlot = startSlot + count; - // SPEC: Clients MUST respond with blobs sidecars from their view of the current fork choice -- that is, blobs - // sidecars as included by blocks from the single chain defined by the current head. Of note, blocks from slots - // before the finalization MUST lead to the finalized block reported in the Status handshake. - // https://github.com/ethereum/consensus-specs/blob/11a037fd9227e29ee809c9397b09f8cc3383a8c0/specs/eip4844/p2p-interface.md#blobssidecarsbyrange-v1 - + const finalized = db.blockArchive; + const unfinalized = db.block; const finalizedSlot = chain.forkChoice.getFinalizedBlock().slot; - // Finalized range of blobs - // TODO DENEB: Should the finalized block be included here or below? - + // Finalized range of blocks if (startSlot <= finalizedSlot) { // Chain of blobs won't change - for await (const {key, value} of db.finalized.binaryEntriesStream({gte: startSlot, lt: endSlot})) { + for await (const {key, value} of finalized.binaryEntriesStream({gte: startSlot, lt: endSlot})) { yield { data: value, - fork: chain.config.getForkName(db.finalized.decodeKey(key)), + fork: chain.config.getForkName(finalized.decodeKey(key)), }; } } - // Non-finalized range of blobs - + // Non-finalized range of blocks if (endSlot > finalizedSlot) { const headRoot = chain.forkChoice.getHeadRoot(); // TODO DENEB: forkChoice should mantain an array of canonical blocks, and change only on reorg @@ -68,7 +48,7 @@ export async function* onBlocksOrBlobSidecarsByRange( // re-org there's no need to abort the request // Spec: https://github.com/ethereum/consensus-specs/blob/a1e46d1ae47dd9d097725801575b46907c12a1f8/specs/eip4844/p2p-interface.md#blobssidecarsbyrange-v1 - const blockBytes = await db.unfinalized.getBinary(fromHex(block.blockRoot)); + const blockBytes = await unfinalized.getBinary(fromHex(block.blockRoot)); if (!blockBytes) { // Handle the same to onBeaconBlocksByRange throw new ResponseError(RespStatus.SERVER_ERROR, `No item for root ${block.blockRoot} slot ${block.slot}`); diff --git a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts index 4f065ce5499b..2cd852492220 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts @@ -14,20 +14,23 @@ export async function* onBlobSidecarsByRange( // Non-finalized range of blobs const {startSlot, count} = validateBlobSidecarsByRangeRequest(request); const endSlot = startSlot + count; + + const finalized = db.blobSidecarsArchive; + const unfinalized = db.blobSidecars; const finalizedSlot = chain.forkChoice.getFinalizedBlock().slot; // Finalized range of blobs - if (startSlot <= finalizedSlot) { // Chain of blobs won't change - for await (const {key, value: blobSideCarsBytesWrapped} of db.blobSidecarsArchive.binaryEntriesStream({ + for await (const {key, value: blobSideCarsBytesWrapped} of finalized.binaryEntriesStream({ gte: startSlot, lt: endSlot, })) { - yield* iterateBlobBytesFromWrapper(chain, blobSideCarsBytesWrapped, db.blobSidecarsArchive.decodeKey(key)); + yield* iterateBlobBytesFromWrapper(chain, blobSideCarsBytesWrapped, finalized.decodeKey(key)); } } + // Non-finalized range of blobs if (endSlot > finalizedSlot) { const headRoot = chain.forkChoice.getHeadRoot(); // TODO DENEB: forkChoice should mantain an array of canonical blocks, and change only on reorg @@ -44,7 +47,7 @@ export async function* onBlobSidecarsByRange( // re-org there's no need to abort the request // Spec: https://github.com/ethereum/consensus-specs/blob/a1e46d1ae47dd9d097725801575b46907c12a1f8/specs/eip4844/p2p-interface.md#blobssidecarsbyrange-v1 - const blobSideCarsBytesWrapped = await db.blobSidecars.getBinary(fromHex(block.blockRoot)); + const blobSideCarsBytesWrapped = await unfinalized.getBinary(fromHex(block.blockRoot)); if (!blobSideCarsBytesWrapped) { // Handle the same to onBeaconBlocksByRange throw new ResponseError(RespStatus.SERVER_ERROR, `No item for root ${block.blockRoot} slot ${block.slot}`); diff --git a/packages/beacon-node/src/network/reqresp/rateLimit.ts b/packages/beacon-node/src/network/reqresp/rateLimit.ts index c57876bb7105..881ab36bc05d 100644 --- a/packages/beacon-node/src/network/reqresp/rateLimit.ts +++ b/packages/beacon-node/src/network/reqresp/rateLimit.ts @@ -37,12 +37,12 @@ export const rateLimitQuotas: Record = { getRequestCount: getRequestCountFn(ReqRespMethod.BeaconBlocksByRoot, (req) => req.length), }, [ReqRespMethod.BlobSidecarsByRange]: { - // TODO DENEB: For now same value as blobs in BeaconBlocksByRange https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130 + // Rationale: MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK byPeer: {quota: MAX_REQUEST_BLOB_SIDECARS, quotaTimeMs: 10_000}, getRequestCount: getRequestCountFn(ReqRespMethod.BlobSidecarsByRange, (req) => req.count), }, [ReqRespMethod.BlobSidecarsByRoot]: { - // TODO DENEB: For now same value as blobs in BeaconBlocksByRoot https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130 + // Rationale: quota of BeaconBlocksByRoot * MAX_BLOBS_PER_BLOCK byPeer: {quota: 128 * MAX_BLOBS_PER_BLOCK, quotaTimeMs: 10_000}, getRequestCount: getRequestCountFn(ReqRespMethod.BlobSidecarsByRoot, (req) => req.length), }, diff --git a/packages/beacon-node/src/node/nodejs.ts b/packages/beacon-node/src/node/nodejs.ts index fdef161001db..6e129076848c 100644 --- a/packages/beacon-node/src/node/nodejs.ts +++ b/packages/beacon-node/src/node/nodejs.ts @@ -157,10 +157,8 @@ export class BeaconNode { setMaxListeners(Infinity, controller.signal); const signal = controller.signal; - // TODO DENEB, where is the best place to do this? + // If deneb is configured, load the trusted setup if (config.DENEB_FORK_EPOCH < Infinity) { - // TODO DENEB: "c-kzg" is not installed by default, so if the library is not installed this will throw - // See "Not able to build lodestar from source" https://github.com/ChainSafe/lodestar/issues/4886 await initCKZG(); loadEthereumTrustedSetup(TrustedFileMode.Txt, opts.chain.trustedSetup); } diff --git a/packages/beacon-node/src/sync/unknownBlock.ts b/packages/beacon-node/src/sync/unknownBlock.ts index 82654f501346..cefe2617900a 100644 --- a/packages/beacon-node/src/sync/unknownBlock.ts +++ b/packages/beacon-node/src/sync/unknownBlock.ts @@ -408,15 +408,7 @@ export class UnknownBlockSync { for (let i = 0; i < MAX_ATTEMPTS_PER_BLOCK; i++) { const peer = shuffledPeers[i % shuffledPeers.length]; try { - // TODO DENEB: Use - const [blockInput] = await beaconBlocksMaybeBlobsByRoot( - this.config, - this.network, - peer, - [blockRoot], - this.chain.clock.currentSlot, - this.chain.forkChoice.getFinalizedBlock().slot - ); + const [blockInput] = await beaconBlocksMaybeBlobsByRoot(this.config, this.network, peer, [blockRoot]); // Peer does not have the block, try with next peer if (blockInput === undefined) { diff --git a/packages/beacon-node/test/e2e/api/impl/config.test.ts b/packages/beacon-node/test/e2e/api/impl/config.test.ts index b41a30a51967..4bdedfa16391 100644 --- a/packages/beacon-node/test/e2e/api/impl/config.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/config.test.ts @@ -10,9 +10,6 @@ const CONSTANT_NAMES_SKIP_LIST = new Set([ // This constant can also be derived from existing constants so it's not critical. // PARTICIPATION_FLAG_WEIGHTS = [TIMELY_SOURCE_WEIGHT, TIMELY_TARGET_WEIGHT, TIMELY_HEAD_WEIGHT] "PARTICIPATION_FLAG_WEIGHTS", - // TODO DENEB: This constant was added then removed on a spec re-write. - // When developing DENEB branch the tracked version still doesn't have released the removal - "DOMAIN_BLOB_SIDECAR", // TODO DENEB: Configure the blob subnets in a followup PR "BLOB_SIDECAR_SUBNET_COUNT", ]); diff --git a/packages/beacon-node/test/spec/presets/finality.test.ts b/packages/beacon-node/test/spec/presets/finality.test.ts index 5bfd32ea6a7e..0ec4017064f4 100644 --- a/packages/beacon-node/test/spec/presets/finality.test.ts +++ b/packages/beacon-node/test/spec/presets/finality.test.ts @@ -26,7 +26,7 @@ const finality: TestRunnerFn = (fork) => const signedBlock = testcase[`blocks_${i}`] as bellatrix.SignedBeaconBlock; state = stateTransition(state, signedBlock, { - // TODO DENEB: Should assume valid and available for this test? + // Should assume payload valid and blob data available for this test executionPayloadStatus: ExecutionPayloadStatus.valid, dataAvailableStatus: DataAvailableStatus.available, verifyStateRoot: false, diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index cb1b5a0df3f0..e7cb8a90dbb4 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -4,7 +4,6 @@ import { CachedBeaconStateAllForks, CachedBeaconStateBellatrix, CachedBeaconStateCapella, - DataAvailableStatus, ExecutionPayloadStatus, getBlockRootAtSlot, } from "@lodestar/state-transition"; @@ -75,8 +74,6 @@ const operationFns: Record> = executionPayloadStatus: testCase.execution.execution_valid ? ExecutionPayloadStatus.valid : ExecutionPayloadStatus.invalid, - // TODO Deneb: Make this value dynamic on fork Deneb - dataAvailableStatus: DataAvailableStatus.preDeneb, }); }, diff --git a/packages/beacon-node/test/spec/presets/sanity.test.ts b/packages/beacon-node/test/spec/presets/sanity.test.ts index 91836f67ccf8..57afb8cf3d28 100644 --- a/packages/beacon-node/test/spec/presets/sanity.test.ts +++ b/packages/beacon-node/test/spec/presets/sanity.test.ts @@ -67,7 +67,7 @@ const sanityBlocks: TestRunnerFn = (f for (let i = 0; i < testcase.meta.blocks_count; i++) { const signedBlock = testcase[`blocks_${i}`] as deneb.SignedBeaconBlock; wrappedState = stateTransition(wrappedState, signedBlock, { - // TODO DENEB: Should assume valid and available for this test? + // Assume valid and available for this test executionPayloadStatus: ExecutionPayloadStatus.valid, dataAvailableStatus: DataAvailableStatus.available, verifyStateRoot: verify, diff --git a/packages/beacon-node/test/spec/presets/transition.test.ts b/packages/beacon-node/test/spec/presets/transition.test.ts index 3124116b2f4d..77919d76c3b1 100644 --- a/packages/beacon-node/test/spec/presets/transition.test.ts +++ b/packages/beacon-node/test/spec/presets/transition.test.ts @@ -55,7 +55,7 @@ const transition = for (let i = 0; i < meta.blocks_count; i++) { const signedBlock = testcase[`blocks_${i}`] as allForks.SignedBeaconBlock; state = stateTransition(state, signedBlock, { - // TODO DENEB: Should assume valid and available for this test? + // Assume valid and available for this test executionPayloadStatus: ExecutionPayloadStatus.valid, dataAvailableStatus: DataAvailableStatus.available, verifyStateRoot: true, diff --git a/packages/beacon-node/test/unit/network/fork.test.ts b/packages/beacon-node/test/unit/network/fork.test.ts index cbda5f2b1b34..be748d2e8185 100644 --- a/packages/beacon-node/test/unit/network/fork.test.ts +++ b/packages/beacon-node/test/unit/network/fork.test.ts @@ -132,7 +132,6 @@ const testScenarios = [ for (const testScenario of testScenarios) { const {phase0, altair, bellatrix, capella, testCases} = testScenario; - // TODO DENEB: Is it necessary to test? const deneb = Infinity; describe(`network / fork: phase0: ${phase0}, altair: ${altair}, bellatrix: ${bellatrix} capella: ${capella}`, () => { diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 4965c21397b4..27091774cc20 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -10,7 +10,7 @@ export function processExecutionPayload( fork: ForkSeq, state: CachedBeaconStateBellatrix | CachedBeaconStateCapella, body: allForks.FullOrBlindedBeaconBlockBody, - externalData: BlockExternalData + externalData: Omit ): void { const payload = getFullOrBlindedPayloadFromBody(body); // Verify consistency of the parent hash, block number, base fee per gas and gas limit diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index f9e93741fa74..8fd98f4df03e 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -43,7 +43,7 @@ export function stateTransition( state: CachedBeaconStateAllForks, signedBlock: allForks.FullOrBlindedSignedBeaconBlock, options: StateTransitionOpts = { - // TODO DENEB: Review what default values make sense + // Assume default to be valid and available executionPayloadStatus: ExecutionPayloadStatus.valid, dataAvailableStatus: DataAvailableStatus.available, },