diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 6dbe216d069a..834fdd2f986a 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -268,9 +268,67 @@ export class Network implements INetwork { } async beaconBlocksMaybeBlobsByRoot(peerId: PeerId, request: phase0.BeaconBlocksByRootRequest): Promise { - // TODO EIP-4844: Will throw an error for blocks post EIP-4844 - const blocks = await this.reqResp.beaconBlocksByRoot(peerId, request); - return blocks.map((block) => getBlockInput.preEIP4844(this.config, block)); + // Assume all requests are post EIP-4844 + if (this.config.getForkSeq(this.chain.forkChoice.getFinalizedBlock().slot) >= ForkSeq.eip4844) { + const blocksAndBlobs = await this.reqResp.beaconBlockAndBlobsSidecarByRoot(peerId, request); + return blocksAndBlobs.map(({beaconBlock, blobsSidecar}) => + getBlockInput.postEIP4844(this.config, beaconBlock, blobsSidecar) + ); + } + + // Assume all request are pre EIP-4844 + else if (this.config.getForkSeq(this.clock.currentSlot) < ForkSeq.eip4844) { + const blocks = await this.reqResp.beaconBlocksByRoot(peerId, request); + return blocks.map((block) => getBlockInput.preEIP4844(this.config, block)); + } + + // NOTE: Consider blocks may be post or pre EIP-4844 + // TODO EIP-4844: Request either blocks, or blocks+blobs + else { + const results = await Promise.all( + request.map( + async (beaconBlockRoot): Promise => { + const [resultBlockBlobs, resultBlocks] = await Promise.allSettled([ + this.reqResp.beaconBlockAndBlobsSidecarByRoot(peerId, [beaconBlockRoot]), + this.reqResp.beaconBlocksByRoot(peerId, [beaconBlockRoot]), + ]); + + if (resultBlockBlobs.status === "fulfilled" && resultBlockBlobs.value.length === 1) { + const {beaconBlock, blobsSidecar} = resultBlockBlobs.value[0]; + return getBlockInput.postEIP4844(this.config, beaconBlock, blobsSidecar); + } + + if (resultBlocks.status === "rejected") { + return Promise.reject(resultBlocks.reason); + } + + // Promise fullfilled + no result = block not found + if (resultBlocks.value.length < 1) { + return null; + } + + const block = resultBlocks.value[0]; + + if (this.config.getForkSeq(block.message.slot) >= ForkSeq.eip4844) { + // beaconBlockAndBlobsSidecarByRoot should have succeeded + if (resultBlockBlobs.status === "rejected") { + // Recycle existing error for beaconBlockAndBlobsSidecarByRoot if any + return Promise.reject(resultBlockBlobs.reason); + } else { + throw Error( + `Received post EIP-4844 ${beaconBlockRoot} over beaconBlocksByRoot not beaconBlockAndBlobsSidecarByRoot` + ); + } + } + + // Block is pre EIP-4844 + return getBlockInput.preEIP4844(this.config, block); + } + ) + ); + + return results.filter((blockOrNull): blockOrNull is BlockInput => blockOrNull !== null); + } } /** diff --git a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts index 7261aaad13ab..7f3e5c167c88 100644 --- a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts +++ b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts @@ -270,6 +270,21 @@ export class ReqRespBeaconNode extends ReqResp implements IReqRespBeaconNode { ); } + async beaconBlockAndBlobsSidecarByRoot( + peerId: PeerId, + request: eip4844.BeaconBlockAndBlobsSidecarByRootRequest + ): Promise { + return collectMaxResponse( + this.sendRequest( + peerId, + ReqRespMethod.BeaconBlockAndBlobsSidecarByRoot, + [Version.V1], + request + ), + request.length + ); + } + /** * Returns the list of protocols that must be subscribed during a specific fork. * Any protocol not in this list must be un-subscribed. diff --git a/packages/beacon-node/src/network/reqresp/interface.ts b/packages/beacon-node/src/network/reqresp/interface.ts index 4039e86ab79f..d07cde6df181 100644 --- a/packages/beacon-node/src/network/reqresp/interface.ts +++ b/packages/beacon-node/src/network/reqresp/interface.ts @@ -14,6 +14,10 @@ export interface IReqRespBeaconNode { ): Promise; beaconBlocksByRoot(peerId: PeerId, request: phase0.BeaconBlocksByRootRequest): Promise; blobsSidecarsByRange(peerId: PeerId, request: eip4844.BlobsSidecarsByRangeRequest): Promise; + beaconBlockAndBlobsSidecarByRoot( + peerId: PeerId, + request: eip4844.BeaconBlockAndBlobsSidecarByRootRequest + ): Promise; pruneOnPeerDisconnect(peerId: PeerId): void; lightClientBootstrap(peerId: PeerId, request: Uint8Array): Promise; lightClientOptimisticUpdate(peerId: PeerId): Promise; diff --git a/packages/beacon-node/src/network/reqresp/types.ts b/packages/beacon-node/src/network/reqresp/types.ts index 6cd425159d6a..66cedd61abc1 100644 --- a/packages/beacon-node/src/network/reqresp/types.ts +++ b/packages/beacon-node/src/network/reqresp/types.ts @@ -10,6 +10,7 @@ export enum ReqRespMethod { BeaconBlocksByRange = "beacon_blocks_by_range", BeaconBlocksByRoot = "beacon_blocks_by_root", BlobsSidecarsByRange = "blobs_sidecars_by_range", + BeaconBlockAndBlobsSidecarByRoot = "beacon_block_and_blobs_sidecar_by_root", LightClientBootstrap = "light_client_bootstrap", LightClientUpdatesByRange = "light_client_updates_by_range", LightClientFinalityUpdate = "light_client_finality_update", @@ -26,6 +27,7 @@ type RequestBodyByMethod = { [ReqRespMethod.BeaconBlocksByRange]: unknown; [ReqRespMethod.BeaconBlocksByRoot]: unknown; [ReqRespMethod.BlobsSidecarsByRange]: unknown; + [ReqRespMethod.BeaconBlockAndBlobsSidecarByRoot]: unknown; [ReqRespMethod.LightClientBootstrap]: unknown; [ReqRespMethod.LightClientUpdatesByRange]: unknown; [ReqRespMethod.LightClientFinalityUpdate]: unknown; diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index a6a8b95459c9..1f3f6901cc75 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -111,6 +111,7 @@ describe("network / peers / PeerManager", function () { beaconBlocksByRange = sinon.stub(); beaconBlocksByRoot = sinon.stub(); blobsSidecarsByRange = sinon.stub(); + beaconBlockAndBlobsSidecarByRoot = sinon.stub(); pruneOnPeerDisconnect = sinon.stub(); lightClientBootstrap = sinon.stub(); lightClientOptimisticUpdate = sinon.stub();