Skip to content

Client diversity piechart update #15251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 36 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4bb1a87
Created React PieChart component
LifeofDan-EL Apr 7, 2025
11827ed
Merge branch 'ethereum:dev' into client-diversity
LifeofDan-EL Apr 7, 2025
1553d14
Testing to see if the chart works, before removing and updating the d…
LifeofDan-EL Apr 7, 2025
fb4c103
Merge branch 'client-diversity' of https://github.com/LifeofDan-EL/et…
LifeofDan-EL Apr 7, 2025
84292b1
Fix lint errors
LifeofDan-EL Apr 7, 2025
480a1e1
Fix lint errors
LifeofDan-EL Apr 7, 2025
45761c8
Changed import way for the PieChart
LifeofDan-EL Apr 8, 2025
0c8ac7c
Revert yarn.lock and .env.example to match upstream/dev
LifeofDan-EL Apr 8, 2025
99615fa
Merge branch 'ethereum:dev' into client-diversity
LifeofDan-EL Apr 8, 2025
202418c
Improved PieChart
LifeofDan-EL Apr 8, 2025
f8d0a70
Fixing import issue
LifeofDan-EL Apr 8, 2025
171eefa
Slight improvement on the PieChart
LifeofDan-EL Apr 8, 2025
f689074
Merge branch 'ethereum:dev' into client-diversity
LifeofDan-EL Apr 11, 2025
1ce8c30
Delete .yarnrc.yml
LifeofDan-EL Apr 11, 2025
73091d9
Delete .yarn directory
LifeofDan-EL Apr 11, 2025
1f0116e
Updated styling to use color palette
LifeofDan-EL Apr 11, 2025
cbe8b2e
Changed to accent colors
LifeofDan-EL Apr 12, 2025
7cfd42c
Remove sticking out label, then attaching the percentage value to the…
LifeofDan-EL Apr 12, 2025
352ed27
Trying to fix payload issue
LifeofDan-EL Apr 12, 2025
c57d2c2
Added ResponsiveContainer to PieChart
LifeofDan-EL Apr 16, 2025
8c7ad14
Working on responsiveness
LifeofDan-EL Apr 16, 2025
c112033
Working on responsiveness
LifeofDan-EL Apr 16, 2025
a6b359b
Working on responsiveness
LifeofDan-EL Apr 16, 2025
57ec8f0
Working on responsiveness
LifeofDan-EL Apr 16, 2025
8ffc3da
Working on responsiveness
LifeofDan-EL Apr 16, 2025
7e6926d
Working on responsiveness
LifeofDan-EL Apr 16, 2025
ce7e234
Working on responsiveness
LifeofDan-EL Apr 16, 2025
d8b85c6
Still working on it
LifeofDan-EL Apr 16, 2025
64c2c57
Working on responsiveness
LifeofDan-EL Apr 16, 2025
d2b2910
Working on responsiveness
LifeofDan-EL Apr 16, 2025
003b4d0
Testing for responsiveness
LifeofDan-EL Apr 16, 2025
b697fe3
Updated content
LifeofDan-EL Apr 18, 2025
e0d3b85
Merge branch 'ethereum:dev' into client-diversity
LifeofDan-EL Apr 18, 2025
9724d25
Formatted footnote better
LifeofDan-EL Apr 18, 2025
dfdfc39
Merge branch 'client-diversity' of https://github.com/LifeofDan-EL/et…
LifeofDan-EL Apr 18, 2025
8273f9f
Working on footnote issue
LifeofDan-EL Apr 18, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,51 @@ Although these are unlikely scenarios, the Ethereum eco-system can mitigate thei

There is also a human cost to having majority clients. It puts excess strain and responsibility on a small development team. The lesser the client diversity, the greater the burden of responsibility for the developers maintaining the majority client. Spreading this responsibility across multiple teams is good for both the health of Ethereum's network of nodes and its network of people.

## Current client diversity {#current-client-diversity}

![Pie chart showing client diversity](./client-diversity.png)
_Diagram data from [ethernodes.org](https://ethernodes.org) and [clientdiversity.org](https://clientdiversity.org/)_

The two pie charts above show snapshots of the current client diversity for the execution and consensus layers (at time of writing in January 2022). The execution layer is overwhelmingly dominated by [Geth](https://geth.ethereum.org/), with [Open Ethereum](https://openethereum.github.io/) a distant second, [Erigon](https://github.com/ledgerwatch/erigon) third and [Nethermind](https://nethermind.io/) fourth, with other clients comprising less than 1 % of the network. The most commonly used client on the consensus layer - [Prysm](https://prysmaticlabs.com/#projects) - is not as dominant as Geth but still represents over 60% of the network. [Lighthouse](https://lighthouse.sigmaprime.io/) and [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) make up ~20% and ~14% respectively, and other clients are rarely used.

The execution layer data were obtained from [Ethernodes](https://ethernodes.org) on 23-Jan-2022. Data for consensus clients was obtained from [Michael Sproul](https://github.com/sigp/blockprint). Consensus client data is more difficult to obtain because the consensus layer clients do not always have unambiguous traces that can be used to identify them. The data was generated using a classification algorithm that sometimes confuses some of the minority clients (see [here](https://twitter.com/sproulM_/status/1440512518242197516) for more details). In the diagram above, these ambiguous classifications are treated with an either/or label (e.g. Nimbus/Teku). Nevertheless, it is clear that the majority of the network is running Prysm. The data is a snapshot over a fixed set of blocks (in this case Beacon blocks in slots 2048001 to 2164916) and Prysm's dominance has sometimes been higher, exceeding 68%. Despite only being snapshots, the values in the diagram provide a good general sense of the current state of client diversity.
### Current client diversity {#current-client-diversity}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 items-start mt-6">
<div className="flex justify-center">
<PieChart
data={[
{ name: "Geth", value: 41 },
{ name: "Nethermind", value: 38 },
{ name: "Besu", value: 16 },
{ name: "Erigon", value: 3 },
{ name: "Reth", value: 2 },
{ name: "Other", value: 0 },
]}
title="Execution Clients"
/>
</div>
<div className="flex justify-center">
<PieChart
data={[
{ name: "Prysm", value: 36.09 },
{ name: "Lighthouse", value: 34.06},
{ name: "Teku", value: 21.47 },
{ name: "Nimbus", value: 4.85 },
{ name: "Grandine", value: 1.97 },
{ name: "Lodestar", value: 1.57 },
{ name: "Others", value: 0.0 },
]}
title="Consensus Clients"
/>
</div>
</div>

<div className="mt-8 prose prose-sm">
_This diagram may be outdated — go to [ethernodes.org](https://ethernodes.org) and [clientdiversity.org](https://clientdiversity.org/) for up‑to‑date information._
</div>


The two pie charts above show snapshots of the current client diversity for the execution and consensus layers (at time of writing in April 2025). Client diversity has improved over the years, and the execution layer has seen a reduction in the domination by [Geth](https://geth.ethereum.org/), with [Nethermind](https://www.nethermind.io/nethermind-client) a close second, [Besu](https://besu.hyperledger.org/) third and [Erigon](https://github.com/ledgerwatch/erigon) fourth, with other clients comprising less than 3 % of the network. The most commonly used client on the consensus layer - [Prysm](https://prysmaticlabs.com/#projects) - is quite close with the second most used. [Lighthouse](https://lighthouse.sigmaprime.io/) and [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) make up ~34% and ~21% respectively, and other clients are rarely used.

The execution layer data were obtained from [supermajority.info](https://supermajority.info/) on 18-Apr-2025. Data for consensus clients was obtained from [Michael Sproul](https://github.com/sigp/blockprint). Consensus client data is more difficult to obtain because the consensus layer clients do not always have unambiguous traces that can be used to identify them. The data was generated using a classification algorithm that sometimes confuses some of the minority clients (see [here](https://twitter.com/sproulM_/status/1440512518242197516) for more details). In the diagram above, these ambiguous classifications are treated with an either/or label (e.g. Nimbus/Teku). Nevertheless, it is clear that the majority of the network is running Prysm. Despite only being snapshots, the values in the diagram provide a good general sense of the current state of client diversity.

Up to date client diversity data for the consensus layer is now available at [clientdiversity.org](https://clientdiversity.org/).

## Execution layer {#execution-layer}

Until now, the conversation around client diversity has focused mainly on the consensus layer. However, the execution client [Geth](https://geth.ethereum.org) currently accounts for around 85% of all nodes. This percentage is problematic for the same reasons as for consensus clients. For example, a bug in Geth affecting transaction handling or constructing execution payloads could lead to consensus clients finalizing problematic or bugged transactions. Therefore, Ethereum would be healthier with a more even distribution of execution clients, ideally with no client representing more than 33% of the network.
Until now, the conversation around client diversity has focused mainly on the consensus layer. However, the execution client [Geth](https://geth.ethereum.org) currently accounts for around 41% of all nodes. This percentage is problematic for the same reasons as for consensus clients. For example, a bug in Geth affecting transaction handling or constructing execution payloads could lead to consensus clients finalizing problematic or bugged transactions. Therefore, Ethereum would be healthier with a more even distribution of execution clients, ideally with no client representing more than 33% of the network.

## Use a minority client {#use-minority-client}

Expand All @@ -66,6 +97,8 @@ Addressing client diversity requires more than individual users to choose minori

[Erigon](https://github.com/ledgerwatch/erigon)

[Reth](https://github.com/paradigmxyz/reth)

[Go-Ethereum](https://geth.ethereum.org/)

### Consensus clients {#consensus-clients}
Expand Down
2 changes: 2 additions & 0 deletions src/components/MdComponents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ChildOnlyProp } from "@/lib/types"

import Contributors from "@/components/Contributors"
import MarkdownImage from "@/components/MarkdownImage"
import { PieChart } from "@/components/PieChart"
import TooltipLink from "@/components/TooltipLink"
import YouTube from "@/components/YouTube"

Expand Down Expand Up @@ -166,6 +167,7 @@ export const reactComponents = {
GlossaryTooltip,
InfoBanner,
Page,
PieChart,
QuizWidget: StandaloneQuizWidget,
IssuesList,
Tag,
Expand Down
150 changes: 150 additions & 0 deletions src/components/PieChart/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"use client";

import { FaArrowTrendUp } from "react-icons/fa6";
import {
Cell,
Legend,
Pie,
PieChart as RechartsPieChart,
ResponsiveContainer,
} from "recharts";

import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";

type PieChartDataPoint = { name: string; value: number };

/**
* PieChartProps defines the properties for the PieChart component.
*
* @property {PieChartDataPoint[]} data - The data to be displayed in the chart. Each object should have a `name` and `value` property.
* @property {string} [title] - The title of the chart.
* @property {string} [description] - The description of the chart.
* @property {string} [footerText] - The footer text of the chart.
* @property {string} [footerSubText] - The footer subtext of the chart.
*/
type PieChartProps = {
data: PieChartDataPoint[];
title?: string;
description?: string;
footerText?: string;
footerSubText?: string;
};

const defaultChartConfig = {
value: {
label: "Value",
color: "hsl(var(--accent-a))",
},
} satisfies ChartConfig;

const COLORS = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few issues with these colors:

  • there is not enough contrast in dark mode
  • these are not part of our current color palette

This is the current colors that we have https://dev--63b7ea99632763723c7f4d6b.chromatic.com/?path=/story/design-system-colors--primitives

@konopkja what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I looked at the preview after deployment and I agree there isn't enough contrast. Let me use values from the colour palette.

"hsla(var(--accent-a))",
"hsla(var(--accent-b))",
"hsla(var(--accent-c))",
];
/*
PieChart component renders a pie chart with the provided data, utilizing accent colors,
and a vertical legend positioned to the right.
*/

export function PieChart({
data,
title,
description,
footerText,
footerSubText,
}: PieChartProps) {
return (
<Card className="w-full">
<CardHeader>
{title && <CardTitle className="text-center">{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
<CardContent>
<ChartContainer config={defaultChartConfig}>
<div className="w-full min-h-[350px]">
<ResponsiveContainer width="100%" height={350}>
<RechartsPieChart
margin={{ top: 10, right: 10, bottom: 10, left: 10 }}
>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent />}
/>
<Legend
layout="vertical"
verticalAlign="middle"
align="right"
wrapperStyle={{
fontSize: "0.85rem",
paddingLeft: "10px",
lineHeight: "1.8em",
maxWidth: "40%", // Control legend width
}}
formatter={(value, entry) => {
const payload =
entry.payload as unknown as PieChartDataPoint;
// Format to 2 decimal places if needed
const formattedValue = Number.isInteger(payload.value)
? payload.value
: payload.value.toFixed(2);
return `${value} (${formattedValue}%)`;
}}
/>
<Pie
data={data}
dataKey="value"
nameKey="name"
cx="35%"
cy="50%"
outerRadius={75}
innerRadius={0}
paddingAngle={1}
label={false}
>
{data.map((_, index) => (
<Cell
key={`cell-${index}`}
fill={COLORS[index % COLORS.length]}
/>
))}
</Pie>
</RechartsPieChart>
</ResponsiveContainer>
</div>
</ChartContainer>
</CardContent>
{(footerText || footerSubText) && (
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
{footerText && (
<div className="flex items-center gap-2 font-medium leading-none">
{footerText} <FaArrowTrendUp className="h-4 w-4" />
</div>
)}
{footerSubText && (
<div className="text-muted-foreground flex items-center gap-2 leading-none">
{footerSubText}
</div>
)}
</div>
</div>
</CardFooter>
)}
</Card>
);
}