From efe7cbb493abb599a0d660374b296fb0186c3513 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 4 Nov 2019 08:08:49 -0700 Subject: [PATCH] Add --identity flag for client identification in node browsers (#150) Support the "--identity" flag. This adds a fifth field to the normally four part clientId, with the identity in the second position. For example, if the CLI flag "--identity PegaSysEng" were passed in the clientID reported by ethernodes would read `besu/PegaSysEng/v1.3.2/linux-x86_64/oracle_openjdk-java-11` Whereas without the flag it would just read `besu/v1.3.2/linux-x86_64/oracle_openjdk-java-11` Signed-off-by: Danno Ferrin Signed-off-by: edwardmack --- .../java/org/hyperledger/besu/BesuInfo.java | 23 +++++++++------- .../org/hyperledger/besu/RunnerBuilder.java | 10 +++++-- .../org/hyperledger/besu/cli/BesuCommand.java | 11 +++++++- .../org/hyperledger/besu/BesuInfoTest.java | 27 +++++++++++++++++++ .../hyperledger/besu/cli/BesuCommandTest.java | 10 +++++++ .../besu/cli/CommandTestAbstract.java | 1 + .../src/test/resources/everything_config.toml | 1 + 7 files changed, 70 insertions(+), 13 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/BesuInfo.java b/besu/src/main/java/org/hyperledger/besu/BesuInfo.java index aae241da000..00e458f5590 100644 --- a/besu/src/main/java/org/hyperledger/besu/BesuInfo.java +++ b/besu/src/main/java/org/hyperledger/besu/BesuInfo.java @@ -16,20 +16,23 @@ import org.hyperledger.besu.util.PlatformDetector; +import java.util.Optional; + public final class BesuInfo { - private static final String CLIENT_IDENTITY = "besu"; - private static final String VERSION = - CLIENT_IDENTITY - + "/v" - + BesuInfo.class.getPackage().getImplementationVersion() - + "/" - + PlatformDetector.getOS() - + "/" - + PlatformDetector.getVM(); + private static final String CLIENT = "besu"; + private static final String VERSION = BesuInfo.class.getPackage().getImplementationVersion(); + private static final String OS = PlatformDetector.getOS(); + private static final String VM = PlatformDetector.getVM(); private BesuInfo() {} public static String version() { - return VERSION; + return String.format("%s/v%s/%s/%s", CLIENT, VERSION, OS, VM); + } + + public static String nodeName(final Optional maybeIdentity) { + return maybeIdentity + .map(identity -> String.format("%s/%s/v%s/%s/%s", CLIENT, identity, VERSION, OS, VM)) + .orElse(version()); } } diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index 14d76a451cc..0dc79f66843 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -131,6 +131,7 @@ public class RunnerBuilder { private ObservableMetricsSystem metricsSystem; private Optional permissioningConfiguration = Optional.empty(); private Collection staticNodes = Collections.emptyList(); + private Optional identityString = Optional.empty(); public RunnerBuilder vertx(final Vertx vertx) { this.vertx = vertx; @@ -247,6 +248,11 @@ public RunnerBuilder staticNodes(final Collection staticNodes) { return this; } + public RunnerBuilder identityString(final Optional identityString) { + this.identityString = identityString; + return this; + } + public Runner build() { Preconditions.checkNotNull(besuController); @@ -290,7 +296,7 @@ public Runner build() { .setBindPort(p2pListenPort) .setMaxPeers(maxPeers) .setSupportedProtocols(subProtocols) - .setClientId(BesuInfo.version()) + .setClientId(BesuInfo.nodeName(identityString)) .setLimitRemoteWireConnectionsEnabled(limitRemoteWireConnectionsEnabled) .setFractionRemoteWireConnectionsAllowed(fractionRemoteConnectionsAllowed); networkingConfiguration.setRlpx(rlpxConfiguration).setDiscovery(discoveryConfiguration); @@ -581,7 +587,7 @@ private Map jsonRpcMethods( final Map methods = new JsonRpcMethodsFactory() .methods( - BesuInfo.version(), + BesuInfo.nodeName(identityString), ethNetworkConfig.getNetworkId(), besuController.getGenesisConfigOptions(), network, diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 613ffe61348..bdc4c9f61df 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -207,6 +207,13 @@ protected KeyLoader getKeyLoader() { // CLI options defined by user at runtime. // Options parsing is done with CLI library Picocli https://picocli.info/ + @Option( + names = "--identity", + paramLabel = "", + description = "Identification for this node in the Client ID", + arity = "1") + private final Optional identityString = Optional.empty(); + // Completely disables P2P within Besu. @Option( names = {"--p2p-enabled"}, @@ -786,7 +793,7 @@ public void parse( public void run() { try { prepareLogging(); - logger.info("Starting Besu version: {}", BesuInfo.version()); + logger.info("Starting Besu version: {}", BesuInfo.nodeName(identityString)); validateOptions().configure().controller().startPlugins().startSynchronization(); } catch (final Exception e) { throw new ParameterException(this.commandLine, e.getMessage(), e); @@ -846,6 +853,7 @@ private BesuCommand registerConverters() { commandLine.registerConverter(Wei.class, (arg) -> Wei.of(Long.parseUnsignedLong(arg))); commandLine.registerConverter(PositiveNumber.class, PositiveNumber::fromString); commandLine.registerConverter(Hash.class, Hash::fromHexString); + commandLine.registerConverter(Optional.class, Optional::of); metricCategoryConverter.addCategories(BesuMetricCategory.class); metricCategoryConverter.addCategories(StandardMetricCategory.class); @@ -1413,6 +1421,7 @@ private void synchronize( .metricsSystem(metricsSystem) .metricsConfiguration(metricsConfiguration) .staticNodes(staticNodes) + .identityString(identityString) .build(); addShutdownHook(runner); diff --git a/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java b/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java index 0b6fcbf0479..8491702a644 100644 --- a/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java +++ b/besu/src/test/java/org/hyperledger/besu/BesuInfoTest.java @@ -16,6 +16,8 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.Optional; + import org.junit.Test; public final class BesuInfoTest { @@ -30,4 +32,29 @@ public final class BesuInfoTest { public void versionStringIsEthstatsFriendly() { assertThat(BesuInfo.version()).matches("[^/]+/v(\\d+\\.\\d+\\.\\d+[^/]*|null)/[^/]+/[^/]+"); } + + /** + * Ethstats wants a version string like <foo>/v<bar>/<baz>/<bif>. Foo is the + * client identity (besu, Geth, Parity, etc). Bar is the version, in semantic version form + * (1.2.3-whatever), baz is OS and chip architecture, and bif is "compiler" - which we use as JVM + * info. + */ + @Test + public void noIdentityNodeNameIsEthstatsFriendly() { + assertThat(BesuInfo.nodeName(Optional.empty())) + .matches("[^/]+/v(\\d+\\.\\d+\\.\\d+[^/]*|null)/[^/]+/[^/]+"); + } + + /** + * Ethstats also accepts a version string like + * <foo>/%lt;qux>/v<bar>/<baz>/<bif>. Foo is the client identity (besu, + * Geth, Parity, etc). Qux is user identity (PegaSysEng, Yes-EIP-1679, etc) Bar is the version, in + * semantic version form (1.2.3-whatever), baz is OS and chip architecture, and bif is "compiler" + * - which we use as JVM info. + */ + @Test + public void userIdentityNodeNameIsEthstatsFriendly() { + assertThat(BesuInfo.nodeName(Optional.of("TestUserIdentity"))) + .matches("[^/]+/[^/]+/v(\\d+\\.\\d+\\.\\d+[^/]*|null)/[^/]+/[^/]+"); + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 55279d99736..611997e4a4f 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -996,6 +996,16 @@ public void genesisPathDisabledUnderDocker() { assertThat(commandOutput.toString()).isEmpty(); } + @Test + public void identityValueTrueMustBeUsed() { + parseCommand("--identity", "test"); + + verify(mockRunnerBuilder.identityString(eq(Optional.of("test")))).build(); + + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()).isEmpty(); + } + @Test public void p2pEnabledOptionValueTrueMustBeUsed() { parseCommand("--p2p-enabled", "true"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 3cc3809a6a2..f28246fd427 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -207,6 +207,7 @@ public void initMocks() throws Exception { when(mockRunnerBuilder.metricsSystem(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.metricsConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.staticNodes(any())).thenReturn(mockRunnerBuilder); + when(mockRunnerBuilder.identityString(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.build()).thenReturn(mockRunner); when(storageService.getByName("rocksdb")).thenReturn(Optional.of(rocksDBStorageFactory)); diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index d77d6bb25bd..dfa3c032859 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -14,6 +14,7 @@ logging="INFO" node-private-key-file="./path/to/privateKey" # P2P network +identity="PegaSysEng" p2p-enabled=true nat-method="NONE" discovery-enabled=false