diff --git a/packages/cli/src/cmds/validator/handler.ts b/packages/cli/src/cmds/validator/handler.ts index 985505344c63..703398d4f026 100644 --- a/packages/cli/src/cmds/validator/handler.ts +++ b/packages/cli/src/cmds/validator/handler.ts @@ -162,6 +162,7 @@ export async function validatorHandler(args: IValidatorCliArgs & GlobalArgs): Pr disableAttestationGrouping: args.disableAttestationGrouping, valProposerConfig, distributed: args.distributed, + useProduceBlockV3: args.useProduceBlockV3, }, metrics ); diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index 6e212caca212..8daa1feda4bf 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -46,6 +46,8 @@ export type IValidatorCliArgs = AccountValidatorArgs & builder?: boolean; "builder.selection"?: string; + useProduceBlockV3?: boolean; + importKeystores?: string[]; importKeystoresPassword?: string; @@ -243,6 +245,12 @@ export const validatorOptions: CliCommandOptions = { group: "builder", }, + useProduceBlockV3: { + type: "boolean", + description: "Enable/disable usage of produceBlockV3 that might not be supported by all beacon clients yet", + defaultDescription: `${defaultOptions.useProduceBlockV3}`, + }, + importKeystores: { alias: ["keystore"], // Backwards compatibility with old `validator import` cmdx description: "Path(s) to a directory or single file path to validator keystores, i.e. Launchpad validators", diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index 1fff76c023ca..861bebcd1765 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -24,7 +24,7 @@ import {IClock, LoggerVc} from "../util/index.js"; import {PubkeyHex} from "../types.js"; import {Metrics} from "../metrics.js"; import {formatBigDecimal} from "../util/format.js"; -import {ValidatorStore} from "./validatorStore.js"; +import {ValidatorStore, defaultOptions} from "./validatorStore.js"; import {BlockDutiesService, GENESIS_SLOT} from "./blockDuties.js"; const ETH_TO_WEI = BigInt("1000000000000000000"); @@ -81,7 +81,8 @@ export class BlockProposingService { private readonly api: Api, private readonly clock: IClock, private readonly validatorStore: ValidatorStore, - private readonly metrics: Metrics | null + private readonly metrics: Metrics | null, + private readonly useProduceBlockV3: boolean = defaultOptions.useProduceBlockV3 ) { this.dutiesService = new BlockDutiesService( config, @@ -141,7 +142,8 @@ export class BlockProposingService { }); this.metrics?.proposerStepCallProduceBlock.observe(this.clock.secFromSlot(slot)); - const blockContents = await this.produceBlockWrapper(slot, randaoReveal, graffiti, { + const produceBlockFn = this.useProduceBlockV3 ? this.produceBlockWrapper : this.produceBlockV2Wrapper; + const blockContents = await produceBlockFn(slot, randaoReveal, graffiti, { feeRecipient, strictFeeRecipientCheck, builderSelection, @@ -222,6 +224,7 @@ export class BlockProposingService { // TODO PR: should be used in api call instead of adding in log strictFeeRecipientCheck, builderSelection, + api: "produceBlockV3", }; let fullOrBlindedBlockWithContents: FullOrBlindedBlockWithContents; @@ -261,4 +264,63 @@ export class BlockProposingService { return {...fullOrBlindedBlockWithContents, debugLogCtx}; }; + + /** a wrapper function used for backward compatibility with the clients who don't have v3 implemented yet */ + private produceBlockV2Wrapper = async ( + slot: Slot, + randaoReveal: BLSSignature, + graffiti: string, + {builderSelection}: routes.validator.ExtraProduceBlockOps + ): Promise}> => { + // other clients have always implemented builder vs execution race in produce blinded block + // so if builderSelection is executiononly then only we call produceBlockV2 else produceBlockV3 always + const debugLogCtx = {builderSelection}; + let fullOrBlindedBlockWithContents: FullOrBlindedBlockWithContents; + + if (builderSelection === routes.validator.BuilderSelection.ExecutionOnly) { + Object.assign(debugLogCtx, {api: "produceBlockV2"}); + const res = await this.api.validator.produceBlockV2(slot, randaoReveal, graffiti); + ApiError.assert(res, "Failed to produce block: validator.produceBlockV2"); + const {response} = res; + + if (isBlockContents(response.data)) { + fullOrBlindedBlockWithContents = { + block: response.data.block, + blobs: response.data.blobSidecars, + version: response.version, + executionPayloadBlinded: false, + } as FullOrBlindedBlockWithContents; + } else { + fullOrBlindedBlockWithContents = { + block: response.data, + blobs: null, + version: response.version, + executionPayloadBlinded: false, + } as FullOrBlindedBlockWithContents; + } + } else { + Object.assign(debugLogCtx, {api: "produceBlindedBlock"}); + const res = await this.api.validator.produceBlindedBlock(slot, randaoReveal, graffiti); + ApiError.assert(res, "Failed to produce block: validator.produceBlockV2"); + const {response} = res; + + if (isBlindedBlockContents(response.data)) { + fullOrBlindedBlockWithContents = { + block: response.data.blindedBlock, + blobs: response.data.blindedBlobSidecars, + version: response.version, + executionPayloadBlinded: true, + } as FullOrBlindedBlockWithContents; + } else { + fullOrBlindedBlockWithContents = { + block: response.data, + blobs: null, + version: response.version, + executionPayloadBlinded: true, + } as FullOrBlindedBlockWithContents; + } + } + + return {...fullOrBlindedBlockWithContents, debugLogCtx}; + }; } diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 4a5f5b33c1d4..8a5841733dd2 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -115,6 +115,7 @@ export const defaultOptions = { suggestedFeeRecipient: "0x0000000000000000000000000000000000000000", defaultGasLimit: 30_000_000, builderSelection: routes.validator.BuilderSelection.MaxProfit, + useProduceBlockV3: true, }; /** diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 01a01b2afa20..47a579cdcbb9 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -38,6 +38,7 @@ export type ValidatorOptions = { closed?: boolean; valProposerConfig?: ValidatorProposerConfig; distributed?: boolean; + useProduceBlockV3?: boolean; }; // TODO: Extend the timeout, and let it be customizable @@ -121,7 +122,15 @@ export class Validator { const chainHeaderTracker = new ChainHeaderTracker(logger, api, emitter); - this.blockProposingService = new BlockProposingService(config, loggerVc, api, clock, validatorStore, metrics); + this.blockProposingService = new BlockProposingService( + config, + loggerVc, + api, + clock, + validatorStore, + metrics, + opts.useProduceBlockV3 + ); this.attestationService = new AttestationService( loggerVc,