diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index d416c7ac4700..f412fc5940c4 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -237,7 +237,7 @@ export type Api = { graffiti: string ): Promise< ApiClientResponse< - {[HttpStatusCode.OK]: {data: allForks.BeaconBlock; version: ForkName}}, + {[HttpStatusCode.OK]: ProduceBlockOrContentsRes}, HttpStatusCode.BAD_REQUEST | HttpStatusCode.SERVICE_UNAVAILABLE > >; @@ -275,10 +275,7 @@ export type Api = { ): Promise< ApiClientResponse< { - [HttpStatusCode.OK]: { - data: allForks.BlindedBeaconBlock | BlindedBlockContents; - version: ForkName; - }; + [HttpStatusCode.OK]: ProduceBlindedBlockOrContentsRes; }, HttpStatusCode.BAD_REQUEST | HttpStatusCode.SERVICE_UNAVAILABLE > @@ -526,7 +523,7 @@ export function getReqSerializers(): ReqSerializers { {jsonCase: "eth2"} ); - const produceBlock: ReqSerializers["produceBlockV3"] = { + const produceBlockV3: ReqSerializers["produceBlockV3"] = { writeReq: (slot, randaoReveal, graffiti, skipRandaoVerification) => ({ params: {slot}, query: { @@ -574,10 +571,10 @@ export function getReqSerializers(): ReqSerializers { }, }, - produceBlock: produceBlock as ReqSerializers["produceBlock"], - produceBlockV2: produceBlock as ReqSerializers["produceBlock"], - produceBlockV3: produceBlock, - produceBlindedBlock: produceBlock as ReqSerializers["produceBlock"], + produceBlock: produceBlockV3 as ReqSerializers["produceBlock"], + produceBlockV2: produceBlockV3 as ReqSerializers["produceBlockV2"], + produceBlockV3, + produceBlindedBlock: produceBlockV3 as ReqSerializers["produceBlindedBlock"], produceAttestationData: { writeReq: (index, slot) => ({query: {slot, committee_index: index}}), @@ -704,7 +701,7 @@ export function getReturnTypes(): ReturnTypes { getSyncCommitteeDuties: ContainerDataExecutionOptimistic(ArrayOf(SyncDuty)), produceBlock: ContainerData(ssz.phase0.BeaconBlock), - produceBlockV2: WithVersion((fork: ForkName) => ssz[fork].BeaconBlock), + produceBlockV2: produceBlockOrContents, produceBlockV3: { toJson: (data) => data.executionPayloadBlinded === true @@ -718,9 +715,7 @@ export function getReturnTypes(): ReturnTypes { } }, }, - produceBlindedBlock: WithVersion( - (fork: ForkName) => ssz.allForksBlinded[isForkExecution(fork) ? fork : ForkName.bellatrix].BeaconBlock - ), + produceBlindedBlock: produceBlindedBlockOrContents, produceAttestationData: ContainerData(ssz.phase0.AttestationData), produceSyncCommitteeContribution: ContainerData(ssz.altair.SyncCommitteeContribution), diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index bfc55dbe02cf..ce25a6833edb 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -347,42 +347,58 @@ export function getValidatorApi({ }; const produceBlockV3: ServerApi["produceBlockV3"] = async function produceBlockV3( - _slot, - _randaoReveal, - _graffiti, + slot, + randaoReveal, + graffiti, + // TODO deneb: skip randao verification _skipRandaoVerification?: boolean ) { - throw Error("not implemented"); + // Start calls for building execution and builder blocks + const blindedBlockPromise = chain.executionBuilder + ? produceBlindedBlockOrContents(slot, randaoReveal, graffiti) + : null; + const fullBlockPromise = + // At any point either the builder or execution or both flows should be active. + // + // Ideally such a scenario should be prevented on startup, but proposerSettingsFile or keymanager + // configurations could cause a validator pubkey to have builder disabled with builder selection builder only + // (TODO: independently make sure such an options update is not successful for a validator pubkey) + // + // So if builder is disabled ignore builder selection of builderonly if caused by user mistake + !chain.executionBuilder + ? // TODO deneb: builderSelection needs to be figured out if to be done beacon side + // || builderSelection !== BuilderSelection.BuilderOnly + produceFullBlockOrContents(slot, randaoReveal, graffiti) + : null; + + // just throw random error for now + if (fullBlockPromise === null || blindedBlockPromise === null) { + throw Error("random error"); + } else { + throw Error("random error"); + } }; - const produceBlockV2: ServerApi["produceBlockV2"] = async function produceBlockV2( + const produceBlock: ServerApi["produceBlock"] = async function produceBlock( slot, randaoReveal, graffiti ) { - const {data, version, executionPayloadValue} = await produceFullBlockOrContents(slot, randaoReveal, graffiti); - if ((data as BlockContents).block !== undefined) { - throw Error(`Invalid block contents for produceBlock at fork=${version}`); + const producedData = await produceFullBlockOrContents(slot, randaoReveal, graffiti); + if (isForkBlobs(producedData.version)) { + throw Error(`Invalid call to produceBlock for deneb+ fork=${producedData.version}`); } else { - return {data: data as allForks.BeaconBlock, version, executionPayloadValue}; + // TODO: need to figure out why typescript requires typecasting here + // by typing of produceFullBlockOrContents respose it should have figured this out itself + return producedData as {data: allForks.BeaconBlock}; } }; - const produceBlindedBlock: ServerApi["produceBlindedBlock"] = - async function produceBlindedBlock(slot, randaoReveal, graffiti) { - const {data, version, executionPayloadValue} = await produceBlindedBlockOrContents(slot, randaoReveal, graffiti); - if (isForkBlobs(version)) { - throw Error(`Invalid produceBlindedBlock api usage post deneb at fork=${version}`); - } else { - return {data: data as allForks.BlindedBeaconBlock, version, executionPayloadValue}; - } - }; - return { - produceBlock: produceBlockV2, - produceBlockV2, + produceBlock, + produceBlockV2: produceFullBlockOrContents, produceBlockV3, - produceBlindedBlock, + produceBlindedBlock: produceBlindedBlockOrContents, async produceAttestationData(committeeIndex, slot) { notWhileSyncing();