Skip to content

Commit

Permalink
feat: add cli flags to configure http wire format (#6840)
Browse files Browse the repository at this point in the history
  • Loading branch information
nflaig authored Jun 3, 2024
1 parent 785a641 commit f21fc3c
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 16 deletions.
3 changes: 2 additions & 1 deletion packages/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ export * from "./beacon/index.js";
export {HttpStatusCode} from "./utils/httpStatusCode.js";
export {WireFormat} from "./utils/wireFormat.js";
export type {HttpErrorCodes, HttpSuccessCodes} from "./utils/httpStatusCode.js";
export {ApiResponse, HttpClient, FetchError, isFetchError, fetch} from "./utils/client/index.js";
export {ApiResponse, HttpClient, FetchError, isFetchError, fetch, defaultInit} from "./utils/client/index.js";
export type {ApiRequestInit} from "./utils/client/request.js";
export type {Endpoint} from "./utils/types.js";
export type {
ApiClientMethods,
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/utils/client/httpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const URL_SCORE_DELTA_ERROR = 2 * URL_SCORE_DELTA_SUCCESS;
const URL_SCORE_MAX = 10 * URL_SCORE_DELTA_SUCCESS;
const URL_SCORE_MIN = 0;

const defaultInit: Required<ExtraRequestInit> = {
export const defaultInit: Required<ExtraRequestInit> = {
timeoutMs: DEFAULT_TIMEOUT_MS,
retries: DEFAULT_RETRIES,
retryDelay: DEFAULT_RETRY_DELAY,
Expand Down
4 changes: 3 additions & 1 deletion packages/beacon-node/test/utils/node/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ export async function getAndInitDevValidators({
Validator.initializeFromBeaconNode({
db,
config: node.config,
api: useRestApi ? getNodeApiUrl(node) : getApiFromServerHandlers(node.api),
api: {
clientOrUrls: useRestApi ? getNodeApiUrl(node) : getApiFromServerHandlers(node.api),
},
slashingProtection,
logger,
processShutdownCallback: () => {},
Expand Down
26 changes: 24 additions & 2 deletions packages/cli/src/cmds/validator/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
ValidatorProposerConfig,
defaultOptions,
} from "@lodestar/validator";
import {routes} from "@lodestar/api";
import {WireFormat, routes} from "@lodestar/api";
import {getMetrics} from "@lodestar/validator";
import {
RegistryMetricCreator,
Expand Down Expand Up @@ -152,7 +152,13 @@ export async function validatorHandler(args: IValidatorCliArgs & GlobalArgs): Pr
db,
config,
slashingProtection,
api: args.beaconNodes,
api: {
clientOrUrls: args.beaconNodes,
globalInit: {
requestWireFormat: parseWireFormat(args, "http.requestWireFormat"),
responseWireFormat: parseWireFormat(args, "http.responseWireFormat"),
},
},
logger,
processShutdownCallback,
signers,
Expand Down Expand Up @@ -269,3 +275,19 @@ function parseBroadcastValidation(broadcastValidation?: string): routes.beacon.B

return broadcastValidation as routes.beacon.BroadcastValidation;
}

function parseWireFormat(args: IValidatorCliArgs, key: keyof IValidatorCliArgs): WireFormat | undefined {
const wireFormat = args[key];

if (wireFormat !== undefined) {
switch (wireFormat) {
case WireFormat.json:
case WireFormat.ssz:
break;
default:
throw new YargsError(`Invalid input for ${key}, must be one of "${WireFormat.json}" or "${WireFormat.ssz}"`);
}
}

return wireFormat;
}
18 changes: 18 additions & 0 deletions packages/cli/src/cmds/validator/options.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {WireFormat, defaultInit} from "@lodestar/api";
import {defaultOptions} from "@lodestar/validator";
import {CliCommandOptions} from "@lodestar/utils";
import {LogArgs, logOptions} from "../../options/logOptions.js";
Expand Down Expand Up @@ -55,6 +56,9 @@ export type IValidatorCliArgs = AccountValidatorArgs &
importKeystores?: string[];
importKeystoresPassword?: string;

"http.requestWireFormat"?: string;
"http.responseWireFormat"?: string;

"externalSigner.url"?: string;
"externalSigner.pubkeys"?: string[];
"externalSigner.fetch"?: boolean;
Expand Down Expand Up @@ -304,6 +308,20 @@ export const validatorOptions: CliCommandOptions<IValidatorCliArgs> = {
type: "boolean",
},

"http.requestWireFormat": {
type: "string",
description: `Wire format to use in HTTP requests to beacon node. Can be one of \`${WireFormat.json}\` or \`${WireFormat.ssz}\``,
defaultDescription: `${defaultInit.requestWireFormat}`,
group: "http",
},

"http.responseWireFormat": {
type: "string",
description: `Preferred wire format for HTTP responses from beacon node. Can be one of \`${WireFormat.json}\` or \`${WireFormat.ssz}\``,
defaultDescription: `${defaultInit.responseWireFormat}`,
group: "http",
},

// External signer

"externalSigner.url": {
Expand Down
31 changes: 20 additions & 11 deletions packages/validator/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {BLSPubkey, phase0, ssz} from "@lodestar/types";
import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config";
import {Genesis} from "@lodestar/types/phase0";
import {Logger, toSafePrintableUrl} from "@lodestar/utils";
import {getClient, ApiClient, routes} from "@lodestar/api";
import {getClient, ApiClient, routes, ApiRequestInit, defaultInit} from "@lodestar/api";
import {computeEpochAtSlot, getCurrentSlot} from "@lodestar/state-transition";
import {Clock, IClock} from "./util/clock.js";
import {waitForGenesis} from "./genesis.js";
Expand Down Expand Up @@ -45,7 +45,10 @@ export type ValidatorOptions = {
slashingProtection: ISlashingProtection;
db: LodestarValidatorDatabaseController;
config: ChainForkConfig;
api: ApiClient | string | string[];
api: {
clientOrUrls: ApiClient | string | string[];
globalInit?: ApiRequestInit;
};
signers: Signer[];
logger: Logger;
processShutdownCallback: ProcessShutdownCallback;
Expand Down Expand Up @@ -158,20 +161,21 @@ export class Validator {
const loggerVc = getLoggerVc(logger, clock);

let api: ApiClient;
if (typeof opts.api === "string" || Array.isArray(opts.api)) {
const {clientOrUrls, globalInit} = opts.api;
if (typeof clientOrUrls === "string" || Array.isArray(clientOrUrls)) {
// This new api instance can make do with default timeout as a faster timeout is
// not necessary since this instance won't be used for validator duties
api = getClient(
{
urls: typeof opts.api === "string" ? [opts.api] : opts.api,
urls: typeof clientOrUrls === "string" ? [clientOrUrls] : clientOrUrls,
// Validator would need the beacon to respond within the slot
// See https://github.com/ChainSafe/lodestar/issues/5315 for rationale
globalInit: {timeoutMs: config.SECONDS_PER_SLOT * 1000, signal: controller.signal},
globalInit: {timeoutMs: config.SECONDS_PER_SLOT * 1000, signal: controller.signal, ...globalInit},
},
{config, logger, metrics: metrics?.restApiClient}
);
} else {
api = opts.api;
api = clientOrUrls;
}

const indicesService = new IndicesService(logger, api, metrics);
Expand Down Expand Up @@ -270,14 +274,19 @@ export class Validator {
const {logger, config} = opts;

let api: ApiClient;
if (typeof opts.api === "string" || Array.isArray(opts.api)) {
const urls = typeof opts.api === "string" ? [opts.api] : opts.api;
const {clientOrUrls, globalInit} = opts.api;
if (typeof clientOrUrls === "string" || Array.isArray(clientOrUrls)) {
const urls = typeof clientOrUrls === "string" ? [clientOrUrls] : clientOrUrls;
// This new api instance can make do with default timeout as a faster timeout is
// not necessary since this instance won't be used for validator duties
api = getClient({urls, globalInit: {signal: opts.abortController.signal}}, {config, logger});
logger.info("Beacon node", {urls: urls.map(toSafePrintableUrl).toString()});
api = getClient({urls, globalInit: {signal: opts.abortController.signal, ...globalInit}}, {config, logger});
logger.info("Beacon node", {
urls: urls.map(toSafePrintableUrl).toString(),
requestWireFormat: globalInit?.requestWireFormat ?? defaultInit.requestWireFormat,
responseWireFormat: globalInit?.responseWireFormat ?? defaultInit.responseWireFormat,
});
} else {
api = opts.api;
api = clientOrUrls;
}

const genesis = await waitForGenesis(api, opts.logger, opts.abortController.signal);
Expand Down

0 comments on commit f21fc3c

Please sign in to comment.