Skip to content

Commit 9ba2205

Browse files
authored
ETCM-365: Version info in Hello.clientId (#794)
1 parent dcb6d7b commit 9ba2205

File tree

9 files changed

+289
-6
lines changed

9 files changed

+289
-6
lines changed

build.sbt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ val root = {
6666
val root = project
6767
.in(file("."))
6868
.configs(Integration, Benchmark, Evm, Ets, Snappy, Rpc)
69+
.enablePlugins(BuildInfoPlugin)
70+
.settings(
71+
buildInfoKeys := Seq[BuildInfoKey](name, version, git.gitHeadCommit),
72+
buildInfoPackage := "io.iohk.ethereum.utils"
73+
)
6974
.settings(commonSettings: _*)
7075
.settings(
7176
libraryDependencies ++= dep
@@ -116,8 +121,9 @@ Test / parallelExecution := true
116121
testOptions in Test += Tests.Argument("-oDG")
117122

118123
// protobuf compilation
124+
// Into a subdirectory of src_managed to avoid it deleting other generated files; see https://github.com/sbt/sbt-buildinfo/issues/149
119125
PB.targets in Compile := Seq(
120-
scalapb.gen() -> (sourceManaged in Compile).value
126+
scalapb.gen() -> (sourceManaged in Compile).value / "protobuf"
121127
)
122128

123129
// have the protobuf API version file as a resource

project/plugins.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.7.5")
66
addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.0")
77
addSbtPlugin("com.thesamet" % "sbt-protoc" % "0.99.25")
88
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.5.1")
9+
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")
10+
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
911

1012
libraryDependencies += "com.trueaccord.scalapb" %% "compilerplugin" % "0.6.6"

project/repo.nix

Lines changed: 200 additions & 0 deletions
Large diffs are not rendered by default.

src/main/resources/application.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mantis {
2-
# Identifier used when connecting to other clients
3-
client-id = "mantis"
2+
# Optionally augment the client ID sent in Hello messages.
3+
client-identity = null
44

55
# Version string (reported by an RPC method)
66
client-version = "mantis/v2.0"

src/main/scala/io/iohk/ethereum/utils/Config.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ object Config {
2323

2424
val testmode: Boolean = config.getBoolean("testmode")
2525

26-
val clientId: String = config.getString("client-id")
26+
val clientId: String =
27+
VersionInfo.nodeName(ConfigUtils.getOptionalValue(config, _.getString, "client-identity"))
2728

2829
val clientVersion: String = config.getString("client-version")
2930

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.iohk.ethereum.utils
2+
3+
object VersionInfo {
4+
5+
/** Produce a node name that get sent in `WireProtocol.Hello.clientId` according to Ethereum conventions.
6+
*
7+
* Check out examples on https://etcnodes.org
8+
*
9+
* e.g.
10+
* - mantis/v3.0-cd5ae33/linux-amd64/ubuntu-openjdk64bitservervm-java-11.0.9
11+
* - besu/v20.10.0/linux-x86_64/oracle_openjdk-java-11
12+
* - coregeth/v1.11.8-stable-305b5089/linux-amd64/go1.14.4
13+
*
14+
* Apparently ethstats expects either 4 parts or 5:
15+
* - client/version/os/compiler
16+
* - client/identity/version/os/compiler
17+
*/
18+
def nodeName(maybeIdentity: Option[String] = None): String = {
19+
val app = {
20+
val name = BuildInfo.name
21+
val id = maybeIdentity.map("/" + _).getOrElse("")
22+
s"$name$id"
23+
}
24+
val version = {
25+
val version = BuildInfo.version
26+
val commit = BuildInfo.gitHeadCommit.map("-" + _.take(7)).getOrElse("")
27+
s"v$version$commit"
28+
}
29+
val os = {
30+
val name = norm(prop("os.name"))
31+
val arch = norm(prop("os.arch"))
32+
s"$name-$arch"
33+
}
34+
val vm = {
35+
val vendor = norm(prop("java.vendor"))
36+
val vmName = norm(prop("java.vm.name"))
37+
val version = prop("java.version")
38+
s"$vendor-$vmName-java-$version"
39+
}
40+
s"$app/$version/$os/$vm"
41+
}
42+
43+
private def prop(name: String) =
44+
System.getProperty(name)
45+
46+
private def norm(value: String) =
47+
value.toLowerCase.replaceAll("[^a-z0-9]+", "")
48+
}

src/test/resources/application.conf

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
mantis {
22

3-
client-id = "mantis"
4-
53
datadir = "/tmp/mantis-test/"
64

75
secure-random-algo = "NativePRNGNonBlocking"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.iohk.ethereum.utils
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
6+
class ConfigSpec extends AnyFlatSpec with Matchers {
7+
"clientId" should "by default come from VersionInfo" in {
8+
Config.clientId shouldBe VersionInfo.nodeName()
9+
}
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.iohk.ethereum.utils
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
6+
class VersionInfoSpec extends AnyFlatSpec with Matchers {
7+
behavior of "nodeName"
8+
9+
it should "match ethstats expected structure and preserve major and minor Java version" in {
10+
VersionInfo.nodeName() should fullyMatch regex """mantis/v\d(\.\d+)*-[a-z0-9]{7}/[^/]+-[^/]+/[^/]+-.[^/]+-java-\d+\.\d+[._0-9]*"""
11+
}
12+
13+
it should "augment the name with an identity" in {
14+
val name = VersionInfo.nodeName(Some("iohk"))
15+
name should startWith("mantis/iohk/v")
16+
name.count(_ == '/') shouldBe 4
17+
}
18+
}

0 commit comments

Comments
 (0)