{
    "version": "https://jsonfeed.org/version/1",
    "title": "StereumLabs Docs Blog",
    "home_page_url": "https://docs.stereumlabs.com/blog",
    "description": "Neutral, hardware-backed measurements of Ethereum execution and consensus clients.",
    "items": [
        {
            "id": "https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack",
            "content_html": "<p>Ethereum runs on two layers: an <strong>execution client</strong> (EC) handles the EVM, transactions, and world state, and a <strong>consensus client</strong> (CC) handles Proof-of-Stake fork choice and validator duties. Six EC implementations and seven CC implementations exist in production today, paired in dozens of combinations across the network. StereumLabs runs all of them, side by side, on identical hardware in our Vienna data center, and publishes the numbers.</p>\n<p>This post is the technical introduction to that platform: the bare-metal fleet, the metrics and logs pipeline, the label conventions that make the pairings comparable, and the in-house AI workflow that turns the resulting telemetry into the blog posts you are reading.</p>\n<p>RockLogic publishes <a href=\"https://rocklogic.at/de/cases/ai-on-own-data\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">a separate case study</a> on the business side of this workflow: how the same \"AI on own data\" pattern keeps customer telemetry inside the perimeter while still producing useful answers. This post is the technical view from the other side of the same workflow.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Inside the StereumLabs stack: how we measure Ethereum clients from bare metal up\" src=\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDkwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxtYXJrZXIgaWQ9ImFycm93LXRodW1iIiB2aWV3Qm94PSIwIDAgMTAgMTAiIHJlZlg9IjkiIHJlZlk9IjUiIG1hcmtlcldpZHRoPSI2IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+CiAgICAgIDxwYXRoIGQ9Ik0gMCAwIEwgMTAgNSBMIDAgMTAgeiIgZmlsbD0iI2E1YjRjZiIvPgogICAgPC9tYXJrZXI+CiAgPC9kZWZzPgoKICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9IiMwZTE1MzAiLz4KICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9InVybCgjZ3JpZCkiLz4KCiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjE2MDAiIGhlaWdodD0iMTQiIGZpbGw9IiM1MDQ2ZTUiLz4KCiAgPHRleHQgeD0iMTAwIiB5PSIxMDAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMzIiIGZvbnQtd2VpZ2h0PSI2MDAiIGxldHRlci1zcGFjaW5nPSIwIj5TdGVyZXVtTGFiczwvdGV4dD4KCiAgPHRleHQgeD0iODAwIiB5PSIzMzAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMTEwIiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBsZXR0ZXItc3BhY2luZz0iLTMiPkluc2lkZSB0aGUgc3RhY2s8L3RleHQ+CgogIDx0ZXh0IHg9IjgwMCIgeT0iNDA1IiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjM0IiBmb250LXdlaWdodD0iNDAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5Ib3cgd2UgbWVhc3VyZSBFdGhlcmV1bSBjbGllbnRzPC90ZXh0PgogIDx0ZXh0IHg9IjgwMCIgeT0iNDU1IiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjM0IiBmb250LXdlaWdodD0iNDAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5mcm9tIGJhcmUgbWV0YWwgdXA8L3RleHQ+CgogIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsIDY0MCkiPgogICAgPHJlY3QgeD0iMTgwIiB5PSIwIiB3aWR0aD0iMjYwIiBoZWlnaHQ9IjkwIiByeD0iNiIgZmlsbD0iIzRmNDZlNSIgc3Ryb2tlPSIjODE4Y2Y4IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHRleHQgeD0iMzEwIiB5PSI0OCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QmFyZSBtZXRhbDwvdGV4dD4KICAgIDx0ZXh0IHg9IjMxMCIgeT0iNzQiIGZpbGw9IiNjN2QyZmUiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkVQWUMgOTY1NFAgwrcgTkRDMjwvdGV4dD4KCiAgICA8cGF0aCBkPSJNIDQ1NSA0NSBMIDQ4NSA0NSIgc3Ryb2tlPSIjYTViNGNmIiBzdHJva2Utd2lkdGg9IjIiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctdGh1bWIpIi8+CgogICAgPHJlY3QgeD0iNTAwIiB5PSIwIiB3aWR0aD0iMjYwIiBoZWlnaHQ9IjkwIiByeD0iNiIgZmlsbD0iI2MyNDEwYyIgc3Ryb2tlPSIjZmI5MjNjIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHRleHQgeD0iNjMwIiB5PSI0OCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+UHJvbWV0aGV1cyArIEVTPC90ZXh0PgogICAgPHRleHQgeD0iNjMwIiB5PSI3NCIgZmlsbD0iI2ZlZDdhYSIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MTVzIHNjcmFwZSDCtyBmdWxsIHJldGVudGlvbjwvdGV4dD4KCiAgICA8cGF0aCBkPSJNIDc3NSA0NSBMIDgwNSA0NSIgc3Ryb2tlPSIjYTViNGNmIiBzdHJva2Utd2lkdGg9IjIiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctdGh1bWIpIi8+CgogICAgPHJlY3QgeD0iODIwIiB5PSIwIiB3aWR0aD0iMjYwIiBoZWlnaHQ9IjkwIiByeD0iNiIgZmlsbD0iIzEwYjk4MSIgc3Ryb2tlPSIjMzRkMzk5IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHRleHQgeD0iOTUwIiB5PSI0OCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+R3JhZmFuYTwvdGV4dD4KICAgIDx0ZXh0IHg9Ijk1MCIgeT0iNzQiIGZpbGw9IiNhN2YzZDAiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmxhYmVsbGVkLCBjb21wYXJhYmxlPC90ZXh0PgoKICAgIDxwYXRoIGQ9Ik0gMTA5NSA0NSBMIDExMjUgNDUiIHN0cm9rZT0iI2E1YjRjZiIgc3Ryb2tlLXdpZHRoPSIyIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LXRodW1iKSIvPgoKICAgIDxyZWN0IHg9IjExNDAiIHk9IjAiIHdpZHRoPSIyNjAiIGhlaWdodD0iOTAiIHJ4PSI2IiBmaWxsPSIjN2MzYWVkIiBzdHJva2U9IiNhNzhiZmEiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgICA8dGV4dCB4PSIxMjcwIiB5PSI0OCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Q2xhdWRlICsgTUNQPC90ZXh0PgogICAgPHRleHQgeD0iMTI3MCIgeT0iNzQiIGZpbGw9IiNkZGQ2ZmUiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmRyYWZ0cyB0aGlzIGJsb2c8L3RleHQ+CiAgPC9nPgoKICA8dGV4dCB4PSIxMDAiIHk9Ijg0NSIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIyMiI+Um9ja0xvZ2ljIEdtYkg8L3RleHQ+CiAgPHRleHQgeD0iMTUwMCIgeT0iODQ1IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjIyIiB0ZXh0LWFuY2hvcj0iZW5kIj5kb2NzLnN0ZXJldW1sYWJzLmNvbTwvdGV4dD4KPC9zdmc+Cg==\" width=\"1600\" height=\"900\" class=\"img_ev3q\"></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-measurement-question\">The measurement question<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#the-measurement-question\" class=\"hash-link\" aria-label=\"Direct link to The measurement question\" title=\"Direct link to The measurement question\" translate=\"no\">​</a></h2>\n<p>Every Ethereum client team publishes their own benchmarks. Every cloud provider publishes their own reference architectures. Every node operator has a folder of opinions. What is rarer is a fleet where all six execution clients and all seven consensus clients run on <strong>identical hardware, identical scenarios, identical scrape cadence, and identical label conventions</strong>, with the raw data kept long enough to ask new questions about old runs.</p>\n<p>StereumLabs exists to fill that gap. The technical choices below are not the only ones that could work, but they are the ones that keep comparability cheap, reproducibility verifiable, and post-hoc questions answerable without re-running anything.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-hardware-base\">The hardware base<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#the-hardware-base\" class=\"hash-link\" aria-label=\"Direct link to The hardware base\" title=\"Direct link to The hardware base\" translate=\"no\">​</a></h2>\n<p>The bare-metal anchor lives in our Vienna NDC2 data center, run end-to-end by RockLogic. Bare metal cuts out three moving parts that contaminate cloud measurements: instance families that change underneath you, noisy neighbours that blur tail latencies, and IOPS guarantees that come with footnotes. For a measurement product, all three are problems we prefer not to have.</p>\n<table><thead><tr><th>Component</th><th>Detail</th><th>Why it matters</th></tr></thead><tbody><tr><td>CPU</td><td>AMD EPYC 9654P (96 cores, single socket)</td><td>96 cores let us isolate one client per VM with substantial headroom, so a busy client cannot crowd out its co-tenants</td></tr><tr><td>Memory</td><td>ECC DDR5</td><td>Bit-flip detection is a measurement-quality concern, not a paranoia tax. Silent corruption skews log-derived percentiles</td></tr><tr><td>Storage</td><td>ZFS raidz1 on Solidigm D7-P5520 NVMe</td><td>Predictable IOPS, durable through single-disk failure, ARC behavior that we can describe rather than guess at</td></tr><tr><td>Network</td><td>2x Broadcom P225P (each dual-port 25 GbE)</td><td>Four 25 GbE ports per host. Enough headroom to separate measurement traffic from client P2P without crosstalk</td></tr><tr><td>Hypervisor</td><td>Proxmox VE 9.1</td><td>Open source, scriptable, lets us pin CPU sets per VM. Snapshots make scenario rollbacks cheap</td></tr><tr><td>OS in guests</td><td>Ubuntu 22.04 LTS</td><td>Boring, well-understood, matches what most operators run</td></tr><tr><td>Time sync</td><td>NTP</td><td>Clocks synchronised across the fleet so <code>head updated</code> timestamps are comparable across hosts</td></tr></tbody></table>\n<p>The bare-metal fleet is paired with a smaller cloud footprint in GCP. The cloud cohort exists for one specific reason: to surface, at indicator level, how much of what we measure is the <strong>client</strong> and how much is the <strong>environment</strong>. Without any cloud comparator, every measurement we publish is implicitly \"what Erigon does on a bare-metal NVMe box in Vienna\". With one, we can flag when a result changes meaningfully across environments. The GCP cohort is small and currently focused on Geth and a subset of pairings. It is sized to catch direction-of-effect differences, not to characterise the full performance surface of any commercial cloud. Where a finding turns on the comparator (such as the inbound-firewall observation discussed later in this post), we say so explicitly.</p>\n<p>A typical EC plus CC pairing occupies two VMs: one for the execution client, one for the consensus client. Splitting the roles across two hosts is deliberate. It means node_exporter on each VM gives us <strong>clean per-layer resource consumption</strong>, with no need to attribute CPU or RAM to one or the other after the fact.</p>\n<p>The math is straightforward: six EC families times six CC families is 36 pairings, plus the standalone Caplin host that runs both layers in one binary, plus the GCP cohort that mirrors a subset of those pairings. The full fleet sits at roughly 90 hosts across both deployments. The 36 pairing matrix below is the bare-metal NDC2 core; the GCP comparator widens the picture but does not change its shape.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Fleet coverage matrix: every consensus client paired with every execution client, plus standalone Caplin\" src=\"https://docs.stereumlabs.com/assets/images/stereumlabs-fleet-matrix-317b3288b9ca6c5122bf381226790fbc.svg\" width=\"1800\" height=\"1100\" class=\"img_ev3q\"></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-data-pipeline\">The data pipeline<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#the-data-pipeline\" class=\"hash-link\" aria-label=\"Direct link to The data pipeline\" title=\"Direct link to The data pipeline\" translate=\"no\">​</a></h2>\n<p>The pipeline has three rails: metrics, logs, and dashboards. Each rail is boring on its own. The interesting part is how they are wired together so that a question asked today can be answered against data captured weeks ago.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"metrics\">Metrics<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#metrics\" class=\"hash-link\" aria-label=\"Direct link to Metrics\" title=\"Direct link to Metrics\" translate=\"no\">​</a></h3>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Data pipeline: sources to consumers across the StereumLabs fleet\" src=\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxODAwIDEwMDAiIGZvbnQtZmFtaWx5PSItYXBwbGUtc3lzdGVtLCAnU2Vnb2UgVUknLCBSb2JvdG8sIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYiPgogIDxkZWZzPgogICAgPHBhdHRlcm4gaWQ9ImdyaWQtcGlwZSIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxtYXJrZXIgaWQ9ImFycm93LXBpcGUiIHZpZXdCb3g9IjAgMCAxMCAxMCIgcmVmWD0iOSIgcmVmWT0iNSIgbWFya2VyV2lkdGg9IjciIG1hcmtlckhlaWdodD0iNyIgb3JpZW50PSJhdXRvIj4KICAgICAgPHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBmaWxsPSIjOTRhM2I4Ii8+CiAgICA8L21hcmtlcj4KICA8L2RlZnM+CgogIDxyZWN0IHdpZHRoPSIxODAwIiBoZWlnaHQ9IjEwMDAiIGZpbGw9IiMwZTE1MzAiLz4KICA8cmVjdCB3aWR0aD0iMTgwMCIgaGVpZ2h0PSIxMDAwIiBmaWxsPSJ1cmwoI2dyaWQtcGlwZSkiLz4KCiAgPHRleHQgeD0iOTAwIiB5PSI3MCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIzNCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+RGF0YSBwaXBlbGluZTogc291cmNlcyB0byBjb25zdW1lcnM8L3RleHQ+CiAgPHRleHQgeD0iOTAwIiB5PSIxMTAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjM2KyBWTXMgwrcgMTVzIG1ldHJpYyBzY3JhcGUgwrcgRmlsZWJlYXQgbG9nIHNoaXAgwrcgZnVsbCByZXRlbnRpb24gaW4gcHJvbWV0aGV1cy1jb2xkIGFuZCBFbGFzdGljc2VhcmNoPC90ZXh0PgoKICA8dGV4dCB4PSIxODAiIHk9IjE4MCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiIgZm9udC13ZWlnaHQ9IjYwMCI+U09VUkNFUzwvdGV4dD4KICA8dGV4dCB4PSI2NDAiIHk9IjE4MCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiIgZm9udC13ZWlnaHQ9IjYwMCI+U0NSQVBFICZhbXA7IFNISVA8L3RleHQ+CiAgPHRleHQgeD0iMTA4MCIgeT0iMTgwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2IiBmb250LXdlaWdodD0iNjAwIj5TVE9SQUdFPC90ZXh0PgogIDx0ZXh0IHg9IjE1MjAiIHk9IjE4MCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiIgZm9udC13ZWlnaHQ9IjYwMCI+Q09OU1VNRVJTPC90ZXh0PgoKICA8bGluZSB4MT0iMTIwIiB5MT0iMTk1IiB4Mj0iNTQwIiB5Mj0iMTk1IiBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMSIvPgogIDxsaW5lIHgxPSI2MjAiIHkxPSIxOTUiIHgyPSI5NjAiIHkyPSIxOTUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPGxpbmUgeDE9IjEwNjAiIHkxPSIxOTUiIHgyPSIxNDAwIiB5Mj0iMTk1IiBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMSIvPgogIDxsaW5lIHgxPSIxNTAwIiB5MT0iMTk1IiB4Mj0iMTc0MCIgeTI9IjE5NSIgc3Ryb2tlPSIjMWMyNjU0IiBzdHJva2Utd2lkdGg9IjEiLz4KCiAgPGc+CiAgICA8cmVjdCB4PSIxMjAiIHk9IjIzMCIgd2lkdGg9IjM4MCIgaGVpZ2h0PSI4MCIgcng9IjYiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzRmNDZlNSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9IjMxMCIgeT0iMjY1IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIwIiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5FQyBwcm9jZXNzIC9tZXRyaWNzPC90ZXh0PgogICAgPHRleHQgeD0iMzEwIiB5PSIyOTAiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmJlc3UgwrcgZXJpZ29uIMK3IGV0aHJleCDCtyBnZXRoIMK3IG5ldGhlcm1pbmQgwrcgcmV0aDwvdGV4dD4KCiAgICA8cmVjdCB4PSIxMjAiIHk9IjM0MCIgd2lkdGg9IjM4MCIgaGVpZ2h0PSI4MCIgcng9IjYiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzRmNDZlNSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9IjMxMCIgeT0iMzc1IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIwIiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5DQyBwcm9jZXNzIC9tZXRyaWNzPC90ZXh0PgogICAgPHRleHQgeD0iMzEwIiB5PSI0MDAiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmdyYW5kaW5lIMK3IGxpZ2h0aG91c2UgwrcgbG9kZXN0YXIgwrcgbmltYnVzIMK3IHByeXNtIMK3IHRla3U8L3RleHQ+CgogICAgPHJlY3QgeD0iMTIwIiB5PSI0NTAiIHdpZHRoPSIzODAiIGhlaWdodD0iODAiIHJ4PSI2IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiM0ZjQ2ZTUiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgICA8dGV4dCB4PSIzMTAiIHk9IjQ4NSIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyMCIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+bm9kZV9leHBvcnRlcjwvdGV4dD4KICAgIDx0ZXh0IHg9IjMxMCIgeT0iNTEwIiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5wZXItaG9zdCBjcHUgwrcgbWVtb3J5IMK3IGRpc2sgwrcgbmV0d29yazwvdGV4dD4KCiAgICA8cmVjdCB4PSIxMjAiIHk9IjYwMCIgd2lkdGg9IjM4MCIgaGVpZ2h0PSI4MCIgcng9IjYiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iI2MyNDEwYyIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9IjMxMCIgeT0iNjM1IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIwIiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5jb250YWluZXIgbG9nczwvdGV4dD4KICAgIDx0ZXh0IHg9IjMxMCIgeT0iNjYwIiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5FQyBhbmQgQ0MgwrcgfjMwayBsaW5lcy9zZWMgZmxlZXQtd2lkZTwvdGV4dD4KICA8L2c+CgogIDxnPgogICAgPHJlY3QgeD0iNjIwIiB5PSIzNTAiIHdpZHRoPSIzMjAiIGhlaWdodD0iMTAwIiByeD0iNiIgZmlsbD0iIzMxMmU4MSIgc3Ryb2tlPSIjODE4Y2Y4IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHRleHQgeD0iNzgwIiB5PSIzOTAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlByb21ldGhldXMgc2NyYXBlcjwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc4MCIgeT0iNDIwIiBmaWxsPSIjYzdkMmZlIiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4xNXMgaW50ZXJ2YWwgwrcgY3VzdG9tIGxhYmVscyBhcHBsaWVkPC90ZXh0PgoKICAgIDxyZWN0IHg9IjYyMCIgeT0iNTgwIiB3aWR0aD0iMzIwIiBoZWlnaHQ9IjEwMCIgcng9IjYiIGZpbGw9IiM5YTM0MTIiIHN0cm9rZT0iI2ZiOTIzYyIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9Ijc4MCIgeT0iNjIwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5GaWxlYmVhdDwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc4MCIgeT0iNjUwIiBmaWxsPSIjZmVkN2FhIiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5zdHJ1Y3R1cmVkIHNoaXAgwrcgaG9zdCArIGNsaWVudCBsYWJlbHM8L3RleHQ+CiAgPC9nPgoKICA8Zz4KICAgIDxyZWN0IHg9IjEwNjAiIHk9IjIzMCIgd2lkdGg9IjM0MCIgaGVpZ2h0PSIxMDAiIHJ4PSI2IiBmaWxsPSIjMzEyZTgxIiBzdHJva2U9IiM4MThjZjgiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgICA8dGV4dCB4PSIxMjMwIiB5PSIyNzAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPnByb21ldGhldXMtZnJlZTwvdGV4dD4KICAgIDx0ZXh0IHg9IjEyMzAiIHk9IjMwMCIgZmlsbD0iI2M3ZDJmZSIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+N2QgZGVsYXkgwrcgOTBkIHJldGVudGlvbjwvdGV4dD4KCiAgICA8cmVjdCB4PSIxMDYwIiB5PSIzNzAiIHdpZHRoPSIzNDAiIGhlaWdodD0iMTAwIiByeD0iNiIgZmlsbD0iIzMxMmU4MSIgc3Ryb2tlPSIjODE4Y2Y4IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHRleHQgeD0iMTIzMCIgeT0iNDEwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5wcm9tZXRoZXVzLWNvbGQ8L3RleHQ+CiAgICA8dGV4dCB4PSIxMjMwIiB5PSI0NDAiIGZpbGw9IiNjN2QyZmUiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPm5vIHJldGVudGlvbiBjYXAgwrcgYWxsIG1ldHJpY3M8L3RleHQ+CgogICAgPHJlY3QgeD0iMTA2MCIgeT0iNTgwIiB3aWR0aD0iMzQwIiBoZWlnaHQ9IjEwMCIgcng9IjYiIGZpbGw9IiM5YTM0MTIiIHN0cm9rZT0iI2ZiOTIzYyIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9IjEyMzAiIHk9IjYyMCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyMiIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+RWxhc3RpY3NlYXJjaDwvdGV4dD4KICAgIDx0ZXh0IHg9IjEyMzAiIHk9IjY1MCIgZmlsbD0iI2ZlZDdhYSIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+aW5kZXhlZCBsb2dzIMK3IHBlci1jbGllbnQgZmllbGRzPC90ZXh0PgogIDwvZz4KCiAgPGc+CiAgICA8cmVjdCB4PSIxNTAwIiB5PSIyMzAiIHdpZHRoPSIyNDAiIGhlaWdodD0iOTAiIHJ4PSI2IiBmaWxsPSIjMDY1ZjQ2IiBzdHJva2U9IiMzNGQzOTkiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgICA8dGV4dCB4PSIxNjIwIiB5PSIyNzAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkdyYWZhbmE8L3RleHQ+CiAgICA8dGV4dCB4PSIxNjIwIiB5PSIyOTUiIGZpbGw9IiNhN2YzZDAiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPnB1YmxpYyBkYXNoYm9hcmRzPC90ZXh0PgoKICAgIDxyZWN0IHg9IjE1MDAiIHk9IjM0NSIgd2lkdGg9IjI0MCIgaGVpZ2h0PSI5MCIgcng9IjYiIGZpbGw9IiMwNjVmNDYiIHN0cm9rZT0iIzM0ZDM5OSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9IjE2MjAiIHk9IjM4NSIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyMCIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+RGF0YSBleHBvcnRzPC90ZXh0PgogICAgPHRleHQgeD0iMTYyMCIgeT0iNDEwIiBmaWxsPSIjYTdmM2QwIiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5DU1YgLyBQYXJxdWV0IChFbnRlcnByaXNlKTwvdGV4dD4KCiAgICA8cmVjdCB4PSIxNTAwIiB5PSI1MzUiIHdpZHRoPSIyNDAiIGhlaWdodD0iOTAiIHJ4PSI2IiBmaWxsPSIjNGMxZDk1IiBzdHJva2U9IiNhNzhiZmEiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgICA8dGV4dCB4PSIxNjIwIiB5PSI1NzUiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPktpYmFuYTwvdGV4dD4KICAgIDx0ZXh0IHg9IjE2MjAiIHk9IjYwMCIgZmlsbD0iI2RkZDZmZSIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+bG9nIHNlYXJjaCDCtyBhZCBob2M8L3RleHQ+CgogICAgPHJlY3QgeD0iMTUwMCIgeT0iNjUwIiB3aWR0aD0iMjQwIiBoZWlnaHQ9IjkwIiByeD0iNiIgZmlsbD0iIzRjMWQ5NSIgc3Ryb2tlPSIjYTc4YmZhIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHRleHQgeD0iMTYyMCIgeT0iNjkwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIwIiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5NQ1AgKyBBSTwvdGV4dD4KICAgIDx0ZXh0IHg9IjE2MjAiIHk9IjcxNSIgZmlsbD0iI2RkZDZmZSIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+ZHJhZnRzIGJsb2cgcG9zdHM8L3RleHQ+CiAgPC9nPgoKICA8cGF0aCBkPSJNIDUwMCAyNzAgQyA1NjAgMjcwLCA1ODAgMzkwLCA2MjAgMzkwIiBzdHJva2U9IiM5NGEzYjgiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgbWFya2VyLWVuZD0idXJsKCNhcnJvdy1waXBlKSIvPgogIDxwYXRoIGQ9Ik0gNTAwIDM4MCBDIDU2MCAzODAsIDU4MCA0MDAsIDYyMCA0MDAiIHN0cm9rZT0iIzk0YTNiOCIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LXBpcGUpIi8+CiAgPHBhdGggZD0iTSA1MDAgNDkwIEMgNTYwIDQ5MCwgNTgwIDQxMCwgNjIwIDQxMCIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctcGlwZSkiLz4KCiAgPHBhdGggZD0iTSA1MDAgNjQwIEwgNjIwIDYzMCIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctcGlwZSkiLz4KCiAgPHBhdGggZD0iTSA5NDAgMzgwIEMgOTkwIDM4MCwgMTAxMCAyODAsIDEwNjAgMjgwIiBzdHJva2U9IiM5NGEzYjgiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgbWFya2VyLWVuZD0idXJsKCNhcnJvdy1waXBlKSIvPgogIDxwYXRoIGQ9Ik0gOTQwIDQyMCBDIDk5MCA0MjAsIDEwMTAgNDIwLCAxMDYwIDQyMCIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctcGlwZSkiLz4KCiAgPHBhdGggZD0iTSA5NDAgNjMwIEwgMTA2MCA2MzAiIHN0cm9rZT0iIzk0YTNiOCIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LXBpcGUpIi8+CgogIDxwYXRoIGQ9Ik0gMTQwMCAyODAgQyAxNDUwIDI4MCwgMTQ2MCAyNzUsIDE1MDAgMjc1IiBzdHJva2U9IiM5NGEzYjgiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgbWFya2VyLWVuZD0idXJsKCNhcnJvdy1waXBlKSIvPgoKICA8cGF0aCBkPSJNIDE0MDAgNDIwIEMgMTQ1MCA0MjAsIDE0NjAgMjc1LCAxNTAwIDI3NSIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctcGlwZSkiLz4KICA8cGF0aCBkPSJNIDE0MDAgNDIwIEMgMTQ1MCA0MjAsIDE0NjAgMzkwLCAxNTAwIDM5MCIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctcGlwZSkiLz4KICA8cGF0aCBkPSJNIDE0MDAgNDIwIEMgMTQ1MCA0MjAsIDE0NjAgNjk1LCAxNTAwIDY5NSIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3ctcGlwZSkiLz4KCiAgPHBhdGggZD0iTSAxNDAwIDYzMCBDIDE0NTAgNjMwLCAxNDYwIDI3NSwgMTUwMCAyNzUiIHN0cm9rZT0iIzk0YTNiOCIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LXBpcGUpIi8+CiAgPHBhdGggZD0iTSAxNDAwIDYzMCBDIDE0NTAgNjMwLCAxNDYwIDM5MCwgMTUwMCAzOTAiIHN0cm9rZT0iIzk0YTNiOCIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LXBpcGUpIi8+CiAgPHBhdGggZD0iTSAxNDAwIDYzMCBDIDE0NTAgNjMwLCAxNDYwIDU4MCwgMTUwMCA1ODAiIHN0cm9rZT0iIzk0YTNiOCIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LXBpcGUpIi8+CiAgPHBhdGggZD0iTSAxNDAwIDYzMCBDIDE0NTAgNjMwLCAxNDYwIDY5NSwgMTUwMCA2OTUiIHN0cm9rZT0iIzk0YTNiOCIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LXBpcGUpIi8+CgogIDx0ZXh0IHg9IjkwMCIgeT0iOTcwIiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7CqSBSb2NrTG9naWMgR21iSCDCtyBTdGVyZXVtTGFiczwvdGV4dD4KPC9zdmc+Cg==\" width=\"1800\" height=\"1000\" class=\"img_ev3q\"></p>\n<p>Every EC and CC process exposes a <code>/metrics</code> endpoint in Prometheus text format. Every host runs <code>node_exporter</code> for OS-level counters. Scrape cadence is <strong>15 seconds</strong>, which is a deliberate compromise: short enough to catch most state transitions, long enough that cardinality stays manageable.</p>\n<p>We run two Prometheus tiers:</p>\n<ul>\n<li class=\"\"><strong><code>prometheus-free</code></strong>: short retention, mirrored subset of metrics, available to Free-tier subscribers with a 7-day data delay.</li>\n<li class=\"\"><strong><code>prometheus-cold</code></strong>: full metric set, no retention cap. This is where we run <code>avg_over_time(...[7d:1h])</code> queries when we write a blog post.</li>\n</ul>\n<p>Cold storage is what makes most of the StereumLabs blog series possible. The Caplin standalone analysis from last week pulled metrics that were captured before Caplin v3.3.10 had been added to the fleet, and ran the same queries against the new host. No re-runs, no warm-up periods, no \"we'll publish in two weeks once we have data\".</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"logs\">Logs<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#logs\" class=\"hash-link\" aria-label=\"Direct link to Logs\" title=\"Direct link to Logs\" translate=\"no\">​</a></h3>\n<p>Logs travel a parallel path on the same diagram above: Filebeat streams logs from every container into Elasticsearch, where Kibana and the MCP server (Model Context Protocol, the read-only query gateway our AI workflow uses; covered later in this post) consume them in the same way Grafana consumes Prometheus. Logs are the second half of what we measure, and frequently the half that surfaces things metrics cannot. The classic example: the per-block <code>head updated</code> line in Erigon contains four fields (execution time, commit time, age, mgas/s) that no <code>/metrics</code> endpoint exposes. Without log capture, the <a class=\"\" href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos\">Caplin standalone vs classic comparison</a> would have been a far shallower piece.</p>\n<p>Logs land in Elasticsearch with structured fields for <code>container_name</code>, <code>host</code>, <code>ec_client</code>, <code>cc_client</code>, and the rest of the StereumLabs label vocabulary. Fleet-wide ingest currently runs around <strong>30,000 log lines per second</strong> with debug logging enabled across every container.</p>\n<p>A side effect of capturing everything is that we can write log-derived percentile tables that ask questions the original log format was not designed for. We do not need to instrument the client. We just need it to log enough.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"dashboards\">Dashboards<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#dashboards\" class=\"hash-link\" aria-label=\"Direct link to Dashboards\" title=\"Direct link to Dashboards\" translate=\"no\">​</a></h3>\n<p>Grafana sits on top of both Prometheus and Elasticsearch. Dashboards are the public face of the platform: panels with <code>info</code> icons that link back to the definitions page, time-aligned charts for cross-client comparison, lifecycle badges (<code>active</code>, <code>experimental</code>, <code>legacy</code>) so you know whether to cite a result. Plan-tier-gated access controls how much retention and how many users you get.</p>\n<p>The naming convention is <code>Category – Metric (Scope)</code>, units are SI, and per-core normalization is always labeled. The reason we are strict about it: <strong>the only way cross-client comparisons stay legible</strong> is if a panel titled \"CPU – Utilization (EC process)\" means the same thing on every dashboard regardless of which client it is plotting.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"custom-labels-the-comparability-layer\">Custom labels: the comparability layer<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#custom-labels-the-comparability-layer\" class=\"hash-link\" aria-label=\"Direct link to Custom labels: the comparability layer\" title=\"Direct link to Custom labels: the comparability layer\" translate=\"no\">​</a></h2>\n<p>Every metric series in <code>prometheus-cold</code> carries a fixed set of StereumLabs labels:</p>\n<ul>\n<li class=\"\"><strong><code>ec_client</code></strong>: execution client name (<code>besu</code>, <code>erigon</code>, <code>ethrex</code>, <code>geth</code>, <code>nethermind</code>, <code>reth</code>).</li>\n<li class=\"\"><strong><code>ec_version</code></strong>: pinned version string.</li>\n<li class=\"\"><strong><code>cc_client</code></strong>: consensus client name (<code>grandine</code>, <code>lighthouse</code>, <code>lodestar</code>, <code>nimbus</code>, <code>prysm</code>, <code>teku</code>, plus <code>caplin</code> when running standalone).</li>\n<li class=\"\"><strong><code>cc_version</code></strong>: pinned version string.</li>\n<li class=\"\"><strong><code>role</code></strong>: <code>ec</code> or <code>cc</code>, so a query can target the layer regardless of which process the metric came from.</li>\n<li class=\"\"><strong><code>deployment</code></strong>: provider code (<code>NDC2</code> for bare-metal Vienna, <code>GCP</code> for cloud).</li>\n<li class=\"\"><strong><code>location</code></strong>: provider-specific region or zone identifier.</li>\n</ul>\n<p>The result is that a query like</p>\n<div class=\"language-promql codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-promql codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">avg_over_time(</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  node_cpu_seconds_total{role=\"ec\", ec_client=\"erigon\", deployment=\"NDC2\"}[7d:1h]</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">)</span><br></span></code></pre></div></div>\n<p>returns exactly the slice you would ask a human for in plain English: \"the 7-day Erigon EC CPU average on bare metal\". No prior knowledge of the underlying scrape topology needed.</p>\n<p>Most of the unglamorous engineering effort goes into keeping this label vocabulary consistent. It is also what made the <a class=\"\" href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis\">EC P2P peering deep dive</a> feasible: that post compared roughly 90 hosts across six EC families and two deployment classes in one chart. Without consistent labels, the same comparison would have required a custom ETL job for each section.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"neutrality-and-how-we-keep-runs-comparable\">Neutrality and how we keep runs comparable<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#neutrality-and-how-we-keep-runs-comparable\" class=\"hash-link\" aria-label=\"Direct link to Neutrality and how we keep runs comparable\" title=\"Direct link to Neutrality and how we keep runs comparable\" translate=\"no\">​</a></h2>\n<p>Neutral measurement is a methodological commitment, not a marketing claim. The concrete rules we enforce inside the fleet:</p>\n<ul>\n<li class=\"\"><strong>Start from defaults.</strong> Every client runs vendor defaults unless a documented, client-team-recommended deviation is required for stability or scenario correctness. Each deviation is annotated in the run manifest.</li>\n<li class=\"\"><strong>Equalize budgets.</strong> Every VM in a comparison cohort gets the same vCPU, RAM, and disk allocation. The Caplin standalone post explicitly called out the asymmetry where it existed, because pretending it did not is the fastest way to publish noise as signal.</li>\n<li class=\"\"><strong>Pin versions.</strong> Versions are explicit in the labels, in the manifest, and in the dashboard headers. When a client team ships a new release, we add a new host. We do not silently upgrade the existing one underneath the data.</li>\n<li class=\"\"><strong>Reject skew.</strong> NTP is enforced across the fleet. Runs with material clock drift during the measurement window are excluded from comparisons and flagged in the run notes.</li>\n<li class=\"\"><strong>Document trade-offs.</strong> Pruning modes, cache sizes, peer caps: anything that affects interpretation is in the run notes, not the appendix of an internal wiki.</li>\n</ul>\n<p>A run manifest is the concrete artifact that carries all of this. It records the pinned client versions, the host specs (vCPU, RAM, disk, hypervisor), the start and end of the measurement window, any deviations from defaults with their justifications, and the acceptance checks that gate publication. Together with the panel-definition links from the dashboard each chart was drawn against, the manifest is what makes a published result re-runnable later. Enterprise subscribers get the full manifest attached to every dashboard view; public posts cite the relevant subset in their methodology notes.</p>\n<p>The hard part of this work is rarely the infrastructure itself. Most of the effort goes into the rules that keep runs comparable: label vocabulary, version pinning, deviation logging, scenario manifests, deciding what counts as \"enough\" data. The RockLogic AI case study makes a parallel observation: hooking a model up to the data was an afternoon; defining what a useful answer looks like took weeks. Spinning up Prometheus and Grafana is well-documented and quick. Turning that into a substrate where a researcher in 2027 can re-run today's query against the same definitions and get a comparable result is the ongoing commitment, and it is what subscribers are paying for.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"how-this-fits-alongside-other-measurement-work\">How this fits alongside other measurement work<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#how-this-fits-alongside-other-measurement-work\" class=\"hash-link\" aria-label=\"Direct link to How this fits alongside other measurement work\" title=\"Direct link to How this fits alongside other measurement work\" translate=\"no\">​</a></h2>\n<p>StereumLabs is not the only public effort to characterize Ethereum client behavior, and not the first. A non-exhaustive list of work that we read, learn from, and consider complementary:</p>\n<ul>\n<li class=\"\"><strong>MigaLabs' <a href=\"https://github.com/migalabs/armiarma\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Armiarma</a></strong>: a libp2p crawler focused on Ethereum's CL network, producing peer-set and gossipsub data. MigaLabs also publishes broader network analysis at <a href=\"https://migalabs.es/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">migalabs.es</a>. Their network-wide view is wider than ours; our per-pairing resource view is more granular.</li>\n<li class=\"\"><strong>The EF's <a href=\"https://ethpandaops.io/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">ethpandaops</a></strong>: Kurtosis-based reproducible Ethereum devnets (<code>ethereum-package</code>), the <code>ethereum-metrics-exporter</code>, <code>checkpointz</code>, mainnet monitoring tooling, and related infrastructure. Their toolset covers a much wider operator surface than ours; our addition is the controlled cross-client comparison on identical hardware.</li>\n<li class=\"\"><strong><a href=\"https://probelab.io/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Probe-Lab</a></strong>: P2P network measurement across libp2p ecosystems (Ethereum, IPFS, Filecoin and others) using their own tooling stack (Parsec, Nebula, Hermes, Ukla). Different protocol layers, complementary insights.</li>\n<li class=\"\"><strong>MEV-Boost relay observability</strong> via projects like <a href=\"https://relayscan.io/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">relayscan.io</a> and <a href=\"https://mevboost.pics/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">mevboost.pics</a>: payload-flow and relay-bid visibility that sits one level above what we measure.</li>\n<li class=\"\"><strong>Client-team published benchmarks</strong>: Nethermind, Sigma Prime, the Erigon team and others publish their own perf work. Our value-add is running their releases head-to-head on neutral hardware rather than each team optimising their own demo setup.</li>\n</ul>\n<p>Our niche is the cross-product: every EC and CC implementation, paired with every other, on identical hardware under identical scenarios, with the raw telemetry retained long enough to ask new questions of old runs. Where another effort goes wider or deeper on one axis, we cite it; where our data complements theirs, we say so.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-this-stack-has-produced\">What this stack has produced<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#what-this-stack-has-produced\" class=\"hash-link\" aria-label=\"Direct link to What this stack has produced\" title=\"Direct link to What this stack has produced\" translate=\"no\">​</a></h2>\n<p>What matters is what the platform makes visible. A non-exhaustive recap of recent output:</p>\n<ul>\n<li class=\"\">The <a class=\"\" href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos\">Caplin standalone vs classic Erigon comparison</a> found that the monolithic node executes EVM blocks 12 to 31% faster at the median but pays a 2x penalty on MDBX commits, ending up roughly tied at end-to-end p50 across 50,000 sampled blocks.</li>\n<li class=\"\">The <a class=\"\" href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis\">EC P2P peering deep dive</a> found that Reth maintains over 5x the peer count of Besu under stock defaults on our fleet, and that in our GCP cohort the default cloud firewall rules silently blocked DevP2P inbound on Geth. An operator using the same provider defaults would inherit that artifact unless they opened the port explicitly.</li>\n<li class=\"\">The <a class=\"\" href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026\">EC sync speed comparison</a> quantified the gap between the fastest and slowest initial sync at over an order of magnitude on identical hardware.</li>\n<li class=\"\">The <a class=\"\" href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\">Nimbus v26.3.1 block-building post</a> characterised how each EC behaves when Nimbus drives block-building duties, using a shadow setup that mirrors 1,000 validator pubkeys across five EC pairings over a 48-hour window.</li>\n<li class=\"\">The <a class=\"\" href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources\">Teku cross-version analysis</a> traced how resource consumption shifted across three Teku releases.</li>\n<li class=\"\">A two-week AI-assisted security-audit campaign (May 4 to May 18, 2026) used the fleet as a live test-bed, producing 54 finding documents, 6 Ethereum Foundation Bug Bounty submissions, 13 paste-ready upstream PR drafts across 7 client projects, and 24 Kurtosis devnet PoCs. Several findings (gossip-rejection spikes, engine-API timeout storms, P99 latency divergences) surfaced first as anomalies in the Prometheus and Elasticsearch stack. A dedicated post will cover the campaign.</li>\n</ul>\n<p>None of these required new instrumentation. They required asking new questions of data that was already in <code>prometheus-cold</code> and Elasticsearch. That is the payoff of the upfront effort to keep everything labelled, retained, and reproducible.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-ai-workflow-closing-the-loop\">The AI workflow: closing the loop<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#the-ai-workflow-closing-the-loop\" class=\"hash-link\" aria-label=\"Direct link to The AI workflow: closing the loop\" title=\"Direct link to The AI workflow: closing the loop\" translate=\"no\">​</a></h2>\n<p>This is where the post connects back to the <a href=\"https://rocklogic.at/de/cases/ai-on-own-data\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">RockLogic case study</a>.</p>\n<p>Every StereumLabs blog post you read carries <code>stereumlabs-ai</code> as a co-author. The label is literal. Anthropic Claude has read-only MCP access to our Prometheus and Elasticsearch instances, drives the queries, reads the results, drafts the prose, and proposes the tables. A human editor reviews, corrects, and approves before publication. The case study describes that workflow from a business angle: data stays in-house, output is cited and reproducible, weeks of analysis collapse into hours. This post is the technical view of the same loop from the other side.</p>\n<p>The wiring looks like this:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"AI workflow: telemetry to blog post, with raw data confined to the EU perimeter\" src=\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxODAwIDgwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC1haSIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxtYXJrZXIgaWQ9ImFycm93LWFpIiB2aWV3Qm94PSIwIDAgMTAgMTAiIHJlZlg9IjkiIHJlZlk9IjUiIG1hcmtlcldpZHRoPSI3IiBtYXJrZXJIZWlnaHQ9IjciIG9yaWVudD0iYXV0byI+CiAgICAgIDxwYXRoIGQ9Ik0gMCAwIEwgMTAgNSBMIDAgMTAgeiIgZmlsbD0iI2E1YjRjZiIvPgogICAgPC9tYXJrZXI+CiAgICA8bWFya2VyIGlkPSJhcnJvdy1ldSIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJXaWR0aD0iNyIgbWFya2VySGVpZ2h0PSI3IiBvcmllbnQ9ImF1dG8iPgogICAgICA8cGF0aCBkPSJNIDAgMCBMIDEwIDUgTCAwIDEwIHoiIGZpbGw9IiMzNGQzOTkiLz4KICAgIDwvbWFya2VyPgogIDwvZGVmcz4KCiAgPHJlY3Qgd2lkdGg9IjE4MDAiIGhlaWdodD0iODAwIiBmaWxsPSIjMGUxNTMwIi8+CiAgPHJlY3Qgd2lkdGg9IjE4MDAiIGhlaWdodD0iODAwIiBmaWxsPSJ1cmwoI2dyaWQtYWkpIi8+CgogIDx0ZXh0IHg9IjkwMCIgeT0iNzAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMzQiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkFJIHdvcmtmbG93OiB0ZWxlbWV0cnkgdG8gYmxvZyBwb3N0PC90ZXh0PgogIDx0ZXh0IHg9IjkwMCIgeT0iMTEwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5SYXcgZGF0YSBzdGF5cyBpbiB0aGUgRVUgcGVyaW1ldGVyLiBPbmx5IGN1cmF0ZWQgcXVlcnkgc2xpY2VzIGFuZCB0aGVpciBhbnN3ZXJzIGNyb3NzIHRoZSBDbGF1ZGUgQVBJIGJvdW5kYXJ5LjwvdGV4dD4KCiAgPHJlY3QgeD0iNjAiIHk9IjIwMCIgd2lkdGg9IjY0MCIgaGVpZ2h0PSI0NDAiIHJ4PSIxNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMzRkMzk5IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1kYXNoYXJyYXk9IjEwIDYiLz4KICA8dGV4dCB4PSI5MCIgeT0iMjQwIiBmaWxsPSIjMzRkMzk5IiBmb250LXNpemU9IjE2IiBmb250LXdlaWdodD0iNzAwIiBsZXR0ZXItc3BhY2luZz0iMiI+RVUgUEVSSU1FVEVSIMK3IFNURVJFVU1MQUJTIElORlJBU1RSVUNUVVJFPC90ZXh0PgoKICA8cmVjdCB4PSIxMDAiIHk9IjI5MCIgd2lkdGg9IjI4MCIgaGVpZ2h0PSI4MCIgcng9IjYiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzgxOGNmOCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSIyNDAiIHk9IjMyNSIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyMCIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+cHJvbWV0aGV1cy1jb2xkPC90ZXh0PgogIDx0ZXh0IHg9IjI0MCIgeT0iMzUwIiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5hbGwgbWV0cmljIHNlcmllczwvdGV4dD4KCiAgPHJlY3QgeD0iMTAwIiB5PSI0MDAiIHdpZHRoPSIyODAiIGhlaWdodD0iODAiIHJ4PSI2IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiNmYjkyM2MiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iMjQwIiB5PSI0MzUiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkVsYXN0aWNzZWFyY2g8L3RleHQ+CiAgPHRleHQgeD0iMjQwIiB5PSI0NjAiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmluZGV4ZWQgbG9nczwvdGV4dD4KCiAgPHJlY3QgeD0iMTAwIiB5PSI1MTAiIHdpZHRoPSIyODAiIGhlaWdodD0iODAiIHJ4PSI2IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiMzNGQzOTkiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iMjQwIiB5PSI1NDUiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmNsaWVudCBtZXRyaWMgZGVmczwvdGV4dD4KICA8dGV4dCB4PSIyNDAiIHk9IjU3MCIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+bGFiZWxzLCB1bml0cywgc2NvcGU8L3RleHQ+CgogIDxyZWN0IHg9IjQ1MCIgeT0iMzk1IiB3aWR0aD0iMjQwIiBoZWlnaHQ9IjEwMCIgcng9IjYiIGZpbGw9IiM0YzFkOTUiIHN0cm9rZT0iI2E3OGJmYSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI1NzAiIHk9IjQzNSIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyMiIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+TUNQIHNlcnZlcjwvdGV4dD4KICA8dGV4dCB4PSI1NzAiIHk9IjQ2NSIgZmlsbD0iI2RkZDZmZSIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+cmVhZC1vbmx5IHF1ZXJ5IGdhdGV3YXk8L3RleHQ+CgogIDxwYXRoIGQ9Ik0gMzgwIDMzMCBDIDQxNSAzMzAsIDQyNSA0NDAsIDQ1MCA0NDAiIHN0cm9rZT0iI2E1YjRjZiIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LWFpKSIvPgogIDxwYXRoIGQ9Ik0gMzgwIDQ0MCBMIDQ1MCA0NDUiIHN0cm9rZT0iI2E1YjRjZiIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LWFpKSIvPgogIDxwYXRoIGQ9Ik0gMzgwIDU1MCBDIDQxNSA1NTAsIDQyNSA0NTUsIDQ1MCA0NTUiIHN0cm9rZT0iI2E1YjRjZiIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LWFpKSIvPgoKICA8cGF0aCBkPSJNIDY5MCA0NDUgTCA3NzAgNDQ1IiBzdHJva2U9IiMzNGQzOTkiIHN0cm9rZS13aWR0aD0iMi41IiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LWV1KSIvPgogIDx0ZXh0IHg9IjczMCIgeT0iNDMwIiBmaWxsPSIjMzRkMzk5IiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LXdlaWdodD0iNjAwIj5jdXJhdGVkIHNsaWNlPC90ZXh0PgoKICA8cmVjdCB4PSI3NzAiIHk9IjM5NSIgd2lkdGg9IjI0MCIgaGVpZ2h0PSIxMDAiIHJ4PSI2IiBmaWxsPSIjNGY0NmU1IiBzdHJva2U9IiM4MThjZjgiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iODkwIiB5PSI0MzUiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkNsYXVkZTwvdGV4dD4KICA8dGV4dCB4PSI4OTAiIHk9IjQ2NSIgZmlsbD0iI2M3ZDJmZSIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+dmlhIExpYnJlQ2hhdDwvdGV4dD4KCiAgPHBhdGggZD0iTSAxMDEwIDQ0NSBMIDEwOTAgNDQ1IiBzdHJva2U9IiNhNWI0Y2YiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgbWFya2VyLWVuZD0idXJsKCNhcnJvdy1haSkiLz4KCiAgPHJlY3QgeD0iMTA5MCIgeT0iMzk1IiB3aWR0aD0iMjIwIiBoZWlnaHQ9IjEwMCIgcng9IjYiIGZpbGw9IiM3YzJkMTIiIHN0cm9rZT0iI2ZiOTIzYyIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSIxMjAwIiB5PSI0MzUiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkRyYWZ0IHBvc3Q8L3RleHQ+CiAgPHRleHQgeD0iMTIwMCIgeT0iNDY1IiBmaWxsPSIjZmVkN2FhIiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj53aXRoIGNpdGF0aW9uczwvdGV4dD4KCiAgPHBhdGggZD0iTSAxMzEwIDQ0NSBMIDEzOTAgNDQ1IiBzdHJva2U9IiNhNWI0Y2YiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgbWFya2VyLWVuZD0idXJsKCNhcnJvdy1haSkiLz4KCiAgPHJlY3QgeD0iMTM5MCIgeT0iMzk1IiB3aWR0aD0iMjIwIiBoZWlnaHQ9IjEwMCIgcng9IjYiIGZpbGw9IiMzNjUzMTQiIHN0cm9rZT0iI2EzZTYzNSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSIxNTAwIiB5PSI0MzUiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI2MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkh1bWFuIHJldmlldzwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSI0NjUiIGZpbGw9IiNkOWY5OWQiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmVkaXRvciBjaGVja3MgJmFtcDsgZWRpdHM8L3RleHQ+CgogIDxwYXRoIGQ9Ik0gMTUwMCA0OTUgTCAxNTAwIDU2MCBMIDkwMCA1NjAgTCA5MDAgNTEwIiBzdHJva2U9IiNmYjkyM2MiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgc3Ryb2tlLWRhc2hhcnJheT0iNiA0IiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LWFpKSIvPgogIDx0ZXh0IHg9IjEyMDAiIHk9IjU4NSIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1zdHlsZT0iaXRhbGljIj5jb3JyZWN0aW9ucyBsb29wIGJhY2sgdG8gZHJhZnQ8L3RleHQ+CgogIDxyZWN0IHg9IjE2MjAiIHk9IjM5NSIgd2lkdGg9IjE0MCIgaGVpZ2h0PSIxMDAiIHJ4PSI2IiBmaWxsPSIjMDY1ZjQ2IiBzdHJva2U9IiMzNGQzOTkiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iMTY5MCIgeT0iNDM1IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIwIiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5QdWJsaXNoPC90ZXh0PgogIDx0ZXh0IHg9IjE2OTAiIHk9IjQ2NSIgZmlsbD0iI2E3ZjNkMCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+YmxvZyBwb3N0PC90ZXh0PgoKICA8cGF0aCBkPSJNIDE2MTAgNDQ1IEwgMTYyMCA0NDUiIHN0cm9rZT0iI2E1YjRjZiIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93LWFpKSIvPgoKICA8dGV4dCB4PSI5MDAiIHk9Ijc2MCIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+wqkgUm9ja0xvZ2ljIEdtYkggwrcgU3RlcmV1bUxhYnM8L3RleHQ+Cjwvc3ZnPgo=\" width=\"1800\" height=\"800\" class=\"img_ev3q\"></p>\n<p>A few properties of that loop that are worth being explicit about:</p>\n<ul>\n<li class=\"\"><strong>Raw telemetry stays on EU infrastructure.</strong> The MCP (Model Context Protocol) server runs inside the same perimeter as Prometheus and Elasticsearch. What crosses the boundary to the Claude API is a curated query slice and its result, not the underlying logs or metric series.</li>\n<li class=\"\"><strong>Citations are mandatory and auditable.</strong> Every number that lands in a published post is required to come back from a query the model can name and a result the editor can re-execute. The editor can re-run the cited PromQL or Elasticsearch query before publication to confirm the number, and reject the claim if it does not reproduce. \"The system claims\" is not a publishable sentence.</li>\n<li class=\"\"><strong>Context is trimmed aggressively.</strong> A 7-day <code>avg_over_time</code> query returns one number, not a histogram. A <code>head updated</code> log extraction returns a summary table, not 50,000 lines. The model is given the smallest input that answers the question. The trimming is a structural mitigation, not a guarantee of correctness; it makes hallucinated numbers much harder to slip past a citation check, but it does not eliminate them.</li>\n<li class=\"\"><strong>Human review is the final filter.</strong> Stefan Kobrc (Founder, RockLogic) is the named editor on every StereumLabs post. The editor's job is to re-run a sample of the cited queries, sanity-check the conclusions against domain knowledge, and reject claims that the data does not support. When a correction lands after publication, it is logged in the post's revision history rather than silently rewritten.</li>\n<li class=\"\"><strong>Format compliance is enforced.</strong> The post you are reading uses the same frontmatter, the same table style, and the same link conventions as every other StereumLabs post because the workflow checks for it before output.</li>\n</ul>\n<p>The same pattern is what we offer to customers in the <a href=\"https://rocklogic.at/de/cases/ai-on-own-data\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">RockLogic case study</a>. We run it on ourselves first, on our own infrastructure with our own data, before pointing it at anyone else's.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-is-harder-than-it-looks-and-what-we-cannot-fully-control\">What is harder than it looks, and what we cannot fully control<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#what-is-harder-than-it-looks-and-what-we-cannot-fully-control\" class=\"hash-link\" aria-label=\"Direct link to What is harder than it looks, and what we cannot fully control\" title=\"Direct link to What is harder than it looks, and what we cannot fully control\" translate=\"no\">​</a></h2>\n<p>Five observations from running this platform. The first three are operational costs we accept. The last two are biases worth flagging so that readers can weigh them against their own deployment.</p>\n<p><strong>Metric heterogeneity across clients is the dominant operational cost.</strong> Caplin v3.3.10 ships a comprehensive <code>libp2p_rcmgr_*</code> family but no current libp2p peers gauge. Prysm exposes <code>connected_libp2p_peers{agent=\"...\"}</code> with per-implementation breakdowns. Lighthouse, Lodestar, Nimbus, Teku, and Grandine each use different metric names for what is conceptually the same thing. Every cross-client query is implicitly a translation layer. We maintain that layer as part of the dashboard panel definitions and as part of the AI workflow's instruction set.</p>\n<p><strong>Log format chaos is the second cost.</strong> Some clients log structured JSON, some log key=value, some log unstructured prose, some log all three depending on subsystem. Stripping ANSI color codes is a normal preprocessing step. Writing a parser like the one for Erigon's <code>head updated</code> line is the easy part; validating it against edge cases is what takes time.</p>\n<p><strong>Keeping runs comparable is the third cost, and the largest.</strong> The same conclusion the AI case study reaches about its own workflow: the hard part is not the technology but the editorial spine. For us, that means resisting the temptation to publish numbers from runs that were \"almost equivalent\". Almost is where bias lives.</p>\n<p><strong>Single-site bias.</strong> All bare-metal hosts sit in one Vienna data center (NDC2) and share an upstream BGP path and ASN-level peer reachability. That means peer-set composition, geographic latency to other mainnet nodes, and inbound discoverability are correlated across the fleet. Findings about peer count, peer diversity, or P2P churn carry an implicit \"as seen from one network position\". We add the GCP cohort to break that correlation in one direction, but two environments are an indicator, not a characterisation. Reproducing a finding from a different site or ASN is one good way to test how site-bound it is.</p>\n<p><strong>Scrape cadence has a tail-latency floor.</strong> 15-second Prometheus scrapes are sufficient for resource averages and steady-state behaviour, but they are too coarse for tail-latency analysis. GC pauses, individual slot timings (Ethereum slots are 12 seconds, so aliasing is possible on slot-aligned metrics), and sub-second spikes are visible only through log-derived percentiles, not through the metrics graph. Where we publish p99 numbers, they come from log parsing, not from <code>histogram_quantile</code> on 15s buckets. The relevant posts call this out where it affects interpretation.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"plans-access-and-what-is-public\">Plans, access, and what is public<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#plans-access-and-what-is-public\" class=\"hash-link\" aria-label=\"Direct link to Plans, access, and what is public\" title=\"Direct link to Plans, access, and what is public\" translate=\"no\">​</a></h2>\n<p>Three subscription tiers, structured around what we can responsibly support at each price point:</p>\n<table><thead><tr><th>Plan</th><th>Price</th><th>Data delay</th><th>Retention</th><th>Grafana users</th><th>Custom runs</th><th>Exports</th></tr></thead><tbody><tr><td>Free</td><td>EUR 0</td><td>7 days</td><td>90 days</td><td>1</td><td>no</td><td>no</td></tr><tr><td>Pro</td><td>EUR 3,200 / month, billed annually</td><td>near real-time</td><td>unlimited</td><td>5</td><td>no</td><td>no</td></tr><tr><td>Enterprise</td><td>custom</td><td>near real-time</td><td>unlimited</td><td>custom</td><td>yes</td><td>yes</td></tr></tbody></table>\n<p>The tiers map to different reader profiles. <strong>Free</strong> is the right level for ecosystem observers, students, and curious operators who want to read the published numbers and verify our claims against a delayed but otherwise full dataset. <strong>Pro</strong> is sized for client teams, research groups, consultants, competitive-intelligence shops, and press who need real-time access and unlimited retention across the fleet but do not need their own cohorts. <strong>Enterprise</strong> is for institutional operators and infrastructure providers who want to commission custom runs against their own questions, ingest data into their own pipelines via exports, and get a contracted scope of work with named contacts. Prices are EUR, excluding VAT, per the <a class=\"\" href=\"https://docs.stereumlabs.com/docs/plans-and-prices\">public plans page</a>.</p>\n<p>The Free tier exists because we think the public Ethereum ecosystem benefits from having neutral measurements visible to anyone. Paid tiers fund the bare-metal fleet, datacenter, hardware refresh, on-call rotation, and ongoing engineering effort that keeps the data reproducible week over week.</p>\n<p>The blog and the <a class=\"\" href=\"https://docs.stereumlabs.com/docs/dashboards/list/catalog\">public dashboards</a> are open without subscription. Every post links back to the definitions, the methodology, and the scope page, so a critical reader can trace any claim back to the query that produced it.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"who-this-is-for\">Who this is for<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#who-this-is-for\" class=\"hash-link\" aria-label=\"Direct link to Who this is for\" title=\"Direct link to Who this is for\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\"><strong>Client teams</strong> comparing your own release against the rest of the field on identical hardware, without having to stand up the rest of the field yourself.</li>\n<li class=\"\"><strong>Institutional node operators</strong> sizing infrastructure decisions against measurements taken at production-equivalent scale.</li>\n<li class=\"\"><strong>Researchers</strong> running cross-client studies who need a reproducible substrate that is documented down to the firmware version.</li>\n<li class=\"\"><strong>Security researchers and bug-bounty hunters</strong> using cross-client production observability to surface anomalies that source review alone misses.</li>\n<li class=\"\"><strong>Builders of derivative tooling</strong> (indexers, RPC providers, MEV searchers) who want to know how the client they depend on behaves under load.</li>\n</ul>\n<p>If you are in one of the above categories and want a custom dimension of the fleet measured against your specific question, Enterprise scope custom runs are designed for that. Start with the question, not with the SKU. Write to <a href=\"mailto:contact@stereumlabs.com\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">contact@stereumlabs.com</a> describing what you want to learn, and we will scope it together, either inside the current scenario matrix or by spinning up a new VM cohort.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"summary\">Summary<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#summary\" class=\"hash-link\" aria-label=\"Direct link to Summary\" title=\"Direct link to Summary\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>Dimension</th><th>What StereumLabs does</th></tr></thead><tbody><tr><td>Hardware anchor</td><td>🟢 Bare-metal EPYC 9654P fleet in Vienna NDC2, with GCP cloud comparator</td></tr><tr><td>Coverage</td><td>🟢 6 EC × 6 CC pairings on bare-metal (36 hosts) plus 1 standalone Caplin plus a GCP comparator cohort; ~90 hosts total</td></tr><tr><td>Metrics retention</td><td>🟢 <code>prometheus-cold</code> keeps everything, scrape every 15s</td></tr><tr><td>Log capture</td><td>🟢 Filebeat to Elasticsearch from every container</td></tr><tr><td>Comparability</td><td>🟢 Fixed label vocabulary across all series</td></tr><tr><td>Neutrality</td><td>🟢 Vendor defaults except for documented, justified deviations</td></tr><tr><td>Reproducibility</td><td>🟢 Definitions, manifests, and procedures published per dashboard</td></tr><tr><td>AI workflow</td><td>🟢 Claude via MCP against own data; raw telemetry stays in EU; mandatory citations</td></tr><tr><td>Public access</td><td>🟢 Free tier with 7-day delay; Pro and Enterprise for full retention</td></tr><tr><td>Source of insight</td><td>🟢 Weekly blog series on EC and CC behavior, archive growing since launch</td></tr><tr><td>Closed surface</td><td>🟡 Custom run authoring is Enterprise-only</td></tr><tr><td>Coverage gap</td><td>🟡 Pre-merge clients and L2 sequencers out of current scope</td></tr></tbody></table>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"where-to-go-next\">Where to go next<a href=\"https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack#where-to-go-next\" class=\"hash-link\" aria-label=\"Direct link to Where to go next\" title=\"Direct link to Where to go next\" translate=\"no\">​</a></h2>\n<p>If you read one thing next, make it the <a class=\"\" href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos\">Caplin standalone vs classic Erigon comparison</a>. It is the most recent end-to-end example of this stack answering a concrete question, and it shows what the manifest, the labels, and the AI workflow combined produce.</p>\n<p>After that:</p>\n<ul>\n<li class=\"\">Browse the <a class=\"\" href=\"https://docs.stereumlabs.com/blog\">blog archive</a> for previous analyses across the EC and CC fleet.</li>\n<li class=\"\">Follow <a href=\"https://x.com/rocklogicgmbh\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">RockLogic on X</a> for new posts as they ship.</li>\n<li class=\"\">For the methodology in depth, read <a class=\"\" href=\"https://docs.stereumlabs.com/docs/scope\">Purpose and Scope</a> and the <a class=\"\" href=\"https://docs.stereumlabs.com/docs/scope/client-metrics\">Client Metrics List</a>.</li>\n<li class=\"\">For the business-side companion to this post, see the <a href=\"https://rocklogic.at/de/cases/ai-on-own-data\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">RockLogic AI on own data case study</a>.</li>\n</ul>\n<p>If you want to talk about a custom measurement, a Pro or Enterprise account, or a question you would like the fleet pointed at, write to <a href=\"mailto:contact@stereumlabs.com\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">contact@stereumlabs.com</a>. Tell us the question, not the SKU, and we will scope it with you.</p>",
            "url": "https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack",
            "title": "StereumLabs introduced: the stack behind our Ethereum client measurements",
            "summary": "A technical companion to the RockLogic 'AI on own data' case study. We open the hood on the StereumLabs measurement platform: the bare-metal fleet, the metrics and logs pipeline, the label conventions that make 36 execution-client + consensus-client pairings comparable, and the in-house AI workflow that turns the resulting telemetry into the blog posts you read here.",
            "date_modified": "2026-05-20T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "StereumLabs",
                "methodology",
                "bare-metal",
                "Proxmox",
                "Prometheus",
                "Elasticsearch",
                "Grafana",
                "Filebeat",
                "MCP",
                "observability",
                "reproducibility",
                "security-audit",
                "bug-bounty"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos",
            "content_html": "<p>Before The Merge in September 2022, an Ethereum node was a single Proof-of-Work client. Geth, Parity, Erigon, Nethermind, or Besu, each handling everything from networking and the EVM to mining and chain selection inside one binary. The Merge split that role in two: an execution layer (EL) for the EVM, transactions, mempool, and world state, and a consensus layer (CL) for Proof-of-Stake fork choice, finality, attestations, and block proposals. The two halves talk to each other over the engine API, a JSON-RPC channel authenticated with a JWT secret.</p>\n<p>Most operators run those two layers as two separate binaries that talk over the engine API. Caplin v3.3.10 collapses them back into a single Erigon binary. We added a Caplin standalone host to the StereumLabs fleet on April 8, 2026, and let it run alongside the classic Erigon plus CC pairings under identical mainnet conditions. This post reports what we measured: where the monolithic architecture wins, where it pays a tax, and where it leaves observability holes.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Caplin standalone vs classic Erigon and CC split: architectural diagram\" src=\"https://docs.stereumlabs.com/assets/images/erigon-caplin-thumbnail-a69721318032392cc76b912f28c352c9.png\" width=\"2440\" height=\"1299\" class=\"img_ev3q\"></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"setup\">Setup<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#setup\" class=\"hash-link\" aria-label=\"Direct link to Setup\" title=\"Direct link to Setup\" translate=\"no\">​</a></h2>\n<p>The standalone deployment runs on a single bare-metal VM in our <a href=\"https://docs.stereumlabs.com/docs/scope/list-of-vms\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Vienna NDC2 cluster</a>. Caplin runs as part of the Erigon binary with the consensus and execution layers sharing one executable, one MDBX database, and one combined libp2p plus devp2p networking stack. The host has 16 vCPU, 31.3 GB RAM, and 1.9 TB of NVMe storage, running Ubuntu 22.04.</p>\n<p>The classic Erigon combos run as two separate binaries on two VMs per pairing. We split EC and CC by design across two hosts so that node-exporter measurements give us clean per-layer resource consumption. The EC side gets 12 vCPU, 15.6 GB RAM, and 1.9 TB. The CC side gets 8 vCPU, 11.7 GB RAM, and 527.8 GB. Combined, that is 20 vCPU, 27.3 GB RAM, and roughly 2.4 TB of disk per pairing.</p>\n<table><thead><tr><th>Profile</th><th>Architecture</th><th>CPU</th><th>RAM</th><th>Disk</th></tr></thead><tbody><tr><td>Caplin standalone</td><td>EL plus CL combined in one Erigon binary</td><td>16 vCPU</td><td>31.3 GB</td><td>1.9 TB</td></tr><tr><td>Classic Erigon plus CC</td><td>Two separate binaries (EL and CL)</td><td>20 vCPU</td><td>27.3 GB</td><td>2.4 TB</td></tr></tbody></table>\n<p>That asymmetry matters. The standalone has 20% fewer vCPUs and 21% less disk, but 15% more RAM concentrated on one host. Any direct comparison has to account for it. We summed the resource consumption across the CC and EC VMs of each classic pairing and compared the total to the standalone single host.</p>\n<p>We measured resource and stability metrics over a 7 day window using <code>avg_over_time(...[7d:1h])</code> against our cold Prometheus datasource. Block processing latency comes from parsing 50,165 <code>head updated</code> log lines extracted via Elasticsearch, covering the trailing 24 hours across the standalone and all six Erigon plus CC pairings.</p>\n<p>All six classic Erigon EC instances are paired with the same CC versions: Lighthouse v8.1.3, Lodestar v1.42.0, Nimbus v26.3.1, Prysm v7.1.3, Teku 26.4.0, and Grandine 2.0.4. Both the standalone and the classic ECs run Erigon v3.3.10. For the StereumLabs label conventions and metric availability per client, see <a href=\"https://docs.stereumlabs.com/docs/scope/client-metrics\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Client metrics scope</a>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"resource-footprint\">Resource footprint<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#resource-footprint\" class=\"hash-link\" aria-label=\"Direct link to Resource footprint\" title=\"Direct link to Resource footprint\" translate=\"no\">​</a></h2>\n<p>The first question is whether one binary holding two layers consumes more or less than two binaries holding one layer each.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Resource footprint comparison: Caplin standalone vs sum of classic Erigon plus CC\" src=\"https://docs.stereumlabs.com/assets/images/erigon-caplin-resources-9c4cef815e7147c707822545effcb393.png\" width=\"2768\" height=\"1043\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Metric</th><th>Caplin standalone</th><th>Erigon plus CC range</th><th>Erigon plus CC median</th></tr></thead><tbody><tr><td>CPU (vCPU cores)</td><td>1.21</td><td>0.68 to 2.20</td><td>1.20</td></tr><tr><td>RAM used (GB)</td><td>13.0</td><td>11.35 to 14.32</td><td>13.09</td></tr><tr><td>Disk read (MB/s)</td><td>5.0</td><td>5.17 to 17.01</td><td>5.82</td></tr><tr><td>Disk write (MB/s)</td><td>18.1</td><td>14.69 to 31.42</td><td>16.07</td></tr><tr><td>Network RX (MB/s)</td><td>0.73</td><td>0.77 to 2.04</td><td>1.75</td></tr><tr><td>Network TX (MB/s)</td><td>0.73</td><td>0.46 to 1.70</td><td>1.23</td></tr><tr><td>Swap usage (GB)</td><td>3.83</td><td>2.47 to 4.58</td><td>3.61</td></tr></tbody></table>\n<p>Caplin standalone lands at or near the median of the Erigon plus CC pairings on every dimension except network, where it consumes well under half what the classic combos do. That gap is structural. In our split deployment, every <code>engine_forkchoiceUpdated</code>, <code>engine_newPayload</code>, and <code>engine_getBlobsV2</code> call traverses the network between the CC and EC VMs. In the standalone binary, those calls become in-process function invocations that never touch a NIC.</p>\n<p>Memory deserves a closer look. Caplin's container log reports <code>Rss=26.1GB Pss=26.1GB Anonymous=11.7GB Swap=3.7GB</code>, which seems to contradict the 13 GB we measured from <code>node_memory_MemTotal_bytes minus node_memory_MemAvailable_bytes</code>. Both numbers are correct. MDBX is memory-mapped, and roughly 14.5 GB of Erigon's RSS is shared-clean page cache that the kernel can reclaim instantly under pressure. <code>MemAvailable</code> correctly counts those pages as free. The 13 GB figure represents the working set that cannot be evicted without forcing reads from disk.</p>\n<p>The 3.83 GB swap is also nothing unusual. Every classic Erigon EC swaps between 2.4 and 2.8 GB on its own, and the paired CC adds another 0 to 2.1 GB. Combined, the Erigon plus CC swap usage ranges from 2.5 to 4.6 GB, putting Caplin's 3.83 GB right in the middle. This is normal MDBX cold-page eviction behavior.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-peer-story\">The peer story<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#the-peer-story\" class=\"hash-link\" aria-label=\"Direct link to The peer story\" title=\"Direct link to The peer story\" translate=\"no\">​</a></h2>\n<p>Caplin standalone runs two separate P2P networks from a single binary. devp2p for execution layer peers, libp2p for the consensus layer. Each has its own peer count.</p>\n<p>On the execution side, devp2p reports 64 connected peers, split evenly across the eth/68 and eth/69 protocol versions. The classic Erigon EC instances on the same fleet report 42 to 43 peers each. Same Erigon binary, same network, same configuration philosophy, but the standalone consistently maintains roughly 50% more EC peers. The likely cause is the larger CPU and memory budget on the standalone host. For more on how the various ECs behave at the P2P layer, see our <a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">EC P2P peering deep dive</a>.</p>\n<p>On the consensus side, the picture is harder to extract. Caplin v3.3.10 does not expose a current libp2p peer count gauge in Prometheus. The metric appears only in the periodic container log line <code>P2P app=caplin peers=127</code>. We had to switch to log parsing to recover the value.</p>\n<table><thead><tr><th>CC</th><th>libp2p peer count</th></tr></thead><tbody><tr><td>Grandine</td><td>201</td></tr><tr><td>Lodestar</td><td>200</td></tr><tr><td>Lighthouse</td><td>198 to 200</td></tr><tr><td>Teku</td><td>98 to 100</td></tr><tr><td>Caplin standalone</td><td><strong>127</strong></td></tr><tr><td>Nimbus</td><td>81</td></tr><tr><td>Prysm</td><td>~73</td></tr></tbody></table>\n<p>Caplin sits in the upper-middle band, below the aggressive peer collectors (Grandine, Lodestar, Lighthouse) but well above the more conservative implementations.</p>\n<div class=\"theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>Observability gap</div><div class=\"admonitionContent_BuS1\"><p>Caplin v3.3.10 ships a comprehensive <code>libp2p_rcmgr_*</code> metric family covering connection lifetime counters, but no current peers gauge. Operators have to scrape the <code>P2P app=caplin peers=N</code> log line, which is emitted once per minute. This is the most significant observability gap we encountered.</p></div></div>\n<p>A side benefit of Prysm's <code>connected_libp2p_peers{agent=\"...\"}</code> metric is that we can ask the Prysm fleet how many Caplin nodes it sees in the wider network. The answer is sobering: across all five working Prysm pairings combined, only 7 peers identify as <code>agent=\"erigon/caplin\"</code>. Caplin nodes remain rare in the mainnet peer graph. Some of those 7 may even be our own standalone connecting to multiple Prysm instances on the same datacenter network. Standalone Caplin is still a young deployment pattern.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"block-processing-where-caplin-wins\">Block processing: where Caplin wins<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#block-processing-where-caplin-wins\" class=\"hash-link\" aria-label=\"Direct link to Block processing: where Caplin wins\" title=\"Direct link to Block processing: where Caplin wins\" translate=\"no\">​</a></h2>\n<p>To compare execution performance precisely, we parsed every <code>head updated</code> log line from the trailing 24 hours on the standalone and all six classic Erigon EC instances. The line format gives us four numeric fields per imported block: arrival age relative to slot start, EVM execution time, MDBX commit time, and the moving average gas throughput.</p>\n<p>After parsing, we have between 5,113 and 7,174 samples per host, totaling roughly 50,000 blocks. The dataset is large enough that the percentile estimates are stable.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"evm-execution-time\">EVM execution time<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#evm-execution-time\" class=\"hash-link\" aria-label=\"Direct link to EVM execution time\" title=\"Direct link to EVM execution time\" translate=\"no\">​</a></h3>\n<p>This is the time from the block being received and verified to its transactions being fully executed by the EVM, before the database commit phase.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Block execution time percentiles across Caplin standalone and six classic Erigon pairings\" src=\"https://docs.stereumlabs.com/assets/images/erigon-caplin-execution-time-49337bd5c00c71c79d172e5150af1efd.png\" width=\"2055\" height=\"1116\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Host</th><th>n</th><th>p50 (ms)</th><th>p90 (ms)</th><th>p99 (ms)</th></tr></thead><tbody><tr><td><strong>Caplin standalone</strong></td><td>7142</td><td><strong>865</strong></td><td><strong>1955</strong></td><td><strong>5233</strong></td></tr><tr><td>Erigon plus Lodestar</td><td>7157</td><td>981</td><td>2049</td><td>5239</td></tr><tr><td>Erigon plus Lighthouse</td><td>7118</td><td>1014</td><td>2102</td><td>5396</td></tr><tr><td>Erigon plus Grandine</td><td>7141</td><td>1026</td><td>2161</td><td>5268</td></tr><tr><td>Erigon plus Nimbus</td><td>7164</td><td>1037</td><td>2208</td><td>5587</td></tr><tr><td>Erigon plus Prysm</td><td>6847</td><td>1039</td><td>2170</td><td>5532</td></tr><tr><td>Erigon plus Teku</td><td>5113</td><td>1135</td><td>2637</td><td>5371</td></tr></tbody></table>\n<p>At the median, Caplin executes blocks 12% faster than the next-fastest pairing (Lodestar) and 31% faster than the slowest (Teku). At the 90th percentile the lead is similar. At the 99th percentile the standalone still leads, though by a smaller margin.</p>\n<p>The same story shows up in throughput. Mgas per second is the metric Erigon reports as a 12-block moving average inside the head updated line.</p>\n<table><thead><tr><th>Host</th><th>p50 (Mgas/s)</th><th>p90 (Mgas/s)</th><th>p99 (Mgas/s)</th></tr></thead><tbody><tr><td><strong>Caplin standalone</strong></td><td><strong>33.6</strong></td><td><strong>49.4</strong></td><td><strong>89.6</strong></td></tr><tr><td>Erigon plus Lodestar</td><td>29.3</td><td>43.0</td><td>80.7</td></tr><tr><td>Erigon plus Lighthouse</td><td>28.3</td><td>42.0</td><td>74.8</td></tr><tr><td>Erigon plus Grandine</td><td>28.2</td><td>41.4</td><td>75.1</td></tr><tr><td>Erigon plus Nimbus</td><td>27.7</td><td>41.3</td><td>73.9</td></tr><tr><td>Erigon plus Prysm</td><td>27.7</td><td>41.1</td><td>77.4</td></tr><tr><td>Erigon plus Teku</td><td>25.8</td><td>38.7</td><td>93.3</td></tr></tbody></table>\n<p>Caplin processes 14% to 30% more gas per second than any classic Erigon pairing across the percentile range. The Erigon binary is identical on every host, so the speedup is some combination of three things. The standalone has four extra vCPUs (16 vs 12). It avoids engine API marshaling because the CL hands payloads to the EL through in-process calls instead of JSON-RPC. And state lookups during execution skip serialization across the engine API boundary. Our data cannot fully separate the architectural contribution from the hardware contribution, but both push in the same direction.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"block-processing-where-caplin-pays\">Block processing: where Caplin pays<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#block-processing-where-caplin-pays\" class=\"hash-link\" aria-label=\"Direct link to Block processing: where Caplin pays\" title=\"Direct link to Block processing: where Caplin pays\" translate=\"no\">​</a></h2>\n<p>Now the unflattering side. After execution, Erigon writes state changes to MDBX. In a classic deployment, this commit phase covers only EL state. In the standalone, the same phase also has to persist consensus-layer updates from the imported block, including beacon block headers, attestation aggregations, sync committee participation, and validator state changes.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Commit time percentiles: Caplin standalone vs classic Erigon pairings\" src=\"https://docs.stereumlabs.com/assets/images/erigon-caplin-commit-time-230cdc8b657eb1e5388b104118bd9844.png\" width=\"2055\" height=\"1116\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Host</th><th>p50 (ms)</th><th>p90 (ms)</th><th>p99 (ms)</th></tr></thead><tbody><tr><td>Erigon plus Nimbus</td><td>118</td><td>163</td><td>234</td></tr><tr><td>Erigon plus Lighthouse</td><td>120</td><td>167</td><td>240</td></tr><tr><td>Erigon plus Lodestar</td><td>121</td><td>166</td><td>246</td></tr><tr><td>Erigon plus Teku</td><td>121</td><td>172</td><td>297</td></tr><tr><td>Erigon plus Grandine</td><td>123</td><td>172</td><td>294</td></tr><tr><td>Erigon plus Prysm</td><td>126</td><td>175</td><td>274</td></tr><tr><td><strong>Caplin standalone</strong></td><td><strong>262</strong></td><td><strong>362</strong></td><td><strong>519</strong></td></tr></tbody></table>\n<p>Caplin's commit takes more than twice as long. The penalty is consistent across percentiles and time of day. The most plausible explanation is workload size: the standalone has to write more state to MDBX during the same block boundary because it owns both layers. Whether that happens as one MDBX transaction, two, or several sequential ones is something we did not verify at the source level. The metric is the total time the commit phase reports, regardless of how many transactions sit inside it.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"end-to-end-a-wash-at-the-median-slightly-long-tailed\">End-to-end: a wash at the median, slightly long-tailed<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#end-to-end-a-wash-at-the-median-slightly-long-tailed\" class=\"hash-link\" aria-label=\"Direct link to End-to-end: a wash at the median, slightly long-tailed\" title=\"Direct link to End-to-end: a wash at the median, slightly long-tailed\" translate=\"no\">​</a></h2>\n<p>Adding execution and commit gives the total time to fully process a new head block. This is the number that matters for downstream signaling, RPC freshness, and validator readiness.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"End to end head update time at p50: stacked execution plus commit\" src=\"https://docs.stereumlabs.com/assets/images/erigon-caplin-end-to-end-f442f8a764bcfdb11256db556234f479.png\" width=\"2055\" height=\"1080\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Host</th><th>Exec p50 + Commit p50 (ms)</th></tr></thead><tbody><tr><td>Erigon plus Lodestar</td><td>1102</td></tr><tr><td><strong>Caplin standalone</strong></td><td><strong>1127</strong></td></tr><tr><td>Erigon plus Lighthouse</td><td>1134</td></tr><tr><td>Erigon plus Grandine</td><td>1149</td></tr><tr><td>Erigon plus Nimbus</td><td>1155</td></tr><tr><td>Erigon plus Prysm</td><td>1165</td></tr><tr><td>Erigon plus Teku</td><td>1256</td></tr></tbody></table>\n<p>At the 50th percentile end-to-end, Caplin is essentially tied with the fastest classic pairings. Lodestar plus Erigon edges it out by 25 ms, which is well within sampling noise. Caplin beats every other pairing by 7 to 129 ms.</p>\n<p>At the 99th percentile, the picture inverts slightly. The standalone's longer commit pushes its tail above some of the classic pairings, even though its execution tail is among the fastest. The total p99 spreads from 5485 ms (Lodestar plus Erigon) to 5821 ms (Nimbus plus Erigon), with Caplin at 5752 ms.</p>\n<p>So the honest framing is this: the monolithic node executes faster, commits slower, and ends up roughly equivalent at the median. The execution win is real but the commit penalty cancels most of it. Caplin's advantage is that it gets there with one binary instead of two.</p>\n<p>Block age, the time from slot start to when the EC first observes the block via gossip, is identical across all hosts: p50 of 3 to 4 seconds, p99 of 9 to 12 seconds. The network is not the differentiator here. Whatever happens after a block arrives is what we are measuring.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"stability-and-log-hygiene\">Stability and log hygiene<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#stability-and-log-hygiene\" class=\"hash-link\" aria-label=\"Direct link to Stability and log hygiene\" title=\"Direct link to Stability and log hygiene\" translate=\"no\">​</a></h2>\n<p>Over the 7 day window, the Caplin standalone process did not restart once. Its current uptime is 9.7 days. Internal RPC failure counter (<code>rpc_failure</code>) reads zero. The single warning we found in the entire week was a <code>forkchoice was invalid</code> message at 06:53 UTC on May 8, an isolated event with no follow-up symptoms.</p>\n<p>We compared container log volumes and warning rates across the standalone and all six classic Erigon EC hosts. The classic ECs ship between 123,000 and 154,000 log lines per week. The standalone ships 100,744. Less log volume on a setup that handles both layers seems counterintuitive until you look at what the classic ECs are saying.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Container log volume and warning rate per host over 7 days\" src=\"https://docs.stereumlabs.com/assets/images/erigon-caplin-log-volume-b602fcc4f8526d39ea780d13b3be3c75.png\" width=\"2055\" height=\"1080\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Host</th><th>Lines / 7d</th><th>WARN</th><th>ERROR</th><th>Panic</th><th>WARN rate</th></tr></thead><tbody><tr><td><strong>Caplin standalone</strong></td><td><strong>100,744</strong></td><td>1</td><td>0</td><td>0</td><td>0.001%</td></tr><tr><td>Erigon plus Lodestar</td><td>123,020</td><td>16</td><td>0</td><td>0</td><td>0.013%</td></tr><tr><td>Erigon plus Nimbus</td><td>137,857</td><td>2</td><td>0</td><td>0</td><td>0.001%</td></tr><tr><td>Erigon plus Prysm</td><td>139,585</td><td>365</td><td>0</td><td>0</td><td>0.261%</td></tr><tr><td>Erigon plus Lighthouse</td><td>140,865</td><td>22</td><td>0</td><td>0</td><td>0.016%</td></tr><tr><td>Erigon plus Grandine</td><td>141,026</td><td>66</td><td>0</td><td>0</td><td>0.047%</td></tr><tr><td>Erigon plus Teku</td><td>154,006</td><td>13</td><td>0</td><td>0</td><td>0.008%</td></tr></tbody></table>\n<p>The dominant Erigon log pattern that appears in classic ECs but not in the standalone is <code>[NewPayload] Handling new payload</code>, fired once per engine API call from the CC. On the Teku-paired Erigon EC we measured 28 of these in 5 minutes. Extrapolated, that accounts for roughly 336 lines per hour, or about 56,000 lines per week of pure engine API chatter. Take that out and the classic ECs fall close to Caplin's volume.</p>\n<p>Zero ERROR-level lines and zero panics across the entire Erigon family for 7 days. Both architectures are equally calm in steady state. The only meaningful difference is that the standalone has fewer log lines to ignore.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"database-and-storage-efficiency\">Database and storage efficiency<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#database-and-storage-efficiency\" class=\"hash-link\" aria-label=\"Direct link to Database and storage efficiency\" title=\"Direct link to Database and storage efficiency\" translate=\"no\">​</a></h2>\n<p>The Caplin standalone reports an MDBX <code>chaindata</code> size of 34.34 GB. Five of the six classic Erigon EC pairings sit between 20.05 GB (Lodestar pair, recently resynced) and 39.94 GB (Prysm pair, with extra unprune'd cache), with most clustering around 34.4 GB.</p>\n<p>That is striking. The standalone holds the entire EL state plus the entire CL beacon state, including beacon blocks, attestations, sync committees, validator state, and randao mixes. Yet its database is the same size as an EC-only Erigon. Either MDBX's append-only B-tree representation is exceptionally efficient for the beacon-state schema, or the standalone backfill is not yet complete. Caplin v3.3.10 does not expose a backfill progress metric, so we cannot tell from outside the process which case applies.</p>\n<p>This is the second observability gap worth flagging. Operators upgrading or restarting a Caplin standalone have no externally visible signal that historical CL state has finished downloading.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"caplins-cl-side-health\">Caplin's CL-side health<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#caplins-cl-side-health\" class=\"hash-link\" aria-label=\"Direct link to Caplin's CL-side health\" title=\"Direct link to Caplin's CL-side health\" translate=\"no\">​</a></h2>\n<p>The consensus side of Caplin exposes a different metric set than dedicated CCs, but the few metrics that exist look healthy:</p>\n<table><thead><tr><th>Metric</th><th>Caplin value</th></tr></thead><tbody><tr><td><code>aggregate_quality_50</code></td><td>0.995</td></tr><tr><td><code>attestation_block_processing_time</code></td><td>65 ms</td></tr><tr><td><code>active_validators_count</code></td><td>913,144</td></tr><tr><td><code>committee_size</code></td><td>438</td></tr><tr><td><code>current_epoch</code></td><td>446,409</td></tr></tbody></table>\n<p>The attestation aggregation quality at the 50th percentile is 99.5%, meaning Caplin is folding nearly every unique-validator attestation it sees into the largest available aggregate. Attestation block processing time of 65 ms is faster than most CC implementations report for similar work.</p>\n<p>Block proposal metrics (<code>block_producer_delay</code>) read NaN. The Caplin standalone host is one of the few in our fleet that runs without attached validator keys, so it never proposes blocks. The classic Erigon plus CC pairings on Vienna NDC2 do have validators attached on their CC sides, but that workload is on the CC, not on the EC, and it does not influence the EC commit numbers we measured. Comparing block proposal performance directly between the architectures requires a future investigation that runs Caplin standalone with attached validators. The Nimbus block-building work in our <a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Nimbus v26.3.1 post</a> gives a sense of what that comparison would look like once we have the data.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"architectural-trade-offs-that-dont-show-up-in-metrics\">Architectural trade-offs that don't show up in metrics<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#architectural-trade-offs-that-dont-show-up-in-metrics\" class=\"hash-link\" aria-label=\"Direct link to Architectural trade-offs that don't show up in metrics\" title=\"Direct link to Architectural trade-offs that don't show up in metrics\" translate=\"no\">​</a></h2>\n<p>Two operational properties of the standalone are real but not measurable from the outside.</p>\n<p>The first is failure-domain coupling. With separate binaries (whether on one VM or two), an EC restart leaves the CC running and able to continue gossiping, observing the chain head, and serving its own RPC clients. The CC may flag the EC as offline, but it does not crash. In the standalone, an EC restart is a CC restart by definition. There is no degraded mode where one layer keeps operating while the other recovers.</p>\n<p>The second is upgrade granularity. With separate binaries, you can update the EC while leaving the CC stable, or vice versa. This matters when one layer ships a critical fix and the other is in a regression window. The standalone bundles the upgrade. There is no path to upgrade only the EL or only the CL while keeping the other version pinned.</p>\n<p>Neither point is a defect, both are intentional consequences of the design choice. They are worth weighing against the resource and stability gains.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"who-is-this-for\">Who is this for?<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#who-is-this-for\" class=\"hash-link\" aria-label=\"Direct link to Who is this for?\" title=\"Direct link to Who is this for?\" translate=\"no\">​</a></h2>\n<p>Erigon has a strong reputation as the most efficient archive-class Ethereum execution client. Its compact MDBX storage and pipelined sync turn full historical state into a workable handful of terabytes where many other clients require multiples of that. We documented some of that elsewhere in <a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Execution client sync speed</a>. Caplin standalone extends that strength by adding the consensus layer to the same binary. The operational unit becomes a single binary holding everything: full historical EVM state, beacon chain history, and a complete view of Ethereum from genesis to tip.</p>\n<p>That makes Caplin standalone a particularly good match for:</p>\n<ul>\n<li class=\"\"><strong>Archive node operators</strong> wanting the smallest possible disk and CPU footprint for a complete node.</li>\n<li class=\"\"><strong>RPC providers</strong> prioritizing operational simplicity, predictable resource ceilings, and a single point of telemetry.</li>\n<li class=\"\"><strong>Indexers, subgraph operators, and data extractors</strong> that need to query both EL state and CL beacon data from the same host without engineering two-binary coordination.</li>\n<li class=\"\"><strong>MEV searchers and analytics platforms</strong> consuming real-time chain state plus historical data.</li>\n<li class=\"\"><strong>Solo stakers</strong> who are comfortable accepting failure-domain coupling in exchange for a smaller hardware bill and simpler runbooks.</li>\n</ul>\n<p>It is less appropriate for:</p>\n<ul>\n<li class=\"\"><strong>High-availability validator infrastructure</strong> where you want the CC to keep functioning while the EC is being restarted, replaced, or upgraded.</li>\n<li class=\"\"><strong>Operators with strict change-management policies</strong> that pin EL and CL upgrades on independent cadences, particularly during regression windows.</li>\n<li class=\"\"><strong>Multi-CC redundancy patterns</strong> where running a different CC alongside the primary protects against bugs in one implementation. Caplin replaces the CC role, it cannot run alongside one.</li>\n</ul>\n<p>For pure staking-only setups without external RPC consumers, the case for the standalone is genuinely close. The resource efficiency is real, the stability so far has been very good, and the operational surface area is smaller. The case against it comes down to one question: how much do you value being able to recover one layer while the other keeps working? If the answer is \"a lot\", the split deployment still has a meaningful edge. If the answer is \"less than I value the simpler operations\", the standalone earns its place.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"summary\">Summary<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#summary\" class=\"hash-link\" aria-label=\"Direct link to Summary\" title=\"Direct link to Summary\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>Dimension</th><th>Result</th></tr></thead><tbody><tr><td>EVM execution speed</td><td>🟢 Caplin <strong>+12 to +31%</strong> faster at p50</td></tr><tr><td>Gas throughput</td><td>🟢 Caplin <strong>+14 to +30%</strong> higher across percentiles</td></tr><tr><td>MDBX commit time</td><td>🔴 Caplin <strong>2x slower</strong> (more state per block boundary)</td></tr><tr><td>End-to-end head update at p50</td><td>⚪ Roughly equivalent to fastest classic pair</td></tr><tr><td>End-to-end at p99</td><td>⚪ Mid-pack, slightly long-tailed</td></tr><tr><td>EL peer count</td><td>🟢 Caplin <strong>+50%</strong> vs classic Erigon EC</td></tr><tr><td>CL peer count</td><td>🟢 Upper-middle band (127 vs 73 to 201)</td></tr><tr><td>Resource footprint</td><td>🟢 At or below median of combo sums; minus 40 to 60% network</td></tr><tr><td>Log volume</td><td>🟢 <strong>18 to 35% less</strong> than classic ECs</td></tr><tr><td>Warning rate (7d)</td><td>🟢 0.001% (tied with Nimbus pairing for lowest)</td></tr><tr><td>Stability</td><td>🟢 0 restarts, 9.7d continuous uptime</td></tr><tr><td>libp2p peer gauge</td><td>🔴 Not exposed in Prometheus, log-only</td></tr><tr><td>Backfill progress</td><td>🔴 Not exposed</td></tr><tr><td>Failure-domain isolation</td><td>🔴 Single binary for both layers</td></tr><tr><td>Update granularity</td><td>🔴 EL and CL upgrade together</td></tr></tbody></table>\n<p>We will revisit this comparison once Caplin v3.3.10 has accumulated enough peer adoption to escape the seven-peers-in-our-Prysm-fleet floor, and once we can measure block proposal performance with attached validators on a standalone host. Until then, the standalone holds up well as a production candidate, the trade-offs are exactly where the architecture says they should be, and the audience it fits best is broader than the staking-only crowd usually assumes.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"methodology-notes\">Methodology notes<a href=\"https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos#methodology-notes\" class=\"hash-link\" aria-label=\"Direct link to Methodology notes\" title=\"Direct link to Methodology notes\" translate=\"no\">​</a></h2>\n<p>Resource and stability metrics queried from our cold Prometheus datasource using <code>avg_over_time(...[7d:1h])</code> instant queries evaluated at the end of the 7 day window. Host-level metrics filtered with <code>device!~\"lo|veth.*|docker.*|br.*\"</code> to exclude virtual interfaces. Process-level metrics filtered by <code>job</code> to separate Caplin and Erigon scrapes from <code>node_exporter</code>.</p>\n<p>Block processing latencies extracted from Filebeat-shipped container logs via Elasticsearch. We parsed <code>head updated</code> log lines using regex matching for <code>execution=</code>, <code>commit=</code>, <code>age=</code>, and <code>mgas/s=</code> fields. Sample sizes are 5,113 to 7,174 blocks per host over 24 hours. ANSI color codes stripped before parsing.</p>\n<p>Peer counts on the consensus side use a mix of Prometheus gauges and log-extracted values. Caplin standalone CL peers come from the <code>P2P app=caplin peers=N</code> log line emitted once per minute, since v3.3.10 does not expose a current libp2p peer gauge. Cross-fleet Caplin visibility uses Prysm's <code>connected_libp2p_peers{agent=\"erigon/caplin\"}</code>.</p>\n<p>For the StereumLabs label conventions and how to point your own dashboards at our data, see <a href=\"https://docs.stereumlabs.com/docs/dashboards/build-your-own\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Build your own dashboards</a>. For prior context on EC behavior under similar conditions, see our posts on <a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">EC P2P peering</a>, <a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">EC sync speed</a>, and <a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Teku cross-version analysis</a>.</p>\n<p>If you want a custom version of this analysis for your own fleet or a deeper look at any single dimension, write to us at <a href=\"mailto:contact@stereumlabs.com\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">contact@stereumlabs.com</a>.</p>",
            "url": "https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos",
            "title": "Erigon's monolithic node: 25% faster execution, 2x slower commits",
            "summary": "Caplin v3.3.10 is the first standalone setup in our fleet, running a complete Ethereum node from a single Erigon binary. We compared it head-to-head with all six classic Erigon plus CC pairings across 50,000 blocks and seven days of operational data.",
            "date_modified": "2026-05-13T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "Erigon",
                "Caplin",
                "consensus client",
                "execution client",
                "standalone",
                "performance",
                "MDBX",
                "architecture",
                "archive node"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis",
            "content_html": "<p>Every execution client connects to different peers, sees a different slice of the network, and churns through connections at wildly different rates. We queried Prometheus metrics and Elasticsearch container logs across our entire fleet to find out what each EC actually experiences at the P2P layer, and what it means for Ethereum's network health.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"EC P2P peering analysis thumbnail\" src=\"https://docs.stereumlabs.com/assets/images/thumbnail-814e56f998d713e2f1884d032ef851f7.png\" width=\"1830\" height=\"975\" class=\"img_ev3q\"></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"why-p2p-peering-matters\">Why P2P peering matters<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#why-p2p-peering-matters\" class=\"hash-link\" aria-label=\"Direct link to Why P2P peering matters\" title=\"Direct link to Why P2P peering matters\" translate=\"no\">​</a></h2>\n<p>When people talk about Ethereum client diversity, the conversation usually centers around \"what percentage of the network runs Geth?\" But there's a deeper question that rarely gets asked: <strong>what does each client actually see?</strong></p>\n<p>Every execution client maintains its own set of P2P connections through the DevP2P protocol. These peers are the node's window into the Ethereum network. Through them, the node receives new transactions, propagates blocks, and participates in the state sync protocol. If your peers are slow, your node sees transactions late. If your peers all run the same client, a single bug could blind you.</p>\n<p>We set out to answer a set of straightforward questions using our NDC2 bare-metal fleet in Vienna and GCP cloud instances (roughly 90 hosts running all 6 execution clients paired with all 6 consensus clients):</p>\n<ul>\n<li class=\"\">How many peers does each EC maintain?</li>\n<li class=\"\">Who are those peers? What clients do they run?</li>\n<li class=\"\">How fast does each EC cycle through its peer set?</li>\n<li class=\"\">Does the consensus client you pair with your EC influence its P2P behavior?</li>\n<li class=\"\">What happens when DevP2P inbound ports are blocked?</li>\n<li class=\"\">What does all of this mean for Ethereum's network health?</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-fleet-and-the-data-sources\">The fleet and the data sources<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#the-fleet-and-the-data-sources\" class=\"hash-link\" aria-label=\"Direct link to The fleet and the data sources\" title=\"Direct link to The fleet and the data sources\" translate=\"no\">​</a></h2>\n<p>Our analysis combines two data sources: <strong>Prometheus metrics</strong> (7-day rolling averages via <code>avg_over_time(...[7d:1h])</code> queries against our <code>prometheus-cold</code> datasource) and <strong>Elasticsearch container logs</strong> shipped by Filebeat from every EC container on the fleet. We've previously covered how these clients differ in <a class=\"\" href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026\">sync speed</a> and <a class=\"\" href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\">block building</a>. This time, we're looking at how they differ in who they talk to.</p>\n<p>Each EC exposes peer data differently. Some have rich Prometheus gauges; some log periodic peer reports; some give us almost nothing. Let's focus on what we actually found.</p>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>note</div><div class=\"admonitionContent_BuS1\"><p>All peer counts and diversity percentages in this post are 7-day averages from the fleet unless noted otherwise. Individual snapshots can vary, as we'll see in the churn section.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"peer-counts-from-25-to-130\">Peer counts: from 25 to 130<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#peer-counts-from-25-to-130\" class=\"hash-link\" aria-label=\"Direct link to Peer counts: from 25 to 130\" title=\"Direct link to Peer counts: from 25 to 130\" translate=\"no\">​</a></h2>\n<p>The first and most basic question: how many peers does each EC maintain?</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"EC peer counts\" src=\"https://docs.stereumlabs.com/assets/images/peer_counts-b2c540b1883aa02564b2f5de2b5cce23.png\" width=\"1484\" height=\"732\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC</th><th>Avg peers</th><th>Configured limit</th><th>% of limit</th></tr></thead><tbody><tr><td>Reth v2.1.0</td><td>130</td><td>~130</td><td>100%</td></tr><tr><td>Ethrex v10.0.0</td><td>105</td><td>high (uncapped?)</td><td>—</td></tr><tr><td>Nethermind 1.36.2</td><td>50</td><td>50</td><td>100%</td></tr><tr><td>Geth v1.17.2</td><td>50</td><td>~50</td><td>99%</td></tr><tr><td>Erigon v3.3.10</td><td>42</td><td>~50</td><td>84%</td></tr><tr><td>Besu 26.4.0</td><td>24</td><td><strong>25</strong></td><td>95%</td></tr></tbody></table>\n<p>The spread is striking: Reth maintains over 5x the connections Besu does. Every client except Erigon runs at or near its configured maximum, which means the peer limit is the binding constraint. Erigon is the outlier, consistently operating below its limit, and we'll see why when we look at its protocol behavior.</p>\n<div class=\"theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>For operators</div><div class=\"admonitionContent_BuS1\"><p>Besu's default <code>--max-peers=25</code> is the lowest of any EC. If you're running Besu, consider raising this to at least 50. With only 25 peers, a single-client bug affecting your dominant peer type can severely degrade your view of the network.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-happens-when-devp2p-inbound-ports-are-blocked\">What happens when DevP2P inbound ports are blocked?<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#what-happens-when-devp2p-inbound-ports-are-blocked\" class=\"hash-link\" aria-label=\"Direct link to What happens when DevP2P inbound ports are blocked?\" title=\"Direct link to What happens when DevP2P inbound ports are blocked?\" translate=\"no\">​</a></h2>\n<p>Our GCP cloud instances ran Geth with the same configuration as our NDC2 bare-metal fleet, but with one critical difference: the GCP default firewall did not have port 30303 (DevP2P) opened for inbound traffic. This is a very common situation: most cloud providers (GCP, AWS, Azure) block all inbound traffic by default, and operators who don't explicitly open port 30303 TCP+UDP end up in exactly this state. The Geth process itself has no idea, it starts normally, makes outbound connections, and follows the chain.</p>\n<p>The effect on peering is dramatic:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Geth peering: open vs blocked inbound ports\" src=\"https://docs.stereumlabs.com/assets/images/gcp_vs_ndc2-c968ad8395b0de50b8481bdfcfc067cc.png\" width=\"1183\" height=\"733\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Metric</th><th>Port 30303 open (NDC2)</th><th>Port 30303 blocked (GCP)</th></tr></thead><tbody><tr><td>Total peers</td><td><strong>50</strong></td><td><strong>15</strong></td></tr><tr><td>Inbound peers</td><td>34</td><td><strong>0</strong></td></tr><tr><td>Outbound peers</td><td>16</td><td>15</td></tr></tbody></table>\n<p>With inbound blocked, Geth receives <strong>zero incoming DevP2P connections</strong>. Its 15 peers are entirely self-initiated outbound connections. With the port open (NDC2), the same Geth configuration receives 34 additional inbound connections, reaching the full 50-peer capacity.</p>\n<p>The outbound count is essentially identical (~15-16 both ways), confirming this isn't a Geth software or configuration difference. It's purely a network access issue. Geth initiates the same number of outbound connections regardless of whether it can receive inbound ones, but other nodes on the network simply can't reach it.</p>\n<p>What makes this finding more nuanced is the consensus layer comparison. The CC-side libp2p peers are nearly identical: 158 on NDC2 vs 161 on GCP. The CCs use different ports and protocols (libp2p with QUIC and TCP), and those traverse NATs and firewalls without issues. This means an operator whose CC shows healthy peer counts has no obvious signal that their EC is running with 70% fewer connections than it could have. Everything looks fine on the consensus side while the execution layer is quietly degraded.</p>\n<div class=\"theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>A common misconfiguration</div><div class=\"admonitionContent_BuS1\"><p>This is not a \"cloud is worse than bare-metal\" finding. Our GCP instances simply had port 30303 blocked by the default firewall, and we expect many cloud-hosted Ethereum nodes to be in the same situation. If you run a node on any cloud provider, check whether TCP and UDP port 30303 are open for inbound traffic. If not, your EC is operating with outbound-only connections, roughly 70% fewer peers, a thinner mempool view, and slower block/transaction propagation. Your CC peer count will look healthy and give no indication of the problem.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"who-are-the-peers\">Who are the peers?<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#who-are-the-peers\" class=\"hash-link\" aria-label=\"Direct link to Who are the peers?\" title=\"Direct link to Who are the peers?\" translate=\"no\">​</a></h2>\n<p>This is where things get interesting. Let's focus on the data we actually have: two ECs expose per-client peer breakdowns in Prometheus, and one logs it periodically.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"besu-75-of-peers-are-reth\">Besu: 75% of peers are Reth<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#besu-75-of-peers-are-reth\" class=\"hash-link\" aria-label=\"Direct link to Besu: 75% of peers are Reth\" title=\"Direct link to Besu: 75% of peers are Reth\" translate=\"no\">​</a></h3>\n<p>Besu exposes <code>besu_peers_peer_count_by_client</code>, giving us a full breakdown:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Besu peer composition\" src=\"https://docs.stereumlabs.com/assets/images/besu_peer_composition-be826dd89483476fcdab2040e465878b.png\" width=\"875\" height=\"882\" class=\"img_ev3q\"></p>\n<p>Out of Besu's 24 peers on average, <strong>18 are Reth nodes</strong>. Only about 2 are Geth, and Erigon barely registers. This is a remarkably skewed distribution. With three quarters of its connections going to a single client, a Reth-specific networking bug would effectively isolate Besu nodes from most of their peers.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ethrex-a-broader-but-geth-heavy-view\">Ethrex: a broader but Geth-heavy view<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#ethrex-a-broader-but-geth-heavy-view\" class=\"hash-link\" aria-label=\"Direct link to Ethrex: a broader but Geth-heavy view\" title=\"Direct link to Ethrex: a broader but Geth-heavy view\" translate=\"no\">​</a></h3>\n<p>Ethrex exposes <code>ethrex_p2p_peer_clients</code> with more granular labels:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Ethrex peer composition\" src=\"https://docs.stereumlabs.com/assets/images/ethrex_peer_composition-2aebbc2df32b4548b7efff410f40ade9.png\" width=\"841\" height=\"884\" class=\"img_ev3q\"></p>\n<p>Ethrex sees a much more diverse peer set. Geth leads at 43%, but the remaining 57% is spread across five other clients. Notably, Ethrex picks up \"exotic\" peers that other clients don't: <code>gnode</code> (likely a Geth fork or private deployment), various Nimbus execution layer variants, and even mempool scrapers. Ethrex appears to be the most permissive in accepting connections from non-standard clients.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"nethermind-the-most-transparent\">Nethermind: the most transparent<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#nethermind-the-most-transparent\" class=\"hash-link\" aria-label=\"Direct link to Nethermind: the most transparent\" title=\"Direct link to Nethermind: the most transparent\" translate=\"no\">​</a></h3>\n<p>Nethermind doesn't expose per-client peer counts in Prometheus, but it does something even better: it <strong>logs a full diversity report every 5 minutes</strong> in its container output. These log lines are goldmines:</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">Peers: 49 | node diversity: Reth (37%), Geth (22%), Nethermind (20%), Unknown (14%), Erigon (4%), Besu (2%)</span><br></span></code></pre></div></div>\n<p>We pulled these from Elasticsearch across all 6 Nethermind instances (each paired with a different CC) and found something unexpected: <strong>the peer composition varies dramatically between instances in the same datacenter.</strong></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Nethermind peer diversity by CC pairing\" src=\"https://docs.stereumlabs.com/assets/images/nethermind_diversity_by_pairing-f94959736a0cdc8e058aea3b2fb09fea.png\" width=\"1483\" height=\"807\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>CC pairing</th><th>Top peer</th><th>2nd peer</th><th>3rd peer</th></tr></thead><tbody><tr><td>Lighthouse</td><td>Reth 37%</td><td>Geth 22%</td><td>Nethermind 20%</td></tr><tr><td>Grandine</td><td>Nethermind 46%</td><td>Reth 26%</td><td>Unknown 14%</td></tr><tr><td>Lodestar</td><td>Nethermind 47%</td><td>Reth 20%</td><td>Geth 18%</td></tr><tr><td>Teku</td><td>Nethermind 57%</td><td>Reth 18%</td><td>Geth 12%</td></tr><tr><td>Prysm</td><td>Nethermind 62%</td><td>Reth 27%</td><td>Erigon 6%</td></tr><tr><td>Nimbus</td><td><strong>Nethermind 70%</strong></td><td>Reth 12%</td><td>Unknown 6%</td></tr></tbody></table>\n<p>The Nimbus-paired Nethermind instance sees <strong>70% Nethermind peers</strong>, while the Lighthouse-paired one sees a relatively healthy mix with Reth leading at 37%. Same client, same datacenter, same network, vastly different peer views.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"does-the-consensus-client-affect-ec-peering\">Does the consensus client affect EC peering?<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#does-the-consensus-client-affect-ec-peering\" class=\"hash-link\" aria-label=\"Direct link to Does the consensus client affect EC peering?\" title=\"Direct link to Does the consensus client affect EC peering?\" translate=\"no\">​</a></h2>\n<p>This is one of the more subtle findings from the analysis. The short answer: <strong>the CC does not affect how many peers the EC gets, but it does affect which peers the EC keeps.</strong></p>\n<p>We checked peer counts per CC pairing across every EC on the fleet. The numbers are remarkably uniform:</p>\n<table><thead><tr><th>EC</th><th>Lowest CC pairing</th><th>Highest CC pairing</th><th>Spread</th></tr></thead><tbody><tr><td>Geth</td><td>49.3 (Lighthouse)</td><td>49.6 (Teku)</td><td>0.3</td></tr><tr><td>Erigon</td><td>41.8 (Teku)</td><td>41.9 (Lighthouse)</td><td>0.1</td></tr><tr><td>Nethermind</td><td>50.0 (Lighthouse)</td><td>50.3 (Grandine)</td><td>0.3</td></tr><tr><td>Ethrex</td><td>104.3 (Prysm)</td><td>106.3 (Lighthouse)</td><td>2.0</td></tr><tr><td>Besu</td><td>23.6 (Lighthouse)</td><td>24.3 (Prysm)</td><td>0.7</td></tr></tbody></table>\n<p>The CC pairing has essentially zero influence on peer count. Every Geth instance gets ~50 peers regardless of whether it runs with Lighthouse, Nimbus, or Teku. The same holds for every other EC.</p>\n<p>But peer composition is a different story. The Nethermind diversity logs show a 50-percentage-point swing in Nethermind peer concentration (20% with Lighthouse vs 70% with Nimbus). The Besu Prometheus data tells a similar story at smaller scale: the Grandine-paired Besu gets 18.6 Reth peers while the Nimbus-paired one gets 17.8, with corresponding shifts in Nethermind and Geth counts.</p>\n<p>The mechanism isn't direct. The CC doesn't participate in DevP2P at all. But the CC influences the EC's startup timing, engine API call patterns, CPU and memory pressure on the shared host, and the timing of when the EC first reaches out to the discovery network. Early peer bonding creates path dependency: the peers you discover first tend to persist, and the ones that persist shape which new peers you discover next through the Kademlia routing table. Different CCs create subtly different boot conditions, and those conditions cascade into measurably different peer equilibria.</p>\n<p>This has a practical implication: <strong>two operators running the same EC and the same CC version might still see different peer compositions</strong>, simply because their nodes booted at different moments or under different system load. Peer diversity is partly a matter of luck.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"protocol-adoption-eth68-vs-eth69\">Protocol adoption: eth68 vs eth69<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#protocol-adoption-eth68-vs-eth69\" class=\"hash-link\" aria-label=\"Direct link to Protocol adoption: eth68 vs eth69\" title=\"Direct link to Protocol adoption: eth68 vs eth69\" translate=\"no\">​</a></h2>\n<p>Nethermind also logs the protocol version split among its peers, and Erigon reports its \"GoodPeers\" broken down by protocol:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Protocol version adoption\" src=\"https://docs.stereumlabs.com/assets/images/protocol_versions-b5a7f132e9bfcb4940bd42cb13e8c22f.png\" width=\"1784\" height=\"728\" class=\"img_ev3q\"></p>\n<p><strong>Nethermind's view:</strong> eth69 dominates at 80-96% depending on the instance. The Prysm-paired node sees the highest eth69 adoption (96%), while Grandine and Lighthouse-paired nodes see around 80%. This makes sense: Nethermind and Reth (its top peers) both adopted eth69 early.</p>\n<p><strong>Erigon's behavior is peculiar:</strong> every pairing shows exactly 32 eth68 GoodPeers. The eth69 count varies (9-32), but eth68 is always hard-capped at 32. The standalone Caplin instance gets 32+32=64 good peers, but CC-paired instances get only ~42. This hard cap on eth68 peers likely explains why Erigon consistently runs below its connection limit: it's artificially constraining its usable peer set by protocol version.</p>\n<div class=\"theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>warning</div><div class=\"admonitionContent_BuS1\"><p>Erigon's eth68 hard cap at 32 means it's effectively running with a smaller usable peer set than its connection count suggests. If you're running Erigon and noticing slow block propagation, this protocol-level constraint could be a contributing factor.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"peer-churn-who-cycles-and-who-holds\">Peer churn: who cycles and who holds<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#peer-churn-who-cycles-and-who-holds\" class=\"hash-link\" aria-label=\"Direct link to Peer churn: who cycles and who holds\" title=\"Direct link to Peer churn: who cycles and who holds\" translate=\"no\">​</a></h2>\n<p>How fast does each EC rotate through its peer connections? This matters for network resilience: too little churn means stale, possibly slow peers accumulate; too much churn means constant overhead from handshakes and state negotiation.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Peer churn rates\" src=\"https://docs.stereumlabs.com/assets/images/churn_rates-2181b0f165ebd54b0cd1bd5a1b56b7ff.png\" width=\"1481\" height=\"729\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC</th><th>Key churn metric</th><th>Rate</th><th>Interpretation</th></tr></thead><tbody><tr><td>Nethermind</td><td>Incoming connection attempts</td><td>3.10/s</td><td>High inbound demand, rejecting most (at limit)</td></tr><tr><td>Reth</td><td>\"Too many peers\" rejections</td><td>3.08/s</td><td>Constantly turning away new connections</td></tr><tr><td>Nethermind</td><td>Outgoing connections</td><td>0.65/s</td><td>Moderate active peer seeking</td></tr><tr><td>Nethermind</td><td>Total disconnects</td><td>0.34/s</td><td>Healthy rotation (~1,200/hour)</td></tr><tr><td>Besu</td><td>Disconnections</td><td>0.12/s</td><td>Aggressive pruning despite few peers</td></tr><tr><td>Besu</td><td>New connections</td><td>0.009/s</td><td>Very slow peer acquisition</td></tr><tr><td>Ethrex</td><td>Disconnections</td><td>0.00006/s</td><td><strong>Near zero</strong>, essentially static peer set</td></tr></tbody></table>\n<p>The spread here is staggering: a factor of roughly 50,000x between the most and least churning clients.</p>\n<p><strong>Besu</strong> has the most aggressive peer rotation relative to its pool size: it disconnects at 14x the rate it connects. With only 25 slots, it's constantly cycling. Average peer sessions are very short.</p>\n<p><strong>Nethermind</strong> receives the most incoming connection attempts (3.1/s) but maintains a steady 50. Most incoming connections are rejected because the limit is reached, not because of quality issues.</p>\n<p><strong>Reth</strong> is the most sought-after peer on the network. It rejects ~3 connections per second, tracks 7,400 peers in its peer table (the largest DHT view of any EC on the fleet), and has 540 backed-off peers at any given time. Its 130 connected peers are stable and long-lived.</p>\n<p><strong>Ethrex</strong> has the most stable peering of any client we measured: essentially zero disconnection rate. Once it connects a peer, it keeps it indefinitely. This is a double-edged sword: stable peering means reliable gossip propagation, but no rotation means stale or slow peers are never pruned.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"every-ec-sees-a-different-ethereum\">Every EC sees a different Ethereum<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#every-ec-sees-a-different-ethereum\" class=\"hash-link\" aria-label=\"Direct link to Every EC sees a different Ethereum\" title=\"Direct link to Every EC sees a different Ethereum\" translate=\"no\">​</a></h2>\n<p>One of the most striking findings from this analysis is that <strong>no two execution clients see the same network</strong>. Even running on the same hardware in the same datacenter:</p>\n<ul>\n<li class=\"\">Besu's 24 peers are 75% Reth. Its Ethereum is a Reth-dominated network.</li>\n<li class=\"\">Ethrex's 105 peers are 43% Geth. Its Ethereum looks more like the \"true\" network composition.</li>\n<li class=\"\">Nethermind's view changes depending on which CC it runs with. One instance sees 70% Nethermind peers; another sees 37% Reth.</li>\n<li class=\"\">Erigon's protocol-level constraints give it a smaller effective peer set than its connection count suggests.</li>\n<li class=\"\">Reth casts the widest net (7,400 tracked peers, 130 connected) but aggressively rejects newcomers.</li>\n</ul>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Each EC&amp;#39;s view of the network\" src=\"https://docs.stereumlabs.com/assets/images/network_views_compared-77543ebb78c412028d68770a43c71910.png\" width=\"2085\" height=\"617\" class=\"img_ev3q\"></p>\n<p>This per-client perspective gap is a form of <strong>network fragmentation</strong> that isn't visible in aggregate statistics. The overall network might be 55% Geth, but individual nodes don't experience that average. They experience their own biased sample.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-this-means-for-ethereums-network-health\">What this means for Ethereum's network health<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#what-this-means-for-ethereums-network-health\" class=\"hash-link\" aria-label=\"Direct link to What this means for Ethereum's network health\" title=\"Direct link to What this means for Ethereum's network health\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"client-diversity-at-the-ec-layer-is-worse-than-it-looks\">Client diversity at the EC layer is worse than it looks<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#client-diversity-at-the-ec-layer-is-worse-than-it-looks\" class=\"hash-link\" aria-label=\"Direct link to Client diversity at the EC layer is worse than it looks\" title=\"Direct link to Client diversity at the EC layer is worse than it looks\" translate=\"no\">​</a></h3>\n<p>Aggregate client diversity numbers (e.g., \"Geth runs on 55% of nodes\") describe the network as a whole, but individual nodes experience a much more concentrated version. When we hear that no single client exceeds 55% network share, it sounds like the network has a safety margin. But our data shows that at the individual node level, the picture is far less balanced.</p>\n<p>A Besu node with 75% Reth peers doesn't live in a \"55% Geth\" network. It lives in a \"75% Reth\" network. If Reth pushes a release with a networking regression, that Besu node doesn't lose 20% of its peers (proportional to Reth's global share). It loses 75% of them. Similarly, a Nimbus-paired Nethermind node with 70% Nethermind peers is exposed to a Nethermind-specific issue at 3-4x the rate the aggregate numbers would suggest.</p>\n<p>This matters in concrete scenarios:</p>\n<p><strong>Client-specific bugs during chain events.</strong> When a contentious or complex fork activates (as has happened multiple times in Ethereum's history), clients occasionally disagree on block validity for a short window. During these periods, nodes need diverse peers to hear both sides of the fork quickly. A Besu node whose 18 Reth peers all follow one fork branch would receive almost no blocks from the other branch for critical minutes.</p>\n<p><strong>Cascading failures from bad releases.</strong> If a popular client ships a broken release that causes resource exhaustion or crashes, nodes heavily peered with that client lose their connections simultaneously. On a healthy, diverse peer set, losing one client type drops you from 50 to 40 peers. On a Besu node with 75% Reth, it drops you from 24 to 6. Six peers is below the threshold where gossip propagation remains reliable.</p>\n<p><strong>Transaction propagation and MEV.</strong> Transactions are propagated through the EC peer mesh. If your peers are disproportionately one client, your node's mempool is shaped by that client's transaction acceptance logic, ordering behavior, and propagation timing. For validators, this can mean seeing fewer unique transactions and missing MEV opportunities. We've previously shown how <a class=\"\" href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\">EC choice affects block building output</a> when paired with the same CC, and peer composition is one of the contributing factors: a node with a thin, homogeneous peer set simply sees fewer transactions to include.</p>\n<p><strong>Consensus finality during network partitions.</strong> If a network-level event (e.g., a BGP hijack, a cloud provider outage) takes out a large fraction of one client's nodes, the remaining network's ability to finalize depends on which clients can still communicate. Nodes with homogeneous peer sets are more likely to end up on the isolated side of a partition.</p>\n<p>The fundamental issue is that DevP2P's discovery mechanism (Kademlia DHT with distance-based routing) is optimized for finding <em>any</em> peers, not <em>diverse</em> peers. Unlike the consensus layer's gossipsub protocol, which has explicit scoring and mesh-balancing mechanisms, the execution layer has no built-in incentive for client diversity. Peers are peers, regardless of what software they run. This means diversity at the node level is largely a side effect of the overall network composition and the node's own discovery path, and our data shows that path can lead to surprisingly concentrated outcomes.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"besus-low-peer-limit-amplifies-the-problem\">Besu's low peer limit amplifies the problem<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#besus-low-peer-limit-amplifies-the-problem\" class=\"hash-link\" aria-label=\"Direct link to Besu's low peer limit amplifies the problem\" title=\"Direct link to Besu's low peer limit amplifies the problem\" translate=\"no\">​</a></h3>\n<p>With a default of 25 peers and 75% of those being Reth, a Besu node has roughly 6 non-Reth connections to the Ethereum network. That's not just thin, it's fragile. At 6 connections, the loss of even 2-3 peers (through normal churn) can temporarily leave the node with only 3-4 diverse connections. Gossip propagation at that level is unreliable.</p>\n<p>For comparison, Ethrex with 105 peers and 43% Geth still has 60 non-Geth peers even if every Geth node disappeared. That's still a functioning, well-connected node.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ethrexs-zero-churn-peering-needs-attention\">Ethrex's zero-churn peering needs attention<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#ethrexs-zero-churn-peering-needs-attention\" class=\"hash-link\" aria-label=\"Direct link to Ethrex's zero-churn peering needs attention\" title=\"Direct link to Ethrex's zero-churn peering needs attention\" translate=\"no\">​</a></h3>\n<p>While stable connections improve gossip reliability in the short term, never pruning peers means degraded connections accumulate. If a peer goes slow but doesn't fully disconnect, Ethrex keeps it, potentially dragging down block and transaction propagation latency over time. Every other EC has some form of peer rotation that naturally filters out underperforming connections.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"blocked-inbound-ports-are-an-invisible-problem\">Blocked inbound ports are an invisible problem<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#blocked-inbound-ports-are-an-invisible-problem\" class=\"hash-link\" aria-label=\"Direct link to Blocked inbound ports are an invisible problem\" title=\"Direct link to Blocked inbound ports are an invisible problem\" translate=\"no\">​</a></h3>\n<p>Our GCP finding (zero inbound peers due to a default firewall that didn't have port 30303 opened) is likely representative of a large number of cloud-hosted Ethereum nodes. Operators who deploy to GCP, AWS, or Azure without explicitly opening DevP2P ports end up with only 15 outbound connections instead of 50, and their CC peer count gives no warning. A significant portion of the network may be operating with degraded EC connectivity without anyone noticing, which reduces the overall density of the gossip mesh and slows transaction propagation at scale.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-consensus-layer-shows-whats-possible\">The consensus layer shows what's possible<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#the-consensus-layer-shows-whats-possible\" class=\"hash-link\" aria-label=\"Direct link to The consensus layer shows what's possible\" title=\"Direct link to The consensus layer shows what's possible\" translate=\"no\">​</a></h3>\n<p>For comparison, the consensus layer's gossipsub mesh shows much better diversity. From our Lighthouse nodes' block gossip mesh:</p>\n<table><thead><tr><th>CC client</th><th>Mesh peers</th><th>Share</th></tr></thead><tbody><tr><td>Prysm</td><td>2.2</td><td>37%</td></tr><tr><td>Lighthouse</td><td>1.6</td><td>27%</td></tr><tr><td>Teku</td><td>1.1</td><td>19%</td></tr><tr><td>Nimbus</td><td>0.5</td><td>9%</td></tr><tr><td>Lodestar</td><td>0.4</td><td>6%</td></tr></tbody></table>\n<p>No single client dominates more than 37%, and the gossipsub scoring system actively maintains diversity. The execution layer's DevP2P protocol has no equivalent mechanism. This is consistent with what we observed in our <a class=\"\" href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients\">blob performance analysis</a>, where data column gossip delay was uniform across all EC pairings, confirming that the CL's P2P layer operates largely independent of the EC underneath. If DevP2P were to adopt some form of diversity-aware peer scoring (even a soft preference for connecting to underrepresented clients), the per-node diversity picture could improve substantially without requiring any consensus-level changes.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"which-ec-failure-would-hurt-ethereum-the-most\">Which EC failure would hurt Ethereum the most?<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#which-ec-failure-would-hurt-ethereum-the-most\" class=\"hash-link\" aria-label=\"Direct link to Which EC failure would hurt Ethereum the most?\" title=\"Direct link to Which EC failure would hurt Ethereum the most?\" translate=\"no\">​</a></h3>\n<p>We can combine our peer dependency data with public network share estimates to model what would actually happen if a specific EC suffered a critical failure (a consensus bug, a bad release causing crashes, or a networking regression that takes all instances offline).</p>\n<p>Current approximate EC network shares (from ethernodes.org and clientdiversity.org, April 2026):</p>\n<table><thead><tr><th>EC</th><th>Network share</th></tr></thead><tbody><tr><td>Geth (incl. forks)</td><td>~50%</td></tr><tr><td>Nethermind</td><td>~21%</td></tr><tr><td>Reth</td><td>~12%</td></tr><tr><td>Besu</td><td>~11%</td></tr><tr><td>Erigon</td><td>~5%</td></tr><tr><td>Ethrex</td><td>~1%</td></tr></tbody></table>\n<p>Before we model scenarios, an important nuance: <strong>an EC going offline does not automatically mean the validator goes offline.</strong> Professional staking operators (Coinbase, Lido's curated set, institutional stakers) typically run multiple ECs with failover at the validator client or signer level. If Geth crashes, their validator client can switch to a Nethermind or Besu backup within seconds. For these operators, an EC failure causes a brief blip, not a prolonged outage.</p>\n<p>Solo stakers, home stakers, and smaller operators are a different story. Most run a single EC paired with a single CC. For them, an EC failure means their validator goes offline until they manually intervene: restart the client, wait for a patch, or migrate to a different EC entirely (which means syncing from scratch, a process that can take <a class=\"\" href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026\">anywhere from 1.5 hours to 8+ days</a> depending on the client).</p>\n<p>The real-world impact of an EC failure therefore depends on the mix of professional vs solo operators running that client. The scenarios below model the P2P cascading effects, which hit everyone regardless of their failover setup.</p>\n<p><strong>Scenario 1: Geth fails.</strong> This is the most impactful scenario by raw numbers. Roughly half of all execution client instances go offline. On our fleet, Ethrex would lose 43% of its peers in one stroke. Nethermind instances peered heavily with Geth (the Lighthouse-paired one sees 22% Geth) lose a significant chunk too. For validators, the impact is split: professional operators with EC failover switch to their backup within seconds and keep attesting. Solo stakers running only Geth go dark until the issue is resolved. Whether finality breaks depends on how many of Geth's ~50% share consists of solo stakers without failover. If even a third of them can't switch quickly, that's ~17% of validators going offline, which combined with normal churn could push the network close to the 1/3 offline threshold where finality stalls. Even short of that threshold, the gossip mesh takes a massive hit: surviving ECs lose a large fraction of their peers simultaneously, transaction propagation slows across the board, and block proposals from surviving validators may include fewer transactions because the mempool is suddenly thinner.</p>\n<p><strong>Scenario 2: Reth fails.</strong> At ~12% network share, a Reth failure seems manageable at first glance. But our data reveals a cascading dependency that makes this worse than the headline number suggests. Besu nodes on the fleet derive <strong>75% of their peers from Reth</strong>. If Reth goes down, the average Besu node drops from 24 peers to 6. At 6 peers, gossip propagation becomes unreliable: blocks arrive late, transactions get missed, and the node may struggle to stay in sync. In effect, a Reth failure doesn't just remove 12% of the network's EC instances. It functionally degrades another 11% (Besu's share), potentially pushing Besu nodes below the peer threshold needed for reliable chain following. Besu validators don't go offline in the strict sense, their EC is still running, but they start missing attestations and producing delayed block proposals because their view of the chain is degraded. That turns a 12% EC outage into something closer to a 20-23% effective network degradation, well beyond what the simple market share numbers would predict.</p>\n<p><strong>Scenario 3: Nethermind fails.</strong> At ~21% share, a Nethermind failure is the most concerning for the professional staking segment, since Nethermind has been the primary beneficiary of the \"move away from Geth\" push (Coinbase, stakefish, and others have publicly migrated large validator sets to Nethermind). These operators likely have failover, but the sheer scale of simultaneous failover events could create its own pressure: backup ECs suddenly handling double the engine API load, discovery networks flooded with reconnection attempts, and a temporary peer diversity shock as the second-largest client disappears from the gossip mesh. The Nethermind-to-Nethermind peering concentration we observed (up to 70% on some instances) means that even surviving Nethermind nodes, those that haven't crashed but are peered with ones that did, lose most of their connections and need to re-discover peers.</p>\n<p><strong>The counterintuitive finding:</strong> By raw network share, Geth is the obvious answer for maximum damage. But <strong>Reth's failure is disproportionately dangerous relative to its 12% market share</strong> because of the peer dependency it has created with Besu. A 12% client taking down its own nodes plus functionally crippling an 11% client through peer starvation is a 2x amplification factor that no aggregate diversity statistic captures.</p>\n<p>This peer dependency amplification is invisible in the standard client diversity charts. The usual framing (\"no client above 33%\") assumes that each client's failure is contained to its own nodes. Our data shows that's not the case at the P2P layer. Client failures cascade through the peer graph, and the pattern of those cascades depends on the specific, measurable peer composition that each client maintains. This is exactly the kind of second-order effect that requires fleet-level observability to detect.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"this-is-just-the-surface\">This is just the surface<a href=\"https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis#this-is-just-the-surface\" class=\"hash-link\" aria-label=\"Direct link to This is just the surface\" title=\"Direct link to This is just the surface\" translate=\"no\">​</a></h2>\n<p>This analysis is a short snapshot of one aspect of our fleet data. At <a href=\"https://stereumlabs.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs</a>, we continuously collect Prometheus metrics and container logs across all 6 consensus clients and all 6 execution clients, in every pairing, on both bare-metal (NDC2 Vienna) and cloud (GCP) infrastructure.</p>\n<p>We use this data for version comparison reports (like our <a class=\"\" href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources\">Teku cross-version analysis</a> and <a class=\"\" href=\"https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources\">Prysm resource comparison</a>), <a class=\"\" href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes\">hardfork impact analysis</a>, security audits, and deep dives like this one. The P2P peering layer alone has months of historical data waiting to be mined: how does peer diversity change over time? Do software updates shift the composition? What happens during hardfork activations? How do different geographic locations affect peering patterns?</p>\n<p>The dashboards are there, the data is there, and there is much more to find. If you're a researcher, an Ethereum client team, or an infrastructure operator and you want to dig deeper, <a href=\"https://stereumlabs.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">get in touch</a>. You can also watch our <a class=\"\" href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking\">EthCC[9] talk</a> for a broader overview of how we use AI-powered observability across the Ethereum staking stack.</p>\n<hr>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>Methodology</div><div class=\"admonitionContent_BuS1\"><ul>\n<li class=\"\"><strong>Prometheus metrics</strong>: 7-day rolling averages using <code>avg_over_time(...[7d:1h])</code> instant queries against our <code>prometheus-cold</code> datasource (UID <code>aez9ck4wz05q8e</code>, Grafana Org 6).</li>\n<li class=\"\"><strong>Elasticsearch logs</strong>: Queried via Grafana's <code>_msearch</code> proxy against Filebeat container log indices. Filtered by <code>container.image.name</code> per EC version.</li>\n<li class=\"\"><strong>Fleet</strong>: NDC2 bare-metal (Vienna) for all 6 ECs paired with all 6 CCs. GCP cloud instances (europe-west3) for Geth paired with all 6 CCs (supernode configuration, default firewall with port 30303 not opened for inbound).</li>\n<li class=\"\"><strong>EC versions</strong>: Besu 26.4.0, Erigon v3.3.10, Ethrex v10.0.0, Geth v1.17.2, Nethermind 1.36.2, Reth v2.1.0.</li>\n<li class=\"\"><strong>CC versions</strong>: Lighthouse v8.1.3, Lodestar v1.42.0, Nimbus multiarch-v26.3.1, Teku 26.4.0, Grandine 2.0.4, Prysm v7.1.3.</li>\n<li class=\"\"><strong>Date of snapshot</strong>: April 29, 2026.</li>\n</ul></div></div>",
            "url": "https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis",
            "title": "How Ethereum execution clients see the P2P network: a peering deep dive",
            "summary": "Every execution client connects to different peers, sees a different slice of the network, and churns through connections at wildly different rates. We queried Prometheus metrics and Elasticsearch container logs across our entire fleet to find out what each EC actually experiences at the P2P layer.",
            "date_modified": "2026-05-06T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "execution client",
                "P2P",
                "DevP2P",
                "peering",
                "network health",
                "Geth",
                "Nethermind",
                "Besu",
                "Reth",
                "Erigon",
                "Ethrex",
                "client diversity"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients",
            "content_html": "<p>We measured gossip verification, KZG batch verification, data column reconstruction, and getBlobsV2 latency across 72 nodes running all six consensus clients. The verification speed spread between fastest and slowest client: 50x.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Blob Performance Across Consensus Clients\" src=\"https://docs.stereumlabs.com/assets/images/thumbnail-63b432c46e6b519bf6c89c76437e56e6.png\" width=\"1830\" height=\"975\" class=\"img_ev3q\"></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-are-blobs\">What are blobs?<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#what-are-blobs\" class=\"hash-link\" aria-label=\"Direct link to What are blobs?\" title=\"Direct link to What are blobs?\" translate=\"no\">​</a></h2>\n<p>Blobs (Binary Large Objects) are a data type attached to Ethereum transactions, introduced with <a href=\"https://eips.ethereum.org/EIPS/eip-4844\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">EIP-4844</a> (\"Proto-Danksharding\") and expanded with the <strong><a class=\"\" href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes\">Fusaka hardfork</a></strong> (December 2025), which activated <strong>PeerDAS</strong> (Peer Data Availability Sampling).</p>\n<p>Before blobs, Layer 2 rollups posted their transaction data into execution layer calldata, competing for the same gas as every other transaction. Blobs created a separate, cheaper data channel for rollup data. Each blob carries about 128 KB and lives on the consensus layer (beacon chain), not in execution layer state, so it does not permanently bloat the blockchain.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"from-blobs-to-data-columns-peerdas\">From blobs to data columns: PeerDAS<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#from-blobs-to-data-columns-peerdas\" class=\"hash-link\" aria-label=\"Direct link to From blobs to data columns: PeerDAS\" title=\"Direct link to From blobs to data columns: PeerDAS\" translate=\"no\">​</a></h3>\n<p>Fusaka took this further with <strong>PeerDAS</strong>. Instead of every node downloading every full blob, blobs are split into <strong>128 data columns</strong> via erasure coding. Each node only needs to custody a few of these columns, typically 4 custody groups for a standard node. This reduces bandwidth requirements while maintaining data availability guarantees through KZG commitments (mathematical proofs). We measured the <a class=\"\" href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes\">hardware impact of PeerDAS on our fleet</a> in a separate post.</p>\n<p>The lifecycle of a blob under PeerDAS:</p>\n<ol>\n<li class=\"\"><strong>A rollup</strong> submits a transaction with blob data attached</li>\n<li class=\"\"><strong>The execution client</strong> receives the transaction and holds the blob in its blob pool</li>\n<li class=\"\"><strong>At block proposal time</strong>, the consensus client can fetch blobs from its local EC via the <code>getBlobsV2</code> Engine API call</li>\n<li class=\"\"><strong>After the block is published</strong>, nodes verify the data column sidecars they receive via gossip, including KZG proof and inclusion proof verification</li>\n<li class=\"\"><strong>If a node does not receive all its custody columns</strong> via gossip in time, it can attempt <strong>reconstruction</strong> from the columns it does have (if it has enough)</li>\n</ol>\n<p>Each of these steps has measurable performance characteristics, and they vary across consensus client implementations. That is what we measured.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"blobs-and-mev-boost\">Blobs and MEV-Boost<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#blobs-and-mev-boost\" class=\"hash-link\" aria-label=\"Direct link to Blobs and MEV-Boost\" title=\"Direct link to Blobs and MEV-Boost\" translate=\"no\">​</a></h3>\n<p>Most validators today use <a href=\"https://boost.flashbots.net/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">MEV-Boost</a> to outsource block building to external builders who compete on profitability. Blob transactions carry their own fee market (blob gas), so builders have an incentive to pack as many blob transactions as possible into their blocks.</p>\n<p>When a validator proposes a block via MEV-Boost, the flow adds a step: the CC receives a blinded block from the relay, reveals it, and then gets the full execution payload including all blobs. The CC must then compute and broadcast all data column sidecars from these blobs before the attestation deadline. This means the proposer's CC must have full data availability (all 128 custody groups) to serve the data column sidecars. If the CC is slow at blob processing, the block's data columns reach the network late, which increases the chance of missed attestations by other validators who depend on timely gossip.</p>\n<p>In practice, MEV-Boost blocks tend to be blob-heavy because builders optimize for maximum gas revenue. A CC that handles blobs well under normal conditions but degrades at 6 blobs per slot will perform worse on MEV-Boost blocks than on locally built blocks.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"test-setup\">Test setup<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#test-setup\" class=\"hash-link\" aria-label=\"Direct link to Test setup\" title=\"Direct link to Test setup\" translate=\"no\">​</a></h2>\n<p>Our <a href=\"https://stereumlabs.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs</a> fleet at the NDC2 datacenter in Vienna, Austria runs all six major consensus clients, each paired with all six major execution clients: 72 nodes total (36 CC×EC pairings on bare metal, plus 6 GCP-hosted supernodes not covered here). Each CC is connected to a validator client that assigns validator duties. The validator clients themselves are not part of the StereumLabs metrics pipeline, but their effect is visible indirectly: because validators are attached, every CC should operate as a supernode (128 custody groups) to guarantee full data availability for block proposals. Whether each CC actually does this is one of the things we checked. For details on methodology and infrastructure, see the <a href=\"https://docs.stereumlabs.com/docs/intro\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs documentation</a>. The fleet is operated by <a href=\"https://rocklogic.at/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">RockLogic GmbH</a>.</p>\n<p><strong>Observation window:</strong> April 24, 2026, 11:00 to 12:00 UTC. All histogram percentiles and rates in this post are computed over this 1-hour window. Counter-based totals (like getBlobsV2 request counts) are cumulative since last process restart. Longer time ranges and historical comparisons can be explored directly on the <a href=\"https://docs.stereumlabs.com/docs/category/dashboards\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs dashboards</a>. If you need a custom analysis or report for a specific time range, client pairing, or metric, reach out to us at <a href=\"mailto:contact@stereumlabs.com\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">contact@stereumlabs.com</a>.</p>\n<table><thead><tr><th>Consensus Client</th><th>Version</th><th>Execution Clients</th></tr></thead><tbody><tr><td>Grandine</td><td>2.0.4</td><td>Besu, Erigon, Ethrex, Geth, Nethermind, Reth</td></tr><tr><td>Lighthouse</td><td>v8.1.3</td><td>Besu, Erigon, Ethrex, Geth, Nethermind, Reth</td></tr><tr><td>Lodestar</td><td>v1.41.1</td><td>Besu, Erigon, Ethrex, Geth, Nethermind, Reth</td></tr><tr><td>Nimbus</td><td>v26.3.1</td><td>Besu, Erigon, Ethrex, Geth, Nethermind, Reth</td></tr><tr><td>Prysm</td><td>v7.1.3</td><td>Besu, Erigon, Ethrex, Geth, Nethermind, Reth</td></tr><tr><td>Teku</td><td>26.4.0</td><td>Besu, Erigon, Ethrex, Geth, Nethermind, Reth</td></tr></tbody></table>\n<p>All nodes run on identical bare-metal hardware in Vienna. Performance differences reflect client implementation, not infrastructure.</p>\n<div class=\"theme-admonition theme-admonition-info admonition_xJq3 alert alert--info\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z\"></path></svg></span>info</div><div class=\"admonitionContent_BuS1\"><p>Metrics are averaged across all EC pairings per CC unless otherwise noted. All histograms are computed over a 1-hour rolling window.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"finding-1-custody-groups-and-the-validator-client-effect\">Finding 1: Custody groups and the validator client effect<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#finding-1-custody-groups-and-the-validator-client-effect\" class=\"hash-link\" aria-label=\"Direct link to Finding 1: Custody groups and the validator client effect\" title=\"Direct link to Finding 1: Custody groups and the validator client effect\" translate=\"no\">​</a></h2>\n<p>Since every CC on our fleet has a validator client attached, each CC should automatically upgrade to 128 custody groups (full supernode) to ensure complete data availability for block proposals. The question is: do they actually do this?</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Custody Groups per CC\" src=\"https://docs.stereumlabs.com/assets/images/custody_groups-618ec72cb12608d73010645f4d82ca38.png\" width=\"1640\" height=\"810\" class=\"img_ev3q\"></p>\n<p>The <code>beacon_custody_groups</code> metric is only exposed by Lodestar, Grandine, and Teku. Lodestar and Grandine both report 128 custody groups, as expected for nodes with validators attached. <strong>Teku reports only 4 custody groups</strong> across all 6 EC pairings, despite having a validator client connected. This is unexpected and may indicate that Teku 26.4.0 does not auto-upgrade custody group count when validator duties are assigned, or that a separate CLI flag is required.</p>\n<p>Lighthouse does not expose <code>beacon_custody_groups</code>, but a different metric tells the story: <code>peers_per_custody_group_count</code> shows Lighthouse tracking 104 to 106 custody groups (out of 128) across all EC pairings. That is consistent with supernode behavior. The missing 22-24 groups likely just have no peers at the moment rather than being uncustodied.</p>\n<p>Nimbus and Prysm do not expose any custody-related metrics at all. We cannot confirm their actual custody group count from Prometheus. However, Nimbus's low data column processing rate (0.23 sidecars/s received, comparable to Teku's 0.29 req/s at 4 custody groups) suggests it may also not be running at full supernode level. Prysm's higher processing rate (3.7 req/s) is more consistent with supernode-level traffic, though still lower than Grandine (11.1 req/s) and Lighthouse (7.5 req/s).</p>\n<p>The custody group count has a direct impact on everything that follows in this post. A node custodying 128 groups downloads, verifies, and stores 32x more data column sidecars than a node custodying 4 groups. This has to be considered when comparing absolute processing rates and latency tails across clients.</p>\n<div class=\"theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>warning</div><div class=\"admonitionContent_BuS1\"><p>Teku operators with validators attached should verify that their node actually custodies all 128 groups. With only 4 groups, the node may not have full data availability when it needs to propose a block. Check the <code>beacon_custody_groups</code> metric in your Grafana.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"finding-2-gossip-verification-speed-varies-50x-between-clients\">Finding 2: Gossip verification speed varies 50x between clients<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#finding-2-gossip-verification-speed-varies-50x-between-clients\" class=\"hash-link\" aria-label=\"Direct link to Finding 2: Gossip verification speed varies 50x between clients\" title=\"Direct link to Finding 2: Gossip verification speed varies 50x between clients\" translate=\"no\">​</a></h2>\n<p>When a data column sidecar arrives via gossip, the consensus client must verify it before accepting it. This includes KZG proof and inclusion proof checks. Verification speed determines how quickly a node can process incoming data columns and meet attestation deadlines.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Gossip Verification Latency\" src=\"https://docs.stereumlabs.com/assets/images/gossip_verification_latency-d6616d04f9662f7699938918e4152de3.png\" width=\"2082\" height=\"734\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>CC</th><th>p50</th><th>p95</th><th>Notes</th></tr></thead><tbody><tr><td><strong>Teku</strong></td><td><strong>3.9 ms</strong></td><td><strong>9.5 ms</strong></td><td>Fastest, tightest distribution</td></tr><tr><td>Nimbus</td><td>3.2 ms</td><td>8.7 ms</td><td>Own metric name*</td></tr><tr><td>Prysm</td><td>4.2 ms</td><td>22.7 ms</td><td>Fast p50, wider tail</td></tr><tr><td>Grandine</td><td>4.0 ms</td><td>19.0 ms</td><td>Despite 128 custody groups</td></tr><tr><td>Lighthouse</td><td>10.6 ms</td><td>24.2 ms</td><td>Middle of the pack</td></tr><tr><td><strong>Lodestar</strong></td><td><strong>35.7 ms</strong></td><td><strong>469 ms</strong></td><td>~50x slower than Teku at p95</td></tr></tbody></table>\n<p><em>Nimbus uses <code>data_column_sidecar_validation_duration</code> rather than the <code>beacon_data_column_sidecar_gossip_verification_seconds</code> metric that other clients expose. The values are not perfectly 1:1 comparable but represent the same operation.</em></p>\n<p><strong>Operator perspective:</strong> At p95, Lodestar takes nearly half a second to verify a single data column. In a blob-heavy slot with 6 blobs (which expand to many data columns), this verification backlog can delay attestation timing. Attestations need to be published within the first 4 seconds of a slot, and each 469ms verification eats into that window.</p>\n<p><strong>Researcher perspective:</strong> Lodestar is the only consensus client written in TypeScript/Node.js. The cryptographic operations (KZG proofs, hash computations) are heavily optimized in compiled languages: Rust for Lighthouse/Grandine, Go for Prysm, Java with JNI for Teku, Nim for Nimbus. A JIT-compiled runtime faces a hard ceiling here.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"finding-3-kzg-batch-verification-confirms-the-pattern\">Finding 3: KZG batch verification confirms the pattern<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#finding-3-kzg-batch-verification-confirms-the-pattern\" class=\"hash-link\" aria-label=\"Direct link to Finding 3: KZG batch verification confirms the pattern\" title=\"Direct link to Finding 3: KZG batch verification confirms the pattern\" translate=\"no\">​</a></h2>\n<p>KZG (Kate-Zaverucha-Goldberg) commitments are the mathematical proofs that guarantee data availability without requiring every node to download every blob. CCs batch-verify multiple KZG proofs at once for efficiency.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"KZG Batch Verification\" src=\"https://docs.stereumlabs.com/assets/images/kzg_batch_verification-0ce19dcf77d8fdb2342c2b2875498636.png\" width=\"1485\" height=\"809\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>CC</th><th>p50</th><th>p95</th></tr></thead><tbody><tr><td><strong>Teku</strong></td><td><strong>3.4 ms</strong></td><td><strong>9.3 ms</strong></td></tr><tr><td>Prysm</td><td>3.5 ms</td><td>31.6 ms</td></tr><tr><td>Grandine</td><td>5.1 ms</td><td>13.7 ms</td></tr><tr><td>Lighthouse</td><td>11.0 ms</td><td>32.0 ms</td></tr><tr><td><strong>Lodestar</strong></td><td><strong>112 ms</strong></td><td><strong>286 ms</strong></td></tr></tbody></table>\n<p>Same pattern: Teku leads, Lodestar trails by an order of magnitude. We looked at <a class=\"\" href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources\">Teku's performance evolution across three versions</a> in a separate post. Worth noting here: <strong>Grandine performs better here than in gossip verification</strong>, which indicates its KZG implementation (likely Rust-native) holds up well even under the supernode load of 128 custody groups.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"finding-4-prysm-struggles-with-data-column-collection\">Finding 4: Prysm struggles with data column collection<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#finding-4-prysm-struggles-with-data-column-collection\" class=\"hash-link\" aria-label=\"Direct link to Finding 4: Prysm struggles with data column collection\" title=\"Direct link to Finding 4: Prysm struggles with data column collection\" translate=\"no\">​</a></h2>\n<p>Prysm's verification speed is competitive (4.2ms p50). Its problem sits elsewhere: <strong>it fails to process the majority of incoming data column sidecars.</strong></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Processing Success Rate\" src=\"https://docs.stereumlabs.com/assets/images/processing_success_rate-1a43af29d620a9d5367daa8d07bfd57d.png\" width=\"1485\" height=\"809\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>CC</th><th>Requests/s</th><th>Successes/s</th><th>Success Rate</th></tr></thead><tbody><tr><td><strong>Grandine</strong></td><td>11.1</td><td>11.1</td><td><strong>100%</strong></td></tr><tr><td>Lighthouse</td><td>7.5</td><td>7.2</td><td>96.4%</td></tr><tr><td>Teku</td><td>0.29</td><td>0.25</td><td>84.9%</td></tr><tr><td>Lodestar</td><td>5.4</td><td>4.4</td><td>81.4%</td></tr><tr><td><strong>Prysm</strong></td><td>3.7</td><td>1.6</td><td><strong>42.9%</strong></td></tr></tbody></table>\n<p><strong>Prysm processes only 43% of data column sidecar requests successfully.</strong> More than half fail, forcing the client into a costly fallback: data column reconstruction.</p>\n<p>Teku's low absolute rate (0.29 req/s) reflects its standard 4-custody-group configuration. It receives fewer data columns. Its 85% success rate may be partially inflated by sampling effects at low volume.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"finding-5-reconstruction-is-expensive-and-prysm-needs-it-constantly\">Finding 5: Reconstruction is expensive, and Prysm needs it constantly<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#finding-5-reconstruction-is-expensive-and-prysm-needs-it-constantly\" class=\"hash-link\" aria-label=\"Direct link to Finding 5: Reconstruction is expensive, and Prysm needs it constantly\" title=\"Direct link to Finding 5: Reconstruction is expensive, and Prysm needs it constantly\" translate=\"no\">​</a></h2>\n<p>When a node does not collect all required data columns via gossip, it can attempt to <strong>reconstruct</strong> missing columns from the ones it has, provided it has at least 50% of the 128 columns. Reconstruction uses erasure coding and is computationally expensive.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Reconstruction\" src=\"https://docs.stereumlabs.com/assets/images/reconstruction-97c463481a3cc5cebca6ee23acdedd47.png\" width=\"2085\" height=\"809\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>CC</th><th>Reconstructions/s</th><th>p50 Latency</th><th>p95 Latency</th></tr></thead><tbody><tr><td><strong>Prysm</strong></td><td><strong>0.33/s</strong></td><td><strong>379 ms</strong></td><td><strong>689 ms</strong></td></tr><tr><td>Lodestar</td><td>0.007/s</td><td>321 ms</td><td>610 ms</td></tr><tr><td>Lighthouse</td><td>~0/s</td><td>289 ms</td><td>834 ms</td></tr><tr><td>Teku</td><td>0</td><td>n/a</td><td>n/a</td></tr><tr><td>Grandine</td><td>0</td><td>n/a</td><td>n/a</td></tr></tbody></table>\n<p><strong>Prysm triggers reconstruction roughly once every 3 seconds</strong>, orders of magnitude more than any other client. With a 379ms median reconstruction latency, this adds real computational overhead.</p>\n<p>Teku and Grandine never need reconstruction. They collect their custody columns via gossip every time, consistent with their high processing success rates.</p>\n<div class=\"theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>tip</div><div class=\"admonitionContent_BuS1\"><p><strong>For Prysm operators:</strong> The 43% success rate and constant reconstruction point to an issue in the gossip subscription or processing pipeline for data column sidecars. If reconstruction starts failing too, the node will miss data availability deadlines. Worth monitoring across future versions.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"finding-6-execution-client-choice-affects-blob-serving-speed\">Finding 6: Execution client choice affects blob serving speed<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#finding-6-execution-client-choice-affects-blob-serving-speed\" class=\"hash-link\" aria-label=\"Direct link to Finding 6: Execution client choice affects blob serving speed\" title=\"Direct link to Finding 6: Execution client choice affects blob serving speed\" translate=\"no\">​</a></h2>\n<p>Since Fusaka, consensus clients can fetch blobs directly from their local execution client via the <code>engine_getBlobsV2</code> API. This is faster than waiting for gossip and helps the CC complete data availability checks sooner after a new block arrives.</p>\n<p>We measured the <code>getBlobsV2</code> response latency from Teku's perspective (the only CC that exposes per-EC latency histograms for this call):</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"getBlobsV2 EC Latency\" src=\"https://docs.stereumlabs.com/assets/images/getblobs_ec_latency-736f9ec1bad96ae9d81c8bb86e34106e.png\" width=\"1485\" height=\"809\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC</th><th>p50</th><th>p95</th></tr></thead><tbody><tr><td><strong>Reth</strong></td><td><strong>6.3 ms</strong></td><td><strong>40 ms</strong></td></tr><tr><td>Ethrex</td><td>8.2 ms</td><td>49 ms</td></tr><tr><td>Besu</td><td>9.4 ms</td><td>47 ms</td></tr><tr><td>Nethermind</td><td>12.1 ms</td><td>55 ms</td></tr><tr><td>Geth</td><td>34.0 ms</td><td>143 ms</td></tr><tr><td><strong>Erigon</strong></td><td><strong>41.4 ms</strong></td><td><strong>201 ms</strong></td></tr></tbody></table>\n<p><strong>Reth serves blobs 6.5x faster than Erigon at p50.</strong> Reth and Ethrex are both Rust-based, newer execution clients with storage designs built after blobs existed. Geth and Erigon have blob pool implementations that predate the PeerDAS access pattern, which likely explains the gap. EC implementation differences also show up in <a class=\"\" href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026\">sync speed</a>, where we measured a range from 1.5 hours to 8+ days on the same hardware.</p>\n<div class=\"theme-admonition theme-admonition-info admonition_xJq3 alert alert--info\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z\"></path></svg></span>info</div><div class=\"admonitionContent_BuS1\"><p><strong>For operators optimizing attestation timing:</strong> The EC's blob serving speed determines how quickly your CC can complete data availability checks after a new block arrives. With Reth or Ethrex, that takes ~6-8ms. With Erigon, it can take 200ms+ at the tail.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"finding-7-nimbus-barely-uses-getblobsv2\">Finding 7: Nimbus barely uses getBlobsV2<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#finding-7-nimbus-barely-uses-getblobsv2\" class=\"hash-link\" aria-label=\"Direct link to Finding 7: Nimbus barely uses getBlobsV2\" title=\"Direct link to Finding 7: Nimbus barely uses getBlobsV2\" translate=\"no\">​</a></h2>\n<p>Total <code>getBlobsV2</code> request counts from the Geth EC perspective (Geth is paired with every CC, so this gives a consistent comparison):</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"getBlobsV2 Usage\" src=\"https://docs.stereumlabs.com/assets/images/getblobs_usage-6efeca022a7d141081c21d6b405db760.png\" width=\"2085\" height=\"808\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>CC</th><th>Requested Blobs</th><th>Misses</th><th>Miss Rate</th></tr></thead><tbody><tr><td>Lighthouse</td><td>174,057</td><td>787</td><td>0.5%</td></tr><tr><td>Teku</td><td>174,138</td><td>843</td><td>0.5%</td></tr><tr><td>Prysm</td><td>168,721</td><td>844</td><td>0.5%</td></tr><tr><td>Grandine</td><td>173,870</td><td>1,085</td><td>0.6%</td></tr><tr><td><strong>Lodestar</strong></td><td><strong>284,042</strong></td><td><strong>16,632</strong></td><td><strong>5.9%</strong></td></tr><tr><td><strong>Nimbus</strong></td><td><strong>10,838</strong></td><td><strong>55</strong></td><td><strong>0.5%</strong></td></tr></tbody></table>\n<p>Two outliers:</p>\n<p><strong>Nimbus makes 16x fewer getBlobsV2 requests</strong> than other clients. It relies primarily on P2P gossip to obtain blob data and uses the getBlobsV2 API as a fallback only. Whether this is intentional (gossip-first strategy) or because the feature is still in early adoption is not clear from the metrics alone. We observed similar architectural differences when <a class=\"\" href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\">investigating Nimbus block building behavior</a>.</p>\n<p><strong>Lodestar makes 63% more requests than the average</strong> and has a 5.9% miss rate, 10x higher than other clients. With 128 custody groups (supernode behavior), Lodestar aggressively tries to fetch blobs from the EL. The high miss rate suggests blobs have already expired from the EC's blob pool by the time Lodestar requests them, pointing to a timing issue in Lodestar's fetch pipeline.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"data-column-gossip-arrival-timing\">Data column gossip arrival timing<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#data-column-gossip-arrival-timing\" class=\"hash-link\" aria-label=\"Direct link to Data column gossip arrival timing\" title=\"Direct link to Data column gossip arrival timing\" translate=\"no\">​</a></h2>\n<p>For context, we also measured when data column sidecars arrive relative to slot start. This is a pure network metric, independent of client implementation:</p>\n<table><thead><tr><th>Metric source</th><th>p50</th><th>p95</th></tr></thead><tbody><tr><td>Lighthouse (all EC pairings)</td><td>~1.57s after slot start</td><td>~3.2s</td></tr><tr><td>Nimbus (all EC pairings)</td><td>~1.39s after slot start</td><td>~3.6s</td></tr></tbody></table>\n<p>Data columns typically arrive 1.4 to 1.6 seconds after the slot begins, with 95% arriving within 3.2 to 3.6 seconds. This is consistent across all EC pairings. Gossip arrival is purely a P2P network phenomenon, not influenced by the local EC.</p>\n<p>CCs therefore have roughly <strong>0.4 to 2.6 seconds</strong> between data column arrival and the attestation deadline (4 seconds into the slot) to complete verification. At Teku's 3.9ms verification speed, that is plenty. At Lodestar's 469ms p95, it gets tight.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"summary-table\">Summary table<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#summary-table\" class=\"hash-link\" aria-label=\"Direct link to Summary table\" title=\"Direct link to Summary table\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>Metric</th><th>Grandine</th><th>Lighthouse</th><th>Teku</th><th>Nimbus</th><th>Prysm</th><th>Lodestar</th></tr></thead><tbody><tr><td>Custody groups</td><td>128</td><td>~105†</td><td>4 🔴</td><td>?</td><td>?</td><td>128</td></tr><tr><td>Gossip verify p50</td><td>4.0 ms</td><td>10.6 ms</td><td>3.9 ms 🟢</td><td>3.2 ms 🟢</td><td>4.2 ms</td><td>35.7 ms 🔴</td></tr><tr><td>Gossip verify p95</td><td>19 ms</td><td>24 ms</td><td>10 ms 🟢</td><td>9 ms 🟢</td><td>23 ms</td><td>469 ms 🔴</td></tr><tr><td>KZG batch p50</td><td>5.1 ms</td><td>11.0 ms</td><td>3.4 ms 🟢</td><td>n/a</td><td>3.5 ms 🟢</td><td>112 ms 🔴</td></tr><tr><td>Processing success</td><td>100% 🟢</td><td>96.4%</td><td>84.9%</td><td>n/a</td><td>42.9% 🔴</td><td>81.4%</td></tr><tr><td>Reconstruction/s</td><td>0 🟢</td><td>~0</td><td>0 🟢</td><td>n/a</td><td>0.33 🔴</td><td>0.007</td></tr><tr><td>getBlobsV2 usage</td><td>174k</td><td>174k</td><td>174k</td><td>11k 🟠</td><td>169k</td><td>284k 🟠</td></tr><tr><td>getBlobsV2 miss%</td><td>0.6%</td><td>0.5%</td><td>0.5%</td><td>0.5%</td><td>0.5%</td><td>5.9% 🔴</td></tr></tbody></table>\n<p>🟢 = best in class · 🟠 = notable outlier · 🔴 = potential concern · †indirect via <code>peers_per_custody_group_count</code></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"takeaways\">Takeaways<a href=\"https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients#takeaways\" class=\"hash-link\" aria-label=\"Direct link to Takeaways\" title=\"Direct link to Takeaways\" translate=\"no\">​</a></h2>\n<p>The 50x spread in gossip verification latency between Teku (3.9ms p50) and Lodestar (469ms p95) is the headline number from this analysis. It feeds directly into data availability timing models: how long does a CC need between receiving a data column and publishing its attestation? At 3.9ms the answer is \"no measurable impact\". At 469ms, each verification burns a chunk of the ~2.6 seconds between typical gossip arrival and the attestation deadline. PeerDAS security models that assume uniform verification times across clients need to account for this spread, especially since Lodestar is the only TypeScript-based CC and carries a runtime disadvantage for the cryptographic operations involved (KZG proofs, hashing).</p>\n<p>The custody group situation turned out more nuanced than expected. All nodes on our fleet have validator clients attached and should therefore custody all 128 groups. Lodestar, Grandine, and Lighthouse do this correctly. Teku 26.4.0 reports only 4 custody groups despite having validators assigned, which raises a question about its auto-upgrade behavior or whether a specific CLI flag is needed. Nimbus and Prysm do not expose custody metrics at all, making it impossible to verify from Prometheus alone. For operators, this is worth checking manually. For anyone modeling PeerDAS network-level data availability, the default custody behavior is not consistent across implementations.</p>\n<p>Prysm's 43% processing success rate with constant reconstruction (0.33/s at 379ms p50 latency) points to a problem upstream of verification. The KZG verification itself is fast (3.5ms p50), so the bottleneck is in the gossip collection or processing pipeline. If reconstruction were to fail on top of that, the node would miss data availability deadlines.</p>\n<p>On the EC side, the choice of execution client has a measurable effect on blob serving latency via <code>getBlobsV2</code>. Reth and Ethrex respond in 6 to 8ms at p50. Geth and Erigon take 34 to 41ms, with Erigon reaching 201ms at p95. Over thousands of attestations, this compounds. It is a new performance dimension that did not exist before Fusaka and is worth considering when choosing an EC pairing, particularly for validators where attestation timing matters.</p>\n<p>Nimbus's minimal use of <code>getBlobsV2</code> (16x fewer requests than other clients) remains an open question. It may be a deliberate gossip-first architecture, or it may reflect early-stage <code>getBlobsV2</code> adoption. The operational impact depends on whether gossip alone is sufficient to meet data availability deadlines reliably. Our <a class=\"\" href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\">earlier analysis of Nimbus block building behavior</a> showed a similar pattern of Nimbus taking its own path on feature adoption.</p>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>note</div><div class=\"admonitionContent_BuS1\"><p><strong>Metric naming:</strong> Prysm uses millisecond-unit variants of several histogram metrics (e.g., <code>beacon_data_column_sidecar_gossip_verification_milliseconds_bucket</code>). Values were converted to seconds for comparison. Nimbus uses distinct metric names (<code>data_column_sidecar_validation_duration</code>, <code>data_column_sidecars_received_total</code>) that are not 1:1 comparable but represent the same operations. All data was queried from our <code>prometheus-cold</code> datasource. For details on our metric collection, see the <a href=\"https://docs.stereumlabs.com/docs/scope/client-metrics\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs client metrics documentation</a>.</p></div></div>",
            "url": "https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients",
            "title": "Blob performance across consensus clients",
            "summary": "We measured gossip verification, KZG proofs, data column reconstruction, and getBlobsV2 latency across 72 Ethereum nodes running all six consensus clients. The results show a 50x spread in verification speed.",
            "date_modified": "2026-04-29T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "analysis",
                "blobs",
                "PeerDAS",
                "consensus-clients",
                "data-availability"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026",
            "content_html": "<p><img decoding=\"async\" loading=\"lazy\" alt=\"Execution Client Sync Speed: From 1.5 hours to 8+ days on identical hardware\" src=\"https://docs.stereumlabs.com/assets/images/thumbnail-d3b86f364f7a3a2355efb9d61813bcf3.png\" width=\"1950\" height=\"1129\" class=\"img_ev3q\"></p>\n<p>We deployed all 6 Ethereum execution clients from scratch on bare metal and tracked exactly how long each one took to fully sync. The results range from impressive to alarming.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"overview\">Overview<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#overview\" class=\"hash-link\" aria-label=\"Direct link to Overview\" title=\"Direct link to Overview\" translate=\"no\">​</a></h2>\n<p>On April 8, 2026 at 19:41 UTC, we deployed the entire NDC2 bare metal fleet from scratch. All 36 execution client instances (6 ECs × 6 consensus client pairings) started within a 12 second window. The chain tip was at block ~24,837,000 (slot ~14,071,100).</p>\n<table><thead><tr><th>Execution Client</th><th>Version</th></tr></thead><tbody><tr><td>Besu</td><td>26.2.0</td></tr><tr><td>Erigon</td><td>v3.3.10</td></tr><tr><td>Ethrex</td><td>9.0.0</td></tr><tr><td>Geth</td><td>v1.17.2</td></tr><tr><td>Nethermind</td><td>1.36.2</td></tr><tr><td>Reth</td><td>v1.11.3</td></tr></tbody></table>\n<p>Each EC is paired with all 6 consensus clients (Grandine 2.0.4, Lighthouse v8.1.3, Lodestar v1.41.1, Nimbus multiarch-v26.3.1, Prysm v7.1.3, Teku 26.4.0). All nodes run on identical bare metal hardware with NVMe storage at our NDC2 datacenter in Vienna. Every EC runs on its own dedicated host, separate from the consensus client.</p>\n<div class=\"theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>Important: Don't trust the consensus client</div><div class=\"admonitionContent_BuS1\"><p>Four of six execution clients (Reth, Geth, Ethrex, Besu) allowed their paired consensus client to report \"in sync\" while the EC itself was still hours or days from completing its own sync. The CC's <code>beacon_head_slot</code> metric is <strong>not</strong> a reliable indicator of EC sync status. All findings in this post are based on <strong>EC container logs and metrics</strong>, not CC reported head slots.</p></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"bare-metal-vs-cloud\">Bare metal vs. cloud<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#bare-metal-vs-cloud\" class=\"hash-link\" aria-label=\"Direct link to Bare metal vs. cloud\" title=\"Direct link to Bare metal vs. cloud\" translate=\"no\">​</a></h3>\n<p>This analysis focuses on our NDC2 bare metal fleet, where each node has dedicated CPU, RAM, and NVMe storage with no resource contention. We also run the same client combinations on Google Cloud Platform (GCP) instances, which are available to <a href=\"https://stereumlabs.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs</a> users for side by side comparison. The two environments serve different purposes: bare metal gives us a controlled, reproducible baseline where hardware is never the variable, while GCP reflects the reality many operators face with shared infrastructure, variable I/O performance, and cloud specific constraints like burst credits and network throttling. Sync behavior can differ significantly between these environments, so we encourage users to explore both datasets on our platform.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"results\">Results<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#results\" class=\"hash-link\" aria-label=\"Direct link to Results\" title=\"Direct link to Results\" translate=\"no\">​</a></h2>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Execution client sync time after fresh deployment\" src=\"https://docs.stereumlabs.com/assets/images/sync-timeline-f7b2d000ade83fba3cab3731eb1386ac.png\" width=\"2132\" height=\"956\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Rank</th><th>EC</th><th>Total Sync Time</th><th>Sync Method</th></tr></thead><tbody><tr><td>1</td><td><strong>Nethermind</strong></td><td>~1h 22min</td><td>Snap sync to pivot, then StateNodes</td></tr><tr><td>2</td><td><strong>Erigon</strong></td><td>~13 hours</td><td>Staged sync (5K block batches)</td></tr><tr><td>3</td><td><strong>Besu</strong></td><td>~13h snap + ~24h backfill = ~37h total</td><td>Pivot based snap sync + backward sync</td></tr><tr><td>4</td><td><strong>Reth</strong></td><td>~5 days 18 hours</td><td>14 stage pipeline (full replay)</td></tr><tr><td>5</td><td><strong>Geth</strong></td><td>~7 days 15 hours</td><td>Snap sync (state healing bottleneck)</td></tr><tr><td>6</td><td><strong>Ethrex</strong></td><td>Not completed (8+ days)</td><td>P2P snap sync (stalled)</td></tr></tbody></table>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"detailed-sync-breakdown\">Detailed sync breakdown<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#detailed-sync-breakdown\" class=\"hash-link\" aria-label=\"Direct link to Detailed sync breakdown\" title=\"Direct link to Detailed sync breakdown\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"nethermind-1362-1h-22min\">Nethermind 1.36.2: 1h 22min<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#nethermind-1362-1h-22min\" class=\"hash-link\" aria-label=\"Direct link to Nethermind 1.36.2: 1h 22min\" title=\"Direct link to Nethermind 1.36.2: 1h 22min\" translate=\"no\">​</a></h3>\n<p>Nethermind was the fastest client by a wide margin. Its container logs show a clean three phase sync:</p>\n<p><strong>Phase 1, FastHeaders (19:42 to 20:59, ~1h 17min):</strong> Nethermind set a pivot at block 24,837,019 and downloaded all headers. The sync mode transitioned through <code>UpdatingPivot</code>, <code>FastHeaders</code>, <code>SnapSync</code>, and finally <code>StateNodes</code>.</p>\n<p><strong>Phase 2, StateNodes (20:59 to 21:04, ~5min):</strong> World state download at the pivot point.</p>\n<p><strong>Phase 3, Block processing (21:04 onward):</strong> First \"Block throughput\" log appeared at 21:04 UTC, showing live block processing at 107 MGas/s and 850 tps. From this point, Nethermind was fully operational.</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">08 Apr 21:04:39 | Block throughput 107.72 MGas/s | 850.4 tps | blobs 12</span><br></span></code></pre></div></div>\n<p><strong>Total: ~1 hour 22 minutes from cold start to processing live blocks.</strong></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"erigon-v3310-13-hours\">Erigon v3.3.10: 13 hours<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#erigon-v3310-13-hours\" class=\"hash-link\" aria-label=\"Direct link to Erigon v3.3.10: 13 hours\" title=\"Direct link to Erigon v3.3.10: 13 hours\" translate=\"no\">​</a></h3>\n<p>Erigon uses its unique staged sync pipeline. The <code>sync</code> Prometheus metric with per stage labels provides precise tracking:</p>\n<ul>\n<li class=\"\"><strong>Headers, Bodies, and Senders:</strong> Jumped to block 24,767,999 within ~20 minutes. Erigon had pre existing frozen block data and only needed recent segments.</li>\n<li class=\"\"><strong>Execution stage:</strong> Progressed in 5,000 block batches (24,768K to 24,773K to 24,778K and so on), advancing ~5K blocks every 60 to 90 minutes.</li>\n<li class=\"\"><strong>Finish stage:</strong> Reached the chain tip at ~08:40 UTC on April 9.</li>\n</ul>\n<p>Two Erigon instances (Lodestar and Teku pairings) required unscheduled process restarts 11 to 12 hours after deployment, indicating memory pressure during the execution stage.</p>\n<p><strong>Total: ~13 hours.</strong></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"besu-2620-37-hours-13h-snap--24h-backfill\">Besu 26.2.0: 37 hours (13h snap + 24h backfill)<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#besu-2620-37-hours-13h-snap--24h-backfill\" class=\"hash-link\" aria-label=\"Direct link to Besu 26.2.0: 37 hours (13h snap + 24h backfill)\" title=\"Direct link to Besu 26.2.0: 37 hours (13h snap + 24h backfill)\" translate=\"no\">​</a></h3>\n<p>Besu performed a <strong>pivot based snap sync</strong> from block 0:</p>\n<p><strong>Phase 1, Snap sync (19:42 to Apr 9 08:57, ~13h 15min):</strong> Besu downloaded headers backward from pivot 24,837,019 to block 0 while simultaneously fetching world state. The <code>ethereum_blockchain_height</code> metric starts at block 15,537,394, which is the first post Merge block (The Merge occurred at block 15,537,393 on September 15, 2022). Besu only needs to forward execute post Merge blocks since pre Merge PoW data is handled differently.</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">Sync completed successfully with pivot block 24839885</span><br></span></code></pre></div></div>\n<p><strong>Phase 2, Backward sync (Apr 9 08:57 to Apr 10 08:54, ~24h):</strong> After pivot sync completed, Besu backfilled pre Merge block bodies and receipts in a separate backward pass.</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">Starting a new backward sync session</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">...</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">Current backward sync session is done</span><br></span></code></pre></div></div>\n<p><strong>Total: ~13h 15min to live operations, ~37h for complete historical data.</strong></p>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>Why does Besu start at The Merge block?</div><div class=\"admonitionContent_BuS1\"><p>Block 15,537,394 is the first Proof of Stake block on Ethereum mainnet. Besu's snap sync downloads headers all the way back to genesis, but it only needs to execute blocks from The Merge forward since pre Merge PoW blocks use a different execution model. The <code>ethereum_blockchain_height</code> metric reflects this forward execution boundary, not an incomplete database.</p></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"reth-v1113-5-days-18-hours\">Reth v1.11.3: 5 days 18 hours<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#reth-v1113-5-days-18-hours\" class=\"hash-link\" aria-label=\"Direct link to Reth v1.11.3: 5 days 18 hours\" title=\"Direct link to Reth v1.11.3: 5 days 18 hours\" translate=\"no\">​</a></h3>\n<p>Reth runs a sequential <strong>14 stage pipeline</strong> from scratch. Container logs with <code>Finished stage</code> messages provide exact timing for every stage:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Reth pipeline stages: Execution dominates at 93% of total sync time\" src=\"https://docs.stereumlabs.com/assets/images/reth-pipeline-d72faca30bae8b52dd8ba33ad1fb2181.png\" width=\"2131\" height=\"474\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Stage</th><th>Name</th><th>Started</th><th>Finished</th><th>Duration</th></tr></thead><tbody><tr><td>1/14</td><td>Headers</td><td>Apr 8, 19:45</td><td>Apr 8, 19:53</td><td><strong>8 min</strong></td></tr><tr><td>2/14</td><td>Bodies</td><td>Apr 8, 19:53</td><td>Apr 8, 23:35</td><td><strong>3h 42min</strong></td></tr><tr><td>3/14</td><td>SenderRecovery</td><td>Apr 8, 23:35</td><td>Apr 8, 23:35</td><td>instant</td></tr><tr><td>4/14</td><td>Execution</td><td>Apr 8, 23:35</td><td><strong>Apr 14, 10:25</strong></td><td><strong>5d 10h 50min</strong></td></tr><tr><td>5/14</td><td>PruneSenderRecovery</td><td>Apr 14, 10:25</td><td>Apr 14, 10:25</td><td>instant</td></tr><tr><td>6/14</td><td>MerkleUnwind</td><td>Apr 14, 10:25</td><td>Apr 14, 10:25</td><td>instant</td></tr><tr><td>7/14</td><td>AccountHashing</td><td>Apr 14, 10:25</td><td>Apr 14, 10:34</td><td>9 min</td></tr><tr><td>8/14</td><td>StorageHashing</td><td>Apr 14, 10:34</td><td>Apr 14, 11:40</td><td>1h 6min</td></tr><tr><td>9/14</td><td>MerkleExecute</td><td>Apr 14, 11:40</td><td>Apr 14, 12:48</td><td>1h 7min</td></tr><tr><td>10/14</td><td>TransactionLookup</td><td>Apr 14, 12:48</td><td>Apr 14, 13:47</td><td>59 min</td></tr><tr><td>11 to 14</td><td>IndexHistory, Prune, Finish</td><td>Apr 14, 13:47</td><td>Apr 14, 13:47</td><td>seconds</td></tr></tbody></table>\n<p>The Execution stage consumed <strong>93% of the total sync time</strong>, replaying all 24.8 million blocks sequentially. Headers downloaded in 8 minutes and bodies in under 4 hours, but the actual block execution took over 5 days.</p>\n<p><strong>Total: 5 days 18 hours. Pipeline finished April 14, 13:47 UTC.</strong></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"geth-v1172-7-days-15-hours\">Geth v1.17.2: 7 days 15 hours<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#geth-v1172-7-days-15-hours\" class=\"hash-link\" aria-label=\"Direct link to Geth v1.17.2: 7 days 15 hours\" title=\"Direct link to Geth v1.17.2: 7 days 15 hours\" translate=\"no\">​</a></h3>\n<p>Geth performed a snap sync from genesis with parallel header and state downloads:</p>\n<p><strong>Headers (19:42 to ~01:00 Apr 9, ~5h):</strong> Geth's header download progressed at ~1.25M headers/hour. Early logs showed \"Syncing beacon headers downloaded=512 left=24,836,569 eta=4h20m\". Geth explicitly rejected live CC blocks during this phase: \"Ignoring payload while snap syncing\".</p>\n<p><strong>State download (parallel with headers, ~1.5h):</strong> State download started simultaneously and progressed rapidly, showing \"state download synced=0.15% eta=1h24m\" at minute 10.</p>\n<p><strong>State healing (dominant bottleneck):</strong> After headers and initial state were downloaded within hours, state healing ran for <strong>days</strong>. This is the phase where Geth patches gaps and inconsistencies in the downloaded state trie.</p>\n<p><strong>Snap sync complete: April 16, 10:32 UTC.</strong></p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">Switching from snap-sync to full-sync    reason=\"snap-sync complete\"</span><br></span></code></pre></div></div>\n<p><strong>Total: ~7 days 15 hours. State healing was the multi day bottleneck.</strong></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ethrex-900-not-completed-8-days\">Ethrex 9.0.0: Not completed (8+ days)<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#ethrex-900-not-completed-8-days\" class=\"hash-link\" aria-label=\"Direct link to Ethrex 9.0.0: Not completed (8+ days)\" title=\"Direct link to Ethrex 9.0.0: Not completed (8+ days)\" translate=\"no\">​</a></h3>\n<p>Ethrex operates in <strong>dual mode</strong>: it immediately processes live blocks via the engine API while running P2P snap sync in the background. This means the paired CC tracks the chain head within seconds of startup, but the EC lacks complete historical state.</p>\n<p><strong>Live blocks (immediate):</strong> At 19:42:32 UTC, Ethrex received its first engine payload for block 24,837,020, just 26 seconds after startup.</p>\n<p><strong>P2P snap sync (ongoing):</strong> Snap sync started at 19:42:35. After ~3 hours it reached the \"Requesting Bytecodes\" phase. However, a restart at some point reset all progress. As of April 16, the snap sync status showed:</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">P2P Snap Sync | elapsed 00h 00m 07s | peers 7 | step Downloading Headers</span><br></span></code></pre></div></div>\n<p>The sync had effectively restarted from scratch with minimal peer connectivity.</p>\n<p><strong>Total: Not completed after 8+ days. The P2P snap sync is effectively stalled.</strong></p>\n<div class=\"theme-admonition theme-admonition-info admonition_xJq3 alert alert--info\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z\"></path></svg></span>About Ethrex</div><div class=\"admonitionContent_BuS1\"><p>Once Ethrex completes its initial sync, our experience with it has been excellent. Block building performance and attestation behavior are on par with established clients, as shown in our <a class=\"\" href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\">Nimbus block building analysis</a>. Getting to that point, however, requires significant patience and may involve manual restarts. The P2P snap sync implementation is still maturing.</p><p>We have developed internal workflows and tooling to work around the current sync challenges, and these are available to <a href=\"https://stereumlabs.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs</a> users who want to run Ethrex in their setup. Additionally, the LambdaClass team is actively working on newer Ethrex versions that are expected to address many of these sync related issues. A deeper analysis of Ethrex sync strategies and workarounds is outside the scope of this post, but we may cover it in a dedicated article in the future.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"peak-resource-usage-during-sync\">Peak resource usage during sync<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#peak-resource-usage-during-sync\" class=\"hash-link\" aria-label=\"Direct link to Peak resource usage during sync\" title=\"Direct link to Peak resource usage during sync\" translate=\"no\">​</a></h2>\n<p>These are <strong>maximum values</strong> observed on each EC host during the first 6 hours after deployment (the peak sync burst period), measured via node exporter. Since each EC runs on its own dedicated host with no other significant services, these numbers reflect EC resource consumption directly.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Peak host resource usage during sync\" src=\"https://docs.stereumlabs.com/assets/images/peak-resources-629c705b2fbc2aa0435252110a2a0efd.png\" width=\"2492\" height=\"921\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Metric</th><th>Nethermind</th><th>Besu</th><th>Geth</th><th>Erigon</th><th>Reth</th><th>Ethrex</th></tr></thead><tbody><tr><td>Peak CPU (cores)</td><td>10.8</td><td>5.2</td><td>9.7</td><td>4.5</td><td>2.9</td><td>7.9</td></tr><tr><td>Peak RAM (GB)</td><td>10.8</td><td>12.0</td><td>5.6</td><td>14.1</td><td>9.4</td><td>19.7</td></tr><tr><td>Peak Disk Read (MB/s)</td><td>561</td><td>27</td><td>44</td><td>176</td><td>61</td><td>219</td></tr><tr><td>Peak Disk Write (MB/s)</td><td>533</td><td>176</td><td>281</td><td>105</td><td>92</td><td>484</td></tr><tr><td>Peak Net RX (MB/s)</td><td>111</td><td>33</td><td>98</td><td>75</td><td>96</td><td>86</td></tr></tbody></table>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Peak disk I/O during sync\" src=\"https://docs.stereumlabs.com/assets/images/disk-io-4c4d04936df818997b3cac29f9771d7d.png\" width=\"2128\" height=\"871\" class=\"img_ev3q\"></p>\n<p><strong>Nethermind</strong> was the heaviest on disk I/O: 561 MB/s reads and 533 MB/s writes during its snap sync burst. It traded high resource intensity for the fastest sync by far.</p>\n<p><strong>Geth</strong> was CPU intensive (9.7 cores) but had the lowest memory footprint (5.6 GB) of any EC during sync.</p>\n<p><strong>Erigon</strong> consumed the most RAM among established clients (14.1 GB) despite being mid pack on sync speed, consistent with its known memory pressure pattern during staged execution.</p>\n<p><strong>Ethrex</strong> had the highest RAM usage overall (19.7 GB) and very high disk writes (484 MB/s), driven by simultaneous live block processing and background snap sync.</p>\n<p><strong>Reth</strong> was the most resource efficient during the initial 6 hour window: lowest CPU (2.9 cores), moderate RAM (9.4 GB), minimal I/O. However, this is misleading because Reth's pipeline was still in the Bodies download stage during this window, with the heavy Execution stage starting later and running for 5+ days.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"key-observations\">Key observations<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#key-observations\" class=\"hash-link\" aria-label=\"Direct link to Key observations\" title=\"Direct link to Key observations\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"1-sync-speed-varies-by-orders-of-magnitude\">1. Sync speed varies by orders of magnitude<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#1-sync-speed-varies-by-orders-of-magnitude\" class=\"hash-link\" aria-label=\"Direct link to 1. Sync speed varies by orders of magnitude\" title=\"Direct link to 1. Sync speed varies by orders of magnitude\" translate=\"no\">​</a></h3>\n<p>The gap between the fastest (Nethermind, 1.5h) and the slowest completed sync (Geth, 7.5 days) is a factor of <strong>120×</strong>. For operators, this means the difference between being back online during a lunch break versus being offline for more than a week.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"2-in-sync-does-not-mean-synced\">2. \"In sync\" does not mean synced<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#2-in-sync-does-not-mean-synced\" class=\"hash-link\" aria-label=\"Direct link to 2. &quot;In sync&quot; does not mean synced\" title=\"Direct link to 2. &quot;In sync&quot; does not mean synced\" translate=\"no\">​</a></h3>\n<p>This is the most operationally dangerous finding. Reth, Geth, Ethrex, and Besu all reported themselves as ready to serve the consensus client while their historical sync was far from complete. Operators monitoring only CC metrics (head slot, attestation inclusion) would see a healthy node while the EC was still days from full sync.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"3-nvme-storage-is-essential-for-fast-sync\">3. NVMe storage is essential for fast sync<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#3-nvme-storage-is-essential-for-fast-sync\" class=\"hash-link\" aria-label=\"Direct link to 3. NVMe storage is essential for fast sync\" title=\"Direct link to 3. NVMe storage is essential for fast sync\" translate=\"no\">​</a></h3>\n<p>Nethermind's 561 MB/s peak disk reads demonstrate why: its snap sync strategy saturates fast storage to finish quickly. On slower drives (SATA SSD or HDD), the sync time would scale proportionally, potentially turning Nethermind's 1.5 hours into many hours.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"4-erigons-staged-sync-is-predictable-but-slow\">4. Erigon's staged sync is predictable but slow<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#4-erigons-staged-sync-is-predictable-but-slow\" class=\"hash-link\" aria-label=\"Direct link to 4. Erigon's staged sync is predictable but slow\" title=\"Direct link to 4. Erigon's staged sync is predictable but slow\" translate=\"no\">​</a></h3>\n<p>Erigon's 5K block batch processing through the execution stage is the primary bottleneck. The staged approach provides clear progress visibility and checkpointing, but at the cost of being 10× slower than Nethermind. Two instances also required restarts due to memory pressure during this phase.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"5-reth-and-geth-need-days-for-historical-execution\">5. Reth and Geth need days for historical execution<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#5-reth-and-geth-need-days-for-historical-execution\" class=\"hash-link\" aria-label=\"Direct link to 5. Reth and Geth need days for historical execution\" title=\"Direct link to 5. Reth and Geth need days for historical execution\" translate=\"no\">​</a></h3>\n<p>Both clients must replay the entire chain history. Reth does this sequentially through its Execution stage (5+ days), while Geth's bottleneck is state trie reconciliation after its initial snap download. These are fundamentally different bottlenecks but produce similar multi day timelines.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"6-ethrex-syncing-requires-patience\">6. Ethrex syncing requires patience<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#6-ethrex-syncing-requires-patience\" class=\"hash-link\" aria-label=\"Direct link to 6. Ethrex syncing requires patience\" title=\"Direct link to 6. Ethrex syncing requires patience\" translate=\"no\">​</a></h3>\n<p>Ethrex delivers solid performance once fully synced, as our previous analyses have shown. The challenge is getting there. Its P2P snap sync is still maturing, and a restart during our test reset all progress. Peer connectivity (7 peers vs. 90+ for other clients) suggests the sync P2P discovery needs further work. The LambdaClass team is actively iterating, and upcoming Ethrex versions are expected to improve the sync experience considerably. For operators willing to invest patience (or use alternative bootstrapping methods), Ethrex is absolutely viable in production once it reaches the chain tip. We offer tooling and guidance for Ethrex sync on <a href=\"https://stereumlabs.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">StereumLabs</a> for those who want to get started today.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"relation-to-block-building-performance\">Relation to block building performance<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#relation-to-block-building-performance\" class=\"hash-link\" aria-label=\"Direct link to Relation to block building performance\" title=\"Direct link to Relation to block building performance\" translate=\"no\">​</a></h2>\n<p>In our <a class=\"\" href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building\">previous analysis of Nimbus block building across 5 ECs</a>, we found that Erigon's slow block execution (423 to 567ms per imported block) causes it to deliver empty block payloads. This sync investigation confirms the pattern: Erigon's execution pipeline is the consistent bottleneck, whether processing historical blocks during sync or building new blocks for proposals.</p>\n<p>Reth was excluded from that analysis because it had not completed its initial sync at the time. This post explains why: its full pipeline takes nearly 6 days.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"methodology\">Methodology<a href=\"https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026#methodology\" class=\"hash-link\" aria-label=\"Direct link to Methodology\" title=\"Direct link to Methodology\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">All data sourced from Prometheus (<code>prometheus-cold</code> datasource) and Elasticsearch (Filebeat container log shipping) on the StereumLabs Grafana instance.</li>\n<li class=\"\">EC sync completion determined from EC container logs: <code>Finished stage</code> (Reth), <code>Snap sync complete</code> (Geth), <code>Sync completed successfully</code> / <code>Backward sync session is done</code> (Besu), <code>Block throughput</code> first appearance (Nethermind), <code>P2P Snap Sync</code> status messages (Ethrex), <code>sync</code> metric per stage progression (Erigon).</li>\n<li class=\"\">Peak resource usage measured via <code>node_exporter</code> metrics with <code>max_over_time(...[6h])</code> queries at each EC's dedicated host.</li>\n<li class=\"\">All nodes run on NDC2 bare metal hardware (Vienna), eliminating cloud induced variance.</li>\n</ul>",
            "url": "https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026",
            "title": "Execution Client Sync Speed: From 1.5 Hours to 8+ Days",
            "summary": "We deployed all 6 Ethereum execution clients from scratch on bare metal and tracked exactly how long each one took to fully sync. The results range from impressive to alarming.",
            "date_modified": "2026-04-22T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "execution client",
                "sync",
                "Besu",
                "Erigon",
                "Ethrex",
                "Geth",
                "Nethermind",
                "Reth",
                "performance",
                "benchmarking",
                "NDC2"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building",
            "content_html": "<p>How does each execution client behave when Nimbus asks it to build a block? We monitored 1,000 validator pubkeys across 5 EC pairings for 48 hours and found that block building performance varies dramatically, with one client producing near-empty blocks while the other four packed in millions of gas.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Nimbus v26.3.1: Validator monitoring and block building across 5 execution clients\" src=\"https://docs.stereumlabs.com/assets/images/thumbnail-2723b2fb05afb7059583d0961cf8ae67.png\" width=\"1785\" height=\"930\" class=\"img_ev3q\"></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"overview\">Overview<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#overview\" class=\"hash-link\" aria-label=\"Direct link to Overview\" title=\"Direct link to Overview\" translate=\"no\">​</a></h2>\n<p>We run 5 Nimbus <code>multiarch-v26.3.1</code> beacon nodes on our NDC2 bare-metal fleet in Vienna, each paired with a different execution client:</p>\n<table><thead><tr><th>Consensus Client</th><th>Execution Client</th><th>Location</th></tr></thead><tbody><tr><td>Nimbus v26.3.1</td><td>Besu 26.2.0</td><td>NDC2, Vienna</td></tr><tr><td>Nimbus v26.3.1</td><td>Erigon v3.3.10</td><td>NDC2, Vienna</td></tr><tr><td>Nimbus v26.3.1</td><td>Ethrex 9.0.0</td><td>NDC2, Vienna</td></tr><tr><td>Nimbus v26.3.1</td><td>Geth v1.17.2</td><td>NDC2, Vienna</td></tr><tr><td>Nimbus v26.3.1</td><td>Nethermind 1.36.2</td><td>NDC2, Vienna</td></tr></tbody></table>\n<p>A sixth node (Nimbus + Reth v1.11.3) is also deployed, but Reth has not yet completed its initial sync and is therefore excluded from this analysis.</p>\n<p>All 5 nodes use Nimbus' built-in <code>validator_monitor</code> feature to passively observe the same set of <strong>1,000 validator pubkeys</strong> on-chain. The validator monitor tracks attestation inclusion, vote correctness, block proposals, and timing data for these validators without requiring the signing keys to be locally attached.</p>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>Shadow setup</div><div class=\"admonitionContent_BuS1\"><p>This is a shadow configuration: a reverse proxy mirrors the validator client's requests to these beacon nodes, but the beacon nodes' responses do not reach the validator client. This means the data reflects how each CC+EC pairing <em>observes and reacts to</em> validator duties, but is not fully representative of a production validator setup where the EC's block building output would actually be submitted to the network.</p></div></div>\n<p>The full analysis covers a 48-hour window ending April 13, 2026. Data sources: Prometheus (<code>prometheus-cold</code>) for metrics and Elasticsearch (Filebeat) for both EC container logs and Nimbus CC container logs.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"block-building-the-headline-finding\">Block building: the headline finding<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#block-building-the-headline-finding\" class=\"hash-link\" aria-label=\"Direct link to Block building: the headline finding\" title=\"Direct link to Block building: the headline finding\" translate=\"no\">​</a></h2>\n<p>When one of the 1,000 monitored validators is selected as block proposer, Nimbus triggers <code>engine_forkchoiceUpdatedV3</code> with payload attributes on its paired EC, asking it to build a block. The EC then constructs the execution payload iteratively, improving it over several seconds until Nimbus calls <code>engine_getPayloadV4</code> to retrieve the result.</p>\n<p>Over 48 hours, block building was triggered for approximately 13 unique blocks. <strong>The results differ dramatically between execution clients.</strong></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"build-latency-vs-payload-output\">Build latency vs. payload output<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#build-latency-vs-payload-output\" class=\"hash-link\" aria-label=\"Direct link to Build latency vs. payload output\" title=\"Direct link to Build latency vs. payload output\" translate=\"no\">​</a></h3>\n<p>Nimbus logs the exact timestamps for <code>Requesting engine payload</code> and <code>Received engine payload</code>, giving us the end-to-end build latency and resulting gas_used for every payload. This CC-side perspective is consistent across all ECs and fills in data even when the EC's own logs lack detail.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Build latency vs. payload gas output\" src=\"https://docs.stereumlabs.com/assets/images/latency_vs_gas-69fff28ab0a4030ad6fed61d39477262.png\" width=\"1420\" height=\"880\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC</th><th>Avg latency</th><th>Min</th><th>Max</th><th>Avg gas (Mgas)</th><th>Blocks</th></tr></thead><tbody><tr><td><strong>Besu</strong></td><td>546ms</td><td>75ms</td><td>848ms</td><td><strong>23.5</strong></td><td>11</td></tr><tr><td><strong>Ethrex</strong></td><td>535ms</td><td>27ms</td><td>728ms</td><td><strong>21.8</strong></td><td>13</td></tr><tr><td><strong>Nethermind</strong></td><td>519ms</td><td>28ms</td><td>696ms</td><td><strong>21.2</strong></td><td>13</td></tr><tr><td><strong>Geth</strong></td><td>524ms</td><td>24ms</td><td>756ms</td><td><strong>15.0</strong></td><td>13</td></tr><tr><td><strong>Erigon</strong></td><td><strong>479ms</strong> (fastest)</td><td>18ms</td><td>523ms</td><td><strong>0.0</strong></td><td>12</td></tr></tbody></table>\n<p>The most counterintuitive finding: <strong>Erigon is the fastest responder (479ms avg) yet delivers 0 gas.</strong> Its transaction pool is apparently unable to supply transactions within the build window, so it returns an empty block quickly rather than spending time filling it. Besu takes 67ms longer on average but uses that time to pack 23.5 Mgas into the payload.</p>\n<p>For high-gas blocks (slots with blob transactions), latency increases across all ECs: Besu peaks at 848ms for a 60M gas block, Ethrex at 728ms for the same block. This confirms that build latency scales with payload complexity.</p>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>note</div><div class=\"admonitionContent_BuS1\"><p>One slot shows anomalously low latency for all ECs (Erigon 18ms, Geth 24ms, Ethrex 27ms, Nethermind 28ms, Besu 75ms). This is likely a cached or pre-built payload that Nimbus retrieved immediately.</p></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"per-block-distribution\">Per-block distribution<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#per-block-distribution\" class=\"hash-link\" aria-label=\"Direct link to Per-block distribution\" title=\"Direct link to Per-block distribution\" translate=\"no\">​</a></h3>\n<p>The averages above compress a wide range of behavior into single numbers. Plotting every individual block build reveals the full distribution:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"All block builds: latency vs. gas output per EC (48h)\" src=\"https://docs.stereumlabs.com/assets/images/all_blocks_scatter-9c77f4b92a19b6b2b2539a2041d9a758.png\" width=\"2138\" height=\"1237\" class=\"img_ev3q\"></p>\n<p>Three distinct patterns emerge:</p>\n<p><strong>Standard blocks (500-650ms, 7-18 Mgas):</strong> The main cluster where most builds land. Besu, Ethrex, and Nethermind consistently occupy the upper band (14-18 Mgas), while Geth sits lower (7-15 Mgas). All four ECs overlap in latency, confirming that response time differences between them are marginal for regular blocks.</p>\n<p><strong>Blob-heavy blocks (700-850ms, 38-60 Mgas):</strong> A few outlier slots where blob transactions push gas usage to 38-60M. These blocks take noticeably longer to build across all ECs, with Besu and Ethrex reaching the gas limit (60M) while Geth tops out around 40-48M. The latency increase is proportional to payload complexity.</p>\n<p><strong>Erigon (480-520ms, 0 Mgas):</strong> Every single Erigon build sits flat on the x-axis at 0 gas, forming a tight horizontal cluster. Regardless of whether the same slot produced a 17M gas block on Besu or a 60M gas block on Ethrex, Erigon delivered an empty payload. This pattern is consistent across all 12 blocks with no exceptions.</p>\n<p>The scatter also reveals a handful of <strong>cached payloads</strong> (sub-100ms) where all ECs returned near-instantly, likely from a previously prepared payload that Nimbus retrieved before the build window elapsed.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"cross-ec-payload-comparison\">Cross-EC payload comparison<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#cross-ec-payload-comparison\" class=\"hash-link\" aria-label=\"Direct link to Cross-EC payload comparison\" title=\"Direct link to Cross-EC payload comparison\" translate=\"no\">​</a></h3>\n<p>By examining the <code>Received engine payload</code> log from all 5 Nimbus CC instances, we can compare the actual gas_used delivered by each EC for the same blocks:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Engine payload gas per block (from Nimbus CC logs, 48h)\" src=\"https://docs.stereumlabs.com/assets/images/payload_gas_comparison-ec8d1578b8c8c71b985d0a9322110f8a.png\" width=\"2141\" height=\"971\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC</th><th>Block #869114</th><th>Block #869617</th><th>Block #867424</th><th>Block #866897</th><th>Avg gas</th></tr></thead><tbody><tr><td><strong>Besu</strong></td><td><strong>17.6M</strong></td><td><strong>15.1M</strong></td><td><strong>13.0M</strong></td><td><strong>17.5M</strong></td><td><strong>~23.5M</strong></td></tr><tr><td><strong>Ethrex</strong></td><td><strong>16.9M</strong></td><td><strong>17.8M</strong></td><td><strong>18.0M</strong></td><td><strong>18.0M</strong></td><td><strong>~21.8M</strong></td></tr><tr><td><strong>Nethermind</strong></td><td><strong>17.3M</strong></td><td><strong>10.1M</strong></td><td><strong>15.4M</strong></td><td><strong>16.6M</strong></td><td><strong>~21.2M</strong></td></tr><tr><td><strong>Geth</strong></td><td>14.0M</td><td>7.1M</td><td>11.0M</td><td>8.3M</td><td>~15.0M</td></tr><tr><td><strong>Erigon</strong></td><td><strong>0</strong></td><td><strong>41K</strong></td><td>—</td><td><strong>0</strong></td><td><strong>~0</strong></td></tr></tbody></table>\n<p>Besu, Ethrex, and Nethermind are the strongest block builders, routinely filling blocks to 15-30% gas utilization. Ethrex is particularly consistent, delivering 14-18M gas for standard blocks. Geth produces lighter payloads. Erigon's payloads are effectively empty.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"besu-the-most-aggressive-builder\">Besu: the most aggressive builder<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#besu-the-most-aggressive-builder\" class=\"hash-link\" aria-label=\"Direct link to Besu: the most aggressive builder\" title=\"Direct link to Besu: the most aggressive builder\" translate=\"no\">​</a></h3>\n<p>Besu produced <strong>661 block improvement iterations</strong> across its built blocks. Its logs show the full iterative building process with reward tracking:</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">New proposal for payloadId 0x36f36d block 24869114</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  gas used 17,624,773  transactions 366  reward 2.22 finney</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  is better than the previous one by 103.24 szabo</span><br></span></code></pre></div></div>\n<p>For block #24,869,114, Besu's best build reached <strong>366 transactions, 17.6M gas, and a 2.22 finney block reward</strong>. It logged every improvement step, including the marginal reward increase between iterations.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"geth-clean-lifecycle-strong-output\">Geth: clean lifecycle, strong output<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#geth-clean-lifecycle-strong-output\" class=\"hash-link\" aria-label=\"Direct link to Geth: clean lifecycle, strong output\" title=\"Direct link to Geth: clean lifecycle, strong output\" translate=\"no\">​</a></h3>\n<p>Geth logged 214 payload updates and provides the clearest view of the block building lifecycle:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Geth block #24,869,114 iterative build timeline\" src=\"https://docs.stereumlabs.com/assets/images/geth_build_timeline-12b69b415ebfa7471f8c852a05fae94d.png\" width=\"1600\" height=\"789\" class=\"img_ev3q\"></p>\n<p>The build started with 6 transactions and grew to <strong>349 transactions over ~10.5 seconds</strong>, with each update taking 25-67ms. Geth logs <code>Starting work on payload</code>, then multiple <code>Updated payload</code> entries (with txs, gas, fees, elapsed time), and finally <code>Stopping work on payload reason=delivery</code> when Nimbus retrieves the result.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ethrex-strong-builder-detailed-execution-breakdown\">Ethrex: strong builder, detailed execution breakdown<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#ethrex-strong-builder-detailed-execution-breakdown\" class=\"hash-link\" aria-label=\"Direct link to Ethrex: strong builder, detailed execution breakdown\" title=\"Direct link to Ethrex: strong builder, detailed execution breakdown\" translate=\"no\">​</a></h3>\n<p>Ethrex does not log block building progress in its own container logs at the default log level. However, Nimbus' CC logs reveal it is one of the strongest builders in the fleet, delivering <strong>21.8 Mgas on average</strong> with one block hitting <strong>100% gas utilization (60M gas)</strong>. Each payload carries <code>extra_data: ethrex 9.0.0</code>.</p>\n<p>What Ethrex does log is an excellent per-block execution breakdown when processing incoming blocks:</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">BLOCK EXECUTION THROUGHPUT (24869233): 0.366 Ggas/s</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  TIME SPENT: 55 ms. Gas Used: 0.020 (33%), #Txs: 134</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  block validation: 1% | exec(w/merkle): 91% | merkle-only: 2% | store: 7%</span><br></span></code></pre></div></div>\n<p>This level of transparency into where execution time is spent (91% in execution+merkle, 7% in storage, 1% in validation) is unique among the tested ECs and valuable for performance profiling.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"nethermind-strong-builder-quiet-logs\">Nethermind: strong builder, quiet logs<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#nethermind-strong-builder-quiet-logs\" class=\"hash-link\" aria-label=\"Direct link to Nethermind: strong builder, quiet logs\" title=\"Direct link to Nethermind: strong builder, quiet logs\" translate=\"no\">​</a></h3>\n<p>Nethermind's own logs only show production requests (<code>Production Request 24869114 PayloadId: 0x2321052e5846b8a2</code>) without per-iteration detail at the default log level. However, <strong>Nimbus' CC logs reveal the full picture:</strong></p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">INF Received engine payload  slot=14103195 payload=\"(block_number: 24869114,</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  gas_used: 17257515, gas_limit: 60000000, extra_data: Nethermind v1.36.2, ...)\"</span><br></span></code></pre></div></div>\n<p>For block #24,869,114, Nethermind delivered <strong>17.3M gas</strong>, competitive with Besu's 17.6M and Ethrex's 16.9M. Across all 13 payloads in 48h, Nethermind consistently produced blocks in the 9-17M gas range.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"erigon-severely-impaired-block-building\">Erigon: severely impaired block building<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#erigon-severely-impaired-block-building\" class=\"hash-link\" aria-label=\"Direct link to Erigon: severely impaired block building\" title=\"Direct link to Erigon: severely impaired block building\" translate=\"no\">​</a></h3>\n<p>Erigon's own logs show it actively attempts to build blocks but consistently fails to include transactions:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Erigon block build outcomes (54 builds, 48h)\" src=\"https://docs.stereumlabs.com/assets/images/erigon_build_outcomes-838549fad876cbf1739ea702cadba87f.png\" width=\"862\" height=\"845\" class=\"img_ev3q\"></p>\n<p><strong>76% of Erigon's 54 block build iterations produced completely empty blocks</strong> with 0 transactions and 0 gas. When it did include transactions, the count was dramatically lower than other clients: a maximum of 36 transactions versus 300+ for Besu and Geth.</p>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">Built block  height=24869114  txs=0  executionRequests=0</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  gas used %=0.000  time=782.686ms</span><br></span></code></pre></div></div>\n<p>The Nimbus CC logs confirm this: across 12 blocks, every single payload from Erigon contained 0 or near-0 gas. This is not a latency issue. At 479ms average, Erigon is the <em>fastest</em> EC to return a payload. The problem is upstream: Erigon's block execution latency (423-567ms per imported block) delays transaction pool maintenance, so when Nimbus asks for a payload, Erigon has nothing to put in it.</p>\n<div class=\"theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>Operator impact</div><div class=\"admonitionContent_BuS1\"><p>In a production setup, if Erigon were the EC responsible for building the block that gets submitted to the network, the validator would propose a near-empty block, forfeiting transaction fees and MEV revenue. For the ~13 blocks built in our 48h window, the difference between Besu's output (2.22 finney reward) and Erigon's (0 reward) is a direct loss per proposal.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"attestation-pipeline-per-ec-timing-differences\">Attestation pipeline: per-EC timing differences<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#attestation-pipeline-per-ec-timing-differences\" class=\"hash-link\" aria-label=\"Direct link to Attestation pipeline: per-EC timing differences\" title=\"Direct link to Attestation pipeline: per-EC timing differences\" translate=\"no\">​</a></h2>\n<p>While all 5 nodes observe the same 1,000 validators and see identical on-chain results (99.996% attestation inclusion rate), <em>how quickly</em> each node observes attestation events varies by EC pairing. Three pipeline stages were measured:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Attestation pipeline delay by EC pairing (p50, 48h)\" src=\"https://docs.stereumlabs.com/assets/images/attestation_delay-b252db05f19f50beb3c94573ea74ed22.png\" width=\"1780\" height=\"881\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Pipeline stage</th><th>Besu</th><th>Erigon</th><th>Ethrex</th><th>Geth</th><th>Nethermind</th><th>Spread</th></tr></thead><tbody><tr><td><strong>Unaggregated attestation</strong> (p50)</td><td><strong>49ms</strong></td><td>50ms</td><td>53ms</td><td>52ms</td><td>52ms</td><td>4ms</td></tr><tr><td><strong>Aggregated attestation</strong> (p50)</td><td><strong>35ms</strong></td><td>35ms</td><td>38ms</td><td>38ms</td><td>38ms</td><td>3ms</td></tr><tr><td><strong>Attestation in aggregate</strong> (p50)</td><td>142ms</td><td><strong>153ms</strong></td><td>141ms</td><td><strong>135ms</strong></td><td>145ms</td><td>18ms</td></tr></tbody></table>\n<p>Besu is the fastest for raw attestation observation. However, Geth leads in the third stage (attestation appearing inside aggregates), which is the most relevant for actual inclusion. Erigon is consistently the slowest in this final stage, adding 18ms of latency versus Geth. Ethrex performs well across all three stages.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"attestation-volume-erigons-observation-gap\">Attestation volume: Erigon's observation gap<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#attestation-volume-erigons-observation-gap\" class=\"hash-link\" aria-label=\"Direct link to Attestation volume: Erigon's observation gap\" title=\"Direct link to Attestation volume: Erigon's observation gap\" translate=\"no\">​</a></h2>\n<p>All 5 nodes should see roughly the same number of attestations for the monitored validators. Over 48 hours, they do not:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Unaggregated attestations received via API (48h)\" src=\"https://docs.stereumlabs.com/assets/images/attestation_volume-65c17df9eb75b2ff90bb44f489d823b2.png\" width=\"1422\" height=\"789\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC pairing</th><th>Attestations received (API)</th><th>Delta vs. best</th></tr></thead><tbody><tr><td>Geth</td><td>404,876</td><td>baseline</td></tr><tr><td>Nethermind</td><td>403,726</td><td>-0.3%</td></tr><tr><td>Besu</td><td>402,563</td><td>-0.6%</td></tr><tr><td>Ethrex</td><td>400,752</td><td>-1.0%</td></tr><tr><td><strong>Erigon</strong></td><td><strong>359,104</strong></td><td><strong>-11.3%</strong></td></tr></tbody></table>\n<p>Erigon misses <strong>~45,000 attestations</strong> that the other 4 nodes see within the same 48-hour window. This is not a network issue; all nodes are on the same bare-metal fleet in Vienna. Erigon's slower block processing causes attestations to expire before the node can process them.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"vote-accuracy-source-target-and-head\">Vote accuracy: source, target, and head<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#vote-accuracy-source-target-and-head\" class=\"hash-link\" aria-label=\"Direct link to Vote accuracy: source, target, and head\" title=\"Direct link to Vote accuracy: source, target, and head\" translate=\"no\">​</a></h2>\n<p>The 1,000 monitored validators' three Casper FFG vote types show dramatically different difficulty levels:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Attestation vote accuracy (48h, 1000 validators)\" src=\"https://docs.stereumlabs.com/assets/images/vote_type_hierarchy-f30e1137467b13ca7e57685aa8b5c144.png\" width=\"1422\" height=\"789\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Vote type</th><th>Hits (48h)</th><th>Misses (48h)</th><th>Hit rate</th><th>What it measures</th></tr></thead><tbody><tr><td><strong>Source</strong></td><td>450,137</td><td>19</td><td>99.996%</td><td>Correct justified checkpoint</td></tr><tr><td><strong>Target</strong></td><td>449,857</td><td>299</td><td>99.934%</td><td>Correct finalized checkpoint</td></tr><tr><td><strong>Head</strong></td><td>~446,200</td><td>~3,987</td><td>99.12%</td><td>Correct chain head at slot boundary</td></tr></tbody></table>\n<p>Head vote accuracy is the hardest duty, with ~210x more misses than source. It requires the node to see the latest block before the slot boundary, making it the most sensitive to processing speed.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"head-vote-diurnal-pattern\">Head vote: diurnal pattern<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#head-vote-diurnal-pattern\" class=\"hash-link\" aria-label=\"Direct link to Head vote: diurnal pattern\" title=\"Direct link to Head vote: diurnal pattern\" translate=\"no\">​</a></h3>\n<p>Over 48 hours, head vote accuracy shows a clear cyclic pattern:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Head vote accuracy over 48 hours\" src=\"https://docs.stereumlabs.com/assets/images/head_vote_48h-d6de3647341b7f10476221c7db2be58d.png\" width=\"1780\" height=\"699\" class=\"img_ev3q\"></p>\n<p>The rate fluctuates between <strong>98.64% and 99.54%</strong>, likely driven by network congestion patterns. All 5 nodes report identical values at each time point, confirming this reflects on-chain truth, not individual node performance.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"block-proposals-via-gossip\">Block proposals via gossip<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#block-proposals-via-gossip\" class=\"hash-link\" aria-label=\"Direct link to Block proposals via gossip\" title=\"Direct link to Block proposals via gossip\" translate=\"no\">​</a></h2>\n<p>Over the monitoring period, the nodes observed <strong>27 block proposals</strong> from the 1,000 monitored validators via gossip. In the last 48 hours, <strong>12 block proposals</strong> were detected via the <code>validator_monitor_block_hit_total</code> counter. All proposals arrived via the gossip network, confirming the validators are actively proposing on-chain.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"nimbus-cc-logs-as-an-observability-source\">Nimbus CC logs as an observability source<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#nimbus-cc-logs-as-an-observability-source\" class=\"hash-link\" aria-label=\"Direct link to Nimbus CC logs as an observability source\" title=\"Direct link to Nimbus CC logs as an observability source\" translate=\"no\">​</a></h2>\n<p>One of the practical takeaways from this analysis: <strong>Nimbus' consensus client logs are a valuable observability layer for block building</strong>, regardless of how detailed the execution client's own logs are.</p>\n<p>Nimbus logs three key events per block building cycle:</p>\n<ol>\n<li class=\"\"><code>Requesting engine payload</code> — timestamp, slot, beacon head, fee recipient</li>\n<li class=\"\"><code>Received engine payload</code> — full payload contents: gas_used, gas_limit, block_number, extra_data</li>\n<li class=\"\"><code>Block proposal included</code> — slot, validator ID</li>\n</ol>\n<p>For Ethrex and Nethermind, whose default log levels don't expose per-iteration block building details, the Nimbus CC logs were the only way to determine that both clients are strong builders (17-22M gas avg). This CC-side perspective also revealed the build latency data that showed Erigon's problem is not response time but empty transaction pools.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ec-log-verbosity-at-default-levels\">EC log verbosity at default levels<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#ec-log-verbosity-at-default-levels\" class=\"hash-link\" aria-label=\"Direct link to EC log verbosity at default levels\" title=\"Direct link to EC log verbosity at default levels\" translate=\"no\">​</a></h2>\n<p>An interesting infrastructure finding: the default log levels produce vastly different volumes across execution clients.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"EC container log volume at default log levels (per hour)\" src=\"https://docs.stereumlabs.com/assets/images/log_verbosity-70585912782b01de617fcc4171b9f731.png\" width=\"1420\" height=\"699\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Execution Client</th><th>Log entries per hour</th><th>Factor vs. least</th></tr></thead><tbody><tr><td>Nethermind 1.36.2</td><td>5,661</td><td>9.4x</td></tr><tr><td>Ethrex 9.0.0</td><td>1,569</td><td>2.6x</td></tr><tr><td>Geth v1.17.2</td><td>1,205</td><td>2.0x</td></tr><tr><td>Reth v1.11.3</td><td>838</td><td>1.4x</td></tr><tr><td>Erigon v3.3.10</td><td>781</td><td>1.3x</td></tr><tr><td>Besu 26.2.0</td><td>604</td><td>1.0x</td></tr></tbody></table>\n<p>Nethermind produces <strong>~9x more log output</strong> than Besu at default log levels. All 6 ECs in our fleet (including Reth, which is syncing) are included here since this is a general infrastructure observation.</p>\n<div class=\"theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>Operator consideration</div><div class=\"admonitionContent_BuS1\"><p>If you're running Nethermind with centralized logging (Filebeat/Elasticsearch or similar), account for its higher log volume when sizing your log storage and ingestion capacity. Consider adjusting Nethermind's log level if storage is constrained.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"summary\">Summary<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#summary\" class=\"hash-link\" aria-label=\"Direct link to Summary\" title=\"Direct link to Summary\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>Dimension</th><th>Besu</th><th>Erigon</th><th>Ethrex</th><th>Geth</th><th>Nethermind</th></tr></thead><tbody><tr><td><strong>Block building (avg gas)</strong></td><td>🟢 <strong>23.5M</strong> (best)</td><td>🔴 <strong>0M</strong> (empty)</td><td>🟢 <strong>21.8M</strong></td><td>⚪ 15.0M</td><td>🟢 <strong>21.2M</strong></td></tr><tr><td><strong>Build latency</strong></td><td>546ms</td><td><strong>479ms</strong> (fastest)</td><td>535ms</td><td>524ms</td><td>519ms</td></tr><tr><td><strong>Attestation delay</strong> (agg.)</td><td>⚪ 142ms</td><td>🔴 153ms</td><td>⚪ 141ms</td><td>🟢 <strong>135ms</strong></td><td>⚪ 145ms</td></tr><tr><td><strong>Attestation volume</strong></td><td>⚪ -0.6%</td><td>🔴 <strong>-11.3%</strong></td><td>⚪ -1.0%</td><td>🟢 Baseline</td><td>⚪ -0.3%</td></tr><tr><td><strong>EC build log detail</strong></td><td>🟢 Full</td><td>⚪ txs + gas</td><td>🟠 None (CC fills gap)</td><td>🟢 Full</td><td>🟠 Minimal (CC fills gap)</td></tr><tr><td><strong>Log verbosity</strong> (default)</td><td>🟢 604/hr</td><td>⚪ 781/hr</td><td>⚪ 1,569/hr</td><td>⚪ 1,205/hr</td><td>🟠 5,661/hr</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"key-takeaways\">Key takeaways<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#key-takeaways\" class=\"hash-link\" aria-label=\"Direct link to Key takeaways\" title=\"Direct link to Key takeaways\" translate=\"no\">​</a></h3>\n<ol>\n<li class=\"\">\n<p><strong>Erigon's block building is severely impaired.</strong> 76% of built blocks were empty, and even when it did include transactions, the count was a fraction of what other clients achieved. Paradoxically, Erigon responds fastest (479ms) but with nothing in the payload. The root cause is its slow block execution (423-567ms) cascading into transaction pool readiness.</p>\n</li>\n<li class=\"\">\n<p><strong>Besu, Ethrex, and Nethermind are all strong block builders.</strong> Besu leads on raw gas output (23.5M avg) and iteration count (661 per block). Ethrex is the most consistent (14-18M gas for standard blocks, 60M for full blocks). Nethermind is competitive at 21.2M avg despite minimal logging.</p>\n</li>\n<li class=\"\">\n<p><strong>Nimbus' CC logs are a valuable observability source.</strong> The <code>Received engine payload</code> log provides payload gas_used, build latency, and block details for every EC, making it the most reliable cross-client comparison tool, especially for ECs like Ethrex and Nethermind whose own logs lack block building detail at default levels.</p>\n</li>\n<li class=\"\">\n<p><strong>Erigon misses ~11% of attestation observations</strong> due to slower block processing. This volume gap is unique to Erigon; the other 4 ECs are within 1% of each other.</p>\n</li>\n<li class=\"\">\n<p><strong>Head vote accuracy (~99.1%) shows a diurnal pattern</strong> visible across all nodes identically, driven by network congestion rather than client behavior.</p>\n</li>\n<li class=\"\">\n<p><strong>Log volume varies 9x</strong> between the most and least verbose EC at default log levels. Nethermind's high verbosity (5,661/hr) is an infrastructure sizing consideration.</p>\n</li>\n</ol>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"methodology-notes\">Methodology notes<a href=\"https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building#methodology-notes\" class=\"hash-link\" aria-label=\"Direct link to Methodology notes\" title=\"Direct link to Methodology notes\" translate=\"no\">​</a></h2>\n<p>All Prometheus data sourced from the <code>prometheus-cold</code> datasource in the StereumLabs Grafana instance. Validator monitor metrics use the <code>validator_monitor_*</code> family with <code>cc_client=\"nimbus\"</code> and <code>validator=\"total\"</code> label selectors. 48-hour data uses <code>increase(...[48h])</code> instant queries and <code>histogram_quantile</code> over <code>rate(...[48h])</code> for delay distributions.</p>\n<p>EC container logs are stored in Elasticsearch (Filebeat 9.3.0 → Elasticsearch 9.3.0) and queried via the <code>container.image.name</code> field to isolate each execution client's output. Block building logs were identified by client-specific patterns: Besu's <code>New proposal for payloadId</code>, Geth's <code>Updated payload</code>/<code>Starting work on payload</code>/<code>Stopping work on payload</code>, and Erigon's <code>Built block</code>/<code>Building block</code>.</p>\n<p>Additionally, Nimbus CC container logs (<code>statusim/nimbus-eth2:multiarch-v26.3.1</code>) were analyzed for engine API interactions: <code>Requesting engine payload</code> (build request timestamps), <code>Received engine payload</code> (payload contents including gas_used), and <code>Block proposal included</code> (on-chain confirmation). This CC-side perspective provides build latency measurements and fills in payload details for ECs whose own logs lack that information at default log levels (notably Ethrex and Nethermind).</p>\n<p>All nodes run on NDC2 bare-metal hardware (Vienna), eliminating cloud-induced variance.</p>\n<p>For details on our label conventions and how to build your own dashboards against our data, see <a href=\"https://docs.stereumlabs.com/docs/dashboards/build-your-own\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Build your own dashboards</a>.</p>",
            "url": "https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building",
            "title": "Nimbus v26.3.1: Validator monitoring and block building across 5 execution clients",
            "summary": "A deep dive into how Nimbus observes 1,000 validators and how Besu, Erigon, Ethrex, Geth, and Nethermind behave when building blocks, processing attestations, and handling the Engine API, measured on our NDC2 bare-metal fleet over 48 hours.",
            "date_modified": "2026-04-15T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "Nimbus",
                "consensus client",
                "block building",
                "validator monitoring",
                "Erigon",
                "Geth",
                "Besu",
                "Nethermind",
                "Ethrex",
                "execution client",
                "PeerDAS",
                "performance"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources",
            "content_html": "<p>A deep dive into how Teku evolved across three releases: the RocksDB migration in 26.2.0, jemalloc in 26.3.0, and what both changes mean for CPU, memory, GC overhead, disk I/O, and block import latency on real hardware.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Teku 25.12.0 vs 26.2.0 vs 26.3.0: Cross-version resource &amp;amp; performance analysis\" src=\"https://docs.stereumlabs.com/assets/images/teku-version-comparison-thumbnail-bf60fe808551255aa87f575a8ee8d59e.png\" width=\"1800\" height=\"945\" class=\"img_ev3q\"></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"overview\">Overview<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#overview\" class=\"hash-link\" aria-label=\"Direct link to Overview\" title=\"Direct link to Overview\" translate=\"no\">​</a></h2>\n<p>We compared three Teku consensus client versions on our NDC2 bare-metal fleet in Vienna, each paired with all 6 execution clients (Besu, Erigon, Ethrex, Geth, Nethermind, Reth). Each version was measured over a 14-day window during its active deployment period using <code>avg_over_time(...[14d:1h])</code> instant queries against our Prometheus-cold datasource.</p>\n<table><thead><tr><th>Version</th><th>Release Date</th><th>Measurement Window</th><th>Key Changes</th></tr></thead><tbody><tr><td><strong>25.12.0</strong></td><td>Dec 16, 2025</td><td>Jan 15 – Jan 29, 2026</td><td>Late block reorg, block building prep, sidecar recovery</td></tr><tr><td><strong>26.2.0</strong></td><td>Feb 11, 2026</td><td>Feb 15 – Mar 1, 2026</td><td>RocksDB as default DB, DAS backfiller, getBlobs API</td></tr><tr><td><strong>26.3.0</strong></td><td>Mar 5, 2026</td><td>Mar 15 – Mar 29, 2026</td><td>jemalloc allocator, SSZ serialization fix, partial sidecar import</td></tr></tbody></table>\n<p>The full report is available as a PDF download at the <a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#download\" class=\"\">bottom of this post</a>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"fleet-level-headline-numbers\">Fleet-level headline numbers<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#fleet-level-headline-numbers\" class=\"hash-link\" aria-label=\"Direct link to Fleet-level headline numbers\" title=\"Direct link to Fleet-level headline numbers\" translate=\"no\">​</a></h2>\n<p>The two architectural changes — LevelDB → RocksDB in 26.2.0 and the jemalloc memory allocator in 26.3.0 — drove the majority of the performance shifts:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Fleet-wide changes from Teku 25.12.0 to 26.3.0\" src=\"https://docs.stereumlabs.com/assets/images/headline_kpis-9393ae7df83cfe2a3df56133aea45e52.png\" width=\"1600\" height=\"882\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Metric</th><th>25.12.0 → 26.3.0</th><th>What happened</th></tr></thead><tbody><tr><td><strong>CPU usage</strong></td><td><strong>−44%</strong></td><td>RocksDB caching + jemalloc reducing GC-driven CPU spikes</td></tr><tr><td><strong>GC overhead</strong></td><td><strong>−36%</strong></td><td>jemalloc reduced heap fragmentation → fewer full GC cycles</td></tr><tr><td><strong>Disk reads (host)</strong></td><td><strong>−79%</strong></td><td>RocksDB block cache eliminates most disk reads</td></tr><tr><td><strong>Disk writes (host)</strong></td><td><strong>−61%</strong></td><td>LSM-tree architecture writes more efficiently than LevelDB</td></tr><tr><td><strong>Block import delay</strong></td><td><strong>−24%</strong></td><td>Fastest average: 297ms in 26.3.0</td></tr><tr><td><strong>RSS memory</strong></td><td><strong>+2.8%</strong></td><td>RocksDB uses more in-memory structures (peaked at +5.5% in 26.2.0, recovered)</td></tr><tr><td><strong>Open file descriptors</strong></td><td><strong>+101%</strong></td><td>Expected: RocksDB holds many SST files open</td></tr><tr><td><strong>Peer count (libp2p)</strong></td><td><strong>+9%</strong></td><td>Steady improvement across versions</td></tr></tbody></table>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"cpu-utilization\">CPU utilization<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#cpu-utilization\" class=\"hash-link\" aria-label=\"Direct link to CPU utilization\" title=\"Direct link to CPU utilization\" translate=\"no\">​</a></h2>\n<p><strong>Metric:</strong> <code>rate(process_cpu_seconds_total{job=\"teku\"}[5m])</code> — Teku JVM process CPU in CPU-seconds per second.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Teku CPU usage by EC pairing across three versions\" src=\"https://docs.stereumlabs.com/assets/images/cpu_usage-78a75dc4aff4ca7fc3172ca116acf05d.png\" width=\"1780\" height=\"886\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC Pairing</th><th>25.12.0</th><th>26.2.0</th><th>26.3.0</th><th>Δ 25.12→26.2</th><th>Δ 26.2→26.3</th></tr></thead><tbody><tr><td>Besu</td><td>0.761</td><td>0.441</td><td>0.431</td><td>🟢 −42%</td><td>🟢 −2%</td></tr><tr><td>Erigon</td><td>0.704</td><td>0.414</td><td>0.409</td><td>🟢 −41%</td><td>🟢 −1%</td></tr><tr><td>Ethrex</td><td>0.594</td><td>0.552</td><td>0.419</td><td>🟢 −7%</td><td>🟢 −24%</td></tr><tr><td>Geth</td><td>0.771</td><td>0.553</td><td>0.429</td><td>🟢 −28%</td><td>🟢 −22%</td></tr><tr><td>Nethermind</td><td>0.720</td><td>0.330</td><td>0.305</td><td>🟢 −54%</td><td>🟢 −8%</td></tr><tr><td>Reth</td><td>0.722</td><td>0.364</td><td>0.377</td><td>🟢 −50%</td><td>🟠 +4%</td></tr><tr><td><strong>Fleet Average</strong></td><td><strong>0.712</strong></td><td><strong>0.442</strong></td><td><strong>0.395</strong></td><td><strong>🟢 −38%</strong></td><td><strong>🟢 −11%</strong></td></tr></tbody></table>\n<p>CPU dropped 38% from 25.12.0 to 26.2.0. RocksDB's block cache and bloom filters reduce per-lookup processing compared to LevelDB. Version 26.3.0 added another 11% reduction through jemalloc's more efficient allocation patterns reducing GC-driven CPU spikes. The Nethermind pairing consistently shows the lowest Teku CPU usage across all three versions.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"memory--jvm-analysis\">Memory &amp; JVM analysis<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#memory--jvm-analysis\" class=\"hash-link\" aria-label=\"Direct link to Memory &amp; JVM analysis\" title=\"Direct link to Memory &amp; JVM analysis\" translate=\"no\">​</a></h2>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"RSS and JVM heap memory across three versions\" src=\"https://docs.stereumlabs.com/assets/images/memory-1b180e20a83db4b2dca15b8c53d99d6b.png\" width=\"2140\" height=\"881\" class=\"img_ev3q\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"process-rss-memory\">Process RSS memory<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#process-rss-memory\" class=\"hash-link\" aria-label=\"Direct link to Process RSS memory\" title=\"Direct link to Process RSS memory\" translate=\"no\">​</a></h3>\n<p><strong>Metric:</strong> <code>process_resident_memory_bytes{job=\"teku\"}</code> — total physical memory consumed by the Teku JVM process.</p>\n<table><thead><tr><th>EC Pairing</th><th>25.12.0 (GB)</th><th>26.2.0 (GB)</th><th>26.3.0 (GB)</th><th>Δ 25.12→26.3</th></tr></thead><tbody><tr><td>Besu</td><td>8.67</td><td>9.43</td><td>9.20</td><td>🟠 +6.2%</td></tr><tr><td>Erigon</td><td>9.10</td><td>9.31</td><td>9.16</td><td>⚪ +0.6%</td></tr><tr><td>Ethrex</td><td>8.74</td><td>9.48</td><td>9.20</td><td>🟠 +5.3%</td></tr><tr><td>Geth</td><td>9.03</td><td>9.50</td><td>9.10</td><td>⚪ +0.7%</td></tr><tr><td>Nethermind</td><td>9.07</td><td>9.34</td><td>9.13</td><td>⚪ +0.6%</td></tr><tr><td>Reth</td><td>8.90</td><td>9.39</td><td>9.20</td><td>🟠 +3.4%</td></tr><tr><td><strong>Fleet Average</strong></td><td><strong>8.92</strong></td><td><strong>9.41</strong></td><td><strong>9.16</strong></td><td><strong>🟠 +2.8%</strong></td></tr></tbody></table>\n<p>RSS peaked in 26.2.0 (+5.5% vs 25.12.0), consistent with RocksDB's larger in-memory structures (block cache, memtables, bloom filters). Version 26.3.0 clawed back roughly half through jemalloc's reduced memory fragmentation, leaving a net +2.8%.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"jvm-heap-memory\">JVM heap memory<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#jvm-heap-memory\" class=\"hash-link\" aria-label=\"Direct link to JVM heap memory\" title=\"Direct link to JVM heap memory\" translate=\"no\">​</a></h3>\n<p><strong>Metric:</strong> <code>jvm_memory_used_bytes{area=\"heap\"}</code> — Java heap utilization.</p>\n<table><thead><tr><th>EC Pairing</th><th>25.12.0 (GB)</th><th>26.2.0 (GB)</th><th>26.3.0 (GB)</th><th>Δ 25.12→26.3</th></tr></thead><tbody><tr><td>Besu</td><td>5.33</td><td>5.73</td><td>5.99</td><td>🟠 +12.3%</td></tr><tr><td>Erigon</td><td>5.76</td><td>5.70</td><td>5.82</td><td>⚪ +1.0%</td></tr><tr><td>Ethrex</td><td>5.89</td><td>5.77</td><td>6.05</td><td>🟠 +2.7%</td></tr><tr><td>Geth</td><td>5.38</td><td>6.14</td><td>6.05</td><td>🟠 +12.3%</td></tr><tr><td>Nethermind</td><td>5.36</td><td>6.01</td><td>6.16</td><td>🟠 +15.0%</td></tr><tr><td>Reth</td><td>5.32</td><td>5.78</td><td>6.15</td><td>🟠 +15.5%</td></tr><tr><td><strong>Fleet Average</strong></td><td><strong>5.51</strong></td><td><strong>5.85</strong></td><td><strong>6.04</strong></td><td><strong>🟠 +9.6%</strong></td></tr></tbody></table>\n<p>Heap grew steadily, reflecting increased in-heap state caching from the RocksDB JNI bridge and the natural growth of Ethereum's state tree. All values remain well within Teku's default 8 GB max heap.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"jvm-native-memory\">JVM native memory<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#jvm-native-memory\" class=\"hash-link\" aria-label=\"Direct link to JVM native memory\" title=\"Direct link to JVM native memory\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>Version</th><th>Fleet Avg (MB)</th><th>Delta</th></tr></thead><tbody><tr><td>25.12.0</td><td>705</td><td>—</td></tr><tr><td>26.2.0</td><td>739</td><td>🟠 +4.8%</td></tr><tr><td>26.3.0</td><td>736</td><td>⚪ −0.4%</td></tr></tbody></table>\n<p>Native (off-heap) memory rose modestly with RocksDB and stabilized with jemalloc.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"jvm-garbage-collection\">JVM garbage collection<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#jvm-garbage-collection\" class=\"hash-link\" aria-label=\"Direct link to JVM garbage collection\" title=\"Direct link to JVM garbage collection\" translate=\"no\">​</a></h2>\n<p><strong>Metric:</strong> <code>rate(jvm_gc_collection_seconds_sum[5m])</code> — fraction of time spent in GC per second. This is a critical Teku-specific metric because GC pauses directly impact block processing latency.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"GC overhead by EC pairing across three versions\" src=\"https://docs.stereumlabs.com/assets/images/gc_overhead-bcbfc290a973ec34413d7880d0ed45be.png\" width=\"1780\" height=\"886\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC Pairing</th><th>25.12.0 (ms/s)</th><th>26.2.0 (ms/s)</th><th>26.3.0 (ms/s)</th><th>Δ 25.12→26.3</th></tr></thead><tbody><tr><td>Besu</td><td>2.77</td><td>2.82</td><td>1.90</td><td>🟢 −31%</td></tr><tr><td>Erigon</td><td>1.59</td><td>3.01</td><td>2.29</td><td>🔴 +44%</td></tr><tr><td>Ethrex</td><td>2.85</td><td>3.87</td><td>1.58</td><td>🟢 −45%</td></tr><tr><td>Geth</td><td>3.29</td><td>3.01</td><td>1.60</td><td>🟢 −51%</td></tr><tr><td>Nethermind</td><td>3.15</td><td>2.14</td><td>1.73</td><td>🟢 −45%</td></tr><tr><td>Reth</td><td>2.83</td><td>2.34</td><td>1.47</td><td>🟢 −48%</td></tr><tr><td><strong>Fleet Average</strong></td><td><strong>2.75</strong></td><td><strong>2.87</strong></td><td><strong>1.76</strong></td><td><strong>🟢 −36%</strong></td></tr></tbody></table>\n<p>GC overhead was flat from 25.12.0 to 26.2.0. The introduction of <strong>jemalloc</strong> in 26.3.0 is the standout: fleet-wide GC time dropped 36%. jemalloc reduces heap fragmentation, meaning fewer large-object promotions to old gen and fewer full GC cycles. For a Java client like Teku, this matters directly — GC pauses are a primary contributor to block import latency.</p>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>note</div><div class=\"admonitionContent_BuS1\"><p>The Erigon pairing shows an anomalous GC increase across all versions. This may reflect interaction effects with Erigon's execution response patterns rather than a Teku-internal issue.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"storage-engine--disk-io\">Storage engine &amp; disk I/O<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#storage-engine--disk-io\" class=\"hash-link\" aria-label=\"Direct link to Storage engine &amp; disk I/O\" title=\"Direct link to Storage engine &amp; disk I/O\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"host-level-disk-io\">Host-level disk I/O<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#host-level-disk-io\" class=\"hash-link\" aria-label=\"Direct link to Host-level disk I/O\" title=\"Direct link to Host-level disk I/O\" translate=\"no\">​</a></h3>\n<p><strong>Metrics:</strong> <code>rate(node_disk_read_bytes_total[5m])</code> and <code>rate(node_disk_written_bytes_total[5m])</code> — host-level metrics that include both Teku CC and its paired EC. Since EC versions didn't change across measurement windows, deltas are attributable to the Teku version change.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Disk read and write rates across three versions\" src=\"https://docs.stereumlabs.com/assets/images/disk_io-40fbd5ce837b8511fb1e0e53aee49c3f.png\" width=\"2140\" height=\"881\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC Pairing</th><th>Read 25.12</th><th>Read 26.2</th><th>Read 26.3</th><th>Write 25.12</th><th>Write 26.2</th><th>Write 26.3</th></tr></thead><tbody><tr><td>Besu</td><td>2,625</td><td>483</td><td>390</td><td>6,040</td><td>1,305</td><td>1,272</td></tr><tr><td>Erigon</td><td>424</td><td>470</td><td>350</td><td>1,141</td><td>1,282</td><td>1,294</td></tr><tr><td>Ethrex</td><td>1,127</td><td>603</td><td>392</td><td>2,143</td><td>1,888</td><td>1,303</td></tr><tr><td>Geth</td><td>1,528</td><td>710</td><td>259</td><td>3,172</td><td>2,003</td><td>1,227</td></tr><tr><td>Nethermind</td><td>1,489</td><td>220</td><td>186</td><td>2,583</td><td>1,145</td><td>1,304</td></tr><tr><td>Reth</td><td>1,916</td><td>326</td><td>283</td><td>4,468</td><td>1,243</td><td>1,220</td></tr><tr><td><strong>Fleet Avg</strong></td><td><strong>1,518</strong></td><td><strong>469</strong></td><td><strong>310</strong></td><td><strong>3,258</strong></td><td><strong>1,478</strong></td><td><strong>1,270</strong></td></tr></tbody></table>\n<p><em>All values in KB/s.</em></p>\n<p>Read throughput dropped <strong>79%</strong> (1,518 → 310 KB/s) and write throughput fell <strong>61%</strong> (3,258 → 1,270 KB/s). RocksDB's block cache and SST-based design is far more read-efficient than LevelDB. The Besu pairing saw the most dramatic read improvement (−85%).</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"rocksdb-internal-metrics-2620-only\">RocksDB internal metrics (26.2.0+ only)<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#rocksdb-internal-metrics-2620-only\" class=\"hash-link\" aria-label=\"Direct link to RocksDB internal metrics (26.2.0+ only)\" title=\"Direct link to RocksDB internal metrics (26.2.0+ only)\" translate=\"no\">​</a></h3>\n<p>These metrics are only available for versions using RocksDB. Version 25.12.0 ran LevelDB which does not expose equivalent counters.</p>\n<table><thead><tr><th>Metric</th><th>26.2.0 Fleet Avg</th><th>26.3.0 Fleet Avg</th><th>Delta</th></tr></thead><tbody><tr><td><code>storage_bytes_read</code> rate (KB/s)</td><td>84.3</td><td>103.6</td><td>🟠 +23%</td></tr><tr><td><code>storage_bytes_written</code> rate (MB/s)</td><td>1.53</td><td>1.35</td><td>🟢 −12%</td></tr><tr><td><code>storage_compact_write_bytes</code> rate (KB/s)</td><td>543.5</td><td>484.0</td><td>🟢 −11%</td></tr></tbody></table>\n<p>Write amplification improved in 26.3.0: both raw write rate and compaction writes decreased ~11%. The slight read increase likely reflects the partial sidecar import feature doing more background reads.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"block-import-performance\">Block import performance<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#block-import-performance\" class=\"hash-link\" aria-label=\"Direct link to Block import performance\" title=\"Direct link to Block import performance\" translate=\"no\">​</a></h2>\n<p><strong>Metric:</strong> <code>beacon_block_import_delay_latest</code> — most recent block import delay in milliseconds. This captures end-to-end latency from receiving a block to completing its import into the beacon state.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Block import delay by EC pairing across three versions\" src=\"https://docs.stereumlabs.com/assets/images/block_import_delay-69329f9ae50f3237c014138e14594f80.png\" width=\"1780\" height=\"886\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC Pairing</th><th>25.12.0 (ms)</th><th>26.2.0 (ms)</th><th>26.3.0 (ms)</th><th>Δ 25.12→26.3</th></tr></thead><tbody><tr><td>Besu</td><td>268</td><td>482</td><td>221</td><td>🟢 −18%</td></tr><tr><td>Erigon</td><td>519</td><td>490</td><td>347</td><td>🟢 −33%</td></tr><tr><td>Ethrex</td><td>772</td><td>303</td><td>209</td><td>🟢 −73%</td></tr><tr><td>Geth</td><td>251</td><td>319</td><td>209</td><td>🟢 −17%</td></tr><tr><td>Nethermind</td><td>239</td><td>513</td><td>444</td><td>🔴 +86%</td></tr><tr><td>Reth</td><td>284</td><td>426</td><td>352</td><td>🔴 +24%</td></tr><tr><td><strong>Fleet Average</strong></td><td><strong>389</strong></td><td><strong>422</strong></td><td><strong>297</strong></td><td><strong>🟢 −24%</strong></td></tr></tbody></table>\n<p>Version 26.2.0 was slightly slower fleet-wide — likely early-stage RocksDB tuning and the concurrent DAS backfiller adding load. Version 26.3.0 brought a strong recovery, achieving the <strong>lowest fleet-wide latency at 297 ms</strong>. The Ethrex pairing improved most dramatically (−73%), while the Nethermind pairing shows persistently elevated import times that warrant EC-side investigation.</p>\n<div class=\"theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>Operator impact</div><div class=\"admonitionContent_BuS1\"><p>Lower block import delay means attestations can be created sooner after a block arrives, directly improving validator effectiveness and reducing inclusion delay.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"p2p-networking--peer-connectivity\">P2P networking &amp; peer connectivity<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#p2p-networking--peer-connectivity\" class=\"hash-link\" aria-label=\"Direct link to P2P networking &amp; peer connectivity\" title=\"Direct link to P2P networking &amp; peer connectivity\" translate=\"no\">​</a></h2>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Peer connectivity metrics across three versions\" src=\"https://docs.stereumlabs.com/assets/images/peers-1e4c26552d85845413d4355f1a142091.png\" width=\"1420\" height=\"794\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Metric</th><th>25.12.0</th><th>26.2.0</th><th>26.3.0</th><th>Trend</th></tr></thead><tbody><tr><td><code>beacon_peer_count</code> (fleet avg)</td><td>44.9</td><td>45.9</td><td>49.5</td><td>🟢 +10%</td></tr><tr><td><code>libp2p_peers</code> (fleet avg)</td><td>90.8</td><td>91.9</td><td>98.9</td><td>🟢 +9%</td></tr><tr><td><code>discovery_live_nodes</code> (fleet avg)</td><td>160.7</td><td>168.4</td><td>176.4</td><td>🟢 +10%</td></tr><tr><td>Gossip rate (msg/s, fleet avg)</td><td>6.23</td><td>5.99</td><td>7.85</td><td>🟢 +26%</td></tr></tbody></table>\n<p>All peer metrics improved steadily. Discovery live nodes grew from ~161 to ~176, suggesting the Discv5 layer is maintaining more active ENR records. Gossip throughput peaked in 26.3.0 — consistent with faster block processing enabling quicker re-gossip.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"data-availability-sampling-das--peerdas\">Data availability sampling (DAS) &amp; PeerDAS<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#data-availability-sampling-das--peerdas\" class=\"hash-link\" aria-label=\"Direct link to Data availability sampling (DAS) &amp; PeerDAS\" title=\"Direct link to Data availability sampling (DAS) &amp; PeerDAS\" translate=\"no\">​</a></h2>\n<p><strong>Metric:</strong> <code>rate(beacon_data_column_sidecar_processing_requests_total[5m])</code> — DAS workload rate.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"DAS sidecar processing rate by EC pairing\" src=\"https://docs.stereumlabs.com/assets/images/das_processing-2b6facd135b0599c4d44633538eeed03.png\" width=\"1780\" height=\"886\" class=\"img_ev3q\"></p>\n<p>DAS processing rates show significant per-pairing variance. The zero values in 25.12.0 for Erigon/Ethrex reflect sync issues that resolved in later versions. Version 26.3.0 allows nodes with &gt;50% custody requirements to begin importing blocks after downloading only 50% of sidecars — an architectural improvement that doesn't compromise data availability guarantees.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"open-file-descriptors--the-trade-off\">Open file descriptors — the trade-off<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#open-file-descriptors--the-trade-off\" class=\"hash-link\" aria-label=\"Direct link to Open file descriptors — the trade-off\" title=\"Direct link to Open file descriptors — the trade-off\" translate=\"no\">​</a></h2>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Open file descriptors by EC pairing across three versions\" src=\"https://docs.stereumlabs.com/assets/images/file_descriptors-9a01c845ae303b6bf2da759e464720f2.png\" width=\"1780\" height=\"886\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>EC Pairing</th><th>25.12.0</th><th>26.2.0</th><th>26.3.0</th><th>Δ 25.12→26.3</th></tr></thead><tbody><tr><td>Besu</td><td>480</td><td>957</td><td>1,329</td><td>🔴 +177%</td></tr><tr><td>Erigon</td><td>780</td><td>931</td><td>1,375</td><td>🔴 +76%</td></tr><tr><td>Ethrex</td><td>801</td><td>1,031</td><td>1,299</td><td>🔴 +62%</td></tr><tr><td>Geth</td><td>643</td><td>939</td><td>1,319</td><td>🔴 +105%</td></tr><tr><td>Nethermind</td><td>682</td><td>751</td><td>1,245</td><td>🔴 +83%</td></tr><tr><td>Reth</td><td>527</td><td>787</td><td>1,279</td><td>🔴 +143%</td></tr><tr><td><strong>Fleet Average</strong></td><td><strong>652</strong></td><td><strong>899</strong></td><td><strong>1,308</strong></td><td><strong>🔴 +101%</strong></td></tr></tbody></table>\n<p>File descriptors doubled — the most visible trade-off of RocksDB. Its LSM-tree architecture holds many SST files open simultaneously for efficient reads. Growth continued from 26.2.0 to 26.3.0 as databases accumulated more SST files through compaction.</p>\n<div class=\"theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>Operator action required</div><div class=\"admonitionContent_BuS1\"><p>Ensure <code>ulimit -n</code> is set to at least <strong>65536</strong> on hosts running Teku 26.x. The default 1024 on many Linux distributions will cause failures. Docker containers should pass <code>--ulimit nofile=65536:65536</code>.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"summary--recommendations\">Summary &amp; recommendations<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#summary--recommendations\" class=\"hash-link\" aria-label=\"Direct link to Summary &amp; recommendations\" title=\"Direct link to Summary &amp; recommendations\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>Dimension</th><th>25.12.0</th><th>26.2.0</th><th>26.3.0</th></tr></thead><tbody><tr><td>CPU Efficiency</td><td>Baseline</td><td>🟢 Major improvement</td><td>🟢 <strong>Best</strong></td></tr><tr><td>Memory Footprint</td><td>🟢 Lowest</td><td>🟠 +5.5%</td><td>🟠 +2.8% (recovering)</td></tr><tr><td>GC Overhead</td><td>Baseline</td><td>⚪ Similar</td><td>🟢 <strong>Best (−36%)</strong></td></tr><tr><td>Disk I/O</td><td>🔴 Highest</td><td>🟢 Major improvement</td><td>🟢 <strong>Best</strong></td></tr><tr><td>Block Import Speed</td><td>Moderate</td><td>🟠 Slight regression</td><td>🟢 <strong>Best (297ms)</strong></td></tr><tr><td>Peer Connectivity</td><td>Good</td><td>Good</td><td>🟢 <strong>Best</strong></td></tr><tr><td>File Descriptors</td><td>🟢 Lowest</td><td>🟠 +38%</td><td>🔴 +101% (monitor)</td></tr><tr><td>Storage Backend</td><td>LevelDB</td><td>RocksDB</td><td>RocksDB + jemalloc</td></tr><tr><td>Stability</td><td>🟢 Stable</td><td>🟢 Stable</td><td>🟢 Mandatory (SSZ fix)</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"key-takeaways\">Key takeaways<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#key-takeaways\" class=\"hash-link\" aria-label=\"Direct link to Key takeaways\" title=\"Direct link to Key takeaways\" translate=\"no\">​</a></h3>\n<ol>\n<li class=\"\">\n<p><strong>Upgrade to 26.3.0 is mandatory.</strong> Beyond the SSZ serialization bug fix, 26.3.0 delivers the best performance profile across nearly every dimension.</p>\n</li>\n<li class=\"\">\n<p><strong>Verify file descriptor limits.</strong> With 26.3.0 averaging 1,308 open FDs (and likely higher under peak load), ensure systems allow at least 65,536 file descriptors.</p>\n</li>\n<li class=\"\">\n<p><strong>Monitor RocksDB compaction.</strong> Add <code>storage_compact_write_bytes</code> and <code>storage_bytes_written</code> to your dashboards. Abnormal compaction spikes can indicate database health issues.</p>\n</li>\n<li class=\"\">\n<p><strong>Consider DAS backfiller tuning.</strong> If 26.x nodes show elevated CPU during backfill, <code>--Xp2p-reworked-sidecar-custody-sync-batch-size=1</code> can throttle the backfiller.</p>\n</li>\n<li class=\"\">\n<p><strong>Watch the Nethermind pairing.</strong> Block import delays are persistently higher with Nethermind across 26.x versions — this warrants investigation on the EL side.</p>\n</li>\n</ol>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"download\">Download the full report<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#download\" class=\"hash-link\" aria-label=\"Direct link to Download the full report\" title=\"Direct link to Download the full report\" translate=\"no\">​</a></h2>\n<p>The complete analysis with additional detail on JVM thread pools, executor queue depths, and RocksDB internal counters is available as a styled PDF:</p>\n<p>📄 <a href=\"https://docs.stereumlabs.com/downloads/teku_version_comparison_report.pdf\" target=\"_blank\">Download full report (PDF)</a></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"methodology-notes\">Methodology notes<a href=\"https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources#methodology-notes\" class=\"hash-link\" aria-label=\"Direct link to Methodology notes\" title=\"Direct link to Methodology notes\" translate=\"no\">​</a></h2>\n<p>All data sourced from the <code>prometheus-cold</code> datasource (Org 6) in the StereumLabs Grafana instance. Query pattern: <code>avg by (ec_client) (avg_over_time(metric{cc_client=\"teku\", cc_version=\"...\", role=\"cc\", job=\"teku\"}[14d:1h]))</code> evaluated as instant queries at the end of each 14-day window. Rate metrics use <code>rate(...[5m])</code> inside the subquery. Host-level metrics filtered with <code>device!~\"lo|veth.*|docker.*|br.*\"</code> to exclude virtual interfaces. All nodes run on NDC2 bare-metal (Vienna), eliminating cloud noise.</p>\n<p>For details on our label conventions and how to build your own dashboards against our data, see <a href=\"https://docs.stereumlabs.com/docs/dashboards/build-your-own\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Build your own dashboards</a>.</p>",
            "url": "https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources",
            "title": "Teku 25.12.0 vs 26.2.0 vs 26.3.0: Cross-version resource & performance analysis",
            "summary": "A comprehensive comparison of three Teku consensus client releases across CPU, memory, JVM garbage collection, disk I/O, block import latency, P2P networking, and PeerDAS metrics — measured on our NDC2 bare-metal fleet across all 6 execution client pairings.",
            "date_modified": "2026-04-08T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "Teku",
                "consensus client",
                "version comparison",
                "RocksDB",
                "jemalloc",
                "PeerDAS",
                "Fulu",
                "performance"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking",
            "content_html": "<p>A recap of our EthCC[9] presentation in Cannes: what StereumLabs is, how we use AI on top of our monitoring data, and what Fusaka actually did to hardware across 36 client pairings.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"EthCC[9] Talk: AI-Powered Observability for Ethereum Staking\" src=\"https://docs.stereumlabs.com/assets/images/ethcc9-talk-thumbnail-bc69eec266ddac6e9360f6f71e57071f.jpg\" width=\"2000\" height=\"1126\" class=\"img_ev3q\"></p>\n<p>On April 2, 2026 we presented StereumLabs at <a href=\"https://ethcc.io/ethcc-9/agenda/meet-fusakapeerdas-runtime-metrics\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">EthCC[9] in Cannes</a>. The talk covered what we've built, why AI on raw metrics alone produces useless output, and concrete Fusaka/PeerDAS runtime data from our bare-metal fleet.</p>\n<p>This post is a written companion to that talk. If you prefer watching, the recording is embedded below. The <a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#slides\" class=\"\">slide deck is available as a PDF download</a>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"video\">Video<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#video\" class=\"hash-link\" aria-label=\"Direct link to Video\" title=\"Direct link to Video\" translate=\"no\">​</a></h2>\n<iframe width=\"100%\" height=\"400\" src=\"https://www.youtube.com/embed/1Eoz8O-WZOY\" title=\"StereumLabs EthCC[9] Talk\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\"></iframe>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-stereumlabs-platform\">The StereumLabs platform<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#the-stereumlabs-platform\" class=\"hash-link\" aria-label=\"Direct link to The StereumLabs platform\" title=\"Direct link to The StereumLabs platform\" translate=\"no\">​</a></h2>\n<p>StereumLabs is our observability and analytics platform for Ethereum staking infrastructure. We run every relevant client combination on dedicated bare-metal hardware: 6 execution layer clients (Geth, Nethermind, Besu, Erigon, Reth, Ethrex), 6 consensus layer clients (Lighthouse, Prysm, Teku, Nimbus, Lodestar, Grandine), plus the standalone Erigon + Caplin pairing. That's 37 combinations, monitored 24/7 with 90-day rolling metrics.</p>\n<p>All nodes run on isolated bare metal. No shared cloud instances, no noisy-neighbor effects. When we measure performance differences between clients, the data is reproducible and directly comparable.</p>\n<p>The platform provides 20+ dashboards covering resource consumption (CPU, RAM, disk, network), client-specific metrics (attestation rates, block processing times, peer counts, GC behavior), and system logs. Client development teams already have free access to the dashboards. The project is supported by an Ethereum Foundation grant.</p>\n<p>But dashboards have limits. And that's where AI comes in.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ai-chatbot-natural-language-meets-live-data\">AI Chatbot: natural language meets live data<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#ai-chatbot-natural-language-meets-live-data\" class=\"hash-link\" aria-label=\"Direct link to AI Chatbot: natural language meets live data\" title=\"Direct link to AI Chatbot: natural language meets live data\" translate=\"no\">​</a></h2>\n<p>We built an AI chatbot connected directly to our full monitoring dataset. Instead of navigating dashboards and writing queries, users ask questions in plain English:</p>\n<ul>\n<li class=\"\">\"Compare disk growth between Geth and Erigon over the last 30 days\"</li>\n<li class=\"\">\"How did the Prysm update from v7.1.1 to v7.1.2 affect resource usage?\"</li>\n<li class=\"\">\"Which consensus client uses the most bandwidth as a supernode?\"</li>\n</ul>\n<p>The result is a structured analysis with actual numbers, across all EL pairings, in seconds.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-instruction-set\">The Instruction Set<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#the-instruction-set\" class=\"hash-link\" aria-label=\"Direct link to The Instruction Set\" title=\"Direct link to The Instruction Set\" translate=\"no\">​</a></h3>\n<p>Here's what most people get wrong about AI in infrastructure monitoring: the model alone doesn't produce useful results. If you point a language model at raw Prometheus metrics, it doesn't know which queries to run, what normal ranges look like, or how to interpret differences between client architectures.</p>\n<p>That's why we've built a continuously evolving Instruction Set. It encodes which metrics matter for which client combination, what normal ranges look like per pairing, how to interpret architectural differences (Go vs. Java GC behavior, Rust memory models), and which queries to run in which order to build a meaningful analysis.</p>\n<p>Without the Instruction Set, the AI produces generic answers. With it, it produces the kind of analysis that would take an experienced engineer hours to assemble manually. We expand it continuously as we encounter new patterns, new client versions, and new edge cases. It's built from years of running these clients professionally.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"proof-prysm-v711-to-v712\">Proof: Prysm v7.1.1 to v7.1.2<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#proof-prysm-v711-to-v712\" class=\"hash-link\" aria-label=\"Direct link to Proof: Prysm v7.1.1 to v7.1.2\" title=\"Direct link to Proof: Prysm v7.1.1 to v7.1.2\" translate=\"no\">​</a></h3>\n<p>When the Prysm team shipped v7.1.2, we asked the chatbot one question and got a full resource impact analysis across all 6 EL pairings:</p>\n<table><thead><tr><th>Metric</th><th>Result</th></tr></thead><tbody><tr><td><strong>Memory (RSS)</strong></td><td>Dropped 5.1% on average. Biggest improvement with Geth pairing (-8.8%)</td></tr><tr><td><strong>Block processing</strong></td><td>Improved 25% overall. Erigon pairing went from 403ms to 90ms (-78%)</td></tr><tr><td><strong>Peer count</strong></td><td>Stable at ~71 across both versions. No regression</td></tr><tr><td><strong>CPU</strong></td><td>Mixed results, EL-dependent. Reth dropped 21%, Besu increased 28%</td></tr></tbody></table>\n<p>This analysis would normally take hours of manual work. The chatbot produced it from a single question. The full report is published on our blog: <a class=\"\" href=\"https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources\">Prysm v7.1.1 &amp; 7.1.2 resources</a>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ai-alerting-from-something-is-wrong-to-heres-why\">AI Alerting: from \"something is wrong\" to \"here's why\"<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#ai-alerting-from-something-is-wrong-to-heres-why\" class=\"hash-link\" aria-label=\"Direct link to AI Alerting: from &quot;something is wrong&quot; to &quot;here's why&quot;\" title=\"Direct link to AI Alerting: from &quot;something is wrong&quot; to &quot;here's why&quot;\" translate=\"no\">​</a></h2>\n<p>The chatbot is great for proactive analysis. But what about when things go wrong at 3am? That's where AI Alerting comes in.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"two-stage-architecture\">Two-stage architecture<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#two-stage-architecture\" class=\"hash-link\" aria-label=\"Direct link to Two-stage architecture\" title=\"Direct link to Two-stage architecture\" translate=\"no\">​</a></h3>\n<p><strong>Stage 1: Near-real-time threshold alerts.</strong> Monitors hard thresholds like attestation rate, disk usage, peer count, and missed blocks. Fires within seconds. No AI inference delay, no additional cost. If the AI layer is slow or unavailable, the basic alert still arrives.</p>\n<p><strong>Stage 2: AI root-cause analysis.</strong> When a threshold alert fires, a webhook triggers the AI. It pulls relevant metrics and logs, correlates the data against our neutral baseline from all 37 client combinations, and delivers a root-cause analysis with actionable next steps. Delivered in 5 to 15 seconds.</p>\n<p>The result: operators don't just get \"attestation rate dropped below 95%.\" They get: \"Your attestation rate dropped because Geth's peer count fell to 3, likely due to a network partition. Your Prysm instance is healthy. Recommended action: check firewall rules and restart the EL client.\"</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"built-in-baseline-instant-context\">Built-in baseline: instant context<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#built-in-baseline-instant-context\" class=\"hash-link\" aria-label=\"Direct link to Built-in baseline: instant context\" title=\"Direct link to Built-in baseline: instant context\" translate=\"no\">​</a></h3>\n<p>What makes our alerting especially useful is the neutral baseline dataset from our own fleet. When an alert fires, the AI automatically compares against data from all 37 client combinations.</p>\n<p>Every alert answers three questions: Is this happening across the Ethereum network right now? Is it specific to this client version? Or is it unique to your local environment?</p>\n<p>That distinction between \"the whole network is seeing elevated block processing times after a fork\" and \"your Geth instance is the only one with this problem\" is the difference between waiting it out and taking immediate action.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"security-monitoring\">Security monitoring<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#security-monitoring\" class=\"hash-link\" aria-label=\"Direct link to Security monitoring\" title=\"Direct link to Security monitoring\" translate=\"no\">​</a></h3>\n<p>The same two-stage architecture applies to security events:</p>\n<ul>\n<li class=\"\"><strong>SSH login checks</strong> — authorized key? Expected source IP? Expected time window?</li>\n<li class=\"\"><strong>Service restart analysis</strong> — when an execution client restarts, the AI verifies that fee recipient addresses haven't been changed. A compromised operator could redirect staking rewards without anyone noticing for days.</li>\n<li class=\"\"><strong>Configuration drift detection</strong> — unauthorized processes, unexpected port openings, validator key access patterns.</li>\n</ul>\n<p>Traditional monitoring tells you \"Geth restarted.\" Our AI layer tells you \"Geth restarted, fee recipient address changed from 0xABC to 0xDEF, this was not initiated through the operator's usual deployment pipeline, severity: critical.\"</p>\n<p>For operators staking millions in ETH, the difference between detecting a compromised reward address in minutes versus days is the difference between a security incident and a financial disaster.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"fusaka--peerdas-what-the-hardfork-did-to-hardware\">Fusaka + PeerDAS: what the hardfork did to hardware<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#fusaka--peerdas-what-the-hardfork-did-to-hardware\" class=\"hash-link\" aria-label=\"Direct link to Fusaka + PeerDAS: what the hardfork did to hardware\" title=\"Direct link to Fusaka + PeerDAS: what the hardfork did to hardware\" translate=\"no\">​</a></h2>\n<p>A significant portion of the talk covered our Fusaka hardfork measurements. We compared two 14-day windows (before and after the December 3, 2025 activation) across all 36 non-supernode client pairings.</p>\n<p>The fleet-level headline numbers:</p>\n<table><thead><tr><th>Metric</th><th>Change</th><th>What happened</th></tr></thead><tbody><tr><td><strong>Network RX</strong></td><td><strong>-60%</strong></td><td>PeerDAS in action: nodes sample slices instead of downloading full blobs</td></tr><tr><td><strong>CPU</strong></td><td><strong>+30%</strong></td><td>Expected trade-off: sampling routines cost compute</td></tr><tr><td><strong>Memory</strong></td><td><strong>-8%</strong></td><td>Less blob data held in RAM</td></tr><tr><td><strong>Disk reads</strong></td><td><strong>-53%</strong></td><td>Fewer full-blob fetches from disk</td></tr></tbody></table>\n<p>Notable client outliers: Nimbus CPU jumped +257% (most compute-intensive PeerDAS implementation), Lighthouse was the only consensus client to reduce CPU (-13%), and Besu saw the largest memory drop (-35%).</p>\n<p>The worst pairing post-fork: Nimbus + Reth at 16.78% CPU.</p>\n<p>The full analysis with per-client breakdowns, heatmaps, daily trends, and PromQL queries is available as a dedicated blog post: <a class=\"\" href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes\">Fusaka hardfork: hardware impact on non-supernodes</a>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"deployment-models\">Deployment models<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#deployment-models\" class=\"hash-link\" aria-label=\"Direct link to Deployment models\" title=\"Direct link to Deployment models\" translate=\"no\">​</a></h2>\n<p>One thing we hear constantly from professional operators: \"I'm interested, but I can't send my metrics to your cloud.\" That's why StereumLabs supports multiple deployment options:</p>\n<ul>\n<li class=\"\"><strong>SaaS</strong> — hosted by us in our ISO 27001 certified environment. Best for smaller operators and researchers.</li>\n<li class=\"\"><strong>Alerting-as-a-Service (pull model)</strong> — you expose a Prometheus endpoint, we scrape it. Your data never enters our systems. It only meets our baseline data at the AI inference layer.</li>\n<li class=\"\"><strong>On-premise</strong> — the entire StereumLabs stack deployed on your infrastructure. Your own API keys. Data never leaves your network.</li>\n</ul>\n<p>The key message: your infrastructure data doesn't become someone else's competitive intelligence.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"current-status\">Current status<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#current-status\" class=\"hash-link\" aria-label=\"Direct link to Current status\" title=\"Direct link to Current status\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>Component</th><th>Status</th></tr></thead><tbody><tr><td>Dashboards (20+)</td><td>Live, all 37 client combinations</td></tr><tr><td>AI Chatbot</td><td>Working proof of concept against live data</td></tr><tr><td>AI Alerting</td><td>Q2 2026</td></tr><tr><td>Security Monitoring</td><td>Q2 2026</td></tr><tr><td>On-premise deployment</td><td>Ready</td></tr></tbody></table>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"get-in-touch\">Get in touch<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#get-in-touch\" class=\"hash-link\" aria-label=\"Direct link to Get in touch\" title=\"Direct link to Get in touch\" translate=\"no\">​</a></h2>\n<p>We're looking for node operators who want to try the AI chatbot, client development teams interested in automated cross-EL impact analysis, and staking protocols looking for monitoring and security standards across their operator ecosystem.</p>\n<p>Reach out at <a href=\"mailto:contact@stereumlabs.com\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">contact@stereumlabs.com</a> or visit <a href=\"https://stereumlabs.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">stereumlabs.com</a>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"slides\">Slides<a href=\"https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking#slides\" class=\"hash-link\" aria-label=\"Direct link to Slides\" title=\"Direct link to Slides\" translate=\"no\">​</a></h2>\n<p>The full slide deck from the talk is available for download:</p>\n<p>📄 <a href=\"https://docs.stereumlabs.com/downloads/StereumLabs_EthCC9.pdf\" target=\"_blank\">Download slides (PDF)</a></p>",
            "url": "https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking",
            "title": "EthCC[9] talk recap: AI-powered observability for Ethereum staking",
            "summary": "A recap of our EthCC[9] presentation in Cannes covering StereumLabs, AI-powered infrastructure monitoring, Fusaka/PeerDAS runtime metrics, and what we're building next.",
            "date_modified": "2026-04-02T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "AI",
                "EthCC",
                "talk",
                "observability",
                "Fusaka",
                "PeerDAS",
                "alerting",
                "security"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes",
            "content_html": "<p>We measured CPU, memory, disk I/O, and network across all 36 CC×EC pairings on our non-supernode fleet — here's what the Fusaka hardfork actually did to hardware consumption.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-is-fusaka\">What is Fusaka?<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#what-is-fusaka\" class=\"hash-link\" aria-label=\"Direct link to What is Fusaka?\" title=\"Direct link to What is Fusaka?\" translate=\"no\">​</a></h2>\n<p>Ethereum's Fusaka hardfork activated on <strong>December 3, 2025 at 21:49 UTC</strong> (slot 13,164,544). It was the second hard fork of 2025 after Pectra (May 2025) and arguably the most consequential upgrade since the Merge. The name combines \"Fulu\" (consensus layer, named after a star) and \"Osaka\" (execution layer, named after the host city of Devcon 2025).</p>\n<p>The headline feature is <strong>PeerDAS</strong> (Peer Data Availability Sampling, <a href=\"https://eips.ethereum.org/EIPS/eip-7594\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">EIP-7594</a>) — a fundamental change in how Ethereum verifies blob data. Instead of every node downloading and verifying every blob, nodes now only need to sample small slices, verifying that the full data exists without actually possessing all of it. Vitalik Buterin called it \"literally sharding\" — Ethereum reaching consensus on blocks without requiring any single node to see more than a tiny fraction of the data.</p>\n<p>Beyond PeerDAS, Fusaka shipped approximately 12 additional EIPs:</p>\n<ul>\n<li class=\"\"><strong>EIP-7935</strong> — raises the default block gas limit, targeting ~60 million gas</li>\n<li class=\"\"><strong>EIP-7825</strong> — introduces a per-transaction gas cap of 16.78 million to prevent single-transaction DoS attacks</li>\n<li class=\"\"><strong>EIP-7892</strong> — the Blob Parameter Only (BPO) mechanism, allowing blob capacity increases between hard forks</li>\n<li class=\"\"><strong>EIP-7951</strong> — secp256r1 precompile for device-native signing and passkeys</li>\n<li class=\"\"><strong>EOF (EVM Object Format)</strong> — a cleaner, more efficient programming structure for smart contracts</li>\n<li class=\"\"><strong>EIP-7918</strong> — stabilizes blob fees</li>\n<li class=\"\"><strong>EIP-7742</strong> — new opcodes including CLZ (count leading zeros) for more efficient cryptographic operations</li>\n</ul>\n<p>Two scheduled BPO forks followed:</p>\n<ul>\n<li class=\"\"><strong>BPO-1</strong> (~December 9–10): blob target/max raised from 6/9 to 10/15</li>\n<li class=\"\"><strong>BPO-2</strong> (~December 23 – January 7): blob target/max raised to 14/21</li>\n</ul>\n<p>We wanted to know: what did all this actually do to the hardware running our nodes?</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"methodology\">Methodology<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#methodology\" class=\"hash-link\" aria-label=\"Direct link to Methodology\" title=\"Direct link to Methodology\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"fleet-setup\">Fleet setup<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#fleet-setup\" class=\"hash-link\" aria-label=\"Direct link to Fleet setup\" title=\"Direct link to Fleet setup\" translate=\"no\">​</a></h3>\n<p>StereumLabs runs approximately <strong>90 hosts</strong> split across GCP cloud instances and NDC2 bare-metal nodes in Vienna, Austria. Each non-supernode host runs one consensus client (CC) paired with one execution client (EC), covering all 36 possible combinations of:</p>\n<ul>\n<li class=\"\"><strong>Consensus clients:</strong> Grandine, Lighthouse, Lodestar, Nimbus, Prysm, Teku</li>\n<li class=\"\"><strong>Execution clients:</strong> Besu, Erigon, Ethrex, Geth, Nethermind, Reth</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"data-source\">Data source<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#data-source\" class=\"hash-link\" aria-label=\"Direct link to Data source\" title=\"Direct link to Data source\" translate=\"no\">​</a></h3>\n<p>All metrics come from our <code>prometheus-cold</code> datasource (UID <code>aez9ck4wz05q8e</code>, Org 6), which covers all available metrics without retention or delay restrictions. Node-level system metrics are collected via <code>prometheus-node-exporter</code> at a 15-second scrape interval.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"comparison-windows\">Comparison windows<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#comparison-windows\" class=\"hash-link\" aria-label=\"Direct link to Comparison windows\" title=\"Direct link to Comparison windows\" translate=\"no\">​</a></h3>\n<p>We compared two 14-day windows:</p>\n<table><thead><tr><th>Period</th><th>Range</th><th>Label</th></tr></thead><tbody><tr><td>Before Fusaka</td><td>November 19 – December 3, 2025</td><td>Pre-fork baseline</td></tr><tr><td>After Fusaka</td><td>December 4 – December 18, 2025</td><td>Post-fork + BPO-1</td></tr></tbody></table>\n<p>Both windows use <code>avg_over_time(...[14d:1h])</code> — a 14-day average at 1-hour subquery resolution, computed as an instant query at the boundary timestamp. This smooths out transient spikes while preserving meaningful shifts.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"filtering\">Filtering<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#filtering\" class=\"hash-link\" aria-label=\"Direct link to Filtering\" title=\"Direct link to Filtering\" translate=\"no\">​</a></h3>\n<p>Supernodes are excluded via the label filter <code>cc_client!~\".*-super\"</code>. Only instances with <code>role=~\"cc|ec\"</code> are included. Network metrics exclude loopback and virtual interfaces (<code>device!~\"lo|veth.*|docker.*|br.*\"</code>).</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"fleet-level-results\">Fleet-level results<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#fleet-level-results\" class=\"hash-link\" aria-label=\"Direct link to Fleet-level results\" title=\"Direct link to Fleet-level results\" translate=\"no\">​</a></h2>\n<p>Here's what happened across the entire non-supernode fleet:</p>\n<table><thead><tr><th>Metric</th><th>Before</th><th>After</th><th>Change</th></tr></thead><tbody><tr><td>CPU utilization (avg)</td><td>4.66%</td><td>6.08%</td><td><strong>+30%</strong></td></tr><tr><td>Memory used (avg)</td><td>6.06 GiB</td><td>5.59 GiB</td><td><strong>−8%</strong></td></tr><tr><td>Network RX (avg)</td><td>2.20 MiB/s</td><td>0.87 MiB/s</td><td><strong>−60%</strong></td></tr><tr><td>Network TX (avg)</td><td>0.20 MiB/s</td><td>0.18 MiB/s</td><td><strong>−13%</strong></td></tr><tr><td>Disk read rate (avg)</td><td>2.58 MiB/s</td><td>1.21 MiB/s</td><td><strong>−53%</strong></td></tr><tr><td>Disk write rate (avg)</td><td>1.73 MiB/s</td><td>1.92 MiB/s</td><td><strong>+11%</strong></td></tr></tbody></table>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Fleet-level hardware changes across the Fusaka hardfork\" src=\"https://docs.stereumlabs.com/assets/images/fleet_summary-ce362e657d05051e0087cfade23c76f3.png\" width=\"1775\" height=\"784\" class=\"img_ev3q\"></p>\n<div class=\"theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>The short version</div><div class=\"admonitionContent_BuS1\"><p>PeerDAS delivered exactly what it promised: dramatically less network bandwidth and lower memory at the cost of modestly higher CPU. Disk reads halved. Operators paying per-GB egress on cloud providers should see meaningful cost savings.</p></div></div>\n<p>Let's dig into each metric.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"network-bandwidth-the-biggest-win\">Network bandwidth: the biggest win<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#network-bandwidth-the-biggest-win\" class=\"hash-link\" aria-label=\"Direct link to Network bandwidth: the biggest win\" title=\"Direct link to Network bandwidth: the biggest win\" translate=\"no\">​</a></h2>\n<p>The most striking result is the <strong>60% drop in network receive bandwidth</strong> — from 2.20 MiB/s to 0.87 MiB/s on average. This is PeerDAS in action: nodes now verify only sampled slices of blob data rather than downloading entire blobs.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"daily-trend\">Daily trend<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#daily-trend\" class=\"hash-link\" aria-label=\"Direct link to Daily trend\" title=\"Direct link to Daily trend\" translate=\"no\">​</a></h3>\n<p>Looking at the daily time series, the decline actually began <strong>before the fork itself</strong> — around November 28–29 — suggesting some nodes started running fork-compatible client versions with PeerDAS-like optimizations ahead of the December 3 activation. On the fork day itself, the fleet-average RX was already down to 0.26 MiB/s.</p>\n<p>The post-fork trend shows a brief recovery as nodes settled into the new protocol, stabilizing around 1.4 MiB/s by mid-December — still a <strong>36% reduction</strong> from the pre-decline baseline of ~2.2 MiB/s.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Fleet average network receive bandwidth — daily trend\" src=\"https://docs.stereumlabs.com/assets/images/network_rx_trend-24db51516409121ff6c6be59af4f38ff.png\" width=\"1749\" height=\"607\" class=\"img_ev3q\"></p>\n<table><thead><tr><th>Date</th><th>RX (MiB/s)</th><th>Event</th></tr></thead><tbody><tr><td>Nov 19</td><td>3.04</td><td></td></tr><tr><td>Nov 28</td><td>2.38</td><td>Pre-fork decline begins</td></tr><tr><td>Dec 3</td><td>0.26</td><td><strong>Fusaka fork</strong></td></tr><tr><td>Dec 4</td><td>1.09</td><td>Post-fork stabilization</td></tr><tr><td>Dec 10</td><td>0.59</td><td>BPO-1</td></tr><tr><td>Dec 18</td><td>1.39</td><td>Settled baseline</td></tr></tbody></table>\n<p>Network transmit bandwidth also decreased, though more modestly — from 0.20 to 0.18 MiB/s (−13%).</p>\n<div class=\"theme-admonition theme-admonition-info admonition_xJq3 alert alert--info\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z\"></path></svg></span>Why this matters for operators</div><div class=\"admonitionContent_BuS1\"><p>For GCP instances, network egress costs $0.085–$0.12/GB depending on region and volume. A node running at 2.2 MiB/s averages ~5.7 TB/month of inbound traffic. At the new 0.87 MiB/s rate, that drops to ~2.2 TB/month — a potential saving of $300–$400/month per node on egress alone, depending on provider and plan.</p></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"cpu-utilization-moderate-increase-one-clear-outlier\">CPU utilization: moderate increase, one clear outlier<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#cpu-utilization-moderate-increase-one-clear-outlier\" class=\"hash-link\" aria-label=\"Direct link to CPU utilization: moderate increase, one clear outlier\" title=\"Direct link to CPU utilization: moderate increase, one clear outlier\" translate=\"no\">​</a></h2>\n<p>Fleet-average CPU rose from <strong>4.66% to 6.08%</strong> — a 30% relative increase, but in absolute terms still very modest. This is the expected trade-off: PeerDAS introduces data availability sampling routines (compute) in exchange for reduced data transfer (bandwidth).</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-fork-day-spike\">The fork-day spike<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#the-fork-day-spike\" class=\"hash-link\" aria-label=\"Direct link to The fork-day spike\" title=\"Direct link to The fork-day spike\" translate=\"no\">​</a></h3>\n<p>The daily time series reveals two notable spikes:</p>\n<ul>\n<li class=\"\"><strong>December 4: 14.82%</strong> — the day after fork activation. All clients simultaneously processed new consensus rules, PeerDAS bootstrapping, and EOF-related state transitions. This spike was transient and resolved within 24 hours.</li>\n<li class=\"\"><strong>December 10: 10.09%</strong> — coincides with BPO-1 raising the blob target/max from 6/9 to 10/15. The higher blob capacity required additional sampling work.</li>\n</ul>\n<p>After settling, the new baseline sits around <strong>5.5–5.7%</strong> — roughly 1 percentage point above pre-fork levels.</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Fleet average CPU and memory — daily trend\" src=\"https://docs.stereumlabs.com/assets/images/cpu_mem_trend-c292ba84c771acfd2e501aae1c3e59ff.png\" width=\"1774\" height=\"697\" class=\"img_ev3q\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"per-consensus-client-breakdown\">Per-consensus-client breakdown<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#per-consensus-client-breakdown\" class=\"hash-link\" aria-label=\"Direct link to Per-consensus-client breakdown\" title=\"Direct link to Per-consensus-client breakdown\" translate=\"no\">​</a></h3>\n<p>Not all consensus clients handled Fusaka equally:</p>\n<table><thead><tr><th>CC client</th><th>Before</th><th>After</th><th>Change</th></tr></thead><tbody><tr><td>Grandine</td><td>5.84%</td><td>7.06%</td><td>+21%</td></tr><tr><td>Lighthouse</td><td>3.81%</td><td>3.30%</td><td><strong>−13%</strong></td></tr><tr><td>Lodestar</td><td>5.80%</td><td>5.85%</td><td>+1%</td></tr><tr><td>Nimbus</td><td>2.63%</td><td>9.40%</td><td><strong>+257%</strong></td></tr><tr><td>Prysm</td><td>4.38%</td><td>4.86%</td><td>+11%</td></tr><tr><td>Teku</td><td>5.66%</td><td>5.96%</td><td>+5%</td></tr></tbody></table>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"CPU change by consensus client\" src=\"https://docs.stereumlabs.com/assets/images/cc_cpu-368f9f6d056fb8f610c6aedcc6e3defc.png\" width=\"1415\" height=\"696\" class=\"img_ev3q\"></p>\n<div class=\"theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>Nimbus CPU anomaly</div><div class=\"admonitionContent_BuS1\"><p><strong>Nimbus</strong> stands out dramatically with a <strong>+257% CPU increase</strong> (2.63% → 9.40%). This suggests its PeerDAS implementation is currently more compute-intensive than competitors. The <code>nimbus + reth</code> pairing hit <strong>16.78%</strong> post-fork — the highest of any combination in the fleet. Nimbus operators should monitor their CPU headroom closely, especially on resource-constrained setups.</p></div></div>\n<p>On the positive side, <strong>Lighthouse</strong> was the only consensus client to <em>decrease</em> CPU usage (−13%), suggesting either an efficient PeerDAS implementation or concurrent optimizations shipped in its fork-compatible release.</p>\n<p><strong>Lodestar</strong> remained essentially flat (+1%), and <strong>Prysm</strong> (+11%), <strong>Teku</strong> (+5%), and <strong>Grandine</strong> (+21%) showed moderate increases — all within comfortable bounds for typical node hardware.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"per-execution-client-breakdown\">Per-execution-client breakdown<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#per-execution-client-breakdown\" class=\"hash-link\" aria-label=\"Direct link to Per-execution-client breakdown\" title=\"Direct link to Per-execution-client breakdown\" translate=\"no\">​</a></h3>\n<p>Execution clients saw a more uniform increase, consistent with the raised gas limit (EIP-7935) and new EVM opcodes (EOF):</p>\n<table><thead><tr><th>EC client</th><th>Before</th><th>After</th><th>Change</th></tr></thead><tbody><tr><td>Besu</td><td>2.58%</td><td>5.19%</td><td><strong>+101%</strong></td></tr><tr><td>Erigon</td><td>3.62%</td><td>5.83%</td><td>+61%</td></tr><tr><td>Ethrex</td><td>4.07%</td><td>6.04%</td><td>+48%</td></tr><tr><td>Geth</td><td>3.99%</td><td>6.53%</td><td><strong>+64%</strong></td></tr><tr><td>Nethermind</td><td>6.83%</td><td>5.08%</td><td><strong>−26%</strong></td></tr><tr><td>Reth</td><td>5.56%</td><td>7.89%</td><td>+42%</td></tr></tbody></table>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"CPU change by execution client\" src=\"https://docs.stereumlabs.com/assets/images/ec_cpu-7d2dfdd6d657c0fe0d5ed88e1ab25b53.png\" width=\"1415\" height=\"696\" class=\"img_ev3q\"></p>\n<p><strong>Besu</strong> (+101%) and <strong>Geth</strong> (+64%) saw the largest relative increases. For Besu, the doubling (from a very low 2.58% baseline) likely reflects the new gas limit activating code paths that were previously idle. Geth's increase is consistent with heavier block processing under the raised 60M gas ceiling.</p>\n<p><strong>Nethermind</strong> bucked the trend entirely with a <strong>−26% decrease</strong> — a surprising result that may indicate a coincidental version update with CPU optimizations during the measurement window.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-full-picture-cpu-heatmap-across-all-36-pairings\">The full picture: CPU heatmap across all 36 pairings<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#the-full-picture-cpu-heatmap-across-all-36-pairings\" class=\"hash-link\" aria-label=\"Direct link to The full picture: CPU heatmap across all 36 pairings\" title=\"Direct link to The full picture: CPU heatmap across all 36 pairings\" translate=\"no\">​</a></h3>\n<p>This heatmap shows the percentage change in CPU utilization for every CC×EC combination. Red means higher CPU after Fusaka, green means lower:</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"CPU utilization change per CC×EC pairing\" src=\"https://docs.stereumlabs.com/assets/images/cpu_heatmap-74964bdbd01959392a57e2849ded1f7c.png\" width=\"1416\" height=\"875\" class=\"img_ev3q\"></p>\n<p>The Nimbus row is unmistakable — deep red across all EC pairings, with <code>nimbus + ethrex</code> showing an extreme +1060% (from 0.83% to 9.63%, though the low baseline suggests the pairing may have been partially offline pre-fork). The Nethermind column is notably green across most CC pairings, reinforcing that Nethermind itself saw a concurrent optimization.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"memory-a-modest-but-welcome-decrease\">Memory: a modest but welcome decrease<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#memory-a-modest-but-welcome-decrease\" class=\"hash-link\" aria-label=\"Direct link to Memory: a modest but welcome decrease\" title=\"Direct link to Memory: a modest but welcome decrease\" translate=\"no\">​</a></h2>\n<p>Average memory usage dropped from <strong>6.06 GiB to 5.59 GiB</strong> (−8%) across the fleet. This aligns perfectly with PeerDAS's design: nodes no longer hold entire blobs in memory, only the sampled slices they need for verification.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"daily-trend-1\">Daily trend<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#daily-trend-1\" class=\"hash-link\" aria-label=\"Direct link to Daily trend\" title=\"Direct link to Daily trend\" translate=\"no\">​</a></h3>\n<p>The CPU + memory daily trend chart above also shows the memory trajectory (orange line). There's a sharp drop on <strong>December 4</strong> (from 6.22 to 5.26 GiB) — the first full day after the fork — followed by a gradual recovery over the next two weeks as caches and new protocol state accumulated. By December 18, memory was back to 6.27 GiB, suggesting the initial drop was partly transient (e.g., cleared blob caches from the pre-fork protocol).</p>\n<p>The 14-day average still shows a net decrease because the early post-fork days pull the average down significantly.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"per-consensus-client-breakdown-1\">Per-consensus-client breakdown<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#per-consensus-client-breakdown-1\" class=\"hash-link\" aria-label=\"Direct link to Per-consensus-client breakdown\" title=\"Direct link to Per-consensus-client breakdown\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>CC client</th><th>Before (GiB)</th><th>After (GiB)</th><th>Change</th></tr></thead><tbody><tr><td>Grandine</td><td>5.79</td><td>4.80</td><td><strong>−17%</strong></td></tr><tr><td>Lighthouse</td><td>5.41</td><td>5.42</td><td>0%</td></tr><tr><td>Lodestar</td><td>7.97</td><td>6.82</td><td>−14%</td></tr><tr><td>Nimbus</td><td>4.89</td><td>3.91</td><td><strong>−20%</strong></td></tr><tr><td>Prysm</td><td>6.14</td><td>6.51</td><td>+6%</td></tr><tr><td>Teku</td><td>6.39</td><td>6.24</td><td>−2%</td></tr></tbody></table>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Memory change by consensus client\" src=\"https://docs.stereumlabs.com/assets/images/cc_mem-7499fe4250f171c71386bfd77d51b1c9.png\" width=\"1415\" height=\"696\" class=\"img_ev3q\"></p>\n<p><strong>Nimbus</strong> (−20%) and <strong>Grandine</strong> (−17%) saw the largest memory reductions. Interestingly, Nimbus traded memory savings for CPU — a classic compute-vs-memory trade-off in its PeerDAS implementation.</p>\n<p><strong>Prysm</strong> was the only consensus client to <em>increase</em> memory (+6%), suggesting it keeps more sampling state in memory than peers. Given Prysm's CPU increase was moderate (+11%), this is a reasonable engineering choice.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"per-execution-client-breakdown-1\">Per-execution-client breakdown<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#per-execution-client-breakdown-1\" class=\"hash-link\" aria-label=\"Direct link to Per-execution-client breakdown\" title=\"Direct link to Per-execution-client breakdown\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>EC client</th><th>Before (GiB)</th><th>After (GiB)</th><th>Change</th></tr></thead><tbody><tr><td>Besu</td><td>6.59</td><td>4.31</td><td><strong>−35%</strong></td></tr><tr><td>Erigon</td><td>5.82</td><td>5.96</td><td>+2%</td></tr><tr><td>Ethrex</td><td>6.50</td><td>6.13</td><td>−6%</td></tr><tr><td>Geth</td><td>7.09</td><td>6.51</td><td>−8%</td></tr><tr><td>Nethermind</td><td>6.15</td><td>5.37</td><td>−13%</td></tr><tr><td>Reth</td><td>4.70</td><td>5.33</td><td>+13%</td></tr></tbody></table>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Memory change by execution client\" src=\"https://docs.stereumlabs.com/assets/images/ec_mem-55a0874c0fb4d37f68a7f284b82e9d2b.png\" width=\"1415\" height=\"696\" class=\"img_ev3q\"></p>\n<p><strong>Besu</strong> saw a dramatic <strong>−35% memory drop</strong> — from 6.59 to 4.31 GiB. This is the largest single-client change in the dataset and likely reflects aggressive cache invalidation during the fork transition. <strong>Reth</strong> moved in the opposite direction (+13%), possibly due to its database engine accumulating more state under the new protocol.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"disk-io-reads-halved-writes-slightly-up\">Disk I/O: reads halved, writes slightly up<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#disk-io-reads-halved-writes-slightly-up\" class=\"hash-link\" aria-label=\"Direct link to Disk I/O: reads halved, writes slightly up\" title=\"Direct link to Disk I/O: reads halved, writes slightly up\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"read-rate\">Read rate<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#read-rate\" class=\"hash-link\" aria-label=\"Direct link to Read rate\" title=\"Direct link to Read rate\" translate=\"no\">​</a></h3>\n<p>Disk reads dropped <strong>53%</strong> — from 2.58 to 1.21 MiB/s. This is directly attributable to PeerDAS: nodes no longer need to retrieve full blobs from disk for verification. The reduction was visible across nearly all pairings.</p>\n<p>Some notable per-pairing changes:</p>\n<ul>\n<li class=\"\"><strong>teku + ethrex</strong> went from 26.18 MiB/s (an extreme outlier pre-fork) to 2.86 MiB/s — a <strong>89% drop</strong></li>\n<li class=\"\"><strong>lighthouse + reth</strong> dropped from 1.71 to 0.55 MiB/s (−68%)</li>\n<li class=\"\"><strong>grandine + reth</strong> moved in the opposite direction — from 0.08 to 3.23 MiB/s — suggesting a change in Grandine's blob retrieval strategy for PeerDAS</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"write-rate\">Write rate<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#write-rate\" class=\"hash-link\" aria-label=\"Direct link to Write rate\" title=\"Direct link to Write rate\" translate=\"no\">​</a></h3>\n<p>Disk writes increased <strong>11%</strong> — from 1.73 to 1.92 MiB/s. The increase is modest and likely comes from:</p>\n<ol>\n<li class=\"\"><strong>PeerDAS sampling metadata</strong> — nodes now store sampling proofs and column indices</li>\n<li class=\"\"><strong>EOF state changes</strong> — the EVM Object Format introduces new bytecode validation and storage patterns</li>\n<li class=\"\"><strong>Higher gas limit</strong> — more transactions per block means more state writes</li>\n</ol>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Disk I/O rate change\" src=\"https://docs.stereumlabs.com/assets/images/disk_io-7ad5e3f1e9177cc2791083cb1a709622.png\" width=\"1055\" height=\"606\" class=\"img_ev3q\"></p>\n<p>This is a small overhead relative to the substantial read savings.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"full-36-pairing-matrices\">Full 36-pairing matrices<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#full-36-pairing-matrices\" class=\"hash-link\" aria-label=\"Direct link to Full 36-pairing matrices\" title=\"Direct link to Full 36-pairing matrices\" translate=\"no\">​</a></h2>\n<p>For the detail-oriented, here are the complete CPU and memory matrices across all CC×EC combinations.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"cpu-utilization--before-fusaka-\">CPU utilization — before Fusaka (%)<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#cpu-utilization--before-fusaka-\" class=\"hash-link\" aria-label=\"Direct link to CPU utilization — before Fusaka (%)\" title=\"Direct link to CPU utilization — before Fusaka (%)\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>CC \\ EC</th><th>Besu</th><th>Erigon</th><th>Ethrex</th><th>Geth</th><th>Nethermind</th><th>Reth</th></tr></thead><tbody><tr><td>Grandine</td><td>2.02</td><td>4.04</td><td>4.92</td><td>5.32</td><td>11.25</td><td>7.48</td></tr><tr><td>Lighthouse</td><td>2.39</td><td>3.20</td><td>2.74</td><td>3.65</td><td>5.20</td><td>4.43</td></tr><tr><td>Lodestar</td><td>2.32</td><td>3.75</td><td>9.62</td><td>3.66</td><td>7.68</td><td>7.73</td></tr><tr><td>Nimbus</td><td>1.41</td><td>2.42</td><td>0.83</td><td>2.40</td><td>5.32</td><td>3.40</td></tr><tr><td>Prysm</td><td>2.58</td><td>3.56</td><td>3.42</td><td>3.35</td><td>4.95</td><td>7.02</td></tr><tr><td>Teku</td><td>4.74</td><td>4.63</td><td>4.23</td><td>5.55</td><td>8.81</td><td>4.11</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"cpu-utilization--after-fusaka-\">CPU utilization — after Fusaka (%)<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#cpu-utilization--after-fusaka-\" class=\"hash-link\" aria-label=\"Direct link to CPU utilization — after Fusaka (%)\" title=\"Direct link to CPU utilization — after Fusaka (%)\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>CC \\ EC</th><th>Besu</th><th>Erigon</th><th>Ethrex</th><th>Geth</th><th>Nethermind</th><th>Reth</th></tr></thead><tbody><tr><td>Grandine</td><td>5.54</td><td>7.28</td><td>6.58</td><td>7.71</td><td>6.62</td><td>9.05</td></tr><tr><td>Lighthouse</td><td>1.28</td><td>1.89</td><td>3.87</td><td>4.64</td><td>3.98</td><td>4.13</td></tr><tr><td>Lodestar</td><td>8.88</td><td>5.69</td><td>5.42</td><td>5.37</td><td>3.46</td><td>6.27</td></tr><tr><td>Nimbus</td><td>6.57</td><td>8.21</td><td>9.63</td><td>8.46</td><td>6.77</td><td>16.78</td></tr><tr><td>Prysm</td><td>4.00</td><td>5.17</td><td>4.42</td><td>5.05</td><td>4.11</td><td>6.40</td></tr><tr><td>Teku</td><td>5.37</td><td>5.97</td><td>7.36</td><td>7.08</td><td>4.98</td><td>5.03</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"memory-usage--before-fusaka-gib\">Memory usage — before Fusaka (GiB)<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#memory-usage--before-fusaka-gib\" class=\"hash-link\" aria-label=\"Direct link to Memory usage — before Fusaka (GiB)\" title=\"Direct link to Memory usage — before Fusaka (GiB)\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>CC \\ EC</th><th>Besu</th><th>Erigon</th><th>Ethrex</th><th>Geth</th><th>Nethermind</th><th>Reth</th></tr></thead><tbody><tr><td>Grandine</td><td>6.12</td><td>5.70</td><td>5.16</td><td>6.18</td><td>7.15</td><td>4.46</td></tr><tr><td>Lighthouse</td><td>6.15</td><td>5.01</td><td>6.52</td><td>6.73</td><td>4.92</td><td>4.40</td></tr><tr><td>Lodestar</td><td>7.27</td><td>6.64</td><td>11.33</td><td>7.76</td><td>7.35</td><td>7.46</td></tr><tr><td>Nimbus</td><td>5.66</td><td>5.21</td><td>2.94</td><td>6.42</td><td>5.94</td><td>3.17</td></tr><tr><td>Prysm</td><td>6.31</td><td>6.08</td><td>8.42</td><td>6.70</td><td>5.66</td><td>4.28</td></tr><tr><td>Teku</td><td>8.01</td><td>6.51</td><td>4.59</td><td>8.74</td><td>7.20</td><td>4.93</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"memory-usage--after-fusaka-gib\">Memory usage — after Fusaka (GiB)<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#memory-usage--after-fusaka-gib\" class=\"hash-link\" aria-label=\"Direct link to Memory usage — after Fusaka (GiB)\" title=\"Direct link to Memory usage — after Fusaka (GiB)\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>CC \\ EC</th><th>Besu</th><th>Erigon</th><th>Ethrex</th><th>Geth</th><th>Nethermind</th><th>Reth</th></tr></thead><tbody><tr><td>Grandine</td><td>3.68</td><td>5.59</td><td>5.48</td><td>5.07</td><td>4.43</td><td>4.96</td></tr><tr><td>Lighthouse</td><td>2.48</td><td>3.57</td><td>7.36</td><td>7.10</td><td>5.58</td><td>6.41</td></tr><tr><td>Lodestar</td><td>5.61</td><td>7.30</td><td>7.05</td><td>8.21</td><td>5.45</td><td>7.32</td></tr><tr><td>Nimbus</td><td>2.24</td><td>5.74</td><td>3.29</td><td>4.73</td><td>4.97</td><td>2.47</td></tr><tr><td>Prysm</td><td>6.35</td><td>6.95</td><td>7.05</td><td>7.33</td><td>5.22</td><td>6.18</td></tr><tr><td>Teku</td><td>4.74</td><td>5.96</td><td>6.26</td><td>8.67</td><td>7.69</td><td>4.14</td></tr></tbody></table>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"things-to-watch\">Things to watch<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#things-to-watch\" class=\"hash-link\" aria-label=\"Direct link to Things to watch\" title=\"Direct link to Things to watch\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"nimbus-cpu-trajectory\">Nimbus CPU trajectory<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#nimbus-cpu-trajectory\" class=\"hash-link\" aria-label=\"Direct link to Nimbus CPU trajectory\" title=\"Direct link to Nimbus CPU trajectory\" translate=\"no\">​</a></h3>\n<p>The +257% CPU increase on Nimbus deserves monitoring over subsequent weeks and versions. If this is a temporary bootstrapping cost (PeerDAS column sync, initial sampling table construction), it should decline. If it persists, Nimbus operators on lower-spec hardware may need to re-evaluate their headroom.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"bpo-2-effects-not-captured-here\">BPO-2 effects (not captured here)<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#bpo-2-effects-not-captured-here\" class=\"hash-link\" aria-label=\"Direct link to BPO-2 effects (not captured here)\" title=\"Direct link to BPO-2 effects (not captured here)\" translate=\"no\">​</a></h3>\n<p>BPO-2 was scheduled for late December 2025 to early January 2026, raising blob parameters from 10/15 to 14/21. Our post-fork window (Dec 4–18) captures BPO-1 but not BPO-2. A follow-up analysis with a wider window would reveal whether the second parameter increase added further CPU or bandwidth pressure.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"memory-recovery-trend\">Memory recovery trend<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#memory-recovery-trend\" class=\"hash-link\" aria-label=\"Direct link to Memory recovery trend\" title=\"Direct link to Memory recovery trend\" translate=\"no\">​</a></h3>\n<p>The sharp initial memory drop post-fork appears to be partly transient — memory was trending back upward by December 18. We'll continue monitoring whether this recovery plateaus below the pre-fork baseline or converges back to original levels.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-nimbus--ethrex-anomaly\">The nimbus + ethrex anomaly<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#the-nimbus--ethrex-anomaly\" class=\"hash-link\" aria-label=\"Direct link to The nimbus + ethrex anomaly\" title=\"Direct link to The nimbus + ethrex anomaly\" translate=\"no\">​</a></h3>\n<p>The <code>nimbus + ethrex</code> pairing showed anomalously low CPU pre-fork (0.83%), which may indicate the pairing was partially offline or in a degraded state during the pre-fork window. The post-fork value of 9.63% is more consistent with fleet norms, suggesting the pairing recovered during or after the fork transition.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"client-version-confounding\">Client version confounding<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#client-version-confounding\" class=\"hash-link\" aria-label=\"Direct link to Client version confounding\" title=\"Direct link to Client version confounding\" translate=\"no\">​</a></h3>\n<p>Client versions were not pinned across the fork boundary — some pairings may have undergone version upgrades alongside Fusaka. This means we cannot cleanly attribute all changes to the fork itself. In particular, Nethermind's −26% CPU decrease may reflect a version update rather than a Fusaka effect.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"bottom-line\">Bottom line<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#bottom-line\" class=\"hash-link\" aria-label=\"Direct link to Bottom line\" title=\"Direct link to Bottom line\" translate=\"no\">​</a></h2>\n<p>Fusaka delivered on its core promise for non-supernode operators: <strong>dramatically lower bandwidth requirements</strong> (−60% receive, −13% transmit) and <strong>modestly lower memory</strong> (−8%), at the cost of a <strong>moderate CPU increase</strong> (+30%) that remains well within typical hardware headroom. Disk reads dropped by half.</p>\n<p>For operators managing hosting costs, the network savings alone are significant — especially on cloud providers where egress is metered. The CPU overhead is real but manageable: even the worst-case fleet average post-fork (6.08%) leaves substantial headroom on modern hardware.</p>\n<p>The main action item is <strong>monitoring Nimbus deployments</strong> for elevated CPU, and <strong>tracking BPO-2 effects</strong> as blob capacity continues to expand.</p>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"appendix-promql-queries-used\">Appendix: PromQL queries used<a href=\"https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes#appendix-promql-queries-used\" class=\"hash-link\" aria-label=\"Direct link to Appendix: PromQL queries used\" title=\"Direct link to Appendix: PromQL queries used\" translate=\"no\">​</a></h2>\n<p>For reproducibility, here are the exact queries run against <code>prometheus-cold</code>:</p>\n<div class=\"language-promql codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockTitle_OeMC\">CPU utilization (non-idle) — per pairing</div><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-promql codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">avg by (cc_client, ec_client) (</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  avg_over_time(</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    (1 - rate(node_cpu_seconds_total{mode=\"idle\", role=~\"cc|ec\", cc_client!~\".*-super\"}[1h]))</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    [14d:1h]</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  )</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">)</span><br></span></code></pre></div></div>\n<div class=\"language-promql codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockTitle_OeMC\">Memory used (GiB) — per pairing</div><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-promql codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">avg by (cc_client, ec_client) (</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  avg_over_time(</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    (node_memory_MemTotal_bytes{role=~\"cc|ec\", cc_client!~\".*-super\"}</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">     - node_memory_MemAvailable_bytes{role=~\"cc|ec\", cc_client!~\".*-super\"})</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    [14d:1h]</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  )</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">) / 1024 / 1024 / 1024</span><br></span></code></pre></div></div>\n<div class=\"language-promql codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockTitle_OeMC\">Disk read rate (MiB/s) — per pairing</div><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-promql codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">avg by (cc_client, ec_client) (</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  avg_over_time(</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    rate(node_disk_read_bytes_total{role=~\"cc|ec\", cc_client!~\".*-super\"}[1h])</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    [14d:1h]</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  )</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">) / 1024 / 1024</span><br></span></code></pre></div></div>\n<div class=\"language-promql codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockTitle_OeMC\">Network receive rate (MiB/s) — per pairing</div><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-promql codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">avg by (cc_client, ec_client) (</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  avg_over_time(</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    rate(node_network_receive_bytes_total{role=~\"cc|ec\", cc_client!~\".*-super\",</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">         device!~\"lo|veth.*|docker.*|br.*\"}[1h])</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    [14d:1h]</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  )</span><br></span><span class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">) / 1024 / 1024</span><br></span></code></pre></div></div>\n<p><strong>Datasource:</strong> <code>prometheus-cold</code> (UID: <code>aez9ck4wz05q8e</code>, Org 6)</p>\n<p><strong>Before snapshot:</strong> instant query at <code>2025-12-03T00:00:00Z</code></p>\n<p><strong>After snapshot:</strong> instant query at <code>2025-12-18T00:00:00Z</code></p>\n<p><strong>Daily time series:</strong> range query from <code>2025-11-19T00:00:00Z</code> to <code>2025-12-18T00:00:00Z</code>, step = 86400s</p>",
            "url": "https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes",
            "title": "Fusaka hardfork: hardware impact on non-supernodes",
            "summary": "We measured CPU, memory, disk I/O, and network across all 36 CC×EC pairings on our non-supernode fleet — here's what the Fusaka hardfork actually did to hardware consumption.",
            "date_modified": "2026-03-30T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "AI",
                "analysis",
                "fusaka",
                "hardfork",
                "PeerDAS",
                "hardware",
                "resources"
            ]
        },
        {
            "id": "https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources",
            "content_html": "<p>Let's have a look at both versions of Prysm 7.1.1 and 7.1.2 and it's resource consumption</p>\n<p>We at StereumLabs run Prysm continuously across all six supported execution-layer clients — Besu, Erigon, Ethrex, Geth, Nethermind, and Reth — on isolated bare-metal nodes. When v7.1.2 landed, we pulled 90-day averages from our Prometheus-cold datasource to see exactly what changed. Here's the short version.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-improved\">What improved<a href=\"https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources#what-improved\" class=\"hash-link\" aria-label=\"Direct link to What improved\" title=\"Direct link to What improved\" translate=\"no\">​</a></h2>\n<p><strong>Memory is the clearest win.</strong> Process RSS dropped by 5.1% on average (3.36 → 3.19 GB), with the biggest gains when paired with Geth (−8.8%) and Besu (−7.8%). Heap in-use stayed flat, which points to the savings coming from outside the Go heap — likely reduced stack allocations or more efficient mmap regions.</p>\n<p><strong>Block processing time also improved significantly</strong> — down 25% on average (142 → 107 ms). The headline number is dominated by the Erigon pairing, which went from 403 ms to 90 ms (−78%). For the production-grade trio of Geth, Nethermind, and Reth, results were stable to slightly better.</p>\n<p><strong>Network connectivity was unaffected.</strong> Average libp2p peer count held at ~71 across both versions.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-to-watch\">What to watch<a href=\"https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources#what-to-watch\" class=\"hash-link\" aria-label=\"Direct link to What to watch\" title=\"Direct link to What to watch\" translate=\"no\">​</a></h2>\n<p>CPU utilization showed a mixed picture that varies by EL pairing — Reth dropped 21%, while Besu increased 28%. Because we measure system-wide CPU across the full node, EL-side changes and PeerDAS load from the Fusaka hard fork both contribute noise here. No clear regression in Prysm itself.</p>\n<p>GC pause duration ticked up marginally (+5.5%, from 0.735 to 0.775 ms) — well within acceptable bounds and unlikely to affect attestation or block proposal timelines.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"bottom-line\">Bottom line<a href=\"https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources#bottom-line\" class=\"hash-link\" aria-label=\"Direct link to Bottom line\" title=\"Direct link to Bottom line\" translate=\"no\">​</a></h2>\n<p>v7.1.2 is a straightforward upgrade for production operators: lower memory footprint, faster block processing on the pairings that matter most, and no regressions in network behavior. If you're running Ethrex, treat its +138% block processing regression as an outlier specific to that experimental client, not a Prysm issue.</p>\n<hr>\n<p>📄 <strong>Full report with per-client breakdowns and methodology:</strong> <a href=\"https://docs.stereumlabs.com/assets/files/prysm_resource_report-b1359b2c8ced083dc5d2dd56bc9abb86.pdf\" target=\"_blank\" class=\"\">Download PDF</a></p>",
            "url": "https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources",
            "title": "Prysm v7.1.1 & 7.1.2 resources",
            "summary": "Let's have a look at both versions of Prysm 7.1.1 and 7.1.2 and it's resource consumption",
            "date_modified": "2026-03-25T00:00:00.000Z",
            "author": {
                "name": "Stefan Kobrc"
            },
            "tags": [
                "AI",
                "analysis",
                "prysm"
            ]
        }
    ]
}