From d61032b977b18cc962cdb23e7a3df7386e503e09 Mon Sep 17 00:00:00 2001
From: nprt <nikola.djoric@parity.io>
Date: Mon, 17 Feb 2025 18:50:46 +0100
Subject: [PATCH] implement web3_clientVersion (#7580)

Implements the `web3_clientVersion` method. This is a common requirement
for external Ethereum libraries when querying a client.

Fixes paritytech/contract-issues#26.

---------

Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
 Cargo.lock                                    | 34 ++++++++++++--
 prdoc/pr_7580.prdoc                           | 10 +++++
 substrate/frame/revive/rpc/Cargo.toml         |  3 ++
 substrate/frame/revive/rpc/build.rs           | 44 +++++++++++++++++++
 .../revive/rpc/src/apis/execution_apis.rs     |  4 ++
 substrate/frame/revive/rpc/src/lib.rs         |  7 +++
 6 files changed, 98 insertions(+), 4 deletions(-)
 create mode 100644 prdoc/pr_7580.prdoc
 create mode 100644 substrate/frame/revive/rpc/build.rs

diff --git a/Cargo.lock b/Cargo.lock
index 6ad92da6958..d33bf6464a4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8187,6 +8187,19 @@ dependencies = [
  "stable_deref_trait",
 ]
 
+[[package]]
+name = "git2"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fda788993cc341f69012feba8bf45c0ba4f3291fcc08e214b4d5a7332d88aff"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+ "libgit2-sys",
+ "log",
+ "url",
+]
+
 [[package]]
 name = "glob"
 version = "0.3.1"
@@ -8729,7 +8742,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2 0.4.9",
+ "socket2 0.5.7",
  "tokio",
  "tower-service",
  "tracing",
@@ -9833,6 +9846,18 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "libgit2-sys"
+version = "0.18.0+1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1a117465e7e1597e8febea8bb0c410f1c7fb93b1e1cddf34363f8390367ffec"
+dependencies = [
+ "cc",
+ "libc",
+ "libz-sys",
+ "pkg-config",
+]
+
 [[package]]
 name = "libloading"
 version = "0.7.4"
@@ -14955,6 +14980,7 @@ dependencies = [
  "env_logger 0.11.3",
  "ethabi",
  "futures",
+ "git2",
  "hex",
  "jsonrpsee",
  "log",
@@ -16475,7 +16501,7 @@ checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9"
 dependencies = [
  "bitcoin_hashes 0.13.0",
  "rand",
- "rand_core 0.5.1",
+ "rand_core 0.6.4",
  "serde",
  "unicode-normalization",
 ]
@@ -20737,7 +20763,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
 dependencies = [
  "bytes",
  "heck 0.5.0",
- "itertools 0.12.1",
+ "itertools 0.13.0",
  "log",
  "multimap",
  "once_cell",
@@ -20783,7 +20809,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac"
 dependencies = [
  "anyhow",
- "itertools 0.12.1",
+ "itertools 0.13.0",
  "proc-macro2 1.0.93",
  "quote 1.0.38",
  "syn 2.0.98",
diff --git a/prdoc/pr_7580.prdoc b/prdoc/pr_7580.prdoc
new file mode 100644
index 00000000000..ba041355506
--- /dev/null
+++ b/prdoc/pr_7580.prdoc
@@ -0,0 +1,10 @@
+title: implement web3_clientVersion
+doc:
+- audience: Runtime Dev
+  description: |-
+    Implements the `web3_clientVersion`  method. This is a common requirement for external Ethereum libraries when querying a client.
+
+    Reference issue with more details: https://github.com/paritytech/contract-issues/issues/26.
+crates:
+- name: pallet-revive-eth-rpc
+  bump: minor
diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml
index b207a6041b9..33d447e67a2 100644
--- a/substrate/frame/revive/rpc/Cargo.toml
+++ b/substrate/frame/revive/rpc/Cargo.toml
@@ -75,3 +75,6 @@ pretty_assertions = { workspace = true }
 static_init = { workspace = true }
 substrate-cli-test-utils = { workspace = true }
 subxt-signer = { workspace = true, features = ["unstable-eth"] }
+
+[build-dependencies]
+git2 = { version = "0.20.0", default-features = false }
diff --git a/substrate/frame/revive/rpc/build.rs b/substrate/frame/revive/rpc/build.rs
new file mode 100644
index 00000000000..d2ea601211a
--- /dev/null
+++ b/substrate/frame/revive/rpc/build.rs
@@ -0,0 +1,44 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use std::process::Command;
+
+/// Get the current branch and commit hash.
+fn main() {
+	let output = Command::new("rustc")
+		.arg("--version")
+		.output()
+		.expect("cannot get the current rustc version");
+	// Exports the default rustc --version output:
+	// e.g. rustc 1.83.0 (90b35a623 2024-11-26)
+	// into the usual Ethereum web3_clientVersion format
+	// e.g. rustc1.83.0
+	let rustc_version = String::from_utf8_lossy(&output.stdout)
+		.split_whitespace()
+		.take(2)
+		.collect::<Vec<_>>()
+		.join("");
+	let target = std::env::var("TARGET").unwrap_or_else(|_| "unknown".to_string());
+
+	let repo = git2::Repository::open("../../../..").expect("should be a repository");
+	let head = repo.head().expect("should have head");
+	let commit = head.peel_to_commit().expect("should have commit");
+	let branch = head.shorthand().unwrap_or("unknown").to_string();
+	let id = &commit.id().to_string()[..7];
+	println!("cargo:rustc-env=GIT_REVISION={branch}-{id}");
+	println!("cargo:rustc-env=RUSTC_VERSION={rustc_version}");
+	println!("cargo:rustc-env=TARGET={target}");
+}
diff --git a/substrate/frame/revive/rpc/src/apis/execution_apis.rs b/substrate/frame/revive/rpc/src/apis/execution_apis.rs
index f55209fce58..b867e8acf30 100644
--- a/substrate/frame/revive/rpc/src/apis/execution_apis.rs
+++ b/substrate/frame/revive/rpc/src/apis/execution_apis.rs
@@ -166,4 +166,8 @@ pub trait EthRpc {
 	/// The string value of current network id
 	#[method(name = "net_version")]
 	async fn net_version(&self) -> RpcResult<String>;
+
+	/// The string value of the current client version
+	#[method(name = "web3_clientVersion")]
+	async fn web3_client_version(&self) -> RpcResult<String>;
 }
diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs
index 8d6797722d4..31af6a5bbb0 100644
--- a/substrate/frame/revive/rpc/src/lib.rs
+++ b/substrate/frame/revive/rpc/src/lib.rs
@@ -352,4 +352,11 @@ impl EthRpcServer for EthRpcServerImpl {
 		let nonce = self.client.nonce(address, block).await?;
 		Ok(nonce)
 	}
+
+	async fn web3_client_version(&self) -> RpcResult<String> {
+		let git_revision = env!("GIT_REVISION");
+		let rustc_version = env!("RUSTC_VERSION");
+		let target = env!("TARGET");
+		Ok(format!("eth-rpc/{git_revision}/{target}/{rustc_version}"))
+	}
 }
-- 
GitLab