diff --git a/Cargo.lock b/Cargo.lock index ccfeb54..5d03d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -877,6 +877,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -1497,6 +1499,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.111", +] + [[package]] name = "derive_more" version = "1.0.0" @@ -1814,6 +1847,8 @@ dependencies = [ "tokio", "tracing", "tracing-subscriber", + "vergen", + "vergen-git2", ] [[package]] @@ -2505,6 +2540,19 @@ dependencies = [ "polyval", ] +[[package]] +name = "git2" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2b37e2f62729cdada11f0e6b3b6fe383c69c29fc619e391223e12856af308c" +dependencies = [ + "bitflags 2.10.0", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "glob" version = "0.3.3" @@ -3084,6 +3132,16 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.83" @@ -3188,6 +3246,18 @@ version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +[[package]] +name = "libgit2-sys" +version = "0.18.3+1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.15" @@ -3917,6 +3987,18 @@ dependencies = [ "escape8259", ] +[[package]] +name = "libz-sys" +version = "1.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -4352,6 +4434,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "oid-registry" version = "0.8.1" @@ -4810,6 +4901,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "polling" version = "3.11.0" @@ -6282,30 +6379,32 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -6705,6 +6804,52 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vergen" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" +dependencies = [ + "anyhow", + "derive_builder", + "rustc_version 0.4.1", + "rustversion", + "time", + "vergen-lib", +] + +[[package]] +name = "vergen-git2" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51ab55ddf1188c8d679f349775362b0fa9e90bd7a4ac69838b2a087623f0d57" +dependencies = [ + "anyhow", + "derive_builder", + "git2", + "rustversion", + "time", + "vergen", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 8762fb8..fe19003 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,7 @@ ethereum_ssz = "0.8.3" ssz_types = "0.10.1" tree_hash = "0.9.1" tree_hash_derive = "0.9.1" + +# Build-time version info +vergen = { version = "9", features = ["build", "rustc"] } +vergen-git2 = "9" diff --git a/bin/ethlambda/Cargo.toml b/bin/ethlambda/Cargo.toml index 425f037..4f58e68 100644 --- a/bin/ethlambda/Cargo.toml +++ b/bin/ethlambda/Cargo.toml @@ -25,3 +25,7 @@ hex.workspace = true ethereum-types.workspace = true clap.workspace = true + +[build-dependencies] +vergen.workspace = true +vergen-git2.workspace = true diff --git a/bin/ethlambda/build.rs b/bin/ethlambda/build.rs new file mode 100644 index 0000000..9fcf812 --- /dev/null +++ b/bin/ethlambda/build.rs @@ -0,0 +1,17 @@ +use vergen::{Emitter, RustcBuilder}; +use vergen_git2::Git2Builder; + +fn main() -> Result<(), Box> { + let git2 = Git2Builder::default().branch(true).sha(true).build()?; + let rustc = RustcBuilder::default() + .semver(true) + .host_triple(true) + .build()?; + + Emitter::default() + .add_instructions(&rustc)? + .add_instructions(&git2)? + .emit()?; + + Ok(()) +} diff --git a/bin/ethlambda/src/main.rs b/bin/ethlambda/src/main.rs index f07b574..d951e45 100644 --- a/bin/ethlambda/src/main.rs +++ b/bin/ethlambda/src/main.rs @@ -1,3 +1,5 @@ +mod version; + use std::{ collections::{BTreeMap, HashMap}, net::{IpAddr, SocketAddr}, @@ -27,6 +29,7 @@ const ASCII_ART: &str = r#" "#; #[derive(Debug, clap::Parser)] +#[command(name = "ethlambda", author = "LambdaClass", version = version::CLIENT_VERSION, about = "ethlambda consensus client")] struct CliOptions { #[arg(long)] custom_network_config_dir: PathBuf, @@ -53,6 +56,10 @@ async fn main() { let options = CliOptions::parse(); + // Set node info metrics + ethlambda_blockchain::metrics::set_node_info("ethlambda", version::CLIENT_VERSION); + ethlambda_blockchain::metrics::set_node_start_time(); + let metrics_socket = SocketAddr::new(options.metrics_address, options.metrics_port); let node_p2p_key = read_hex_file_bytes(&options.node_key); let p2p_socket = SocketAddr::new(IpAddr::from([0, 0, 0, 0]), options.gossipsub_port); diff --git a/bin/ethlambda/src/version.rs b/bin/ethlambda/src/version.rs new file mode 100644 index 0000000..c2977f2 --- /dev/null +++ b/bin/ethlambda/src/version.rs @@ -0,0 +1,15 @@ +/// Client version string with git info. +/// Format: ethlambda/v0.1.0-main-892ad575.../x86_64-unknown-linux-gnu/rustc-v1.85.0 +pub const CLIENT_VERSION: &str = concat!( + env!("CARGO_PKG_NAME"), + "/v", + env!("CARGO_PKG_VERSION"), + "-", + env!("VERGEN_GIT_BRANCH"), + "-", + env!("VERGEN_GIT_SHA"), + "/", + env!("VERGEN_RUSTC_HOST_TRIPLE"), + "/rustc-v", + env!("VERGEN_RUSTC_SEMVER") +); diff --git a/crates/blockchain/src/lib.rs b/crates/blockchain/src/lib.rs index 2ebef53..419be0f 100644 --- a/crates/blockchain/src/lib.rs +++ b/crates/blockchain/src/lib.rs @@ -17,7 +17,7 @@ use tokio::sync::mpsc; use tracing::{error, info, warn}; pub mod key_manager; -mod metrics; +pub mod metrics; pub mod store; /// Messages sent from the blockchain to the P2P layer for publishing. diff --git a/crates/blockchain/src/metrics.rs b/crates/blockchain/src/metrics.rs index 43fc70d..a9ffbd1 100644 --- a/crates/blockchain/src/metrics.rs +++ b/crates/blockchain/src/metrics.rs @@ -55,3 +55,32 @@ pub fn update_safe_target_slot(slot: u64) { }); LEAN_SAFE_TARGET_SLOT.set(slot.try_into().unwrap()); } + +pub fn set_node_info(name: &str, version: &str) { + static LEAN_NODE_INFO: std::sync::LazyLock = + std::sync::LazyLock::new(|| { + prometheus::register_int_gauge_vec!( + "lean_node_info", + "Node information (always 1)", + &["name", "version"] + ) + .unwrap() + }); + LEAN_NODE_INFO.with_label_values(&[name, version]).set(1); +} + +pub fn set_node_start_time() { + static LEAN_NODE_START_TIME_SECONDS: std::sync::LazyLock = + std::sync::LazyLock::new(|| { + prometheus::register_int_gauge!( + "lean_node_start_time_seconds", + "Timestamp when node started" + ) + .unwrap() + }); + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + LEAN_NODE_START_TIME_SECONDS.set(timestamp as i64); +} diff --git a/docs/metrics.md b/docs/metrics.md index 21b8a5e..c6f28ac 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -10,8 +10,8 @@ The exposed metrics follow [the leanMetrics specification](https://github.com/le | Name | Type | Usage | Sample collection event | Labels | Supported | |--------|-------|-------|-------------------------|--------|---------------| -| `lean_node_info` | Gauge | Node information (always 1) | On node start | name, version | □ | -| `lean_node_start_time_seconds` | Gauge | Start timestamp | On node start | | □ | +| `lean_node_info` | Gauge | Node information (always 1) | On node start | name, version | ✅ | +| `lean_node_start_time_seconds` | Gauge | Start timestamp | On node start | | ✅ | ## PQ Signature Metrics @@ -32,7 +32,7 @@ The exposed metrics follow [the leanMetrics specification](https://github.com/le | Name | Type | Usage | Sample collection event | Labels | Buckets | Supported | |--------|-------|-------|-------------------------|--------|---------|-----------| | `lean_head_slot` | Gauge | Latest slot of the lean chain | On get fork choice head | | | ✅ | -| `lean_current_slot` | Gauge | Current slot of the lean chain | On scrape | | | ✅ | +| `lean_current_slot` | Gauge | Current slot of the lean chain | On scrape | | | ✅(*) | | `lean_safe_target_slot` | Gauge | Safe target slot | On safe target update | | | ✅ | |`lean_fork_choice_block_processing_time_seconds`| Histogram | Time taken to process block | On fork choice process block | | 0.005, 0.01, 0.025, 0.05, 0.1, 1 | □ | |`lean_attestations_valid_total`| Counter | Total number of valid attestations | On validate attestation | source=block,gossip | | □ | @@ -59,7 +59,7 @@ The exposed metrics follow [the leanMetrics specification](https://github.com/le | Name | Type | Usage | Sample collection event | Labels | Supported | |--------|-------|-------|-------------------------|--------|-----------| -|`lean_validators_count`| Gauge | Number of validators managed by a node | On scrape | | ✅ | +|`lean_validators_count`| Gauge | Number of validators managed by a node | On scrape | | ✅(*) | ## Network Metrics @@ -68,3 +68,7 @@ The exposed metrics follow [the leanMetrics specification](https://github.com/le |`lean_connected_peers`| Gauge | Number of connected peers | On scrape | client=lantern,qlean,ream,zeam | □ | |`lean_peer_connection_events_total`| Counter | Total number of peer connection events | On peer connection | direction=inbound,outbound
result=success,timeout,error | □ | |`lean_peer_disconnection_events_total`| Counter | Total number of peer disconnection events | On peer disconnection | direction=inbound,outbound
reason=timeout,remote_close,local_close,error | □ | + +--- + +✅(*) **Partial support**: These metrics are implemented but not collected "on scrape" as the spec requires. They are updated on specific events (e.g., on tick, on block processing) rather than being computed fresh on each Prometheus scrape.