diff --git a/docs/pages/validator-management/vc-configuration.md b/docs/pages/validator-management/vc-configuration.md index c62d7e13369..d86edb465c1 100644 --- a/docs/pages/validator-management/vc-configuration.md +++ b/docs/pages/validator-management/vc-configuration.md @@ -82,7 +82,8 @@ With produceBlockV3 (enabled automatically after the Deneb hard fork), the `--bu With Lodestar's `--builder.selection` validator options, you can select: -- `maxprofit`: Default setting for Lodestar set at `--builder.boostFactor=100`. This default setting will always choose the more profitable block. Using this option, you may customize your `--builder.boostFactor` to your preference. Examples of its usage are below. +- `default`: Default setting for Lodestar set at `--builder.boostFactor=90`. This default setting will have a local block boost of ~10%. Note that this value might change in the future depending on what we think is the most appropriate value to help improve censorship resistance of Ethereum. +- `maxprofit`: An alias of `--builder.boostFactor=100`, which will always choose the more profitable block. Using this option, you may customize your `--builder.boostFactor` to your preference. Examples of its usage are below. - `executionalways`: An alias of `--builder.boostFactor=0`, which will select the local execution block, unless it fails to produce due to an error or a delay in the response from the execution client. - `executiononly`: Beacon node will be requested to produce local execution block even if builder relays are configured. This option will always select the local execution block and will error if it couldn't produce one. - `builderalways`: An alias of `--builder.boostFactor=18446744073709551615` (2\*\*64 - 1), which will select the builder block, unless the builder block fails to produce. The builder block may fail to produce if it's not available, not timely or there is an indication of censorship via `shouldOverrideBuilder` from the execution payload response. diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 2bcc9ee0657..1d6b8b80551 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -42,6 +42,7 @@ import {allForksBlockContentsResSerializer} from "../../utils/routes.js"; import {ExecutionOptimistic} from "./beacon/block.js"; export enum BuilderSelection { + Default = "default", BuilderAlways = "builderalways", ExecutionAlways = "executionalways", MaxProfit = "maxprofit", diff --git a/packages/beacon-node/src/api/impl/validator/utils.ts b/packages/beacon-node/src/api/impl/validator/utils.ts index 8932f8951cf..418e0a05278 100644 --- a/packages/beacon-node/src/api/impl/validator/utils.ts +++ b/packages/beacon-node/src/api/impl/validator/utils.ts @@ -60,6 +60,7 @@ export function selectBlockProductionSource({ case routes.validator.BuilderSelection.ExecutionOnly: return ProducedBlockSource.engine; + case routes.validator.BuilderSelection.Default: case routes.validator.BuilderSelection.MaxProfit: return builderBoostFactor !== MAX_BUILDER_BOOST_FACTOR && (builderBoostFactor === BigInt(0) || engineBlockValue >= (builderBlockValue * builderBoostFactor) / BigInt(100)) diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index 358360b32b6..5ca59280250 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -252,7 +252,7 @@ export const validatorOptions: CliCommandOptions = { "builder.selection": { type: "string", description: - "Builder block selection strategy `maxprofit`, `builderalways`, `builderonly`, `executionalways`, or `executiononly`", + "Builder block selection strategy `default`, `maxprofit`, `builderalways`, `builderonly`, `executionalways`, or `executiononly`", defaultDescription: `${defaultOptions.builderSelection}`, group: "builder", }, diff --git a/packages/cli/src/util/proposerConfig.ts b/packages/cli/src/util/proposerConfig.ts index ae56cc45513..509dc8213df 100644 --- a/packages/cli/src/util/proposerConfig.ts +++ b/packages/cli/src/util/proposerConfig.ts @@ -107,6 +107,8 @@ export function readProposerConfigDir(filepath: string, filename: string): Propo export function parseBuilderSelection(builderSelection?: string): routes.validator.BuilderSelection | undefined { if (builderSelection) { switch (builderSelection) { + case "default": + break; case "maxprofit": break; case "builderalways": diff --git a/packages/cli/test/sim/multiFork.test.ts b/packages/cli/test/sim/multiFork.test.ts index 371201a4045..fdedd980e5b 100644 --- a/packages/cli/test/sim/multiFork.test.ts +++ b/packages/cli/test/sim/multiFork.test.ts @@ -47,7 +47,7 @@ const env = await SimulationEnvironment.initWithDefaults( // return with engine full block and publish via publishBlockV2 clientOptions: { useProduceBlockV3: true, - "builder.selection": "maxprofit", + "builder.selection": "default", }, }, }, @@ -65,7 +65,7 @@ const env = await SimulationEnvironment.initWithDefaults( // builder is attached to beacon, and publish via publishBlindedBlockV2 clientOptions: { useProduceBlockV3: true, - "builder.selection": "maxprofit", + "builder.selection": "default", blindedLocal: true, }, }, @@ -100,7 +100,7 @@ const env = await SimulationEnvironment.initWithDefaults( // of local block and subsequent publishing via publishBlindedBlock clientOptions: { useProduceBlockV3: false, - "builder.selection": "maxprofit", + "builder.selection": "default", }, }, }, diff --git a/packages/cli/test/unit/validator/parseProposerConfig.test.ts b/packages/cli/test/unit/validator/parseProposerConfig.test.ts index 993d9640e47..66220ca3329 100644 --- a/packages/cli/test/unit/validator/parseProposerConfig.test.ts +++ b/packages/cli/test/unit/validator/parseProposerConfig.test.ts @@ -26,7 +26,7 @@ const testValue = { feeRecipient: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", builder: { gasLimit: 35000000, - selection: routes.validator.BuilderSelection.MaxProfit, + selection: routes.validator.BuilderSelection.BuilderAlways, boostFactor: BigInt(18446744073709551616), }, }, @@ -37,8 +37,8 @@ const testValue = { feeRecipient: "0xcccccccccccccccccccccccccccccccccccccccc", builder: { gasLimit: 30000000, - selection: routes.validator.BuilderSelection.BuilderAlways, - boostFactor: BigInt(100), + selection: routes.validator.BuilderSelection.MaxProfit, + boostFactor: BigInt(50), }, }, }; diff --git a/packages/cli/test/unit/validator/proposerConfigs/validData.yaml b/packages/cli/test/unit/validator/proposerConfigs/validData.yaml index 5ea7e1bebea..71dabb9d900 100644 --- a/packages/cli/test/unit/validator/proposerConfigs/validData.yaml +++ b/packages/cli/test/unit/validator/proposerConfigs/validData.yaml @@ -9,7 +9,7 @@ proposer_config: fee_recipient: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' builder: gas_limit: "35000000" - selection: "maxprofit" + selection: "builderalways" boost_factor: "18446744073709551616" default_config: graffiti: 'default graffiti' @@ -17,5 +17,5 @@ default_config: fee_recipient: '0xcccccccccccccccccccccccccccccccccccccccc' builder: gas_limit: "30000000" - selection: "builderalways" - boost_factor: "100" + selection: "maxprofit" + boost_factor: "50" diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index d1474e7fdd2..0c3c0b33cea 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -124,7 +124,7 @@ export const defaultOptions = { suggestedFeeRecipient: "0x0000000000000000000000000000000000000000", defaultGasLimit: 30_000_000, builderSelection: routes.validator.BuilderSelection.ExecutionOnly, - builderAliasSelection: routes.validator.BuilderSelection.MaxProfit, + builderAliasSelection: routes.validator.BuilderSelection.Default, builderBoostFactor: BigInt(100), // spec asks for gossip validation by default broadcastValidation: routes.beacon.BroadcastValidation.gossip, @@ -267,6 +267,12 @@ export class ValidatorStore { let boostFactor; switch (selection) { + case routes.validator.BuilderSelection.Default: + // Default value slightly favors local block to improve censorship resistance of Ethereum + // The people have spoken and so it shall be https://x.com/lodestar_eth/status/1772679499928191044 + boostFactor = BigInt(90); + break; + case routes.validator.BuilderSelection.MaxProfit: boostFactor = (this.validators.get(pubkeyHex)?.builder || {}).boostFactor ?? this.defaultProposerConfig.builder.boostFactor;