Client Versions
Analysis of consensus client versions connected to Xatu nodes on Ethereum mainnet.
Show code
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from loaders import load_parquet
Show code
# Load pre-aggregated data
df_hourly = load_parquet("client_hourly", target_date)
df_versions = load_parquet("client_version_dist", target_date)
df_summary = load_parquet("client_summary", target_date)
# Filter out unknown clients for visualizations
df_hourly_known = df_hourly[df_hourly["client"] != "unknown"]
df_versions_known = df_versions[df_versions["client"] != "unknown"]
df_summary_known = df_summary[df_summary["client"] != "unknown"]
# Compute totals from hourly data
total_connections = df_hourly["connections"].sum()
impl_counts = df_hourly_known.groupby("client")["connections"].sum().reset_index()
impl_counts = impl_counts.sort_values("connections", ascending=False)
print(f"Total connections: {total_connections:,}")
print(f"Unique clients: {df_summary['client'].nunique()}")
print(f"Total unique peers: {df_summary['unique_peers'].sum():,}")
Client Implementation Distribution¶
Distribution of consensus client implementations observed across all connections. This shows the diversity of the Ethereum validator client ecosystem.
Show code
fig = px.pie(
impl_counts,
values="connections",
names="client",
title="Client Implementation Distribution",
color_discrete_sequence=px.colors.qualitative.Set2,
)
fig.update_traces(textposition="inside", textinfo="percent+label")
fig.update_layout(height=500)
fig.show()
Connections by Client Implementation¶
Bar chart showing the number of connections per client implementation.
Show code
fig = px.bar(
impl_counts,
x="client",
y="connections",
title="Connections by Client Implementation",
labels={"client": "Client", "connections": "Connections"},
color="client",
color_discrete_sequence=px.colors.qualitative.Set2,
)
fig.update_layout(
showlegend=False,
height=500,
xaxis_tickangle=-45,
)
fig.show()
Client Connections Over Time¶
Stacked area chart showing how client connections are distributed across implementations over time.
Show code
# Pivot hourly data for stacked area chart
hourly_pivot = df_hourly_known.pivot(index="hour", columns="client", values="connections").fillna(0)
fig = go.Figure()
for col in hourly_pivot.columns:
fig.add_trace(go.Scatter(
x=hourly_pivot.index,
y=hourly_pivot[col],
mode="lines",
stackgroup="one",
name=col,
))
fig.update_layout(
title="Client Implementation Connections Over Time",
xaxis_title="Time",
yaxis_title="Connections",
height=500,
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
)
fig.show()
Version Distribution by Client¶
Detailed breakdown of version distribution for each major client implementation (top 15 versions per client).
Show code
# Get clients sorted by total connections (exclude "Others" and "unknown")
top_clients = impl_counts[~impl_counts["client"].isin(["Others", "unknown"])]["client"].tolist()
for i, client in enumerate(top_clients):
df_client = df_versions_known[df_versions_known["client"] == client]
if len(df_client) == 0:
continue
fig = px.bar(
df_client,
x="version",
y="connections",
title=f"{client.capitalize()} Version Distribution",
labels={"version": "Version", "connections": "Connections"},
color_discrete_sequence=[px.colors.qualitative.Set2[i % len(px.colors.qualitative.Set2)]],
)
fig.update_layout(
height=400,
xaxis_tickangle=-45,
)
fig.show()
Summary Statistics¶
Show code
# Format summary table
summary_display = df_summary_known[["client", "connections", "unique_peers", "version_count", "top_version"]].copy()
summary_display.columns = ["Client", "Connections", "Unique Peers", "Versions", "Top Version"]
summary_display = summary_display.sort_values("Connections", ascending=False)
summary_display["Connections"] = summary_display["Connections"].apply(lambda x: f"{x:,}")
summary_display["Unique Peers"] = summary_display["Unique Peers"].apply(lambda x: f"{x:,}")
summary_display