Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow builder only proposal flow for benefit of DVT protocols #5669

Merged
merged 5 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/cli/src/cmds/validator/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ function parseBuilderSelection(builderSelection?: string): BuilderSelection | un
break;
case "builderalways":
break;
case "builderonly":
break;
default:
throw Error("Invalid input for builder selection, check help.");
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cmds/validator/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export const validatorOptions: CliCommandOptions<IValidatorCliArgs> = {

"builder.selection": {
type: "string",
description: "Default builder block selection strategy: maxprofit or builderalways",
description: "Default builder block selection strategy: maxprofit, builderalways, or builderonly",
defaultDescription: `${defaultOptions.builderSelection}`,
group: "builder",
},
Expand Down
39 changes: 31 additions & 8 deletions packages/validator/src/services/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,20 @@ export class BlockProposingService {

const debugLogCtx = {...logCtx, validator: pubkeyHex};

this.logger.debug("Producing block", debugLogCtx);
this.metrics?.proposerStepCallProduceBlock.observe(this.clock.secFromSlot(slot));

const strictFeeRecipientCheck = this.validatorStore.strictFeeRecipientCheck(pubkeyHex);
const isBuilderEnabled = this.validatorStore.isBuilderEnabled(pubkeyHex);
const builderSelection = this.validatorStore.getBuilderSelection(pubkeyHex);
const expectedFeeRecipient = this.validatorStore.getFeeRecipient(pubkeyHex);

this.logger.debug("Producing block", {
...debugLogCtx,
isBuilderEnabled,
builderSelection,
expectedFeeRecipient,
strictFeeRecipientCheck,
});
this.metrics?.proposerStepCallProduceBlock.observe(this.clock.secFromSlot(slot));

const blockContents = await this.produceBlockWrapper(slot, randaoReveal, graffiti, {
expectedFeeRecipient,
strictFeeRecipientCheck,
Expand Down Expand Up @@ -190,10 +196,20 @@ export class BlockProposingService {
> => {
// Start calls for building execution and builder blocks
const blindedBlockPromise = isBuilderEnabled ? this.produceBlindedBlock(slot, randaoReveal, graffiti) : null;
const fullBlockPromise = this.produceBlock(slot, randaoReveal, graffiti);
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
!isBuilderEnabled || builderSelection !== BuilderSelection.BuilderOnly
? this.produceBlock(slot, randaoReveal, graffiti)
: null;

let blindedBlock, fullBlock;
if (blindedBlockPromise !== null) {
if (blindedBlockPromise !== null && fullBlockPromise !== null) {
// reference index of promises in the race
const promisesOrder = [ProducedBlockSource.builder, ProducedBlockSource.engine];
[blindedBlock, fullBlock] = await racePromisesWithCutoff<{
Expand Down Expand Up @@ -225,9 +241,16 @@ export class BlockProposingService {
this.logger.error("Failed to produce execution block", {}, fullBlock);
fullBlock = null;
}
} else {
fullBlock = await fullBlockPromise;
} else if (blindedBlockPromise !== null && fullBlockPromise === null) {
blindedBlock = await blindedBlockPromise;
fullBlock = null;
} else if (blindedBlockPromise === null && fullBlockPromise !== null) {
blindedBlock = null;
fullBlock = await fullBlockPromise;
} else {
throw Error(
`Internal Error: Neither builder nor execution proposal flow activated isBuilderEnabled=${isBuilderEnabled} builderSelection=${builderSelection}`
);
}

const builderBlockValue = blindedBlock?.blockValue ?? BigInt(0);
Expand All @@ -252,7 +275,7 @@ export class BlockProposingService {
break;
}

case BuilderSelection.BuilderAlways:
// For everything else just select the builder
default: {
selectedSource = ProducedBlockSource.builder;
selectedBlock = blindedBlock;
Expand Down
2 changes: 2 additions & 0 deletions packages/validator/src/services/validatorStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export type SignerRemote = {
export enum BuilderSelection {
BuilderAlways = "builderalways",
MaxProfit = "maxprofit",
/** Only activate builder flow for DVT block proposal protocols */
BuilderOnly = "builderonly",
}

type DefaultProposerConfig = {
Expand Down