From 99c0dcb81bb2a9c238fb1094ea0b4ffeee646547 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 30 Oct 2024 18:13:00 +0000 Subject: [PATCH] feat: add keymanager endpoint to retrieve proposer config (#7210) * feat: add keymanager endpoint to retrieve proposer config * Do not return empty builder config * Check all builder proposer config values * Fix settings builder config if undefined * Fix builder config parsing * Use ssz type to handle json serialization Default parsing can't handle BigInt * Revert "Use ssz type to handle json serialization" This reverts commit 01fcea702e32e1f97a0aa351b6623d94dc0fbcea. * Fix boost factor json serialization * Remove unused import * Update test data * Update proposer config test --- packages/api/src/keymanager/index.ts | 1 + packages/api/src/keymanager/routes.ts | 33 +++++++++++++++++++ packages/api/test/unit/keymanager/testData.ts | 15 +++++++++ .../cli/src/cmds/validator/keymanager/impl.ts | 18 ++++++++++ packages/cli/src/util/proposerConfig.ts | 13 +++++--- .../validator/parseProposerConfig.test.ts | 3 +- .../validator/src/services/validatorStore.ts | 4 ++- 7 files changed, 79 insertions(+), 8 deletions(-) diff --git a/packages/api/src/keymanager/index.ts b/packages/api/src/keymanager/index.ts index 1ffcaef897eb..44252acce494 100644 --- a/packages/api/src/keymanager/index.ts +++ b/packages/api/src/keymanager/index.ts @@ -18,6 +18,7 @@ export type { GraffitiData, GasLimitData, BuilderBoostFactorData, + ProposerConfigResponse, } from "./routes.js"; export type {ApiClient}; diff --git a/packages/api/src/keymanager/routes.ts b/packages/api/src/keymanager/routes.ts index 0db096d14e83..c31ae5a04454 100644 --- a/packages/api/src/keymanager/routes.ts +++ b/packages/api/src/keymanager/routes.ts @@ -109,6 +109,17 @@ export type SignerDefinition = { export type RemoteSignerDefinition = Pick; +export type ProposerConfigResponse = { + graffiti?: string; + strictFeeRecipientCheck?: boolean; + feeRecipient?: string; + builder?: { + gasLimit?: number; + selection?: string; + boostFactor?: string; + }; +}; + /** * JSON serialized representation of a single keystore in EIP-2335: BLS12-381 Keystore format. * ``` @@ -356,6 +367,15 @@ export type Endpoints = { EmptyMeta >; + getProposerConfig: Endpoint< + // ⏎ + "GET", + {pubkey: PubkeyHex}, + {params: {pubkey: string}}, + ProposerConfigResponse, + EmptyMeta + >; + /** * Create a signed voluntary exit message for an active validator, identified by a public key known to the validator * client. This endpoint returns a `SignedVoluntaryExit` object, which can be used to initiate voluntary exit via the @@ -635,6 +655,19 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({params: {pubkey}}), + parseReq: ({params: {pubkey}}) => ({pubkey}), + schema: { + params: {pubkey: Schema.StringRequired}, + }, + }, + resp: JsonOnlyResponseCodec, + }, + signVoluntaryExit: { url: "/eth/v1/validator/{pubkey}/voluntary_exit", method: "POST", diff --git a/packages/api/test/unit/keymanager/testData.ts b/packages/api/test/unit/keymanager/testData.ts index bd37798c4685..6b17611d1e0b 100644 --- a/packages/api/test/unit/keymanager/testData.ts +++ b/packages/api/test/unit/keymanager/testData.ts @@ -112,4 +112,19 @@ export const testData: GenericServerTestCases = { args: {pubkey: pubkeyRand}, res: undefined, }, + getProposerConfig: { + args: {pubkey: pubkeyRand}, + res: { + data: { + graffiti: graffitiRandUtf8, + strictFeeRecipientCheck: false, + feeRecipient: ethaddressRand, + builder: { + gasLimit: gasLimitRand, + selection: "maxprofit", + boostFactor: builderBoostFactorRand.toString(), + }, + }, + }, + }, }; diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index b4233f3162cd..545f2f74f06e 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -15,6 +15,7 @@ import { GraffitiData, GasLimitData, BuilderBoostFactorData, + ProposerConfigResponse, } from "@lodestar/api/keymanager"; import {KeymanagerApiMethods as Api} from "@lodestar/api/keymanager/server"; import {Interchange, SignerType, Validator} from "@lodestar/validator"; @@ -364,6 +365,23 @@ export class KeymanagerApi implements Api { return {status: 204}; } + async getProposerConfig({pubkey}: {pubkey: PubkeyHex}): ReturnType { + const config = this.validator.validatorStore.getProposerConfig(pubkey); + + const data: ProposerConfigResponse = { + ...config, + builder: config?.builder + ? { + ...config.builder, + // Default JSON serialization can't handle BigInt + boostFactor: config.builder.boostFactor ? config.builder.boostFactor.toString() : undefined, + } + : undefined, + }; + + return {data}; + } + async signVoluntaryExit({pubkey, epoch}: {pubkey: PubkeyHex; epoch?: Epoch}): ReturnType { if (!isValidatePubkeyHex(pubkey)) { throw new ApiError(400, `Invalid pubkey ${pubkey}`); diff --git a/packages/cli/src/util/proposerConfig.ts b/packages/cli/src/util/proposerConfig.ts index 2c12ce8f8524..4cfa6fa71075 100644 --- a/packages/cli/src/util/proposerConfig.ts +++ b/packages/cli/src/util/proposerConfig.ts @@ -88,11 +88,14 @@ function parseProposerConfigSection( overrideConfig?.strictFeeRecipientCheck ?? (strict_fee_recipient_check ? stringtoBool(strict_fee_recipient_check) : undefined), feeRecipient: overrideConfig?.feeRecipient ?? (fee_recipient ? parseFeeRecipient(fee_recipient) : undefined), - builder: { - gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined), - selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection), - boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor), - }, + builder: + overrideConfig?.builder || builder + ? { + gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined), + selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection), + boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor), + } + : undefined, }; } diff --git a/packages/cli/test/unit/validator/parseProposerConfig.test.ts b/packages/cli/test/unit/validator/parseProposerConfig.test.ts index 83c8c63ef877..40fa57f7feb5 100644 --- a/packages/cli/test/unit/validator/parseProposerConfig.test.ts +++ b/packages/cli/test/unit/validator/parseProposerConfig.test.ts @@ -26,8 +26,7 @@ const testValue = { builder: { gasLimit: 35000000, selection: routes.validator.BuilderSelection.BuilderAlways, - // biome-ignore lint/correctness/noPrecisionLoss: - boostFactor: BigInt(18446744073709551616), + boostFactor: 18446744073709551616n, }, }, }, diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index dfd856b18d13..f959b4e74ff5 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -377,7 +377,9 @@ export class ValidatorStore { graffiti !== undefined || strictFeeRecipientCheck !== undefined || feeRecipient !== undefined || - builder?.gasLimit !== undefined + builder?.gasLimit !== undefined || + builder?.selection !== undefined || + builder?.boostFactor !== undefined ) { proposerConfig = {graffiti, strictFeeRecipientCheck, feeRecipient, builder}; }