Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Ethrex Changelog

## Observability

### 2026-05-27

- Add BAL (EIP-7928) Prometheus instruments (`bal_blocks_total`, `bal_size_bytes`, `bal_size_bytes_histogram`, `bal_account_count`, `bal_slot_count`) and a BAL row in the `ethrex_l1_perf` Grafana dashboard [#6678](https://github.com/lambdaclass/ethrex/pull/6678)

## Perf

### 2026-05-19
Expand Down
13 changes: 13 additions & 0 deletions crates/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ use tokio_util::sync::CancellationToken;

use vm::StoreVmDatabase;

#[cfg(feature = "metrics")]
use ethrex_metrics::bal::METRICS_BAL;
#[cfg(feature = "metrics")]
use ethrex_metrics::blocks::METRICS_BLOCKS;

Expand Down Expand Up @@ -1980,6 +1982,17 @@ impl Blockchain {
);
}

metrics!(if let Some(bal_ref) = produced_bal.as_ref().or(bal) {
let account_count = bal_ref.accounts().len() as u64;
let slot_count = bal_ref.item_count().saturating_sub(account_count);
let size_bytes = bal_ref.length() as f64;
METRICS_BAL.blocks_total.inc();
METRICS_BAL.size_bytes.set(size_bytes);
METRICS_BAL.size_bytes_histogram.observe(size_bytes);
METRICS_BAL.account_count.set(account_count as i64);
METRICS_BAL.slot_count.set(slot_count as i64);
});

Ok((produced_bal, result))
}

Expand Down
76 changes: 76 additions & 0 deletions crates/blockchain/metrics/bal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use prometheus::{
Gauge, Histogram, IntCounter, IntGauge, register_gauge, register_histogram,
register_int_counter, register_int_gauge,
};
use std::sync::LazyLock;

// Metrics defined in this module register into the Prometheus default registry.
// The metrics API exposes them via `gather_default_metrics()`.

pub static METRICS_BAL: LazyLock<MetricsBal> = LazyLock::new(MetricsBal::default);

// Histogram bucket layout for RLP-encoded BAL sizes: 1 KiB base, doubling, 16
// buckets -> 1 KiB, 2 KiB, 4 KiB, ..., 32 MiB. Observed sizes are always >= 1
// byte (the smallest BAL RLP-encodes to a non-empty list), so there is no zero
// floor bucket.
const BAL_SIZE_BUCKET_START_BYTES: f64 = 1024.0;
const BAL_SIZE_BUCKET_FACTOR: f64 = 2.0;
const BAL_SIZE_BUCKET_COUNT: usize = 16;

#[derive(Debug, Clone)]
pub struct MetricsBal {
/// Cumulative count of BAL-carrying blocks processed (post-Amsterdam).
pub blocks_total: IntCounter,
/// RLP-encoded size of the most recent BAL, in bytes (per-block snapshot).
pub size_bytes: Gauge,
/// Distribution of RLP-encoded BAL sizes in bytes.
pub size_bytes_histogram: Histogram,
/// Number of accounts in the most recent BAL (per-block snapshot).
pub account_count: IntGauge,
/// Unique storage slots (writes + reads) in the most recent BAL (per-block snapshot).
pub slot_count: IntGauge,
}

impl Default for MetricsBal {
fn default() -> Self {
Self::new()
}
}

impl MetricsBal {
pub fn new() -> Self {
MetricsBal {
blocks_total: register_int_counter!(
"bal_blocks_total",
"Cumulative count of Block Access List (EIP-7928) carrying blocks processed"
)
.expect("Failed to create bal_blocks_total metric"),
size_bytes: register_gauge!(
"bal_size_bytes",
"RLP-encoded size of the most recent Block Access List, in bytes"
)
.expect("Failed to create bal_size_bytes metric"),
size_bytes_histogram: register_histogram!(
"bal_size_bytes_histogram",
"Distribution of RLP-encoded Block Access List sizes in bytes",
prometheus::exponential_buckets(
BAL_SIZE_BUCKET_START_BYTES,
BAL_SIZE_BUCKET_FACTOR,
BAL_SIZE_BUCKET_COUNT,
)
.expect("Invalid BAL histogram bucket params")
)
.expect("Failed to create bal_size_bytes_histogram metric"),
account_count: register_int_gauge!(
"bal_account_count",
"Number of accounts in the most recent Block Access List"
)
.expect("Failed to create bal_account_count metric"),
slot_count: register_int_gauge!(
"bal_slot_count",
"Unique storage slots (writes + reads) in the most recent BAL"
)
.expect("Failed to create bal_slot_count metric"),
}
}
}
2 changes: 2 additions & 0 deletions crates/blockchain/metrics/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(feature = "api")]
pub mod api;
#[cfg(any(feature = "api", feature = "metrics"))]
pub mod bal;
#[cfg(any(feature = "api", feature = "metrics"))]
pub mod blocks;
#[cfg(feature = "api")]
pub mod l2;
Expand Down
Loading
Loading