diff --git a/packages/lodestar/src/network/peers/client.ts b/packages/lodestar/src/network/peers/client.ts new file mode 100644 index 000000000000..90336bae34f9 --- /dev/null +++ b/packages/lodestar/src/network/peers/client.ts @@ -0,0 +1,27 @@ +export enum ClientKind { + Lighthouse = "Lighthouse", + Nimbus = "Nimbus", + Teku = "Teku", + Prysm = "Prysm", + Lodestar = "Lodestar", + Unknown = "Unknown", +} + +export function clientFromAgentVersion(agentVersion: string): ClientKind { + const slashIndex = agentVersion.indexOf("/"); + const agent = slashIndex >= 0 ? agentVersion.slice(0, slashIndex) : agentVersion; + switch (agent.toLowerCase()) { + case "lighthouse": + return ClientKind.Lighthouse; + case "teku": + return ClientKind.Teku; + case "prysm": + return ClientKind.Prysm; + case "nimbus": + return ClientKind.Nimbus; + case "js-libp2p": + return ClientKind.Lodestar; + default: + return ClientKind.Unknown; + } +} diff --git a/packages/lodestar/src/network/reqresp/request/index.ts b/packages/lodestar/src/network/reqresp/request/index.ts index 9ceb5ef91634..343521c28e62 100644 --- a/packages/lodestar/src/network/reqresp/request/index.ts +++ b/packages/lodestar/src/network/reqresp/request/index.ts @@ -5,7 +5,7 @@ import {Libp2p} from "libp2p/src/connection-manager"; import {IForkDigestContext} from "@chainsafe/lodestar-config"; import {ErrorAborted, ILogger, Context, withTimeout, TimeoutError} from "@chainsafe/lodestar-utils"; import {timeoutOptions} from "../../../constants"; -import {getAgentVersionFromPeerStore, prettyPrintPeerId} from "../../util"; +import {getClientFromPeerStore, prettyPrintPeerId} from "../../util"; import {Method, Encoding, Protocol, Version, IncomingResponseBody, RequestBody} from "../types"; import {formatProtocolId} from "../utils"; import {ResponseError} from "../response"; @@ -55,8 +55,8 @@ export async function sendRequest { const {REQUEST_TIMEOUT, DIAL_TIMEOUT} = {...timeoutOptions, ...options}; const peer = prettyPrintPeerId(peerId); - const agentVersion = getAgentVersionFromPeerStore(peerId, libp2p.peerStore.metadataBook); - const logCtx = {method, encoding, agentVersion, peer, requestId}; + const client = getClientFromPeerStore(peerId, libp2p.peerStore.metadataBook); + const logCtx = {method, encoding, client, peer, requestId}; if (signal?.aborted) { throw new ErrorAborted("sendRequest"); diff --git a/packages/lodestar/src/network/reqresp/response/index.ts b/packages/lodestar/src/network/reqresp/response/index.ts index 4f85e80acfc7..69784aa300d1 100644 --- a/packages/lodestar/src/network/reqresp/response/index.ts +++ b/packages/lodestar/src/network/reqresp/response/index.ts @@ -5,7 +5,7 @@ import {Libp2p} from "libp2p/src/connection-manager"; import {Context, ILogger, TimeoutError, withTimeout} from "@chainsafe/lodestar-utils"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {REQUEST_TIMEOUT, RespStatus} from "../../../constants"; -import {getAgentVersionFromPeerStore, prettyPrintPeerId} from "../../util"; +import {getClientFromPeerStore, prettyPrintPeerId} from "../../util"; import {Protocol, RequestBody, OutgoingResponseBody} from "../types"; import {onChunk} from "../utils"; import {Libp2pStream} from "../interface"; @@ -46,8 +46,8 @@ export async function handleRequest( signal?: AbortSignal, requestId = 0 ): Promise { - const agentVersion = getAgentVersionFromPeerStore(peerId, libp2p.peerStore.metadataBook); - const logCtx = {method: protocol.method, agentVersion, peer: prettyPrintPeerId(peerId), requestId}; + const client = getClientFromPeerStore(peerId, libp2p.peerStore.metadataBook); + const logCtx = {method: protocol.method, client, peer: prettyPrintPeerId(peerId), requestId}; let responseError: Error | null = null; await pipe( diff --git a/packages/lodestar/src/network/util.ts b/packages/lodestar/src/network/util.ts index 598ee671703b..d3a0355ee522 100644 --- a/packages/lodestar/src/network/util.ts +++ b/packages/lodestar/src/network/util.ts @@ -8,6 +8,7 @@ import {Multiaddr} from "multiaddr"; import {networkInterfaces} from "os"; import {ENR} from "@chainsafe/discv5"; import MetadataBook from "libp2p/src/peer-store/metadata-book"; +import {clientFromAgentVersion, ClientKind} from "./peers/client"; // peers @@ -69,6 +70,11 @@ export function prettyPrintPeerId(peerId: PeerId): string { return `${id.substr(0, 2)}...${id.substr(id.length - 6, id.length)}`; } +export function getClientFromPeerStore(peerId: PeerId, metadataBook: MetadataBook): ClientKind { + const agentVersion = getAgentVersionFromPeerStore(peerId, metadataBook); + return clientFromAgentVersion(agentVersion); +} + export function getAgentVersionFromPeerStore(peerId: PeerId, metadataBook: MetadataBook): string { return new TextDecoder().decode(metadataBook.getValue(peerId, "AgentVersion")) || "N/A"; } diff --git a/packages/lodestar/test/unit/network/peers/client.test.ts b/packages/lodestar/test/unit/network/peers/client.test.ts new file mode 100644 index 000000000000..be753529d839 --- /dev/null +++ b/packages/lodestar/test/unit/network/peers/client.test.ts @@ -0,0 +1,38 @@ +import {expect} from "chai"; +import {clientFromAgentVersion, ClientKind} from "../../../../src/network/peers/client"; + +describe("clientFromAgentVersion", () => { + const testCases: {name: string; agentVersion: string; client: ClientKind}[] = [ + { + name: "lighthouse", + agentVersion: "Lighthouse/v2.0.1-fff01b2/x86_64-linux", + client: ClientKind.Lighthouse, + }, + { + name: "teku", + agentVersion: "teku/teku/v21.11.0+62-g501ffa7/linux-x86_64/corretto-java-17", + client: ClientKind.Teku, + }, + { + name: "nimbus", + agentVersion: "nimbus", + client: ClientKind.Nimbus, + }, + { + name: "prysm", + agentVersion: "Prysm/v2.0.2/a80b1c252a9b4773493b41999769bf3134ac373f", + client: ClientKind.Prysm, + }, + { + name: "lodestar", + agentVersion: "js-libp2p/0.32.4", + client: ClientKind.Lodestar, + }, + ]; + + for (const {name, agentVersion, client} of testCases) { + it(name, () => { + expect(clientFromAgentVersion(agentVersion)).to.be.equal(client, `cannot parse ${name} agent version`); + }); + } +});