Skip to content

Add getNodeVersionV2 endpoint#568

Open
eth2353 wants to merge 6 commits intoethereum:masterfrom
eth2353:add-v2-node-version-endpoint
Open

Add getNodeVersionV2 endpoint#568
eth2353 wants to merge 6 commits intoethereum:masterfrom
eth2353:add-v2-node-version-endpoint

Conversation

@eth2353
Copy link

@eth2353 eth2353 commented Dec 22, 2025

Adds a /eth/v2/node/version endpoint for structured version information that also includes information about the attached EL client.

Changes:

The main motivation for this change is for validator clients to have access to information about the EL client attached to a beacon node. Right now, validator clients cannot see "past" the beacon node easily and are therefore blind to what kind of EL client is validating the execution payload. By exposing this information, multi-node validator clients can make safer decisions, e.g. they can require 3 different EL clients to declare the execution payload as valid before they attest to its validity.

@eth2353 eth2353 force-pushed the add-v2-node-version-endpoint branch from 6fe82bf to e0ea5c8 Compare December 28, 2025 14:22
@eth2353 eth2353 marked this pull request as ready for review December 28, 2025 14:23
@rolfyone
Copy link
Contributor

Similar to griffiti watermarks, it's reasonable to expect that there are nodes that either can't or choose not to pass back version specifics..... It's also seen sometimes in these watermarks that only one client (typically the CL) is declared (harder to tell if its unknown or no space).
I agree with the idea of the endpoint but we probably need to be very permissive in the structures that some or all of the information here isn't available, which will mean a lot more optionality in the output - I'm not sure if that dilutes what you're looking for?

@eth2353
Copy link
Author

eth2353 commented Jan 19, 2026

I consider this to be quite different from graffiti data since that is public, whereas the Beacon API is not generally exposed publicly. I don't really see an issue with passing back precise version information here. On the current V1 endpoint most clients already include everything that is proposed in this PR for the CL side, just in a less structured "User-agent" way:

Grandine/2.0.1-39e7dc37/x86_64-linux

Lighthouse/v8.0.0-e3ee7fe/x86_64-linux

Lodestar/v1.37.0/eaf5bc9

Nimbus/v25.12.0-ce4689-stateofus

teku/v25.11.0/linux-x86_64/-eclipseadoptium-openjdk64bitservervm-java-21 (no commit hash)


I can see the beacon node not having EL-side information for some reason (e.g. because the EL client is not responding to the beacon node's Engine API requests). In such cases we could either not include the "execution_client" field in the return data (and make that entire field optional), or explicitly define an UNKNOWN object that could be returned. I'd prefer to do the latter to help indicate that the field should be populated and not just skipped over.

For the usecase I'm looking for, just the client names would suffice, e.g. this node is running Lodestar+Reth. But since most clients already include much more in their current user-agent, I decided to just reuse the Engine API schema.

Copy link
Member

@nflaig nflaig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good to me, this was pretty straight forward to implement ChainSafe/lodestar#8772 for us.

ClientCode:
type: string
description: "A two-character client code that uniquely maps to a client name as defined in the [Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine/identification.md#clientcode)."
enum: [BU, EJ, EG, GE, GR, LH, LS, NM, NB, TE, TK, PM, RH]
Copy link
Member

@nflaig nflaig Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be worth to specify what to return if client code is unknown, we have a non-spec value of XX for this

properties:
code:
$ref: './primitive.yaml#/ClientCode'
name:
Copy link
Member

@nflaig nflaig Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be worth to specify what name to return if information is missing, eg. if we could not retrieve the EL client info yet, I am just returning Unknown right now

@eth2353
Copy link
Author

eth2353 commented Feb 3, 2026

I've added the following changes just now:

  • replaced github.com/.../blob/main/... with permalinks
  • updated the CHANGES.MD file deprecating the v1 endpoint and adding the v2
  • defined expected behavior for the situation where the client information is unknown (e.g. when no exchange of this information has occurred between the BN and EL client yet). In this case, the client code XX and client name Unknown should be used, with the remaining fields (version, commit) returned as empty strings.

I left the conversations regarding the "unknown" behavior unresolved for now in case anyone else wants to chime in on that.

@michaelsproul
Copy link
Contributor

LGTM, happy with "unknown" to signal an EL that is unresponsive or doesn't support the version endpoint

@mehdi-aouadi
Copy link
Contributor

mehdi-aouadi commented Feb 6, 2026

I think using "magic strings" like "Unknown", "XX" and empty strings could be problematic because it forces the consumer to know and handle them (they could consider them valid values since non standard). I'd rather prefer making them nullable or optional.
I can't find any example of nullable fields and idk if there's a reason for that. Making them all optional isn't ideal neither imo (we could end up with an empty response).
Ideally I'd suggest making some fields required like the code and version (minimal identity) and make the other fields nullable or optional. Then regarding the get method, the beacon_node must know itself so it should be required but the execution_client could become nullable or optional. If any required field in the execution_client isn't available then the whole object is null/empty and if any required field of the beacon_node isn't available we should respond with an error.
Example:

ClientVersionV1:
      type: object
      # minimal identity required
      required: [code, version] 
      properties:
        code:
          # required, a client must have a code
          type: string
          example: "LH"
        version:
          # required, a client must have a version
          type: string
          example: "v8.0.1"
        name:
          type: string
          nullable: true
          example: "Lighthouse"
        commit:
          type: string
          nullable: true
          example: "ced49dd2"

And the get method response:

responses:
    "200":
      description: Request successful
      content:
        application/json:
          schema:
            title: GetVersionV2Response
            type: object
            required: [data]
            properties:
              data:
                type: object
                required: [beacon_node]
                properties:
                  beacon_node:
                    # the beacon node always exists and has a valid identity
                    $ref: '../../beacon-node-oapi.yaml#/components/schemas/ClientVersionV1'
                  execution_client:
                    # the execution client is an optional dependency. It can be completely absent, so the whole object is nullable
                    $ref: '../../beacon-node-oapi.yaml#/components/schemas/ClientVersionV1'
                    nullable: true 

TLDR;

  • All info available: 200
  • Required fields for the CL available but other non required fields are not: 200 with other fields set to null
  • Required fields for the CL available but other required fields for the EL are not: 200 with execution_client set to null entirely
  • Required fields for the CL unavailable: Error

@nflaig
Copy link
Member

nflaig commented Feb 6, 2026

I can't find any example of nullable fields and idk if there's a reason for that.

generally we don't want that because the response can't be ssz encoded if a field is nullable or optional but for this endpoint it doesn't matter, I would be fine with allowing null, it's better than making fields optional

there is one example for this

enr:
oneOf:
- type: "null"
- $ref: "./p2p.yaml#/ENR"

it doesn't use nullable: true which seems to be deprecated since openapi 3.1, see #409

Required fields for the CL unavailable: Error

this api should never return an error, I don't see why the CL wouldn't be able to return it's own client info

@mehdi-aouadi
Copy link
Contributor

mehdi-aouadi commented Feb 6, 2026

#409

Thanks for the clarifications.
Then the nullable values should be defined as: type: ["string", "null"] for the primitive types and

execution_client:
 oneOf:
  - $ref: '../../beacon-node-oapi.yaml#/components/schemas/ClientVersionV1'
  - type: "null"

for objects.

By error I meant the already defined 500 error could be enough (if the API isn't able to respond for any reason)

@rolfyone
Copy link
Contributor

rolfyone commented Feb 7, 2026

generally the field would just not be marked required, so if its null its not included in the output...

@rolfyone
Copy link
Contributor

rolfyone commented Feb 7, 2026

I can't find any example of nullable fields and idk if there's a reason for that. Making them all optional isn't ideal neither imo (we could end up with an empty response).

not required would be the normal in the beacon-api - we generally don't pass back 'null' fields, i'd far prefer a field thats not required and just dont pass back the field rather than having 'null' or having strings like unknown, but if it was for execution specifically i'd probably be less worried about saying 'unknown' if a non required field is an issue for some reason.

@nflaig
Copy link
Member

nflaig commented Feb 7, 2026

I am also fine with making fields optional if that's what everyone prefers to do

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants