From 15f19061e5f8622401d9860d69e815e70a14c55e Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 19 Oct 2023 15:21:44 +0800 Subject: [PATCH 01/27] Add id and clv to jwt claim and cli --- .../src/eth1/provider/jsonRpcHttpClient.ts | 17 +++++++++++++++-- packages/beacon-node/src/eth1/provider/jwt.ts | 4 ++-- .../beacon-node/src/execution/engine/http.ts | 8 ++++++++ .../src/options/beaconNodeOptions/execution.ts | 18 ++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index 272de2249686..61675d3348f1 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -4,7 +4,7 @@ import {fetch} from "@lodestar/api"; import {ErrorAborted, TimeoutError, isValidHttpUrl, retry} from "@lodestar/utils"; import {IGauge, IHistogram} from "../../metrics/interface.js"; import {IJson, RpcPayload} from "../interface.js"; -import {encodeJwtToken} from "./jwt.js"; +import {JwtClaim, encodeJwtToken} from "./jwt.js"; export enum JsonRpcHttpClientEvent { /** @@ -83,6 +83,8 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { * the token freshness +-5 seconds (via `iat` property of the token claim) */ private readonly jwtSecret?: Uint8Array; + private readonly jwtId?: string; + private readonly jwtVersion?: string; private readonly metrics: JsonRpcHttpClientMetrics | null; readonly emitter = new JsonRpcHttpClientEventEmitter(); @@ -103,6 +105,10 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { * and it might deny responses to the RPC requests. */ jwtSecret?: Uint8Array; + /** If provided, jwtId will be included in JwtClaim.id */ + jwtId?: string; + /** If provided, jwtVersion will be included in JwtClaim.clv */ + jwtVersion?: string; /** Retry attempts */ retryAttempts?: number; /** Retry delay, only relevant with retry attempts */ @@ -125,6 +131,8 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { } this.jwtSecret = opts?.jwtSecret; + this.jwtId = opts?.jwtId; + this.jwtVersion = opts?.jwtVersion; this.metrics = opts?.metrics ?? null; this.metrics?.configUrlsCount.set(urls.length); @@ -255,7 +263,12 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { * * Jwt auth spec: https://github.com/ethereum/execution-apis/pull/167 */ - const token = encodeJwtToken({iat: Math.floor(new Date().getTime() / 1000)}, this.jwtSecret); + let jwtClaim: JwtClaim = { + iat: Math.floor(new Date().getTime() / 1000), + id: this.jwtId ?? undefined, + clv: this.jwtVersion ?? undefined}; + + const token = encodeJwtToken(jwtClaim, this.jwtSecret); headers["Authorization"] = `Bearer ${token}`; } diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index d9ed24ded165..b8b668cf596c 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -4,8 +4,8 @@ import jwt from "jwt-simple"; const {encode, decode} = jwt; -/** jwt token has iat which is issued at unix timestamp, and an optional exp for expiry */ -type JwtClaim = {iat: number; exp?: number}; +/** jwt token has iat which is issued at unix timestamp, an optional exp for expiry, and an optional id */ +export type JwtClaim = {iat: number; exp?: number; id?: string; clv?: string}; export function encodeJwtToken( claim: JwtClaim, diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index 6f5b3553dcb4..7d17ac59be46 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -55,6 +55,14 @@ export type ExecutionEngineHttpOpts = { * +-5 seconds interval. */ jwtSecretHex?: string; + /** + * A identifier string passed by user in cli arg that will be included in `id` field in jwt claims + */ + jwtId?: string; + /** + * A version string passed by user in cli arg that will be included in `clv` field in jwt claims + */ + jwtVersion?: string; }; export const defaultExecutionEngineHttpOpts: ExecutionEngineHttpOpts = { diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index b1faf482ade8..4cdd762ddf16 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -9,6 +9,8 @@ export type ExecutionEngineArgs = { "execution.retryDelay": number; "execution.engineMock"?: boolean; "jwt-secret"?: string; + "jwt-id"?: string; + "jwt-version"?: string; }; export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["executionEngine"] { @@ -31,6 +33,8 @@ export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["execut jwtSecretHex: args["jwt-secret"] ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) : undefined, + jwtId: args["jwt-id"], + jwtVersion: args["jwt-version"], }; } @@ -80,4 +84,18 @@ export const options: CliCommandOptions = { type: "string", group: "execution", }, + + "jwt-id": { + description: + "An optional identifier to be included in the id field in the claims of the jwt tokens for authentication with EL client's rpc server hosting engine apis", + type: "string", + group: "execution", + }, + + "jwt-version": { + description: + "An option version string to be included in the clv field in the claims of the jwt tokens for authentication with EL client's rpc server hosting engine apis", + type: "string", + group: "execution", + }, }; From 156bd02c6095c6c4412d6996af377292ac96ac08 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 19 Oct 2023 16:21:08 +0800 Subject: [PATCH 02/27] Update doc --- docs/usage/beacon-management.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/usage/beacon-management.md b/docs/usage/beacon-management.md index 5536fbb78a5b..a0338cc9c2b4 100644 --- a/docs/usage/beacon-management.md +++ b/docs/usage/beacon-management.md @@ -35,6 +35,10 @@ You must generate a secret 32-byte (64 characters) hexadecimal string that will When starting up a Lodestar beacon node in any configuration, ensure you add the `--jwt-secret $JWT_SECRET_PATH` flag to point to the saved secret key file. +### Set up and include identifiers in JWT tokens + +Lodestar supports sending JWT authentication tokens with customized id `id` and version `clv` strings. This is particularly useful when running multiple consensus-layer clients with the same JWT secret which makes the execution-layer client difficult to distinguish between the different consensus-layer clients. You can configure the optional strings by adding `--jwt-id $JWT_ID` and/or `--jwt-version $JWT_VERSION` flags. By default, without the related flags added, Lodestar will omit `id` and/or `clv` in the JWT token during the tranmissions. + ### Ensure JWT is configured with your execution node **For Go Ethereum:** From de7e8761133604248c871ce3010164069bbbcb94 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 19 Oct 2023 16:41:06 +0800 Subject: [PATCH 03/27] Add unit test --- .../beacon-node/test/unit/eth1/jwt.test.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/beacon-node/test/unit/eth1/jwt.test.ts b/packages/beacon-node/test/unit/eth1/jwt.test.ts index abf455c9e149..d08df3b3a8b1 100644 --- a/packages/beacon-node/test/unit/eth1/jwt.test.ts +++ b/packages/beacon-node/test/unit/eth1/jwt.test.ts @@ -10,6 +10,14 @@ describe("ExecutionEngine / jwt", () => { expect(decoded).toEqual(claim); }); + it("encode/decode correctly with id and clv", () => { + const jwtSecret = Buffer.from(Array.from({length: 32}, () => Math.round(Math.random() * 255))); + const claim = {iat: Math.floor(new Date().getTime() / 1000), id: "4ac0", clv: "v1.11.3"}; + const token = encodeJwtToken(claim, jwtSecret); + const decoded = decodeJwtToken(token, jwtSecret); + expect(decoded).toEqual(claim); + }); + it("encode a claim correctly from a hex key", () => { const jwtSecretHex = "7e2d709fb01382352aaf830e755d33ca48cb34ba1c21d999e45c1a7a6f88b193"; const jwtSecret = Buffer.from(jwtSecretHex, "hex"); @@ -19,4 +27,29 @@ describe("ExecutionEngine / jwt", () => { "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTJ9.nUDaIyGPgRX76tQ_kDlcIGj4uyFA4lFJGKsD_GHIEzM" ); }); + + it("encode a claim with id and clv correctly from a hex key", () => { + const jwtSecretHex = "7e2d709fb01382352aaf830e755d33ca48cb34ba1c21d999e45c1a7a6f88b193"; + const jwtSecret = Buffer.from(jwtSecretHex, "hex"); + const id = "4ac0"; + const clv = "v1.11.3"; + const claimWithId = {iat: 1645551452, id: id}; + const claimWithVersion = {iat: 1645551452, clv: clv}; + const claimWithIdAndVersion = {iat: 1645551452, id: id, clv: clv}; + + const tokenWithId = encodeJwtToken(claimWithId, jwtSecret); + expect(tokenWithId).toBe( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImlkIjoiNGFjMCJ9.w9l76DePA4ghPlrHlLqZ0q5WyEmdfLjV3NJYQHeQ_c4" + ); + + const tokenWithVersion = encodeJwtToken(claimWithVersion, jwtSecret); + expect(tokenWithVersion).toBe( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImNsdiI6InYxLjExLjMifQ.4c1iWrLaR9dnE07PRt6bLwGJ5xtZaUWJ4-RVtz-5Uog" + ); + + const tokenWithIdAndVersion = encodeJwtToken(claimWithIdAndVersion, jwtSecret); + expect(tokenWithIdAndVersion).toBe( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImlkIjoiNGFjMCIsImNsdiI6InYxLjExLjMifQ.tvpnzAUsYpYMdPgauLsISITXzAAP1uuNfHKzVKITNhs" + ); + }); }); From 70f2f7273dc46df9489cb2a3f494e02d25248db5 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 19 Oct 2023 16:57:34 +0800 Subject: [PATCH 04/27] Update comments and lint --- docs/usage/beacon-management.md | 2 +- packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts | 5 +++-- packages/beacon-node/src/eth1/provider/jwt.ts | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/usage/beacon-management.md b/docs/usage/beacon-management.md index a0338cc9c2b4..c8261ef04cb7 100644 --- a/docs/usage/beacon-management.md +++ b/docs/usage/beacon-management.md @@ -37,7 +37,7 @@ When starting up a Lodestar beacon node in any configuration, ensure you add the ### Set up and include identifiers in JWT tokens -Lodestar supports sending JWT authentication tokens with customized id `id` and version `clv` strings. This is particularly useful when running multiple consensus-layer clients with the same JWT secret which makes the execution-layer client difficult to distinguish between the different consensus-layer clients. You can configure the optional strings by adding `--jwt-id $JWT_ID` and/or `--jwt-version $JWT_VERSION` flags. By default, without the related flags added, Lodestar will omit `id` and/or `clv` in the JWT token during the tranmissions. +Lodestar supports sending JWT authentication tokens with customized id `id` and version `clv` strings. This is particularly useful when running multiple consensus-layer clients with the different JWT secrets which makes the execution-layer client difficult to choose which JWT secret to verify against due to the inability to distinguish between the different consensus-layer clients. You can configure the optional identifiers by adding `--jwt-id $JWT_ID` and/or `--jwt-version $JWT_VERSION` flags. By default, without the related flags added, Lodestar will omit `id` and/or `clv` in the JWT token during the tranmissions. ### Ensure JWT is configured with your execution node diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index 61675d3348f1..0846f9bd62d1 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -263,10 +263,11 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { * * Jwt auth spec: https://github.com/ethereum/execution-apis/pull/167 */ - let jwtClaim: JwtClaim = { + const jwtClaim: JwtClaim = { iat: Math.floor(new Date().getTime() / 1000), id: this.jwtId ?? undefined, - clv: this.jwtVersion ?? undefined}; + clv: this.jwtVersion ?? undefined, + }; const token = encodeJwtToken(jwtClaim, this.jwtSecret); headers["Authorization"] = `Bearer ${token}`; diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index b8b668cf596c..8e95990643e0 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -4,7 +4,9 @@ import jwt from "jwt-simple"; const {encode, decode} = jwt; -/** jwt token has iat which is issued at unix timestamp, an optional exp for expiry, and an optional id */ +/** jwt token has iat which is issued at unix timestamp, an optional exp for expiry, + * an optional id for unique identifier, and an optional clv for client type/version + */ export type JwtClaim = {iat: number; exp?: number; id?: string; clv?: string}; export function encodeJwtToken( From ef35d9f092826ea29a9863b032ad21b7d5604e9d Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 19 Oct 2023 22:14:36 +0800 Subject: [PATCH 05/27] Update unit test --- .../src/slot/upgradeStateToEIP6110.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 packages/state-transition/src/slot/upgradeStateToEIP6110.ts diff --git a/packages/state-transition/src/slot/upgradeStateToEIP6110.ts b/packages/state-transition/src/slot/upgradeStateToEIP6110.ts new file mode 100644 index 000000000000..45585449f424 --- /dev/null +++ b/packages/state-transition/src/slot/upgradeStateToEIP6110.ts @@ -0,0 +1,33 @@ +import {ssz} from "@lodestar/types"; +import {UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; +import {CachedBeaconStateDeneb} from "../types.js"; +import {CachedBeaconStateEIP6110, getCachedBeaconState} from "../cache/stateCache.js"; + +/** + * Upgrade a state from Capella to Deneb. + */ +export function upgradeStateToEIP6110(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateEIP6110 { + const {config} = stateDeneb; + + const stateEIP6110Node = ssz.deneb.BeaconState.commitViewDU(stateDeneb); + const stateEIP6110View = ssz.eip6110.BeaconState.getViewDU(stateEIP6110Node); + + const stateEIP6110 = getCachedBeaconState(stateEIP6110View, stateDeneb); + + stateEIP6110.fork = ssz.phase0.Fork.toViewDU({ + previousVersion: stateDeneb.fork.currentVersion, + currentVersion: config.EIP6110_FORK_VERSION, + epoch: stateDeneb.epochCtx.epoch, + }); + + // latestExecutionPayloadHeader's depositReceiptsRoot set to zeros by default + // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateEIP6110.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + + // Commit new added fields ViewDU to the root node + stateEIP6110.commit(); + // Clear cache to ensure the cache of deneb fields is not used by new EIP6110 fields + stateEIP6110["clearCache"](); + + return stateEIP6110; +} From 0d4dfff8412f7935cf4ccb0c6fc89a35799d97c1 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 19 Oct 2023 22:16:16 +0800 Subject: [PATCH 06/27] Update unit test --- packages/beacon-node/src/eth1/provider/jwt.ts | 4 ++-- packages/beacon-node/test/unit/eth1/jwt.test.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index 8e95990643e0..024583e575eb 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -4,8 +4,8 @@ import jwt from "jwt-simple"; const {encode, decode} = jwt; -/** jwt token has iat which is issued at unix timestamp, an optional exp for expiry, - * an optional id for unique identifier, and an optional clv for client type/version +/** jwt token has iat which is issued at unix timestamp, an optional exp for expiry, + * an optional id for unique identifier, and an optional clv for client type/version */ export type JwtClaim = {iat: number; exp?: number; id?: string; clv?: string}; diff --git a/packages/beacon-node/test/unit/eth1/jwt.test.ts b/packages/beacon-node/test/unit/eth1/jwt.test.ts index d08df3b3a8b1..d3a7a250d7ed 100644 --- a/packages/beacon-node/test/unit/eth1/jwt.test.ts +++ b/packages/beacon-node/test/unit/eth1/jwt.test.ts @@ -39,17 +39,17 @@ describe("ExecutionEngine / jwt", () => { const tokenWithId = encodeJwtToken(claimWithId, jwtSecret); expect(tokenWithId).toBe( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImlkIjoiNGFjMCJ9.w9l76DePA4ghPlrHlLqZ0q5WyEmdfLjV3NJYQHeQ_c4" + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImlkIjoiNGFjMCJ9.g3iKsQk9Q1PSYaGldo9MM0Mds8E59t24K6rHdQ9HXg0" ); const tokenWithVersion = encodeJwtToken(claimWithVersion, jwtSecret); expect(tokenWithVersion).toBe( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImNsdiI6InYxLjExLjMifQ.4c1iWrLaR9dnE07PRt6bLwGJ5xtZaUWJ4-RVtz-5Uog" + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImNsdiI6InYxLjExLjMifQ.s5iLRa04o_rtATWubz6LZc27rVXhE2n9BPpXpnmnR5o" ); const tokenWithIdAndVersion = encodeJwtToken(claimWithIdAndVersion, jwtSecret); expect(tokenWithIdAndVersion).toBe( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImlkIjoiNGFjMCIsImNsdiI6InYxLjExLjMifQ.tvpnzAUsYpYMdPgauLsISITXzAAP1uuNfHKzVKITNhs" + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDU1NTE0NTIsImlkIjoiNGFjMCIsImNsdiI6InYxLjExLjMifQ.QahIO3hcnMV385ES5jedRudsdECMVDembkoQv4BnSTs" ); }); }); From 623320069fc15349d83f96f245f471258550721c Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 19 Oct 2023 22:17:25 +0800 Subject: [PATCH 07/27] Revert "Update unit test" This reverts commit ef35d9f092826ea29a9863b032ad21b7d5604e9d. --- .../src/slot/upgradeStateToEIP6110.ts | 33 ------------------- 1 file changed, 33 deletions(-) delete mode 100644 packages/state-transition/src/slot/upgradeStateToEIP6110.ts diff --git a/packages/state-transition/src/slot/upgradeStateToEIP6110.ts b/packages/state-transition/src/slot/upgradeStateToEIP6110.ts deleted file mode 100644 index 45585449f424..000000000000 --- a/packages/state-transition/src/slot/upgradeStateToEIP6110.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {ssz} from "@lodestar/types"; -import {UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; -import {CachedBeaconStateDeneb} from "../types.js"; -import {CachedBeaconStateEIP6110, getCachedBeaconState} from "../cache/stateCache.js"; - -/** - * Upgrade a state from Capella to Deneb. - */ -export function upgradeStateToEIP6110(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateEIP6110 { - const {config} = stateDeneb; - - const stateEIP6110Node = ssz.deneb.BeaconState.commitViewDU(stateDeneb); - const stateEIP6110View = ssz.eip6110.BeaconState.getViewDU(stateEIP6110Node); - - const stateEIP6110 = getCachedBeaconState(stateEIP6110View, stateDeneb); - - stateEIP6110.fork = ssz.phase0.Fork.toViewDU({ - previousVersion: stateDeneb.fork.currentVersion, - currentVersion: config.EIP6110_FORK_VERSION, - epoch: stateDeneb.epochCtx.epoch, - }); - - // latestExecutionPayloadHeader's depositReceiptsRoot set to zeros by default - // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateEIP6110.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; - - // Commit new added fields ViewDU to the root node - stateEIP6110.commit(); - // Clear cache to ensure the cache of deneb fields is not used by new EIP6110 fields - stateEIP6110["clearCache"](); - - return stateEIP6110; -} From a63cd2259b0e60db951b8ed08ef024925546ba7a Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 19 Oct 2023 22:45:25 +0800 Subject: [PATCH 08/27] Add id and clv to eth1 --- packages/beacon-node/src/eth1/options.ts | 2 ++ packages/beacon-node/src/eth1/provider/eth1Provider.ts | 4 +++- packages/beacon-node/src/execution/engine/index.ts | 2 ++ packages/cli/src/options/beaconNodeOptions/eth1.ts | 7 +++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/eth1/options.ts b/packages/beacon-node/src/eth1/options.ts index 0f49f2d8a95c..2f9abdd69b45 100644 --- a/packages/beacon-node/src/eth1/options.ts +++ b/packages/beacon-node/src/eth1/options.ts @@ -7,6 +7,8 @@ export type Eth1Options = { * protected engine endpoints. */ jwtSecretHex?: string; + jwtId?: string; + jwtVersion?: string; depositContractDeployBlock?: number; unsafeAllowDepositDataOverwrite?: boolean; /** diff --git a/packages/beacon-node/src/eth1/provider/eth1Provider.ts b/packages/beacon-node/src/eth1/provider/eth1Provider.ts index eb8f37d37489..8d10c901b32c 100644 --- a/packages/beacon-node/src/eth1/provider/eth1Provider.ts +++ b/packages/beacon-node/src/eth1/provider/eth1Provider.ts @@ -64,7 +64,7 @@ export class Eth1Provider implements IEth1Provider { constructor( config: Pick, - opts: Pick & {logger?: Logger}, + opts: Pick & {logger?: Logger}, signal?: AbortSignal, metrics?: JsonRpcHttpClientMetrics | null ) { @@ -76,6 +76,8 @@ export class Eth1Provider implements IEth1Provider { // Don't fallback with is truncated error. Throw early and let the retry on this class handle it shouldNotFallback: isJsonRpcTruncatedError, jwtSecret: opts.jwtSecretHex ? fromHex(opts.jwtSecretHex) : undefined, + jwtId: opts.jwtId ?? undefined, + jwtVersion: opts.jwtVersion ?? undefined, metrics: metrics, }); diff --git a/packages/beacon-node/src/execution/engine/index.ts b/packages/beacon-node/src/execution/engine/index.ts index 210cba5fb489..0c92ebf90e8e 100644 --- a/packages/beacon-node/src/execution/engine/index.ts +++ b/packages/beacon-node/src/execution/engine/index.ts @@ -36,6 +36,8 @@ export function getExecutionEngineHttp( signal: modules.signal, metrics: modules.metrics?.executionEnginerHttpClient, jwtSecret: opts.jwtSecretHex ? fromHex(opts.jwtSecretHex) : undefined, + jwtId: opts.jwtId ?? undefined, + jwtVersion: opts.jwtVersion ?? undefined, }); return new ExecutionEngineHttp(rpc, modules); } diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index c6f6dd9177f8..3e66351994b8 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -14,6 +14,9 @@ export type Eth1Args = { export function parseArgs(args: Eth1Args & Partial): IBeaconNodeOptions["eth1"] { let jwtSecretHex: string | undefined; + let jwtId: string | undefined; + let jwtVersion: string | undefined; + let providerUrls = args["eth1.providerUrls"]; // If no providerUrls are explicitly provided, we should pick the execution endpoint @@ -25,12 +28,16 @@ export function parseArgs(args: Eth1Args & Partial): IBeaco jwtSecretHex = args["jwt-secret"] ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) : undefined; + jwtId = args["jwt-id"]; + jwtVersion = args["jwt-version"]; } return { enabled: args["eth1"], providerUrls, jwtSecretHex, + jwtId, + jwtVersion, depositContractDeployBlock: args["eth1.depositContractDeployBlock"], disableEth1DepositDataTracker: args["eth1.disableEth1DepositDataTracker"], unsafeAllowDepositDataOverwrite: args["eth1.unsafeAllowDepositDataOverwrite"], From 445cd005a496b838f63e42dd8d1e93218ca2e17a Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 19 Oct 2023 22:49:20 +0800 Subject: [PATCH 09/27] Lint --- packages/beacon-node/src/eth1/provider/eth1Provider.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/eth1/provider/eth1Provider.ts b/packages/beacon-node/src/eth1/provider/eth1Provider.ts index 8d10c901b32c..2b5e2b3a9a17 100644 --- a/packages/beacon-node/src/eth1/provider/eth1Provider.ts +++ b/packages/beacon-node/src/eth1/provider/eth1Provider.ts @@ -64,7 +64,9 @@ export class Eth1Provider implements IEth1Provider { constructor( config: Pick, - opts: Pick & {logger?: Logger}, + opts: Pick & { + logger?: Logger; + }, signal?: AbortSignal, metrics?: JsonRpcHttpClientMetrics | null ) { From 74dde4a3f968e5ec698edfebf62a332480cc3cc3 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 19 Oct 2023 23:51:59 +0800 Subject: [PATCH 10/27] Address comment --- packages/beacon-node/src/eth1/provider/eth1Provider.ts | 4 ++-- packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts | 4 ++-- packages/beacon-node/src/execution/engine/index.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/eth1/provider/eth1Provider.ts b/packages/beacon-node/src/eth1/provider/eth1Provider.ts index 2b5e2b3a9a17..151d729e66e3 100644 --- a/packages/beacon-node/src/eth1/provider/eth1Provider.ts +++ b/packages/beacon-node/src/eth1/provider/eth1Provider.ts @@ -78,8 +78,8 @@ export class Eth1Provider implements IEth1Provider { // Don't fallback with is truncated error. Throw early and let the retry on this class handle it shouldNotFallback: isJsonRpcTruncatedError, jwtSecret: opts.jwtSecretHex ? fromHex(opts.jwtSecretHex) : undefined, - jwtId: opts.jwtId ?? undefined, - jwtVersion: opts.jwtVersion ?? undefined, + jwtId: opts.jwtId, + jwtVersion: opts.jwtVersion, metrics: metrics, }); diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index 0846f9bd62d1..9577bb96dcae 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -265,8 +265,8 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { */ const jwtClaim: JwtClaim = { iat: Math.floor(new Date().getTime() / 1000), - id: this.jwtId ?? undefined, - clv: this.jwtVersion ?? undefined, + id: this.jwtId, + clv: this.jwtVersion, }; const token = encodeJwtToken(jwtClaim, this.jwtSecret); diff --git a/packages/beacon-node/src/execution/engine/index.ts b/packages/beacon-node/src/execution/engine/index.ts index 0c92ebf90e8e..743abf203de9 100644 --- a/packages/beacon-node/src/execution/engine/index.ts +++ b/packages/beacon-node/src/execution/engine/index.ts @@ -36,8 +36,8 @@ export function getExecutionEngineHttp( signal: modules.signal, metrics: modules.metrics?.executionEnginerHttpClient, jwtSecret: opts.jwtSecretHex ? fromHex(opts.jwtSecretHex) : undefined, - jwtId: opts.jwtId ?? undefined, - jwtVersion: opts.jwtVersion ?? undefined, + jwtId: opts.jwtId, + jwtVersion: opts.jwtVersion, }); return new ExecutionEngineHttp(rpc, modules); } From 0d5f268470063716be267d8f5c7fc1fecfd85c87 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 16:49:17 +0800 Subject: [PATCH 11/27] Update doc to remove jwt version --- docs/usage/beacon-management.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/usage/beacon-management.md b/docs/usage/beacon-management.md index c8261ef04cb7..7f4374c15910 100644 --- a/docs/usage/beacon-management.md +++ b/docs/usage/beacon-management.md @@ -37,7 +37,8 @@ When starting up a Lodestar beacon node in any configuration, ensure you add the ### Set up and include identifiers in JWT tokens -Lodestar supports sending JWT authentication tokens with customized id `id` and version `clv` strings. This is particularly useful when running multiple consensus-layer clients with the different JWT secrets which makes the execution-layer client difficult to choose which JWT secret to verify against due to the inability to distinguish between the different consensus-layer clients. You can configure the optional identifiers by adding `--jwt-id $JWT_ID` and/or `--jwt-version $JWT_VERSION` flags. By default, without the related flags added, Lodestar will omit `id` and/or `clv` in the JWT token during the tranmissions. +Lodestar auto-populates `clv` field in the claims of JWT authentication tokens with a non-configurable value `Lodestar/$CLIENT_VERSION` to communicate the client's version. Lodestar also optionally includes `id` field in the claims with value `$JWT_ID` if the appropriate flag `--jwtId $JWT_ID` is added. +`id` and `clv` are particularly useful when running multiple consensus-layer clients with the different JWT secrets which makes the execution-layer client difficult to choose which JWT secret to verify against due to the inability to distinguish between the different consensus-layer clients. ### Ensure JWT is configured with your execution node From b66e1b7dc807ca373aa81364fc39b324e9d0cdba Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 17:50:24 +0800 Subject: [PATCH 12/27] Remove jwt version from cli arg --- packages/cli/src/options/beaconNodeOptions/eth1.ts | 2 -- packages/cli/src/options/beaconNodeOptions/execution.ts | 9 --------- 2 files changed, 11 deletions(-) diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index 3e66351994b8..0468c96e5934 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -29,7 +29,6 @@ export function parseArgs(args: Eth1Args & Partial): IBeaco ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) : undefined; jwtId = args["jwt-id"]; - jwtVersion = args["jwt-version"]; } return { @@ -37,7 +36,6 @@ export function parseArgs(args: Eth1Args & Partial): IBeaco providerUrls, jwtSecretHex, jwtId, - jwtVersion, depositContractDeployBlock: args["eth1.depositContractDeployBlock"], disableEth1DepositDataTracker: args["eth1.disableEth1DepositDataTracker"], unsafeAllowDepositDataOverwrite: args["eth1.unsafeAllowDepositDataOverwrite"], diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index 4cdd762ddf16..eb4b222587c0 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -10,7 +10,6 @@ export type ExecutionEngineArgs = { "execution.engineMock"?: boolean; "jwt-secret"?: string; "jwt-id"?: string; - "jwt-version"?: string; }; export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["executionEngine"] { @@ -34,7 +33,6 @@ export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["execut ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) : undefined, jwtId: args["jwt-id"], - jwtVersion: args["jwt-version"], }; } @@ -91,11 +89,4 @@ export const options: CliCommandOptions = { type: "string", group: "execution", }, - - "jwt-version": { - description: - "An option version string to be included in the clv field in the claims of the jwt tokens for authentication with EL client's rpc server hosting engine apis", - type: "string", - group: "execution", - }, }; From 137761786250694fa1238cf5dbedf7623a82f14d Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 17:50:50 +0800 Subject: [PATCH 13/27] Populate jwtVersion from beaconHandlerinit --- docs/usage/beacon-management.md | 2 +- .../beacon-node/src/eth1/provider/jsonRpcHttpClient.ts | 7 ++++--- packages/cli/src/cmds/beacon/handler.ts | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/usage/beacon-management.md b/docs/usage/beacon-management.md index 7f4374c15910..07ff133525ef 100644 --- a/docs/usage/beacon-management.md +++ b/docs/usage/beacon-management.md @@ -37,7 +37,7 @@ When starting up a Lodestar beacon node in any configuration, ensure you add the ### Set up and include identifiers in JWT tokens -Lodestar auto-populates `clv` field in the claims of JWT authentication tokens with a non-configurable value `Lodestar/$CLIENT_VERSION` to communicate the client's version. Lodestar also optionally includes `id` field in the claims with value `$JWT_ID` if the appropriate flag `--jwtId $JWT_ID` is added. +Lodestar auto-populates `clv` field in the claims of JWT authentication tokens with a non-configurable value `Lodestar/$CLIENT_VERSION` eg. `Lodestar/v1.3.0/2d0938e` to communicate the client's version. Lodestar also optionally includes `id` field in the claims with value `$JWT_ID` if the appropriate flag `--jwtId $JWT_ID` is added. `id` and `clv` are particularly useful when running multiple consensus-layer clients with the different JWT secrets which makes the execution-layer client difficult to choose which JWT secret to verify against due to the inability to distinguish between the different consensus-layer clients. ### Ensure JWT is configured with your execution node diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index 9577bb96dcae..8888fa23e72b 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -105,9 +105,10 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { * and it might deny responses to the RPC requests. */ jwtSecret?: Uint8Array; - /** If provided, jwtId will be included in JwtClaim.id */ + /** If jwtSecret and jwtId are provided, jwtId will be included in JwtClaim.id */ jwtId?: string; - /** If provided, jwtVersion will be included in JwtClaim.clv */ + /** If jwtSecret is provided, jwtVersion will be included in JwtClaim.clv. + * jwtVersion has default value of empty string */ jwtVersion?: string; /** Retry attempts */ retryAttempts?: number; @@ -132,7 +133,7 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { this.jwtSecret = opts?.jwtSecret; this.jwtId = opts?.jwtId; - this.jwtVersion = opts?.jwtVersion; + this.jwtVersion = opts?.jwtVersion ?? ""; this.metrics = opts?.metrics ?? null; this.metrics?.configUrlsCount.set(urls.length); diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index 4a61c4ab9dee..4ad83b3b9f77 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -199,6 +199,10 @@ export async function beaconHandlerInit(args: BeaconArgs & GlobalArgs) { beaconNodeOptions.set({network: {version: version.split("/")[0]}}); // Add User-Agent header to all builder requests beaconNodeOptions.set({executionBuilder: {userAgent: `Lodestar/${version}`}}); + // Set jwt version with version string + beaconNodeOptions.set({executionEngine: {jwtVersion: `Lodestar/${version}`}}); + // Set jwt version with version string + beaconNodeOptions.set({eth1: {jwtVersion: `Lodestar/${version}`}}); } // Render final options From 485da7a0c43c1210de3d616873c2ead560058df3 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 17:51:45 +0800 Subject: [PATCH 14/27] Rename jwt-id to jwtId --- packages/cli/src/options/beaconNodeOptions/eth1.ts | 2 +- packages/cli/src/options/beaconNodeOptions/execution.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index 0468c96e5934..83f3f14ea202 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -28,7 +28,7 @@ export function parseArgs(args: Eth1Args & Partial): IBeaco jwtSecretHex = args["jwt-secret"] ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) : undefined; - jwtId = args["jwt-id"]; + jwtId = args["jwtId"]; } return { diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index eb4b222587c0..649e35fa8455 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -9,7 +9,7 @@ export type ExecutionEngineArgs = { "execution.retryDelay": number; "execution.engineMock"?: boolean; "jwt-secret"?: string; - "jwt-id"?: string; + "jwtId"?: string; }; export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["executionEngine"] { @@ -32,7 +32,7 @@ export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["execut jwtSecretHex: args["jwt-secret"] ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) : undefined, - jwtId: args["jwt-id"], + jwtId: args["jwtId"], }; } @@ -83,7 +83,7 @@ export const options: CliCommandOptions = { group: "execution", }, - "jwt-id": { + "jwtId": { description: "An optional identifier to be included in the id field in the claims of the jwt tokens for authentication with EL client's rpc server hosting engine apis", type: "string", From d49c06383fbfd245d2b937d019b1360674fb321e Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 18:02:04 +0800 Subject: [PATCH 15/27] Rename jwt-secret to jwtSecret --- docs/usage/beacon-management.md | 6 +++--- packages/cli/src/options/beaconNodeOptions/eth1.ts | 4 ++-- packages/cli/src/options/beaconNodeOptions/execution.ts | 8 ++++---- packages/cli/test/unit/options/beaconNodeOptions.test.ts | 2 +- .../cli/test/utils/simulation/beacon_clients/lodestar.ts | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/usage/beacon-management.md b/docs/usage/beacon-management.md index 07ff133525ef..f0bb00d693bd 100644 --- a/docs/usage/beacon-management.md +++ b/docs/usage/beacon-management.md @@ -33,7 +33,7 @@ You must generate a secret 32-byte (64 characters) hexadecimal string that will ### Configure Lodestar to locate the JWT secret -When starting up a Lodestar beacon node in any configuration, ensure you add the `--jwt-secret $JWT_SECRET_PATH` flag to point to the saved secret key file. +When starting up a Lodestar beacon node in any configuration, ensure you add the `--jwtSecret $JWT_SECRET_PATH` flag to point to the saved secret key file. ### Set up and include identifiers in JWT tokens @@ -59,7 +59,7 @@ Use the `--authrpc.jwtsecret` flag to configure the secret. Use their documentat To start a Lodestar beacon run the command: ```bash -./lodestar beacon --network $NETWORK_NAME --jwt-secret $JWT_SECRET_PATH +./lodestar beacon --network $NETWORK_NAME --jwtSecret $JWT_SECRET_PATH ``` This will assume an execution-layer client is available at the default @@ -68,7 +68,7 @@ location of `https://localhost:8545`. In case execution-layer clients are available at different locations, use `--execution.urls` to specify these locations in the command: ```bash -./lodestar beacon --network $NETWORK_NAME --jwt-secret $JWT_SECRET_PATH --execution.urls $EL_URL1 $EL_URL2 +./lodestar beacon --network $NETWORK_NAME --jwtSecret $JWT_SECRET_PATH --execution.urls $EL_URL1 $EL_URL2 ``` Immediately you should see confirmation that the node has started diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index 83f3f14ea202..2c8e49294fcc 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -25,8 +25,8 @@ export function parseArgs(args: Eth1Args & Partial): IBeaco // jwt auth mechanism. if (providerUrls === undefined && args["execution.urls"]) { providerUrls = args["execution.urls"]; - jwtSecretHex = args["jwt-secret"] - ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) + jwtSecretHex = args["jwtSecret"] + ? extractJwtHexSecret(fs.readFileSync(args["jwtSecret"], "utf-8").trim()) : undefined; jwtId = args["jwtId"]; } diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index 649e35fa8455..a051d65de076 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -8,7 +8,7 @@ export type ExecutionEngineArgs = { "execution.retryAttempts": number; "execution.retryDelay": number; "execution.engineMock"?: boolean; - "jwt-secret"?: string; + "jwtSecret"?: string; "jwtId"?: string; }; @@ -29,8 +29,8 @@ export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["execut * jwtSecret is parsed as hex instead of bytes because the merge with defaults * in beaconOptions messes up the bytes array as as index => value object */ - jwtSecretHex: args["jwt-secret"] - ? extractJwtHexSecret(fs.readFileSync(args["jwt-secret"], "utf-8").trim()) + jwtSecretHex: args["jwtSecret"] + ? extractJwtHexSecret(fs.readFileSync(args["jwtSecret"], "utf-8").trim()) : undefined, jwtId: args["jwtId"], }; @@ -76,7 +76,7 @@ export const options: CliCommandOptions = { group: "execution", }, - "jwt-secret": { + "jwtSecret": { description: "File path to a shared hex-encoded jwt secret which will be used to generate and bundle HS256 encoded jwt tokens for authentication with the EL client's rpc server hosting engine apis. Secret to be exactly same as the one used by the corresponding EL client.", type: "string", diff --git a/packages/cli/test/unit/options/beaconNodeOptions.test.ts b/packages/cli/test/unit/options/beaconNodeOptions.test.ts index b0f0254443dc..85ddfad26d07 100644 --- a/packages/cli/test/unit/options/beaconNodeOptions.test.ts +++ b/packages/cli/test/unit/options/beaconNodeOptions.test.ts @@ -223,7 +223,7 @@ describe("options / beaconNodeOptions", () => { const beaconNodeArgsPartial = { eth1: true, "execution.urls": ["http://my.node:8551"], - "jwt-secret": jwtSecretFile, + "jwtSecret": jwtSecretFile, } as BeaconNodeArgs; const expectedOptions: RecursivePartial = { diff --git a/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts b/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts index e90db5ec1505..3f08b58cb8ac 100644 --- a/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts +++ b/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts @@ -53,7 +53,7 @@ export const generateLodestarBeaconNode: BeaconNodeGenerator Date: Tue, 24 Oct 2023 12:41:40 +0800 Subject: [PATCH 16/27] Use Date.now() for iat Co-authored-by: Nico Flaig --- packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index 8888fa23e72b..d06d144b86ba 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -265,7 +265,7 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { * Jwt auth spec: https://github.com/ethereum/execution-apis/pull/167 */ const jwtClaim: JwtClaim = { - iat: Math.floor(new Date().getTime() / 1000), + iat: Math.floor(Date.now() / 1000), id: this.jwtId, clv: this.jwtVersion, }; From 4b8098c24b8a3b8e36fb8f1d5b23402cc0e06618 Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 24 Oct 2023 12:42:07 +0800 Subject: [PATCH 17/27] Update packages/beacon-node/src/eth1/provider/jwt.ts Co-authored-by: Nico Flaig --- packages/beacon-node/src/eth1/provider/jwt.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index 024583e575eb..5e6daad94a46 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -5,7 +5,7 @@ import jwt from "jwt-simple"; const {encode, decode} = jwt; /** jwt token has iat which is issued at unix timestamp, an optional exp for expiry, - * an optional id for unique identifier, and an optional clv for client type/version + * an optional id as unique identifier, and an optional clv for client type/version */ export type JwtClaim = {iat: number; exp?: number; id?: string; clv?: string}; From 2aa08fec05694ea10effd8571265103ffd762cc7 Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 24 Oct 2023 12:42:36 +0800 Subject: [PATCH 18/27] Update packages/beacon-node/src/execution/engine/http.ts Co-authored-by: Nico Flaig --- packages/beacon-node/src/execution/engine/http.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index 7d17ac59be46..e550f071ee47 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -56,7 +56,7 @@ export type ExecutionEngineHttpOpts = { */ jwtSecretHex?: string; /** - * A identifier string passed by user in cli arg that will be included in `id` field in jwt claims + * An identifier string passed as CLI arg that will be set in `id` field of jwt claims */ jwtId?: string; /** From 40e61e155ff54584d6c18caa92e8f51cb3136f07 Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 24 Oct 2023 12:42:49 +0800 Subject: [PATCH 19/27] Update packages/beacon-node/src/execution/engine/http.ts Co-authored-by: Nico Flaig --- packages/beacon-node/src/execution/engine/http.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index e550f071ee47..cf3865286ea5 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -60,7 +60,7 @@ export type ExecutionEngineHttpOpts = { */ jwtId?: string; /** - * A version string passed by user in cli arg that will be included in `clv` field in jwt claims + * A version string that will be set in `clv` field of jwt claims */ jwtVersion?: string; }; From 20dcfec4c7acf2f1b979117a1b905c31dc90d057 Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 24 Oct 2023 12:43:53 +0800 Subject: [PATCH 20/27] Update packages/cli/src/options/beaconNodeOptions/execution.ts Co-authored-by: Nico Flaig --- packages/cli/src/options/beaconNodeOptions/execution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index a051d65de076..e5446de3b2ba 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -85,7 +85,7 @@ export const options: CliCommandOptions = { "jwtId": { description: - "An optional identifier to be included in the id field in the claims of the jwt tokens for authentication with EL client's rpc server hosting engine apis", + "An optional identifier to be set in the id field of the claims included in jwt tokens for authentication with EL client's rpc server hosting engine apis", type: "string", group: "execution", }, From fef18590d2c02e0a59092af4a8e4272924f141aa Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 24 Oct 2023 13:04:20 +0800 Subject: [PATCH 21/27] Address comments --- .../beacon-node/src/eth1/provider/jsonRpcHttpClient.ts | 5 ++--- packages/beacon-node/test/unit/eth1/jwt.test.ts | 2 +- packages/cli/src/cmds/beacon/handler.ts | 10 +++++----- packages/cli/src/options/beaconNodeOptions/eth1.ts | 1 - 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index d06d144b86ba..3a1b4ddb0ce1 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -107,8 +107,7 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { jwtSecret?: Uint8Array; /** If jwtSecret and jwtId are provided, jwtId will be included in JwtClaim.id */ jwtId?: string; - /** If jwtSecret is provided, jwtVersion will be included in JwtClaim.clv. - * jwtVersion has default value of empty string */ + /** If jwtSecret and jwtVersion are provided, jwtVersion will be included in JwtClaim.clv. */ jwtVersion?: string; /** Retry attempts */ retryAttempts?: number; @@ -133,7 +132,7 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { this.jwtSecret = opts?.jwtSecret; this.jwtId = opts?.jwtId; - this.jwtVersion = opts?.jwtVersion ?? ""; + this.jwtVersion = opts?.jwtVersion; this.metrics = opts?.metrics ?? null; this.metrics?.configUrlsCount.set(urls.length); diff --git a/packages/beacon-node/test/unit/eth1/jwt.test.ts b/packages/beacon-node/test/unit/eth1/jwt.test.ts index d3a7a250d7ed..5ebcdc17e355 100644 --- a/packages/beacon-node/test/unit/eth1/jwt.test.ts +++ b/packages/beacon-node/test/unit/eth1/jwt.test.ts @@ -12,7 +12,7 @@ describe("ExecutionEngine / jwt", () => { it("encode/decode correctly with id and clv", () => { const jwtSecret = Buffer.from(Array.from({length: 32}, () => Math.round(Math.random() * 255))); - const claim = {iat: Math.floor(new Date().getTime() / 1000), id: "4ac0", clv: "v1.11.3"}; + const claim = {iat: Math.floor(new Date().getTime() / 1000), id: "4ac0", clv: "Lodestar/v0.36.0/80c248bb"}; const token = encodeJwtToken(claim, jwtSecret); const decoded = decodeJwtToken(token, jwtSecret); expect(decoded).toEqual(claim); diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index 4ad83b3b9f77..a56916cdb232 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -195,14 +195,14 @@ export async function beaconHandlerInit(args: BeaconArgs & GlobalArgs) { if (args.private) { beaconNodeOptions.set({network: {private: true}}); } else { + const versionStr = `Lodestar/${version}`; + const simpleVersionStr = version.split("/")[0]; // Add simple version string for libp2p agent version - beaconNodeOptions.set({network: {version: version.split("/")[0]}}); + beaconNodeOptions.set({network: {version: simpleVersionStr}}); // Add User-Agent header to all builder requests - beaconNodeOptions.set({executionBuilder: {userAgent: `Lodestar/${version}`}}); + beaconNodeOptions.set({executionBuilder: {userAgent: versionStr}}); // Set jwt version with version string - beaconNodeOptions.set({executionEngine: {jwtVersion: `Lodestar/${version}`}}); - // Set jwt version with version string - beaconNodeOptions.set({eth1: {jwtVersion: `Lodestar/${version}`}}); + beaconNodeOptions.set({executionEngine: {jwtVersion: versionStr}, eth1: {jwtVersion: versionStr}}); } // Render final options diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index 2c8e49294fcc..196deb59161f 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -15,7 +15,6 @@ export type Eth1Args = { export function parseArgs(args: Eth1Args & Partial): IBeaconNodeOptions["eth1"] { let jwtSecretHex: string | undefined; let jwtId: string | undefined; - let jwtVersion: string | undefined; let providerUrls = args["eth1.providerUrls"]; From 262afb2c3e8d86202318ca982700f01e84cc777f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 24 Oct 2023 13:58:28 +0200 Subject: [PATCH 22/27] Fix jsdoc --- packages/beacon-node/src/eth1/provider/jwt.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index 5e6daad94a46..2056714fe1ae 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -4,7 +4,8 @@ import jwt from "jwt-simple"; const {encode, decode} = jwt; -/** jwt token has iat which is issued at unix timestamp, an optional exp for expiry, +/** + * jwt token has iat which is issued at unix timestamp, an optional exp for expiry, * an optional id as unique identifier, and an optional clv for client type/version */ export type JwtClaim = {iat: number; exp?: number; id?: string; clv?: string}; From 36844c36c09abcea8b97d2a56aaa4ab92152bbab Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 24 Oct 2023 14:05:39 +0200 Subject: [PATCH 23/27] id is not used for authentication but jwt tokens are, id is just included in those --- packages/cli/src/options/beaconNodeOptions/execution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index e5446de3b2ba..5b3970933430 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -85,7 +85,7 @@ export const options: CliCommandOptions = { "jwtId": { description: - "An optional identifier to be set in the id field of the claims included in jwt tokens for authentication with EL client's rpc server hosting engine apis", + "An optional identifier to be set in the id field of the claims included in jwt tokens used for authentication with EL client's rpc server hosting engine apis", type: "string", group: "execution", }, From 10c6a05ea33e4430c500c49dd81d9e508aa33875 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 24 Oct 2023 20:22:38 +0800 Subject: [PATCH 24/27] Remove jwt claim section from doc --- docs/usage/beacon-management.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/usage/beacon-management.md b/docs/usage/beacon-management.md index f0bb00d693bd..7295db64098d 100644 --- a/docs/usage/beacon-management.md +++ b/docs/usage/beacon-management.md @@ -35,11 +35,6 @@ You must generate a secret 32-byte (64 characters) hexadecimal string that will When starting up a Lodestar beacon node in any configuration, ensure you add the `--jwtSecret $JWT_SECRET_PATH` flag to point to the saved secret key file. -### Set up and include identifiers in JWT tokens - -Lodestar auto-populates `clv` field in the claims of JWT authentication tokens with a non-configurable value `Lodestar/$CLIENT_VERSION` eg. `Lodestar/v1.3.0/2d0938e` to communicate the client's version. Lodestar also optionally includes `id` field in the claims with value `$JWT_ID` if the appropriate flag `--jwtId $JWT_ID` is added. -`id` and `clv` are particularly useful when running multiple consensus-layer clients with the different JWT secrets which makes the execution-layer client difficult to choose which JWT secret to verify against due to the inability to distinguish between the different consensus-layer clients. - ### Ensure JWT is configured with your execution node **For Go Ethereum:** From cc5ffe401c23250d4d1b6c789b6c21128b0ab96b Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 24 Oct 2023 20:32:11 +0800 Subject: [PATCH 25/27] Update private description and lint --- packages/beacon-node/src/eth1/provider/jwt.ts | 2 +- packages/cli/src/cmds/beacon/options.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index 2056714fe1ae..093f53734080 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -4,7 +4,7 @@ import jwt from "jwt-simple"; const {encode, decode} = jwt; -/** +/** * jwt token has iat which is issued at unix timestamp, an optional exp for expiry, * an optional id as unique identifier, and an optional clv for client type/version */ diff --git a/packages/cli/src/cmds/beacon/options.ts b/packages/cli/src/cmds/beacon/options.ts index fff9a0912db6..3947e2ba17d0 100644 --- a/packages/cli/src/cmds/beacon/options.ts +++ b/packages/cli/src/cmds/beacon/options.ts @@ -117,7 +117,8 @@ export const beaconExtraOptions: CliCommandOptions = { }, private: { - description: "Do not send implementation details over p2p identify protocol and in builder requests", + description: + "Do not send implementation details over p2p identify protocol and in builder, execution engine and eth1 requests", type: "boolean", }, From 8eb36c60873937ecdfc10fe24ccd412b09aa2c1a Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 24 Oct 2023 16:12:46 +0200 Subject: [PATCH 26/27] Remove extra white space from jsdoc --- packages/beacon-node/src/eth1/provider/jwt.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index 093f53734080..1e267120957f 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -5,8 +5,8 @@ import jwt from "jwt-simple"; const {encode, decode} = jwt; /** - * jwt token has iat which is issued at unix timestamp, an optional exp for expiry, - * an optional id as unique identifier, and an optional clv for client type/version + * jwt token has iat which is issued at unix timestamp, an optional exp for expiry, + * an optional id as unique identifier, and an optional clv for client type/version */ export type JwtClaim = {iat: number; exp?: number; id?: string; clv?: string}; From f4996d2bc5d33bb6c75e667c220e8e3ef9613337 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 24 Oct 2023 17:31:39 +0200 Subject: [PATCH 27/27] Fix lint issues --- packages/cli/src/options/beaconNodeOptions/execution.ts | 8 ++++---- packages/cli/test/unit/options/beaconNodeOptions.test.ts | 2 +- .../cli/test/utils/simulation/beacon_clients/lodestar.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index 5b3970933430..23f9e6e0706c 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -8,8 +8,8 @@ export type ExecutionEngineArgs = { "execution.retryAttempts": number; "execution.retryDelay": number; "execution.engineMock"?: boolean; - "jwtSecret"?: string; - "jwtId"?: string; + jwtSecret?: string; + jwtId?: string; }; export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["executionEngine"] { @@ -76,14 +76,14 @@ export const options: CliCommandOptions = { group: "execution", }, - "jwtSecret": { + jwtSecret: { description: "File path to a shared hex-encoded jwt secret which will be used to generate and bundle HS256 encoded jwt tokens for authentication with the EL client's rpc server hosting engine apis. Secret to be exactly same as the one used by the corresponding EL client.", type: "string", group: "execution", }, - "jwtId": { + jwtId: { description: "An optional identifier to be set in the id field of the claims included in jwt tokens used for authentication with EL client's rpc server hosting engine apis", type: "string", diff --git a/packages/cli/test/unit/options/beaconNodeOptions.test.ts b/packages/cli/test/unit/options/beaconNodeOptions.test.ts index 85ddfad26d07..4f5050d87daf 100644 --- a/packages/cli/test/unit/options/beaconNodeOptions.test.ts +++ b/packages/cli/test/unit/options/beaconNodeOptions.test.ts @@ -223,7 +223,7 @@ describe("options / beaconNodeOptions", () => { const beaconNodeArgsPartial = { eth1: true, "execution.urls": ["http://my.node:8551"], - "jwtSecret": jwtSecretFile, + jwtSecret: jwtSecretFile, } as BeaconNodeArgs; const expectedOptions: RecursivePartial = { diff --git a/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts b/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts index 3f08b58cb8ac..3faa0bdb0acd 100644 --- a/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts +++ b/packages/cli/test/utils/simulation/beacon_clients/lodestar.ts @@ -53,7 +53,7 @@ export const generateLodestarBeaconNode: BeaconNodeGenerator