diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index 5a2900b2c059..4193553303e7 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -1,10 +1,11 @@ import {expect} from "chai"; import {ssz, deneb} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {BYTES_PER_FIELD_ELEMENT} from "@lodestar/params"; import {beaconBlocksMaybeBlobsByRange} from "../../../src/network/reqresp/index.js"; -import {BlockInputType, BlockSource} from "../../../src/chain/blocks/types.js"; -import {ckzg, initCKZG, loadEthereumTrustedSetup} from "../../../src/util/kzg.js"; +import {BlockInputType, BlockSource, blobSidecarsToBlobsSidecar} from "../../../src/chain/blocks/types.js"; +import {ckzg, initCKZG, loadEthereumTrustedSetup, FIELD_ELEMENTS_PER_BLOB_MAINNET} from "../../../src/util/kzg.js"; import {INetwork} from "../../../src/network/interface.js"; describe("beaconBlocksMaybeBlobsByRange", () => { @@ -31,54 +32,83 @@ describe("beaconBlocksMaybeBlobsByRange", () => { const block1 = ssz.deneb.SignedBeaconBlock.defaultValue(); block1.message.slot = 1; + block1.message.body.blobKzgCommitments.push(ssz.deneb.KZGCommitment.defaultValue()); + const blobSidecar1 = ssz.deneb.BlobSidecar.defaultValue(); + blobSidecar1.slot = 1; + const block2 = ssz.deneb.SignedBeaconBlock.defaultValue(); block2.message.slot = 2; + block2.message.body.blobKzgCommitments.push(ssz.deneb.KZGCommitment.defaultValue()); + const blobSidecar2 = ssz.deneb.BlobSidecar.defaultValue(); + blobSidecar2.slot = 2; + + const block3 = ssz.deneb.SignedBeaconBlock.defaultValue(); + block3.message.slot = 3; + // no blobsidecar for block3 - const blobsSidecar1 = ssz.deneb.BlobsSidecar.defaultValue(); - blobsSidecar1.beaconBlockSlot = 1; - const blobsSidecar2 = ssz.deneb.BlobsSidecar.defaultValue(); - blobsSidecar2.beaconBlockSlot = 2; + const block4 = ssz.deneb.SignedBeaconBlock.defaultValue(); + block4.message.slot = 4; + // two blobsidecars + block4.message.body.blobKzgCommitments.push(ssz.deneb.KZGCommitment.defaultValue()); + block4.message.body.blobKzgCommitments.push(ssz.deneb.KZGCommitment.defaultValue()); + const blobSidecar41 = ssz.deneb.BlobSidecar.defaultValue(); + blobSidecar41.slot = 4; + const blobSidecar42 = ssz.deneb.BlobSidecar.defaultValue(); + blobSidecar42.slot = 4; + blobSidecar42.index = 1; // Array of testcases which are array of matched blocks with/without (if empty) sidecars - const testCases: [string, [deneb.SignedBeaconBlock, deneb.BlobsSidecar | undefined][]][] = [ - ["one block with sidecar", [[block1, blobsSidecar1]]], + const testCases: [string, [deneb.SignedBeaconBlock, deneb.BlobSidecar[] | undefined][]][] = [ + ["one block with sidecar", [[block1, [blobSidecar1]]]], [ "two blocks with sidecar", [ - [block1, blobsSidecar1], - [block2, blobsSidecar2], + [block1, [blobSidecar1]], + [block2, [blobSidecar2]], + ], + ], + ["block with skipped sidecar", [[block3, undefined]]], + ["multiple blob sidecars per block", [[block4, [blobSidecar41, blobSidecar42]]]], + [ + "all blocks together", + [ + [block1, [blobSidecar1]], + [block2, [blobSidecar2]], + [block3, undefined], + [block4, [blobSidecar41, blobSidecar42]], ], ], - ["block with skipped sidecar", [[block1, undefined]]], ]; testCases.map(([testName, blocksWithBlobs]) => { it(testName, async () => { const blocks = blocksWithBlobs.map(([block, _blobs]) => block as deneb.SignedBeaconBlock); - const blobsSidecars = blocksWithBlobs - .map(([_block, blobs]) => blobs as deneb.BlobsSidecar) - .filter((blobs) => blobs !== undefined); - const emptyKzgAggregatedProof = ckzg.computeAggregateKzgProof([]); - const expectedResponse = blocksWithBlobs.map(([block, blobsSidecar]) => { - const blobs = - blobsSidecar !== undefined - ? blobsSidecar - : { - beaconBlockRoot: ssz.deneb.BeaconBlock.hashTreeRoot(block.message), - beaconBlockSlot: block.message.slot, - blobs: [], - kzgAggregatedProof: emptyKzgAggregatedProof, - }; + + const blobSidecars = blocksWithBlobs + .map(([_block, blobs]) => blobs as deneb.BlobSidecars) + .filter((blobs) => blobs !== undefined) + .reduce((acc, elem) => acc.concat(elem), []); + + const expectedResponse = blocksWithBlobs.map(([block, blobSidecars]) => { + const blobs = (blobSidecars !== undefined ? blobSidecars : []).map((bscar) => { + // TODO DENEB: cleanup the following generation as its not required to generate + // proper field elements for the aggregate proofs compute + bscar.blob = generateRandomBlob(); + (bscar.kzgCommitment = ckzg.blobToKzgCommitment(bscar.blob)), + (bscar.kzgProof = ckzg.computeAggregateKzgProof([bscar.blob])); + return bscar; + }); return { type: BlockInputType.postDeneb, block, source: BlockSource.byRange, - blobs, + // TODO DENEB: Cleanup the conversion once migration complete + blobs: blobSidecarsToBlobsSidecar(chainConfig, block, blobs), }; }); const network = { sendBeaconBlocksByRange: async () => blocks, - sendBlobsSidecarsByRange: async () => blobsSidecars, + sendBlobSidecarsByRange: async () => blobSidecars, } as Partial as INetwork; const response = await beaconBlocksMaybeBlobsByRange(config, network, peerId, rangeRequest, 0); @@ -86,3 +116,12 @@ describe("beaconBlocksMaybeBlobsByRange", () => { }); }); }); + +function generateRandomBlob(): deneb.Blob { + const blob = new Uint8Array(FIELD_ELEMENTS_PER_BLOB_MAINNET * BYTES_PER_FIELD_ELEMENT); + const dv = new DataView(blob.buffer, blob.byteOffset, blob.byteLength); + for (let i = 0; i < FIELD_ELEMENTS_PER_BLOB_MAINNET; i++) { + dv.setUint32(i * BYTES_PER_FIELD_ELEMENT, i); + } + return blob; +}