Skip to content

feat(plugin-api): expose Besu node version and commit hash via BesuConfiguration#10227

Open
alejandroGM0 wants to merge 2 commits intobesu-eth:mainfrom
alejandroGM0:feat/expose-besu-version-via-configuration
Open

feat(plugin-api): expose Besu node version and commit hash via BesuConfiguration#10227
alejandroGM0 wants to merge 2 commits intobesu-eth:mainfrom
alejandroGM0:feat/expose-besu-version-via-configuration

Conversation

@alejandroGM0
Copy link
Copy Markdown

@alejandroGM0 alejandroGM0 commented Apr 13, 2026

Summary

  • Add getBesuVersion() and getBesuCommitHash() to BesuConfiguration
  • Implementation in BesuConfigurationImpl delegates to BesuVersionUtils
  • Enables plugins to query the Besu node version at runtime

Motivation

While PluginVerifier provides build-time version compatibility checking via the artifact catalog, plugins have no way to access the node version at runtime through the plugin API. This limits plugins from performing their own compatibility checks, including version info in diagnostics, or adapting behavior to node capabilities.

The only indirect workaround is calling RpcEndpointService.call("web3_clientVersion", ...), but this has significant limitations:

  • Lifecycle restriction: call() throws if invoked before beforeExternalServices() completes
  • Namespace dependency: requires the WEB3 RPC namespace to be enabled
  • Not first-class: goes through the full JSON-RPC dispatch layer for a simple data lookup

Fixes #10226

Changes

  • Added getBesuVersion() to BesuConfiguration -- returns BesuVersionUtils.shortVersion()
  • Added getBesuCommitHash() to BesuConfiguration -- returns BesuVersionUtils.commit()
  • Updated checkAPIChanges known hash
  • Added BesuConfigurationImplTest with tests for both methods

Test plan

  • BesuConfigurationImplTest verifies non-null, non-empty return values
  • checkAPIChanges hash updated
  • ./gradlew :plugin-api:build passes
  • ./gradlew :app:test passes

Copilot AI review requested due to automatic review settings April 13, 2026 15:19
…nfiguration

Plugins currently cannot access the host Besu node version at runtime.
BesuVersionUtils exists in the util module but is not exposed through
any plugin-api service.

Add getBesuVersion() and getBesuCommitHash() to BesuConfiguration,
delegating to BesuVersionUtils. This enables plugins to log diagnostics,
perform runtime compatibility checks, and include version info in custom
RPC responses.

Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
@alejandroGM0 alejandroGM0 force-pushed the feat/expose-besu-version-via-configuration branch from 599d0a8 to 3644bab Compare April 13, 2026 15:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Exposes the running Besu node’s version and git commit hash through the plugin API so plugins can query runtime node build information without relying on JSON-RPC.

Changes:

  • Added getBesuVersion() and getBesuCommitHash() to BesuConfiguration in plugin-api
  • Implemented the new methods in BesuConfigurationImpl via BesuVersionUtils
  • Updated plugin API change hash and added unit tests for the new getters

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java Adds new plugin API methods to expose Besu version and commit hash.
plugin-api/build.gradle Updates checkAPIChanges known hash for the API surface change.
app/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java Implements the new API methods by delegating to BesuVersionUtils.
app/src/test/java/org/hyperledger/besu/services/BesuConfigurationImplTest.java Adds tests to validate non-empty return values for the new methods.

Comment on lines +113 to +122
* @return the Besu node version string, never null
*/
String getBesuVersion();

/**
* Returns the git commit hash of the running Besu build.
*
* @return the short git commit hash, never null
*/
String getBesuCommitHash();
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

Adding abstract methods to a public plugin API interface is source-breaking for any downstream code that implements BesuConfiguration (common in plugin unit tests via fakes/stubs). To reduce upgrade friction, consider making these default methods (with a documented fallback like \"UNKNOWN\") or introducing a new extended interface (e.g., BesuConfigurationV2) / dedicated service for version info so older implementers aren’t forced to update immediately.

Suggested change
* @return the Besu node version string, never null
*/
String getBesuVersion();
/**
* Returns the git commit hash of the running Besu build.
*
* @return the short git commit hash, never null
*/
String getBesuCommitHash();
* <p>The default implementation returns {@code "UNKNOWN"} to preserve source compatibility
* for existing downstream implementations of this public plugin API.
*
* @return the Besu node version string, never null
*/
default String getBesuVersion() {
return "UNKNOWN";
}
/**
* Returns the git commit hash of the running Besu build.
*
* <p>The default implementation returns {@code "UNKNOWN"} to preserve source compatibility
* for existing downstream implementations of this public plugin API.
*
* @return the short git commit hash, never null
*/
default String getBesuCommitHash() {
return "UNKNOWN";
}

Copilot uses AI. Check for mistakes.
Comment on lines +107 to +113
* <p>The format follows semantic versioning: {@code "MAJOR.MINOR.PATCH"} for release builds
* (e.g., {@code "25.3.0"}) or {@code "MAJOR.MINOR.PATCH-qualifier"} for development builds
* (e.g., {@code "25.3.1-dev-ac23d311"}).
*
* <p>Available during all plugin lifecycle phases ({@code register} through {@code stop}).
*
* @return the Besu node version string, never null
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The Javadoc promises semantic-version formatting and a non-null return, but it doesn’t document what happens when build metadata is unavailable (e.g., missing/stripped manifest properties). Please document the exact fallback value(s) (such as \"UNKNOWN\") and whether the value is guaranteed to match the documented SemVer patterns in all build variants.

Suggested change
* <p>The format follows semantic versioning: {@code "MAJOR.MINOR.PATCH"} for release builds
* (e.g., {@code "25.3.0"}) or {@code "MAJOR.MINOR.PATCH-qualifier"} for development builds
* (e.g., {@code "25.3.1-dev-ac23d311"}).
*
* <p>Available during all plugin lifecycle phases ({@code register} through {@code stop}).
*
* @return the Besu node version string, never null
* <p>When build metadata is available, the returned value follows semantic versioning:
* {@code "MAJOR.MINOR.PATCH"} for release builds (e.g., {@code "25.3.0"}) or
* {@code "MAJOR.MINOR.PATCH-qualifier"} for development builds (e.g.,
* {@code "25.3.1-dev-ac23d311"}).
*
* <p>If the version metadata is unavailable (for example, if manifest properties are missing
* or stripped), this method returns the literal string {@code "UNKNOWN"}. That fallback value
* is never null, but it is not guaranteed to match the semantic-version patterns described
* above.
*
* <p>Available during all plugin lifecycle phases ({@code register} through {@code stop}).
*
* @return the Besu node version string; never null, and {@code "UNKNOWN"} if version metadata
* is unavailable

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +36
import org.junit.jupiter.api.Test;

class BesuConfigurationImplTest {

@Test
void getBesuVersion_returnsNonEmptyString() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String version = config.getBesuVersion();
assertThat(version).isNotNull();
assertThat(version).isNotEmpty();
}

@Test
void getBesuCommitHash_returnsNonEmptyString() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String commit = config.getBesuCommitHash();
assertThat(commit).isNotNull();
assertThat(commit).isNotEmpty();
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

These tests only assert non-null/non-empty, so they won’t catch regressions where the methods stop delegating correctly (e.g., returning a constant placeholder) or violate the documented format. Consider asserting equality with BesuVersionUtils.shortVersion() / BesuVersionUtils.commit() and (optionally) validating basic format expectations (e.g., SemVer-like version, hex-ish commit hash) to better pin down the intended contract.

Suggested change
import org.junit.jupiter.api.Test;
class BesuConfigurationImplTest {
@Test
void getBesuVersion_returnsNonEmptyString() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String version = config.getBesuVersion();
assertThat(version).isNotNull();
assertThat(version).isNotEmpty();
}
@Test
void getBesuCommitHash_returnsNonEmptyString() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String commit = config.getBesuCommitHash();
assertThat(commit).isNotNull();
assertThat(commit).isNotEmpty();
import org.hyperledger.besu.util.BesuVersionUtils;
import org.junit.jupiter.api.Test;
class BesuConfigurationImplTest {
@Test
void getBesuVersion_returnsShortVersion() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String version = config.getBesuVersion();
assertThat(version)
.isEqualTo(BesuVersionUtils.shortVersion())
.matches("\\d+\\.\\d+\\.\\d+(?:[-+].+)?");
}
@Test
void getBesuCommitHash_returnsCommitHash() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String commit = config.getBesuCommitHash();
assertThat(commit)
.isEqualTo(BesuVersionUtils.commit())
.matches("[0-9a-fA-F]+");

Copilot uses AI. Check for mistakes.
@alejandroGM0 alejandroGM0 requested a review from Copilot April 13, 2026 17:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment on lines +107 to +109
* <p>The format follows semantic versioning: {@code "MAJOR.MINOR.PATCH"} for release builds
* (e.g., {@code "25.3.0"}) or {@code "MAJOR.MINOR.PATCH-qualifier"} for development builds
* (e.g., {@code "25.3.1-dev-ac23d311"}).
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The Javadoc currently guarantees a specific version string shape (including an example that embeds what looks like a commit hash in the version). Unless BesuVersionUtils.shortVersion() is explicitly specified to always follow this exact format, this is easy to get out of sync with actual behavior. Consider loosening the contract to: (a) state it’s the output of BesuVersionUtils.shortVersion(), and/or (b) describe it as a human-readable version string that is typically SemVer for releases, without guaranteeing qualifier structure.

Suggested change
* <p>The format follows semantic versioning: {@code "MAJOR.MINOR.PATCH"} for release builds
* (e.g., {@code "25.3.0"}) or {@code "MAJOR.MINOR.PATCH-qualifier"} for development builds
* (e.g., {@code "25.3.1-dev-ac23d311"}).
* <p>This is a human-readable Besu version string. For release builds, it is typically a
* semantic version such as {@code "25.3.0"}.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +37
@Test
void getBesuVersion_returnsNonEmptyString() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String version = config.getBesuVersion();
assertThat(version).isNotNull();
assertThat(version).isNotEmpty();
}

@Test
void getBesuCommitHash_returnsNonEmptyString() {
BesuConfigurationImpl config = new BesuConfigurationImpl();
String commit = config.getBesuCommitHash();
assertThat(commit).isNotNull();
assertThat(commit).isNotEmpty();
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

These tests only assert non-null/non-empty, which doesn’t verify the intended contract that BesuConfigurationImpl delegates to BesuVersionUtils. To better protect against regressions (e.g., accidental hard-coding or wiring to the wrong source), assert equality with BesuVersionUtils.shortVersion() / BesuVersionUtils.commit() and consider using isNotBlank() if whitespace-only values would be undesirable.

Copilot uses AI. Check for mistakes.
Loosen the Javadoc contract for getBesuVersion and getBesuCommitHash to match actual runtime behaviour and update tests to verify delegation to BesuVersionUtils. Refresh the plugin-api knownHash accordingly.
@alejandroGM0 alejandroGM0 force-pushed the feat/expose-besu-version-via-configuration branch from 62ce573 to e9f1f79 Compare April 13, 2026 20:27
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.

Plugin API: Expose node version to plugins and establish API stability annotations

2 participants