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: add keymanager endpoint to retrieve proposer config #7210

Merged
merged 11 commits into from
Oct 30, 2024
1 change: 1 addition & 0 deletions packages/api/src/keymanager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type {
GraffitiData,
GasLimitData,
BuilderBoostFactorData,
ProposerConfigResponse,
} from "./routes.js";

export type {ApiClient};
Expand Down
33 changes: 33 additions & 0 deletions packages/api/src/keymanager/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ export type SignerDefinition = {

export type RemoteSignerDefinition = Pick<SignerDefinition, "pubkey" | "url">;

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.
* ```
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -635,6 +655,19 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions<Endpo
resp: EmptyResponseCodec,
},

getProposerConfig: {
url: "/eth/v0/validator/{pubkey}/proposer_config",
method: "GET",
req: {
writeReq: ({pubkey}) => ({params: {pubkey}}),
parseReq: ({params: {pubkey}}) => ({pubkey}),
schema: {
params: {pubkey: Schema.StringRequired},
},
},
resp: JsonOnlyResponseCodec,
},

signVoluntaryExit: {
url: "/eth/v1/validator/{pubkey}/voluntary_exit",
method: "POST",
Expand Down
15 changes: 15 additions & 0 deletions packages/api/test/unit/keymanager/testData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,19 @@ export const testData: GenericServerTestCases<Endpoints> = {
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(),
},
},
},
},
};
18 changes: 18 additions & 0 deletions packages/cli/src/cmds/validator/keymanager/impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -364,6 +365,23 @@ export class KeymanagerApi implements Api {
return {status: 204};
}

async getProposerConfig({pubkey}: {pubkey: PubkeyHex}): ReturnType<Api["getProposerConfig"]> {
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<Api["signVoluntaryExit"]> {
if (!isValidatePubkeyHex(pubkey)) {
throw new ApiError(400, `Invalid pubkey ${pubkey}`);
Expand Down
13 changes: 8 additions & 5 deletions packages/cli/src/util/proposerConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ const testValue = {
builder: {
gasLimit: 35000000,
selection: routes.validator.BuilderSelection.BuilderAlways,
// biome-ignore lint/correctness/noPrecisionLoss: <explanation>
boostFactor: BigInt(18446744073709551616),
boostFactor: 18446744073709551616n,
},
},
},
Expand Down
4 changes: 3 additions & 1 deletion packages/validator/src/services/validatorStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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};
}
Expand Down
Loading